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 19147daec5SRichard Marian Thomaiyar #include <boost/container/flat_map.hpp> 20f267a67dSYong Li #include <filesystem> 211b74a210SRichard Marian Thomaiyar #include <fstream> 22a3702c1fSVernon Mauery #include <ipmid/api.hpp> 23a3702c1fSVernon Mauery #include <manufacturingcommands.hpp> 24a3702c1fSVernon Mauery #include <oemcommands.hpp> 25a3702c1fSVernon Mauery 26a3702c1fSVernon Mauery namespace ipmi 27a3702c1fSVernon Mauery { 28a3702c1fSVernon Mauery 29a3702c1fSVernon Mauery Manufacturing mtm; 30a3702c1fSVernon Mauery 31a3702c1fSVernon Mauery static auto revertTimeOut = 32a3702c1fSVernon Mauery std::chrono::duration_cast<std::chrono::microseconds>( 33a3702c1fSVernon Mauery std::chrono::seconds(60)); // 1 minute timeout 34a3702c1fSVernon Mauery 35f267a67dSYong Li static constexpr uint8_t slotAddressTypeBus = 0; 36f267a67dSYong Li static constexpr uint8_t slotAddressTypeUniqueid = 1; 37f267a67dSYong Li static constexpr uint8_t slotI2CMaxReadSize = 35; 38f267a67dSYong Li 39a3702c1fSVernon Mauery static constexpr const char* callbackMgrService = 40a3702c1fSVernon Mauery "xyz.openbmc_project.CallbackManager"; 41a3702c1fSVernon Mauery static constexpr const char* callbackMgrIntf = 42a3702c1fSVernon Mauery "xyz.openbmc_project.CallbackManager"; 43a3702c1fSVernon Mauery static constexpr const char* callbackMgrObjPath = 44a3702c1fSVernon Mauery "/xyz/openbmc_project/CallbackManager"; 45a3702c1fSVernon Mauery static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate"; 46a3702c1fSVernon Mauery 47a3702c1fSVernon Mauery const static constexpr char* systemDService = "org.freedesktop.systemd1"; 48a3702c1fSVernon Mauery const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1"; 49a3702c1fSVernon Mauery const static constexpr char* systemDMgrIntf = 50a3702c1fSVernon Mauery "org.freedesktop.systemd1.Manager"; 51a3702c1fSVernon Mauery const static constexpr char* pidControlService = "phosphor-pid-control.service"; 52a3702c1fSVernon Mauery 53357ddc74SRichard Marian Thomaiyar static inline Cc resetMtmTimer(ipmi::Context::ptr ctx) 54666dd01cSRichard Marian Thomaiyar { 55666dd01cSRichard Marian Thomaiyar boost::system::error_code ec; 56357ddc74SRichard Marian Thomaiyar ctx->bus->yield_method_call<>(ctx->yield, ec, specialModeService, 57666dd01cSRichard Marian Thomaiyar specialModeObjPath, specialModeIntf, 58666dd01cSRichard Marian Thomaiyar "ResetTimer"); 59666dd01cSRichard Marian Thomaiyar if (ec) 60666dd01cSRichard Marian Thomaiyar { 61666dd01cSRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 62666dd01cSRichard Marian Thomaiyar "Failed to reset the manufacturing mode timer"); 63666dd01cSRichard Marian Thomaiyar return ccUnspecifiedError; 64666dd01cSRichard Marian Thomaiyar } 65666dd01cSRichard Marian Thomaiyar return ccSuccess; 66666dd01cSRichard Marian Thomaiyar } 67666dd01cSRichard Marian Thomaiyar 6838d2b5a6SJason M. Bills int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path) 69a3702c1fSVernon Mauery { 7038d2b5a6SJason M. Bills switch (signal) 7138d2b5a6SJason M. Bills { 7238d2b5a6SJason M. Bills case SmSignalGet::smPowerButton: 7338d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/power"; 7438d2b5a6SJason M. Bills break; 7538d2b5a6SJason M. Bills case SmSignalGet::smResetButton: 7638d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/reset"; 7738d2b5a6SJason M. Bills break; 7838d2b5a6SJason M. Bills case SmSignalGet::smNMIButton: 7938d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/nmi"; 8038d2b5a6SJason M. Bills break; 818e5e2b04SRichard Marian Thomaiyar case SmSignalGet::smIdentifyButton: 828e5e2b04SRichard Marian Thomaiyar path = "/xyz/openbmc_project/chassis/buttons/id"; 838e5e2b04SRichard Marian Thomaiyar break; 8438d2b5a6SJason M. Bills default: 8538d2b5a6SJason M. Bills return -1; 8638d2b5a6SJason M. Bills break; 8738d2b5a6SJason M. Bills } 8838d2b5a6SJason M. Bills return 0; 89a3702c1fSVernon Mauery } 90a3702c1fSVernon Mauery 9137890392SPatrick Venture ipmi_ret_t ledStoreAndSet(SmSignalSet signal, const std::string& setState) 92a3702c1fSVernon Mauery { 93a3702c1fSVernon Mauery LedProperty* ledProp = mtm.findLedProperty(signal); 94a3702c1fSVernon Mauery if (ledProp == nullptr) 95a3702c1fSVernon Mauery { 96a3702c1fSVernon Mauery return IPMI_CC_INVALID_FIELD_REQUEST; 97a3702c1fSVernon Mauery } 98a3702c1fSVernon Mauery 99a3702c1fSVernon Mauery std::string ledName = ledProp->getName(); 100a3702c1fSVernon Mauery std::string ledService = ledServicePrefix + ledName; 101a3702c1fSVernon Mauery std::string ledPath = ledPathPrefix + ledName; 102a3702c1fSVernon Mauery ipmi::Value presentState; 103a3702c1fSVernon Mauery 104a3702c1fSVernon Mauery if (false == ledProp->getLock()) 105a3702c1fSVernon Mauery { 106a3702c1fSVernon Mauery if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf, 107a3702c1fSVernon Mauery "State", &presentState) != 0) 108a3702c1fSVernon Mauery { 109a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 110a3702c1fSVernon Mauery } 111a3702c1fSVernon Mauery ledProp->setPrevState(std::get<std::string>(presentState)); 112a3702c1fSVernon Mauery ledProp->setLock(true); 113a3702c1fSVernon Mauery if (signal == SmSignalSet::smPowerFaultLed || 114a3702c1fSVernon Mauery signal == SmSignalSet::smSystemReadyLed) 115a3702c1fSVernon Mauery { 116a3702c1fSVernon Mauery mtm.revertLedCallback = true; 117a3702c1fSVernon Mauery } 118a3702c1fSVernon Mauery } 11938d2b5a6SJason M. Bills if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 120a3702c1fSVernon Mauery ledStateStr + setState) != 0) 121a3702c1fSVernon Mauery { 122a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 123a3702c1fSVernon Mauery } 124a3702c1fSVernon Mauery return IPMI_CC_OK; 125a3702c1fSVernon Mauery } 126a3702c1fSVernon Mauery 127a3702c1fSVernon Mauery ipmi_ret_t ledRevert(SmSignalSet signal) 128a3702c1fSVernon Mauery { 129a3702c1fSVernon Mauery LedProperty* ledProp = mtm.findLedProperty(signal); 130a3702c1fSVernon Mauery if (ledProp == nullptr) 131a3702c1fSVernon Mauery { 132a3702c1fSVernon Mauery return IPMI_CC_INVALID_FIELD_REQUEST; 133a3702c1fSVernon Mauery } 134a3702c1fSVernon Mauery if (true == ledProp->getLock()) 135a3702c1fSVernon Mauery { 136a3702c1fSVernon Mauery ledProp->setLock(false); 137a3702c1fSVernon Mauery if (signal == SmSignalSet::smPowerFaultLed || 138a3702c1fSVernon Mauery signal == SmSignalSet::smSystemReadyLed) 139a3702c1fSVernon Mauery { 140a3702c1fSVernon Mauery try 141a3702c1fSVernon Mauery { 142a3702c1fSVernon Mauery ipmi::method_no_args::callDbusMethod( 143a3702c1fSVernon Mauery *getSdBus(), callbackMgrService, callbackMgrObjPath, 144a3702c1fSVernon Mauery callbackMgrIntf, retriggerLedUpdate); 145a3702c1fSVernon Mauery } 146a3702c1fSVernon Mauery catch (sdbusplus::exception_t& e) 147a3702c1fSVernon Mauery { 148a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 149a3702c1fSVernon Mauery } 150a3702c1fSVernon Mauery mtm.revertLedCallback = false; 151a3702c1fSVernon Mauery } 152a3702c1fSVernon Mauery else 153a3702c1fSVernon Mauery { 154a3702c1fSVernon Mauery std::string ledName = ledProp->getName(); 155a3702c1fSVernon Mauery std::string ledService = ledServicePrefix + ledName; 156a3702c1fSVernon Mauery std::string ledPath = ledPathPrefix + ledName; 15738d2b5a6SJason M. Bills if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 15838d2b5a6SJason M. Bills ledProp->getPrevState()) != 0) 159a3702c1fSVernon Mauery { 160a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 161a3702c1fSVernon Mauery } 162a3702c1fSVernon Mauery } 163a3702c1fSVernon Mauery } 164a3702c1fSVernon Mauery return IPMI_CC_OK; 165a3702c1fSVernon Mauery } 166a3702c1fSVernon Mauery 167a3702c1fSVernon Mauery void Manufacturing::initData() 168a3702c1fSVernon Mauery { 169a3702c1fSVernon Mauery ledPropertyList.push_back( 170a3702c1fSVernon Mauery LedProperty(SmSignalSet::smPowerFaultLed, "status_amber")); 171a3702c1fSVernon Mauery ledPropertyList.push_back( 172a3702c1fSVernon Mauery LedProperty(SmSignalSet::smSystemReadyLed, "status_green")); 173a3702c1fSVernon Mauery ledPropertyList.push_back( 174a3702c1fSVernon Mauery LedProperty(SmSignalSet::smIdentifyLed, "identify")); 175a3702c1fSVernon Mauery } 176a3702c1fSVernon Mauery 177a3702c1fSVernon Mauery void Manufacturing::revertTimerHandler() 178a3702c1fSVernon Mauery { 179ae13ac62SRichard Marian Thomaiyar 180ae13ac62SRichard Marian Thomaiyar #ifdef BMC_VALIDATION_UNSECURE_FEATURE 181ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::valUnsecure) 182ae13ac62SRichard Marian Thomaiyar { 183ae13ac62SRichard Marian Thomaiyar // Don't revert the behaviour for validation unsecure mode. 184ae13ac62SRichard Marian Thomaiyar return; 185ae13ac62SRichard Marian Thomaiyar } 186ae13ac62SRichard Marian Thomaiyar #endif 187a3702c1fSVernon Mauery if (revertFanPWM) 188a3702c1fSVernon Mauery { 189a3702c1fSVernon Mauery revertFanPWM = false; 190a3702c1fSVernon Mauery disablePidControlService(false); 191a3702c1fSVernon Mauery } 192a3702c1fSVernon Mauery 193d872a4a4SAyushi Smriti if (mtmTestBeepFd != -1) 194d872a4a4SAyushi Smriti { 195d872a4a4SAyushi Smriti ::close(mtmTestBeepFd); 196d872a4a4SAyushi Smriti mtmTestBeepFd = -1; 197d872a4a4SAyushi Smriti } 198d872a4a4SAyushi Smriti 199a3702c1fSVernon Mauery for (const auto& ledProperty : ledPropertyList) 200a3702c1fSVernon Mauery { 201a3702c1fSVernon Mauery const std::string& ledName = ledProperty.getName(); 202a3702c1fSVernon Mauery ledRevert(ledProperty.getSignal()); 203a3702c1fSVernon Mauery } 204a3702c1fSVernon Mauery } 205a3702c1fSVernon Mauery 206a3702c1fSVernon Mauery Manufacturing::Manufacturing() : 207a3702c1fSVernon Mauery revertTimer([&](void) { revertTimerHandler(); }) 208a3702c1fSVernon Mauery { 209a3702c1fSVernon Mauery initData(); 210a3702c1fSVernon Mauery } 211a3702c1fSVernon Mauery 21238d2b5a6SJason M. Bills int8_t Manufacturing::getProperty(const std::string& service, 21338d2b5a6SJason M. Bills const std::string& path, 21438d2b5a6SJason M. Bills const std::string& interface, 21538d2b5a6SJason M. Bills const std::string& propertyName, 21638d2b5a6SJason M. Bills ipmi::Value* reply) 217a3702c1fSVernon Mauery { 218a3702c1fSVernon Mauery try 219a3702c1fSVernon Mauery { 22038d2b5a6SJason M. Bills *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface, 22138d2b5a6SJason M. Bills propertyName); 222a3702c1fSVernon Mauery } 223a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& e) 224a3702c1fSVernon Mauery { 225a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 226a3702c1fSVernon Mauery "ERROR: getProperty"); 227a3702c1fSVernon Mauery return -1; 228a3702c1fSVernon Mauery } 229a3702c1fSVernon Mauery 230a3702c1fSVernon Mauery return 0; 231a3702c1fSVernon Mauery } 232a3702c1fSVernon Mauery 23338d2b5a6SJason M. Bills int8_t Manufacturing::setProperty(const std::string& service, 23438d2b5a6SJason M. Bills const std::string& path, 23538d2b5a6SJason M. Bills const std::string& interface, 23638d2b5a6SJason M. Bills const std::string& propertyName, 23738d2b5a6SJason M. Bills ipmi::Value value) 238a3702c1fSVernon Mauery { 239a3702c1fSVernon Mauery try 240a3702c1fSVernon Mauery { 24138d2b5a6SJason M. Bills ipmi::setDbusProperty(*getSdBus(), service, path, interface, 242a3702c1fSVernon Mauery propertyName, value); 243a3702c1fSVernon Mauery } 244a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& e) 245a3702c1fSVernon Mauery { 246a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 247a3702c1fSVernon Mauery "ERROR: setProperty"); 248a3702c1fSVernon Mauery return -1; 249a3702c1fSVernon Mauery } 250a3702c1fSVernon Mauery 251a3702c1fSVernon Mauery return 0; 252a3702c1fSVernon Mauery } 253a3702c1fSVernon Mauery 254a3702c1fSVernon Mauery int8_t Manufacturing::disablePidControlService(const bool disable) 255a3702c1fSVernon Mauery { 256a3702c1fSVernon Mauery try 257a3702c1fSVernon Mauery { 258a3702c1fSVernon Mauery auto dbus = getSdBus(); 259a3702c1fSVernon Mauery auto method = dbus->new_method_call(systemDService, systemDObjPath, 260a3702c1fSVernon Mauery systemDMgrIntf, 261a3702c1fSVernon Mauery disable ? "StopUnit" : "StartUnit"); 262a3702c1fSVernon Mauery method.append(pidControlService, "replace"); 263a3702c1fSVernon Mauery auto reply = dbus->call(method); 264a3702c1fSVernon Mauery } 265a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& e) 266a3702c1fSVernon Mauery { 267a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 268a3702c1fSVernon Mauery "ERROR: phosphor-pid-control service start or stop failed"); 269a3702c1fSVernon Mauery return -1; 270a3702c1fSVernon Mauery } 271a3702c1fSVernon Mauery return 0; 272a3702c1fSVernon Mauery } 273a3702c1fSVernon Mauery 27438d2b5a6SJason M. Bills ipmi::RspType<uint8_t, // Signal value 27538d2b5a6SJason M. Bills std::optional<uint16_t> // Fan tach value 27638d2b5a6SJason M. Bills > 277357ddc74SRichard Marian Thomaiyar appMTMGetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte, 278147daec5SRichard Marian Thomaiyar uint8_t instance, uint8_t actionByte) 279a3702c1fSVernon Mauery { 280e0511e5fSAyushi Smriti // mfg filter logic is used to allow MTM get signal command only in 281e0511e5fSAyushi Smriti // manfacturing mode. 28238d2b5a6SJason M. Bills 28338d2b5a6SJason M. Bills SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte); 28438d2b5a6SJason M. Bills SmActionGet action = static_cast<SmActionGet>(actionByte); 28538d2b5a6SJason M. Bills 28638d2b5a6SJason M. Bills switch (signalType) 28738d2b5a6SJason M. Bills { 28898705b39Sanil kumar appana case SmSignalGet::smChassisIntrusion: 28998705b39Sanil kumar appana { 29098705b39Sanil kumar appana ipmi::Value reply; 29198705b39Sanil kumar appana if (mtm.getProperty(intrusionService, intrusionPath, intrusionIntf, 29298705b39Sanil kumar appana "Status", &reply) < 0) 29398705b39Sanil kumar appana { 29498705b39Sanil kumar appana return ipmi::responseInvalidFieldRequest(); 29598705b39Sanil kumar appana } 29698705b39Sanil kumar appana std::string* intrusionStatus = std::get_if<std::string>(&reply); 29798705b39Sanil kumar appana if (!intrusionStatus) 29898705b39Sanil kumar appana { 29998705b39Sanil kumar appana return ipmi::responseUnspecifiedError(); 30098705b39Sanil kumar appana } 30198705b39Sanil kumar appana 30298705b39Sanil kumar appana uint8_t status = 0; 30398705b39Sanil kumar appana if (!intrusionStatus->compare("Normal")) 30498705b39Sanil kumar appana { 30598705b39Sanil kumar appana status = static_cast<uint8_t>(IntrusionStatus::normal); 30698705b39Sanil kumar appana } 30798705b39Sanil kumar appana else if (!intrusionStatus->compare("HardwareIntrusion")) 30898705b39Sanil kumar appana { 30998705b39Sanil kumar appana status = 31098705b39Sanil kumar appana static_cast<uint8_t>(IntrusionStatus::hardwareIntrusion); 31198705b39Sanil kumar appana } 31298705b39Sanil kumar appana else if (!intrusionStatus->compare("TamperingDetected")) 31398705b39Sanil kumar appana { 31498705b39Sanil kumar appana status = 31598705b39Sanil kumar appana static_cast<uint8_t>(IntrusionStatus::tamperingDetected); 31698705b39Sanil kumar appana } 31798705b39Sanil kumar appana else 31898705b39Sanil kumar appana { 31998705b39Sanil kumar appana return ipmi::responseUnspecifiedError(); 32098705b39Sanil kumar appana } 32198705b39Sanil kumar appana return ipmi::responseSuccess(status, std::nullopt); 32298705b39Sanil kumar appana } 32338d2b5a6SJason M. Bills case SmSignalGet::smFanPwmGet: 32438d2b5a6SJason M. Bills { 325a3702c1fSVernon Mauery ipmi::Value reply; 326147daec5SRichard Marian Thomaiyar std::string fullPath = fanPwmPath + std::to_string(instance + 1); 32738d2b5a6SJason M. Bills if (mtm.getProperty(fanService, fullPath, fanIntf, "Value", 32838d2b5a6SJason M. Bills &reply) < 0) 32938d2b5a6SJason M. Bills { 33038d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 33138d2b5a6SJason M. Bills } 33238d2b5a6SJason M. Bills double* doubleVal = std::get_if<double>(&reply); 33338d2b5a6SJason M. Bills if (doubleVal == nullptr) 33438d2b5a6SJason M. Bills { 33538d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 33638d2b5a6SJason M. Bills } 33738d2b5a6SJason M. Bills uint8_t sensorVal = std::round(*doubleVal); 338357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 33938d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, std::nullopt); 34038d2b5a6SJason M. Bills } 34138d2b5a6SJason M. Bills break; 34238d2b5a6SJason M. Bills case SmSignalGet::smFanTachometerGet: 34338d2b5a6SJason M. Bills { 344147daec5SRichard Marian Thomaiyar boost::system::error_code ec; 345147daec5SRichard Marian Thomaiyar using objFlatMap = boost::container::flat_map< 346147daec5SRichard Marian Thomaiyar std::string, boost::container::flat_map< 347147daec5SRichard Marian Thomaiyar std::string, std::vector<std::string>>>; 348147daec5SRichard Marian Thomaiyar 349357ddc74SRichard Marian Thomaiyar auto flatMap = ctx->bus->yield_method_call<objFlatMap>( 350357ddc74SRichard Marian Thomaiyar ctx->yield, ec, "xyz.openbmc_project.ObjectMapper", 351147daec5SRichard Marian Thomaiyar "/xyz/openbmc_project/object_mapper", 352147daec5SRichard Marian Thomaiyar "xyz.openbmc_project.ObjectMapper", "GetSubTree", 353147daec5SRichard Marian Thomaiyar fanTachBasePath, 0, std::array<const char*, 1>{fanIntf}); 354147daec5SRichard Marian Thomaiyar if (ec) 355147daec5SRichard Marian Thomaiyar { 356147daec5SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 357147daec5SRichard Marian Thomaiyar "Failed to query fan tach sub tree objects"); 358147daec5SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 359147daec5SRichard Marian Thomaiyar } 360147daec5SRichard Marian Thomaiyar if (instance >= flatMap.size()) 36138d2b5a6SJason M. Bills { 36238d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 36338d2b5a6SJason M. Bills } 364147daec5SRichard Marian Thomaiyar auto itr = flatMap.nth(instance); 36538d2b5a6SJason M. Bills ipmi::Value reply; 366147daec5SRichard Marian Thomaiyar if (mtm.getProperty(fanService, itr->first, fanIntf, "Value", 36738d2b5a6SJason M. Bills &reply) < 0) 36838d2b5a6SJason M. Bills { 36938d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 37038d2b5a6SJason M. Bills } 37138d2b5a6SJason M. Bills 37238d2b5a6SJason M. Bills double* doubleVal = std::get_if<double>(&reply); 37338d2b5a6SJason M. Bills if (doubleVal == nullptr) 37438d2b5a6SJason M. Bills { 37538d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 37638d2b5a6SJason M. Bills } 37738d2b5a6SJason M. Bills uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT; 37838d2b5a6SJason M. Bills std::optional<uint16_t> fanTach = std::round(*doubleVal); 37938d2b5a6SJason M. Bills 380357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 38138d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, fanTach); 38238d2b5a6SJason M. Bills } 38338d2b5a6SJason M. Bills break; 3848e5e2b04SRichard Marian Thomaiyar case SmSignalGet::smIdentifyButton: 3858e5e2b04SRichard Marian Thomaiyar { 3868e5e2b04SRichard Marian Thomaiyar if (action == SmActionGet::revert || action == SmActionGet::ignore) 3878e5e2b04SRichard Marian Thomaiyar { 3888e5e2b04SRichard Marian Thomaiyar // ButtonMasked property is not supported for ID button as it is 3898e5e2b04SRichard Marian Thomaiyar // unnecessary. Hence if requested for revert / ignore, override 3908e5e2b04SRichard Marian Thomaiyar // it to sample action to make tools happy. 3918e5e2b04SRichard Marian Thomaiyar action = SmActionGet::sample; 3928e5e2b04SRichard Marian Thomaiyar } 3938e5e2b04SRichard Marian Thomaiyar // fall-through 3948e5e2b04SRichard Marian Thomaiyar } 39538d2b5a6SJason M. Bills case SmSignalGet::smResetButton: 39638d2b5a6SJason M. Bills case SmSignalGet::smPowerButton: 39738d2b5a6SJason M. Bills case SmSignalGet::smNMIButton: 39838d2b5a6SJason M. Bills { 39938d2b5a6SJason M. Bills std::string path; 40038d2b5a6SJason M. Bills if (getGpioPathForSmSignal(signalType, path) < 0) 40138d2b5a6SJason M. Bills { 40238d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 40338d2b5a6SJason M. Bills } 404a3702c1fSVernon Mauery 405a3702c1fSVernon Mauery switch (action) 406a3702c1fSVernon Mauery { 407a3702c1fSVernon Mauery case SmActionGet::sample: 408a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 409a3702c1fSVernon Mauery "case SmActionGet::sample"); 410a3702c1fSVernon Mauery break; 411a3702c1fSVernon Mauery case SmActionGet::ignore: 412a3702c1fSVernon Mauery { 413a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 414a3702c1fSVernon Mauery "case SmActionGet::ignore"); 41538d2b5a6SJason M. Bills if (mtm.setProperty(buttonService, path, buttonIntf, 41638d2b5a6SJason M. Bills "ButtonMasked", true) < 0) 417a3702c1fSVernon Mauery { 41838d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 419a3702c1fSVernon Mauery } 420a3702c1fSVernon Mauery } 421a3702c1fSVernon Mauery break; 422a3702c1fSVernon Mauery case SmActionGet::revert: 423a3702c1fSVernon Mauery { 424a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 425a3702c1fSVernon Mauery "case SmActionGet::revert"); 42638d2b5a6SJason M. Bills if (mtm.setProperty(buttonService, path, buttonIntf, 42738d2b5a6SJason M. Bills "ButtonMasked", false) < 0) 428a3702c1fSVernon Mauery { 42938d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 430a3702c1fSVernon Mauery } 431a3702c1fSVernon Mauery } 432a3702c1fSVernon Mauery break; 433a3702c1fSVernon Mauery 434a3702c1fSVernon Mauery default: 43538d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 436a3702c1fSVernon Mauery break; 437a3702c1fSVernon Mauery } 438a3702c1fSVernon Mauery 439a3702c1fSVernon Mauery ipmi::Value reply; 44038d2b5a6SJason M. Bills if (mtm.getProperty(buttonService, path, buttonIntf, 44138d2b5a6SJason M. Bills "ButtonPressed", &reply) < 0) 442a3702c1fSVernon Mauery { 44338d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 444a3702c1fSVernon Mauery } 44538d2b5a6SJason M. Bills bool* valPtr = std::get_if<bool>(&reply); 44638d2b5a6SJason M. Bills if (valPtr == nullptr) 447a3702c1fSVernon Mauery { 44838d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 449a3702c1fSVernon Mauery } 450357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 45138d2b5a6SJason M. Bills uint8_t sensorVal = *valPtr; 45238d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, std::nullopt); 453a3702c1fSVernon Mauery } 454a3702c1fSVernon Mauery break; 4551b74a210SRichard Marian Thomaiyar case SmSignalGet::smNcsiDiag: 4561b74a210SRichard Marian Thomaiyar { 4571b74a210SRichard Marian Thomaiyar constexpr const char* netBasePath = "/sys/class/net/eth"; 4581b74a210SRichard Marian Thomaiyar constexpr const char* carrierSuffix = "/carrier"; 4591b74a210SRichard Marian Thomaiyar std::ifstream netIfs(netBasePath + std::to_string(instance) + 4601b74a210SRichard Marian Thomaiyar carrierSuffix); 4611b74a210SRichard Marian Thomaiyar if (!netIfs.good()) 4621b74a210SRichard Marian Thomaiyar { 4631b74a210SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 4641b74a210SRichard Marian Thomaiyar } 4651b74a210SRichard Marian Thomaiyar std::string carrier; 4661b74a210SRichard Marian Thomaiyar netIfs >> carrier; 467357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 4681b74a210SRichard Marian Thomaiyar return ipmi::responseSuccess( 4691b74a210SRichard Marian Thomaiyar static_cast<uint8_t>(std::stoi(carrier)), std::nullopt); 4701b74a210SRichard Marian Thomaiyar } 4711b74a210SRichard Marian Thomaiyar break; 472a3702c1fSVernon Mauery default: 47338d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 474a3702c1fSVernon Mauery break; 475a3702c1fSVernon Mauery } 476a3702c1fSVernon Mauery } 477a3702c1fSVernon Mauery 478357ddc74SRichard Marian Thomaiyar ipmi::RspType<> appMTMSetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte, 479357ddc74SRichard Marian Thomaiyar uint8_t instance, uint8_t actionByte, 4805e3bf557SAyushi Smriti std::optional<uint8_t> pwmSpeed) 481a3702c1fSVernon Mauery { 482e0511e5fSAyushi Smriti // mfg filter logic is used to allow MTM set signal command only in 483e0511e5fSAyushi Smriti // manfacturing mode. 4845e3bf557SAyushi Smriti 4855e3bf557SAyushi Smriti SmSignalSet signalType = static_cast<SmSignalSet>(signalTypeByte); 4865e3bf557SAyushi Smriti SmActionSet action = static_cast<SmActionSet>(actionByte); 4875e3bf557SAyushi Smriti Cc retCode = ccSuccess; 48813b0039dSJames Feist int8_t ret = 0; 4895e3bf557SAyushi Smriti 4905e3bf557SAyushi Smriti switch (signalType) 491a3702c1fSVernon Mauery { 492a3702c1fSVernon Mauery case SmSignalSet::smPowerFaultLed: 493a3702c1fSVernon Mauery case SmSignalSet::smSystemReadyLed: 494a3702c1fSVernon Mauery case SmSignalSet::smIdentifyLed: 4955e3bf557SAyushi Smriti switch (action) 496a3702c1fSVernon Mauery { 497a3702c1fSVernon Mauery case SmActionSet::forceDeasserted: 498a3702c1fSVernon Mauery { 499a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 500a3702c1fSVernon Mauery "case SmActionSet::forceDeasserted"); 501a3702c1fSVernon Mauery 5025e3bf557SAyushi Smriti retCode = ledStoreAndSet(signalType, std::string("Off")); 5035e3bf557SAyushi Smriti if (retCode != ccSuccess) 504a3702c1fSVernon Mauery { 5055e3bf557SAyushi Smriti return ipmi::response(retCode); 506a3702c1fSVernon Mauery } 507a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 508a3702c1fSVernon Mauery } 509a3702c1fSVernon Mauery break; 510a3702c1fSVernon Mauery case SmActionSet::forceAsserted: 511a3702c1fSVernon Mauery { 512a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 513a3702c1fSVernon Mauery "case SmActionSet::forceAsserted"); 514a3702c1fSVernon Mauery 5155e3bf557SAyushi Smriti retCode = ledStoreAndSet(signalType, std::string("On")); 5165e3bf557SAyushi Smriti if (retCode != ccSuccess) 517a3702c1fSVernon Mauery { 5185e3bf557SAyushi Smriti return ipmi::response(retCode); 519a3702c1fSVernon Mauery } 520a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 5215e3bf557SAyushi Smriti if (SmSignalSet::smPowerFaultLed == signalType) 522a3702c1fSVernon Mauery { 523a3702c1fSVernon Mauery // Deassert "system ready" 5245e3bf557SAyushi Smriti retCode = ledStoreAndSet(SmSignalSet::smSystemReadyLed, 525a3702c1fSVernon Mauery std::string("Off")); 526a3702c1fSVernon Mauery } 5275e3bf557SAyushi Smriti else if (SmSignalSet::smSystemReadyLed == signalType) 528a3702c1fSVernon Mauery { 529a3702c1fSVernon Mauery // Deassert "fault led" 5305e3bf557SAyushi Smriti retCode = ledStoreAndSet(SmSignalSet::smPowerFaultLed, 531a3702c1fSVernon Mauery std::string("Off")); 532a3702c1fSVernon Mauery } 533a3702c1fSVernon Mauery } 534a3702c1fSVernon Mauery break; 535a3702c1fSVernon Mauery case SmActionSet::revert: 536a3702c1fSVernon Mauery { 537a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 538a3702c1fSVernon Mauery "case SmActionSet::revert"); 5395e3bf557SAyushi Smriti retCode = ledRevert(signalType); 540a3702c1fSVernon Mauery } 541a3702c1fSVernon Mauery break; 542a3702c1fSVernon Mauery default: 543a3702c1fSVernon Mauery { 5445e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 545a3702c1fSVernon Mauery } 546a3702c1fSVernon Mauery } 547a3702c1fSVernon Mauery break; 548a3702c1fSVernon Mauery case SmSignalSet::smFanPowerSpeed: 549a3702c1fSVernon Mauery { 5505e3bf557SAyushi Smriti if ((action == SmActionSet::forceAsserted) && (!pwmSpeed)) 551a3702c1fSVernon Mauery { 5525e3bf557SAyushi Smriti return ipmi::responseReqDataLenInvalid(); 553a3702c1fSVernon Mauery } 5545e3bf557SAyushi Smriti 5555e3bf557SAyushi Smriti if ((action == SmActionSet::forceAsserted) && (*pwmSpeed > 100)) 5565e3bf557SAyushi Smriti { 5575e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 5585e3bf557SAyushi Smriti } 5595e3bf557SAyushi Smriti 560a3702c1fSVernon Mauery uint8_t pwmValue = 0; 5615e3bf557SAyushi Smriti switch (action) 562a3702c1fSVernon Mauery { 563a3702c1fSVernon Mauery case SmActionSet::revert: 564a3702c1fSVernon Mauery { 565a3702c1fSVernon Mauery if (mtm.revertFanPWM) 566a3702c1fSVernon Mauery { 567a3702c1fSVernon Mauery ret = mtm.disablePidControlService(false); 568a3702c1fSVernon Mauery if (ret < 0) 569a3702c1fSVernon Mauery { 5705e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 571a3702c1fSVernon Mauery } 572a3702c1fSVernon Mauery mtm.revertFanPWM = false; 573a3702c1fSVernon Mauery } 574a3702c1fSVernon Mauery } 575a3702c1fSVernon Mauery break; 576a3702c1fSVernon Mauery case SmActionSet::forceAsserted: 577a3702c1fSVernon Mauery { 5785e3bf557SAyushi Smriti pwmValue = *pwmSpeed; 579a3702c1fSVernon Mauery } // fall-through 580a3702c1fSVernon Mauery case SmActionSet::forceDeasserted: 581a3702c1fSVernon Mauery { 582a3702c1fSVernon Mauery if (!mtm.revertFanPWM) 583a3702c1fSVernon Mauery { 584a3702c1fSVernon Mauery ret = mtm.disablePidControlService(true); 585a3702c1fSVernon Mauery if (ret < 0) 586a3702c1fSVernon Mauery { 5875e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 588a3702c1fSVernon Mauery } 589a3702c1fSVernon Mauery mtm.revertFanPWM = true; 590a3702c1fSVernon Mauery } 591a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 592a3702c1fSVernon Mauery std::string fanPwmInstancePath = 5935e3bf557SAyushi Smriti fanPwmPath + std::to_string(instance + 1); 594a3702c1fSVernon Mauery 5955e3bf557SAyushi Smriti ret = 5965e3bf557SAyushi Smriti mtm.setProperty(fanService, fanPwmInstancePath, fanIntf, 5975e3bf557SAyushi Smriti "Value", static_cast<double>(pwmValue)); 598a3702c1fSVernon Mauery if (ret < 0) 599a3702c1fSVernon Mauery { 6005e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 601a3702c1fSVernon Mauery } 602a3702c1fSVernon Mauery } 603a3702c1fSVernon Mauery break; 604a3702c1fSVernon Mauery default: 605a3702c1fSVernon Mauery { 6065e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 607a3702c1fSVernon Mauery } 608a3702c1fSVernon Mauery } 609a3702c1fSVernon Mauery } 610a3702c1fSVernon Mauery break; 611d872a4a4SAyushi Smriti case SmSignalSet::smSpeaker: 612d872a4a4SAyushi Smriti { 613d872a4a4SAyushi Smriti phosphor::logging::log<phosphor::logging::level::INFO>( 614d872a4a4SAyushi Smriti "Performing Speaker SmActionSet", 615d872a4a4SAyushi Smriti phosphor::logging::entry("ACTION=%d", 616d872a4a4SAyushi Smriti static_cast<uint8_t>(action))); 617d872a4a4SAyushi Smriti switch (action) 618d872a4a4SAyushi Smriti { 619d872a4a4SAyushi Smriti case SmActionSet::forceAsserted: 620d872a4a4SAyushi Smriti { 621d872a4a4SAyushi Smriti char beepDevName[] = "/dev/input/event0"; 622d872a4a4SAyushi Smriti if (mtm.mtmTestBeepFd != -1) 623d872a4a4SAyushi Smriti { 624d872a4a4SAyushi Smriti phosphor::logging::log<phosphor::logging::level::INFO>( 625d872a4a4SAyushi Smriti "mtm beep device is opened already!"); 626d872a4a4SAyushi Smriti // returning success as already beep is in progress 627d872a4a4SAyushi Smriti return ipmi::response(retCode); 628d872a4a4SAyushi Smriti } 629d872a4a4SAyushi Smriti 630d872a4a4SAyushi Smriti if ((mtm.mtmTestBeepFd = 631d872a4a4SAyushi Smriti ::open(beepDevName, O_RDWR | O_CLOEXEC)) < 0) 632d872a4a4SAyushi Smriti { 633d872a4a4SAyushi Smriti phosphor::logging::log<phosphor::logging::level::ERR>( 634d872a4a4SAyushi Smriti "Failed to open input device"); 635d872a4a4SAyushi Smriti return ipmi::responseUnspecifiedError(); 636d872a4a4SAyushi Smriti } 637d872a4a4SAyushi Smriti 638d872a4a4SAyushi Smriti struct input_event event; 639d872a4a4SAyushi Smriti event.type = EV_SND; 640d872a4a4SAyushi Smriti event.code = SND_TONE; 641d872a4a4SAyushi Smriti event.value = 2000; 642d872a4a4SAyushi Smriti 643d872a4a4SAyushi Smriti if (::write(mtm.mtmTestBeepFd, &event, 644d872a4a4SAyushi Smriti sizeof(struct input_event)) != 645d872a4a4SAyushi Smriti sizeof(struct input_event)) 646d872a4a4SAyushi Smriti { 647d872a4a4SAyushi Smriti phosphor::logging::log<phosphor::logging::level::ERR>( 648d872a4a4SAyushi Smriti "Failed to write a tone sound event"); 649d872a4a4SAyushi Smriti ::close(mtm.mtmTestBeepFd); 650d872a4a4SAyushi Smriti mtm.mtmTestBeepFd = -1; 651d872a4a4SAyushi Smriti return ipmi::responseUnspecifiedError(); 652d872a4a4SAyushi Smriti } 653d872a4a4SAyushi Smriti mtm.revertTimer.start(revertTimeOut); 654d872a4a4SAyushi Smriti } 655d872a4a4SAyushi Smriti break; 656d872a4a4SAyushi Smriti case SmActionSet::revert: 657d872a4a4SAyushi Smriti case SmActionSet::forceDeasserted: 658d872a4a4SAyushi Smriti { 659d872a4a4SAyushi Smriti if (mtm.mtmTestBeepFd != -1) 660d872a4a4SAyushi Smriti { 661d872a4a4SAyushi Smriti ::close(mtm.mtmTestBeepFd); 662d872a4a4SAyushi Smriti mtm.mtmTestBeepFd = -1; 663d872a4a4SAyushi Smriti } 664d872a4a4SAyushi Smriti } 665d872a4a4SAyushi Smriti break; 666d872a4a4SAyushi Smriti default: 667d872a4a4SAyushi Smriti { 668d872a4a4SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 669d872a4a4SAyushi Smriti } 670d872a4a4SAyushi Smriti } 671d872a4a4SAyushi Smriti } 672d872a4a4SAyushi Smriti break; 6733594c6d6SRichard Marian Thomaiyar case SmSignalSet::smDiskFaultLed: 6743594c6d6SRichard Marian Thomaiyar { 6753594c6d6SRichard Marian Thomaiyar boost::system::error_code ec; 6763594c6d6SRichard Marian Thomaiyar using objPaths = std::vector<std::string>; 6773594c6d6SRichard Marian Thomaiyar std::string driveBasePath = 6783594c6d6SRichard Marian Thomaiyar "/xyz/openbmc_project/inventory/item/drive/"; 6793594c6d6SRichard Marian Thomaiyar static constexpr const char* driveLedIntf = 6803594c6d6SRichard Marian Thomaiyar "xyz.openbmc_project.Led.Group"; 6813594c6d6SRichard Marian Thomaiyar static constexpr const char* hsbpService = 6823594c6d6SRichard Marian Thomaiyar "xyz.openbmc_project.HsbpManager"; 6833594c6d6SRichard Marian Thomaiyar 6843594c6d6SRichard Marian Thomaiyar auto driveList = ctx->bus->yield_method_call<objPaths>( 6853594c6d6SRichard Marian Thomaiyar ctx->yield, ec, "xyz.openbmc_project.ObjectMapper", 6863594c6d6SRichard Marian Thomaiyar "/xyz/openbmc_project/object_mapper", 6873594c6d6SRichard Marian Thomaiyar "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 6883594c6d6SRichard Marian Thomaiyar driveBasePath, 0, std::array<const char*, 1>{driveLedIntf}); 6893594c6d6SRichard Marian Thomaiyar if (ec) 6903594c6d6SRichard Marian Thomaiyar { 6913594c6d6SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 6923594c6d6SRichard Marian Thomaiyar "Failed to query HSBP drive sub tree objects"); 6933594c6d6SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 6943594c6d6SRichard Marian Thomaiyar } 6953594c6d6SRichard Marian Thomaiyar std::string driveObjPath = 6963594c6d6SRichard Marian Thomaiyar driveBasePath + "Drive_" + std::to_string(instance + 1); 6973594c6d6SRichard Marian Thomaiyar if (std::find(driveList.begin(), driveList.end(), driveObjPath) == 6983594c6d6SRichard Marian Thomaiyar driveList.end()) 6993594c6d6SRichard Marian Thomaiyar { 7003594c6d6SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 7013594c6d6SRichard Marian Thomaiyar } 7023594c6d6SRichard Marian Thomaiyar bool driveLedState = false; 7033594c6d6SRichard Marian Thomaiyar switch (action) 7043594c6d6SRichard Marian Thomaiyar { 7053594c6d6SRichard Marian Thomaiyar case SmActionSet::forceAsserted: 7063594c6d6SRichard Marian Thomaiyar { 7073594c6d6SRichard Marian Thomaiyar driveLedState = true; 7083594c6d6SRichard Marian Thomaiyar } 7093594c6d6SRichard Marian Thomaiyar break; 7103594c6d6SRichard Marian Thomaiyar case SmActionSet::revert: 7113594c6d6SRichard Marian Thomaiyar { 7123594c6d6SRichard Marian Thomaiyar driveLedState = false; 7133594c6d6SRichard Marian Thomaiyar } 7143594c6d6SRichard Marian Thomaiyar break; 7153594c6d6SRichard Marian Thomaiyar case SmActionSet::forceDeasserted: 7163594c6d6SRichard Marian Thomaiyar { 7173594c6d6SRichard Marian Thomaiyar driveLedState = false; 7183594c6d6SRichard Marian Thomaiyar } 7193594c6d6SRichard Marian Thomaiyar break; 7203594c6d6SRichard Marian Thomaiyar default: 7213594c6d6SRichard Marian Thomaiyar { 7223594c6d6SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 7233594c6d6SRichard Marian Thomaiyar } 7243594c6d6SRichard Marian Thomaiyar } 7253594c6d6SRichard Marian Thomaiyar ret = mtm.setProperty(hsbpService, driveObjPath, driveLedIntf, 7263594c6d6SRichard Marian Thomaiyar "Asserted", driveLedState); 7273594c6d6SRichard Marian Thomaiyar if (ret < 0) 7283594c6d6SRichard Marian Thomaiyar { 7293594c6d6SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 7303594c6d6SRichard Marian Thomaiyar } 7313594c6d6SRichard Marian Thomaiyar } 7323594c6d6SRichard Marian Thomaiyar break; 733a3702c1fSVernon Mauery default: 734a3702c1fSVernon Mauery { 7355e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 736a3702c1fSVernon Mauery } 737a3702c1fSVernon Mauery } 7384cc10159SRichard Marian Thomaiyar if (retCode == ccSuccess) 7394cc10159SRichard Marian Thomaiyar { 740357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 7414cc10159SRichard Marian Thomaiyar } 7425e3bf557SAyushi Smriti return ipmi::response(retCode); 743a3702c1fSVernon Mauery } 744a3702c1fSVernon Mauery 745357ddc74SRichard Marian Thomaiyar ipmi::RspType<> mtmKeepAlive(ipmi::Context::ptr ctx, uint8_t reserved, 746666dd01cSRichard Marian Thomaiyar const std::array<char, 5>& intentionalSignature) 747666dd01cSRichard Marian Thomaiyar { 748e0511e5fSAyushi Smriti // mfg filter logic is used to allow MTM keep alive command only in 749e0511e5fSAyushi Smriti // manfacturing mode 750e0511e5fSAyushi Smriti 751666dd01cSRichard Marian Thomaiyar constexpr std::array<char, 5> signatureOk = {'I', 'N', 'T', 'E', 'L'}; 752666dd01cSRichard Marian Thomaiyar if (intentionalSignature != signatureOk || reserved != 0) 753666dd01cSRichard Marian Thomaiyar { 754666dd01cSRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 755666dd01cSRichard Marian Thomaiyar } 756357ddc74SRichard Marian Thomaiyar return ipmi::response(resetMtmTimer(ctx)); 757666dd01cSRichard Marian Thomaiyar } 758666dd01cSRichard Marian Thomaiyar 759e0511e5fSAyushi Smriti static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd) 760e0511e5fSAyushi Smriti { 761e0511e5fSAyushi Smriti return (netFn << 8) | cmd; 762e0511e5fSAyushi Smriti } 763e0511e5fSAyushi Smriti 76485feb130SYong Li ipmi::Cc mfgFilterMessage(ipmi::message::Request::ptr request) 76585feb130SYong Li { 766e0511e5fSAyushi Smriti // Restricted commands, must be executed only in Manufacturing mode 767e0511e5fSAyushi Smriti switch (makeCmdKey(request->ctx->netFn, request->ctx->cmd)) 76885feb130SYong Li { 769e0511e5fSAyushi Smriti // i2c master write read command needs additional checking 770e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead): 77185feb130SYong Li if (request->payload.size() > 4) 77285feb130SYong Li { 773ae13ac62SRichard Marian Thomaiyar // Allow write data count > 1 only in Special mode 774ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 77585feb130SYong Li { 77685feb130SYong Li return ipmi::ccInsufficientPrivilege; 77785feb130SYong Li } 77885feb130SYong Li } 7792d4a0198Sjayaprakash Mutyala return ipmi::ccSuccess; 780e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 781e0511e5fSAyushi Smriti ipmi::intel::general::cmdGetSmSignal): 782e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 783e0511e5fSAyushi Smriti ipmi::intel::general::cmdSetSmSignal): 784e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 785e0511e5fSAyushi Smriti ipmi::intel::general::cmdMtmKeepAlive): 786e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 787e0511e5fSAyushi Smriti ipmi::intel::general::cmdSetManufacturingData): 788e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 789e0511e5fSAyushi Smriti ipmi::intel::general::cmdGetManufacturingData): 790e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdWriteFruData): 79185feb130SYong Li 792ae13ac62SRichard Marian Thomaiyar // Check for Special mode 793ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 794e0511e5fSAyushi Smriti { 795e0511e5fSAyushi Smriti return ipmi::ccInvalidCommand; 796e0511e5fSAyushi Smriti } 7972d4a0198Sjayaprakash Mutyala return ipmi::ccSuccess; 7982d4a0198Sjayaprakash Mutyala case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdDeleteSelEntry): 7992d4a0198Sjayaprakash Mutyala { 8002d4a0198Sjayaprakash Mutyala return ipmi::ccInvalidCommand; 8012d4a0198Sjayaprakash Mutyala } 802e0511e5fSAyushi Smriti } 80385feb130SYong Li return ipmi::ccSuccess; 80485feb130SYong Li } 80585feb130SYong Li 8061f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxEthSize = 6; 8071f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxSupportedEth = 3; 8081f0839c2SRichard Marian Thomaiyar static constexpr const char* factoryEthAddrBaseFileName = 8091f0839c2SRichard Marian Thomaiyar "/var/sofs/factory-settings/network/mac/eth"; 8101f0839c2SRichard Marian Thomaiyar 811357ddc74SRichard Marian Thomaiyar ipmi::RspType<> setManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType, 8121f0839c2SRichard Marian Thomaiyar std::array<uint8_t, maxEthSize> ethData) 8131f0839c2SRichard Marian Thomaiyar { 8141f0839c2SRichard Marian Thomaiyar // mfg filter logic will restrict this command executing only in mfg mode. 8151f0839c2SRichard Marian Thomaiyar if (dataType >= maxSupportedEth) 8161f0839c2SRichard Marian Thomaiyar { 8171f0839c2SRichard Marian Thomaiyar return ipmi::responseParmOutOfRange(); 8181f0839c2SRichard Marian Thomaiyar } 8191f0839c2SRichard Marian Thomaiyar 8201f0839c2SRichard Marian Thomaiyar constexpr uint8_t invalidData = 0; 8211f0839c2SRichard Marian Thomaiyar constexpr uint8_t validData = 1; 8221f0839c2SRichard Marian Thomaiyar constexpr uint8_t ethAddrStrSize = 8231f0839c2SRichard Marian Thomaiyar 19; // XX:XX:XX:XX:XX:XX + \n + null termination; 8241f0839c2SRichard Marian Thomaiyar std::vector<uint8_t> buff(ethAddrStrSize); 8251f0839c2SRichard Marian Thomaiyar std::snprintf(reinterpret_cast<char*>(buff.data()), ethAddrStrSize, 8261f0839c2SRichard Marian Thomaiyar "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", ethData.at(0), 8271f0839c2SRichard Marian Thomaiyar ethData.at(1), ethData.at(2), ethData.at(3), ethData.at(4), 8281f0839c2SRichard Marian Thomaiyar ethData.at(5)); 8291f0839c2SRichard Marian Thomaiyar std::ofstream oEthFile(factoryEthAddrBaseFileName + 8301f0839c2SRichard Marian Thomaiyar std::to_string(dataType), 8311f0839c2SRichard Marian Thomaiyar std::ofstream::out); 8321f0839c2SRichard Marian Thomaiyar if (!oEthFile.good()) 8331f0839c2SRichard Marian Thomaiyar { 8341f0839c2SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 8351f0839c2SRichard Marian Thomaiyar } 8361f0839c2SRichard Marian Thomaiyar 8371f0839c2SRichard Marian Thomaiyar oEthFile << reinterpret_cast<char*>(buff.data()); 8381f0839c2SRichard Marian Thomaiyar oEthFile << fflush; 8391f0839c2SRichard Marian Thomaiyar oEthFile.close(); 8401f0839c2SRichard Marian Thomaiyar 841357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 8421f0839c2SRichard Marian Thomaiyar return ipmi::responseSuccess(); 8431f0839c2SRichard Marian Thomaiyar } 8441f0839c2SRichard Marian Thomaiyar 8451f0839c2SRichard Marian Thomaiyar ipmi::RspType<uint8_t, std::array<uint8_t, maxEthSize>> 846357ddc74SRichard Marian Thomaiyar getManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType) 8471f0839c2SRichard Marian Thomaiyar { 8481f0839c2SRichard Marian Thomaiyar // mfg filter logic will restrict this command executing only in mfg mode. 8491f0839c2SRichard Marian Thomaiyar if (dataType >= maxSupportedEth) 8501f0839c2SRichard Marian Thomaiyar { 8511f0839c2SRichard Marian Thomaiyar return ipmi::responseParmOutOfRange(); 8521f0839c2SRichard Marian Thomaiyar } 8531f0839c2SRichard Marian Thomaiyar std::array<uint8_t, maxEthSize> ethData{0}; 8541f0839c2SRichard Marian Thomaiyar constexpr uint8_t invalidData = 0; 8551f0839c2SRichard Marian Thomaiyar constexpr uint8_t validData = 1; 8561f0839c2SRichard Marian Thomaiyar 8571f0839c2SRichard Marian Thomaiyar std::ifstream iEthFile(factoryEthAddrBaseFileName + 8581f0839c2SRichard Marian Thomaiyar std::to_string(dataType), 8591f0839c2SRichard Marian Thomaiyar std::ifstream::in); 8601f0839c2SRichard Marian Thomaiyar if (!iEthFile.good()) 8611f0839c2SRichard Marian Thomaiyar { 8621f0839c2SRichard Marian Thomaiyar return ipmi::responseSuccess(invalidData, ethData); 8631f0839c2SRichard Marian Thomaiyar } 8641f0839c2SRichard Marian Thomaiyar std::string ethStr; 8651f0839c2SRichard Marian Thomaiyar iEthFile >> ethStr; 8661f0839c2SRichard Marian Thomaiyar uint8_t* data = ethData.data(); 8671f0839c2SRichard Marian Thomaiyar std::sscanf(ethStr.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 8681f0839c2SRichard Marian Thomaiyar data, (data + 1), (data + 2), (data + 3), (data + 4), 8691f0839c2SRichard Marian Thomaiyar (data + 5)); 8701f0839c2SRichard Marian Thomaiyar 871357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 8721f0839c2SRichard Marian Thomaiyar return ipmi::responseSuccess(validData, ethData); 8731f0839c2SRichard Marian Thomaiyar } 8741f0839c2SRichard Marian Thomaiyar 875f267a67dSYong Li /** @brief implements slot master write read IPMI command which can be used for 876f267a67dSYong Li * low-level I2C/SMBus write, read or write-read access for PCIE slots 877f267a67dSYong Li * @param reserved - skip 6 bit 878f267a67dSYong Li * @param addressType - address type 879f267a67dSYong Li * @param bbSlotNum - baseboard slot number 880f267a67dSYong Li * @param riserSlotNum - riser slot number 881f267a67dSYong Li * @param reserved2 - skip 2 bit 882f267a67dSYong Li * @param slaveAddr - slave address 883f267a67dSYong Li * @param readCount - number of bytes to be read 884f267a67dSYong Li * @param writeData - data to be written 885f267a67dSYong Li * 886f267a67dSYong Li * @returns IPMI completion code plus response data 887f267a67dSYong Li */ 888f267a67dSYong Li ipmi::RspType<std::vector<uint8_t>> 889f267a67dSYong Li appSlotI2CMasterWriteRead(uint6_t reserved, uint2_t addressType, 890f267a67dSYong Li uint3_t bbSlotNum, uint3_t riserSlotNum, 891f267a67dSYong Li uint2_t resvered2, uint8_t slaveAddr, 892f267a67dSYong Li uint8_t readCount, std::vector<uint8_t> writeData) 893f267a67dSYong Li { 894f267a67dSYong Li const size_t writeCount = writeData.size(); 895f267a67dSYong Li std::string i2cBus; 896f267a67dSYong Li if (addressType == slotAddressTypeBus) 897f267a67dSYong Li { 898f267a67dSYong Li std::string path = "/dev/i2c-mux/Riser_" + 899f267a67dSYong Li std::to_string(static_cast<uint8_t>(bbSlotNum)) + 900f267a67dSYong Li "_Mux/Pcie_Slot_" + 901f267a67dSYong Li std::to_string(static_cast<uint8_t>(riserSlotNum)); 902f267a67dSYong Li 903f267a67dSYong Li if (std::filesystem::exists(path) && std::filesystem::is_symlink(path)) 904f267a67dSYong Li { 905f267a67dSYong Li i2cBus = std::filesystem::read_symlink(path); 906f267a67dSYong Li } 907f267a67dSYong Li else 908f267a67dSYong Li { 909f267a67dSYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 910f267a67dSYong Li "Master write read command: Cannot get BusID"); 911f267a67dSYong Li return ipmi::responseInvalidFieldRequest(); 912f267a67dSYong Li } 913f267a67dSYong Li } 914f267a67dSYong Li else if (addressType == slotAddressTypeUniqueid) 915f267a67dSYong Li { 916f267a67dSYong Li i2cBus = "/dev/i2c-" + 917f267a67dSYong Li std::to_string(static_cast<uint8_t>(bbSlotNum) | 918f267a67dSYong Li (static_cast<uint8_t>(riserSlotNum) << 3)); 919f267a67dSYong Li } 920f267a67dSYong Li else 921f267a67dSYong Li { 922f267a67dSYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 923f267a67dSYong Li "Master write read command: invalid request"); 924f267a67dSYong Li return ipmi::responseInvalidFieldRequest(); 925f267a67dSYong Li } 926f267a67dSYong Li 927f267a67dSYong Li // Allow single byte write as it is offset byte to read the data, rest allow 928ae13ac62SRichard Marian Thomaiyar // only in Special mode. 929f267a67dSYong Li if (writeCount > 1) 930f267a67dSYong Li { 931ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 932f267a67dSYong Li { 933f267a67dSYong Li return ipmi::responseInsufficientPrivilege(); 934f267a67dSYong Li } 935f267a67dSYong Li } 936f267a67dSYong Li 937f267a67dSYong Li if (readCount > slotI2CMaxReadSize) 938f267a67dSYong Li { 939f267a67dSYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 940f267a67dSYong Li "Master write read command: Read count exceeds limit"); 941f267a67dSYong Li return ipmi::responseParmOutOfRange(); 942f267a67dSYong Li } 943f267a67dSYong Li 944f267a67dSYong Li if (!readCount && !writeCount) 945f267a67dSYong Li { 946f267a67dSYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 947f267a67dSYong Li "Master write read command: Read & write count are 0"); 948f267a67dSYong Li return ipmi::responseInvalidFieldRequest(); 949f267a67dSYong Li } 950f267a67dSYong Li 951f267a67dSYong Li std::vector<uint8_t> readBuf(readCount); 952f267a67dSYong Li 953f267a67dSYong Li ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf); 954f267a67dSYong Li if (retI2C != ipmi::ccSuccess) 955f267a67dSYong Li { 956f267a67dSYong Li return ipmi::response(retI2C); 957f267a67dSYong Li } 958f267a67dSYong Li 959f267a67dSYong Li return ipmi::responseSuccess(readBuf); 960f267a67dSYong Li } 961068b4f2cSYong Li 962068b4f2cSYong Li ipmi::RspType<> clearCMOS() 963068b4f2cSYong Li { 964d0d010b7SYong Li // There is an i2c device on bus 4, the slave address is 0x38. Based on the 965*eaeb6cb0SYong Li // spec, writing 0x1 to address 0x61 on this device, will trigger the clear 966068b4f2cSYong Li // CMOS action. 967d0d010b7SYong Li constexpr uint8_t slaveAddr = 0x38; 968068b4f2cSYong Li std::string i2cBus = "/dev/i2c-4"; 969*eaeb6cb0SYong Li std::vector<uint8_t> writeData = {0x61, 0x1}; 970068b4f2cSYong Li std::vector<uint8_t> readBuf(0); 971068b4f2cSYong Li 972ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 973068b4f2cSYong Li { 974068b4f2cSYong Li return ipmi::responseInsufficientPrivilege(); 975068b4f2cSYong Li } 976068b4f2cSYong Li 977068b4f2cSYong Li ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf); 978068b4f2cSYong Li return ipmi::response(retI2C); 979068b4f2cSYong Li } 980a3702c1fSVernon Mauery } // namespace ipmi 981a3702c1fSVernon Mauery 982a3702c1fSVernon Mauery void register_mtm_commands() __attribute__((constructor)); 983a3702c1fSVernon Mauery void register_mtm_commands() 984a3702c1fSVernon Mauery { 98538d2b5a6SJason M. Bills // <Get SM Signal> 98698bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 98798bbf69aSVernon Mauery ipmi::intel::general::cmdGetSmSignal, 9885e3bf557SAyushi Smriti ipmi::Privilege::Admin, ipmi::appMTMGetSignal); 989a3702c1fSVernon Mauery 99098bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 99198bbf69aSVernon Mauery ipmi::intel::general::cmdSetSmSignal, 9925e3bf557SAyushi Smriti ipmi::Privilege::Admin, ipmi::appMTMSetSignal); 993a3702c1fSVernon Mauery 99498bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 99598bbf69aSVernon Mauery ipmi::intel::general::cmdMtmKeepAlive, 996666dd01cSRichard Marian Thomaiyar ipmi::Privilege::Admin, ipmi::mtmKeepAlive); 997666dd01cSRichard Marian Thomaiyar 99898bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 99998bbf69aSVernon Mauery ipmi::intel::general::cmdSetManufacturingData, 10001f0839c2SRichard Marian Thomaiyar ipmi::Privilege::Admin, ipmi::setManufacturingData); 10011f0839c2SRichard Marian Thomaiyar 100298bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 100398bbf69aSVernon Mauery ipmi::intel::general::cmdGetManufacturingData, 10041f0839c2SRichard Marian Thomaiyar ipmi::Privilege::Admin, ipmi::getManufacturingData); 10051f0839c2SRichard Marian Thomaiyar 100698bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 100798bbf69aSVernon Mauery ipmi::intel::general::cmdSlotI2CMasterWriteRead, 100898bbf69aSVernon Mauery ipmi::Privilege::Admin, 100998bbf69aSVernon Mauery ipmi::appSlotI2CMasterWriteRead); 1010f267a67dSYong Li 1011068b4f2cSYong Li ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnPlatform, 1012068b4f2cSYong Li ipmi::intel::platform::cmdClearCMOS, 1013068b4f2cSYong Li ipmi::Privilege::Admin, ipmi::clearCMOS); 1014068b4f2cSYong Li 101598bbf69aSVernon Mauery ipmi::registerFilter(ipmi::prioOemBase, 101685feb130SYong Li [](ipmi::message::Request::ptr request) { 101785feb130SYong Li return ipmi::mfgFilterMessage(request); 101885feb130SYong Li }); 1019a3702c1fSVernon Mauery } 1020