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> 20a3702c1fSVernon Mauery #include <ipmid/api.hpp> 21a3702c1fSVernon Mauery #include <manufacturingcommands.hpp> 22a3702c1fSVernon Mauery #include <oemcommands.hpp> 23a3702c1fSVernon Mauery 24*fcd2d3a9SJames Feist #include <filesystem> 25*fcd2d3a9SJames Feist #include <fstream> 26*fcd2d3a9SJames Feist 27a3702c1fSVernon Mauery namespace ipmi 28a3702c1fSVernon Mauery { 29a3702c1fSVernon Mauery 30a3702c1fSVernon Mauery Manufacturing mtm; 31a3702c1fSVernon Mauery 32a3702c1fSVernon Mauery static auto revertTimeOut = 33a3702c1fSVernon Mauery std::chrono::duration_cast<std::chrono::microseconds>( 34a3702c1fSVernon Mauery std::chrono::seconds(60)); // 1 minute timeout 35a3702c1fSVernon Mauery 36f267a67dSYong Li static constexpr uint8_t slotAddressTypeBus = 0; 37f267a67dSYong Li static constexpr uint8_t slotAddressTypeUniqueid = 1; 38f267a67dSYong Li static constexpr uint8_t slotI2CMaxReadSize = 35; 39f267a67dSYong Li 40a3702c1fSVernon Mauery static constexpr const char* callbackMgrService = 41a3702c1fSVernon Mauery "xyz.openbmc_project.CallbackManager"; 42a3702c1fSVernon Mauery static constexpr const char* callbackMgrIntf = 43a3702c1fSVernon Mauery "xyz.openbmc_project.CallbackManager"; 44a3702c1fSVernon Mauery static constexpr const char* callbackMgrObjPath = 45a3702c1fSVernon Mauery "/xyz/openbmc_project/CallbackManager"; 46a3702c1fSVernon Mauery static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate"; 47a3702c1fSVernon Mauery 48a3702c1fSVernon Mauery const static constexpr char* systemDService = "org.freedesktop.systemd1"; 49a3702c1fSVernon Mauery const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1"; 50a3702c1fSVernon Mauery const static constexpr char* systemDMgrIntf = 51a3702c1fSVernon Mauery "org.freedesktop.systemd1.Manager"; 52a3702c1fSVernon Mauery const static constexpr char* pidControlService = "phosphor-pid-control.service"; 53a3702c1fSVernon Mauery 54357ddc74SRichard Marian Thomaiyar static inline Cc resetMtmTimer(ipmi::Context::ptr ctx) 55666dd01cSRichard Marian Thomaiyar { 56666dd01cSRichard Marian Thomaiyar boost::system::error_code ec; 57357ddc74SRichard Marian Thomaiyar ctx->bus->yield_method_call<>(ctx->yield, ec, specialModeService, 58666dd01cSRichard Marian Thomaiyar specialModeObjPath, specialModeIntf, 59666dd01cSRichard Marian Thomaiyar "ResetTimer"); 60666dd01cSRichard Marian Thomaiyar if (ec) 61666dd01cSRichard Marian Thomaiyar { 62666dd01cSRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 63666dd01cSRichard Marian Thomaiyar "Failed to reset the manufacturing mode timer"); 64666dd01cSRichard Marian Thomaiyar return ccUnspecifiedError; 65666dd01cSRichard Marian Thomaiyar } 66666dd01cSRichard Marian Thomaiyar return ccSuccess; 67666dd01cSRichard Marian Thomaiyar } 68666dd01cSRichard Marian Thomaiyar 6938d2b5a6SJason M. Bills int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path) 70a3702c1fSVernon Mauery { 7138d2b5a6SJason M. Bills switch (signal) 7238d2b5a6SJason M. Bills { 7338d2b5a6SJason M. Bills case SmSignalGet::smPowerButton: 7438d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/power"; 7538d2b5a6SJason M. Bills break; 7638d2b5a6SJason M. Bills case SmSignalGet::smResetButton: 7738d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/reset"; 7838d2b5a6SJason M. Bills break; 7938d2b5a6SJason M. Bills case SmSignalGet::smNMIButton: 8038d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/nmi"; 8138d2b5a6SJason M. Bills break; 828e5e2b04SRichard Marian Thomaiyar case SmSignalGet::smIdentifyButton: 838e5e2b04SRichard Marian Thomaiyar path = "/xyz/openbmc_project/chassis/buttons/id"; 848e5e2b04SRichard Marian Thomaiyar break; 8538d2b5a6SJason M. Bills default: 8638d2b5a6SJason M. Bills return -1; 8738d2b5a6SJason M. Bills break; 8838d2b5a6SJason M. Bills } 8938d2b5a6SJason M. Bills return 0; 90a3702c1fSVernon Mauery } 91a3702c1fSVernon Mauery 9237890392SPatrick Venture ipmi_ret_t ledStoreAndSet(SmSignalSet signal, const std::string& setState) 93a3702c1fSVernon Mauery { 94a3702c1fSVernon Mauery LedProperty* ledProp = mtm.findLedProperty(signal); 95a3702c1fSVernon Mauery if (ledProp == nullptr) 96a3702c1fSVernon Mauery { 97a3702c1fSVernon Mauery return IPMI_CC_INVALID_FIELD_REQUEST; 98a3702c1fSVernon Mauery } 99a3702c1fSVernon Mauery 100a3702c1fSVernon Mauery std::string ledName = ledProp->getName(); 101a3702c1fSVernon Mauery std::string ledService = ledServicePrefix + ledName; 102a3702c1fSVernon Mauery std::string ledPath = ledPathPrefix + ledName; 103a3702c1fSVernon Mauery ipmi::Value presentState; 104a3702c1fSVernon Mauery 105a3702c1fSVernon Mauery if (false == ledProp->getLock()) 106a3702c1fSVernon Mauery { 107a3702c1fSVernon Mauery if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf, 108a3702c1fSVernon Mauery "State", &presentState) != 0) 109a3702c1fSVernon Mauery { 110a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 111a3702c1fSVernon Mauery } 112a3702c1fSVernon Mauery ledProp->setPrevState(std::get<std::string>(presentState)); 113a3702c1fSVernon Mauery ledProp->setLock(true); 114a3702c1fSVernon Mauery if (signal == SmSignalSet::smPowerFaultLed || 115a3702c1fSVernon Mauery signal == SmSignalSet::smSystemReadyLed) 116a3702c1fSVernon Mauery { 117a3702c1fSVernon Mauery mtm.revertLedCallback = true; 118a3702c1fSVernon Mauery } 119a3702c1fSVernon Mauery } 12038d2b5a6SJason M. Bills if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 121a3702c1fSVernon Mauery ledStateStr + setState) != 0) 122a3702c1fSVernon Mauery { 123a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 124a3702c1fSVernon Mauery } 125a3702c1fSVernon Mauery return IPMI_CC_OK; 126a3702c1fSVernon Mauery } 127a3702c1fSVernon Mauery 128a3702c1fSVernon Mauery ipmi_ret_t ledRevert(SmSignalSet signal) 129a3702c1fSVernon Mauery { 130a3702c1fSVernon Mauery LedProperty* ledProp = mtm.findLedProperty(signal); 131a3702c1fSVernon Mauery if (ledProp == nullptr) 132a3702c1fSVernon Mauery { 133a3702c1fSVernon Mauery return IPMI_CC_INVALID_FIELD_REQUEST; 134a3702c1fSVernon Mauery } 135a3702c1fSVernon Mauery if (true == ledProp->getLock()) 136a3702c1fSVernon Mauery { 137a3702c1fSVernon Mauery ledProp->setLock(false); 138a3702c1fSVernon Mauery if (signal == SmSignalSet::smPowerFaultLed || 139a3702c1fSVernon Mauery signal == SmSignalSet::smSystemReadyLed) 140a3702c1fSVernon Mauery { 141a3702c1fSVernon Mauery try 142a3702c1fSVernon Mauery { 143a3702c1fSVernon Mauery ipmi::method_no_args::callDbusMethod( 144a3702c1fSVernon Mauery *getSdBus(), callbackMgrService, callbackMgrObjPath, 145a3702c1fSVernon Mauery callbackMgrIntf, retriggerLedUpdate); 146a3702c1fSVernon Mauery } 147a3702c1fSVernon Mauery catch (sdbusplus::exception_t& e) 148a3702c1fSVernon Mauery { 149a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 150a3702c1fSVernon Mauery } 151a3702c1fSVernon Mauery mtm.revertLedCallback = false; 152a3702c1fSVernon Mauery } 153a3702c1fSVernon Mauery else 154a3702c1fSVernon Mauery { 155a3702c1fSVernon Mauery std::string ledName = ledProp->getName(); 156a3702c1fSVernon Mauery std::string ledService = ledServicePrefix + ledName; 157a3702c1fSVernon Mauery std::string ledPath = ledPathPrefix + ledName; 15838d2b5a6SJason M. Bills if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 15938d2b5a6SJason M. Bills ledProp->getPrevState()) != 0) 160a3702c1fSVernon Mauery { 161a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 162a3702c1fSVernon Mauery } 163a3702c1fSVernon Mauery } 164a3702c1fSVernon Mauery } 165a3702c1fSVernon Mauery return IPMI_CC_OK; 166a3702c1fSVernon Mauery } 167a3702c1fSVernon Mauery 168a3702c1fSVernon Mauery void Manufacturing::initData() 169a3702c1fSVernon Mauery { 170a3702c1fSVernon Mauery ledPropertyList.push_back( 171a3702c1fSVernon Mauery LedProperty(SmSignalSet::smPowerFaultLed, "status_amber")); 172a3702c1fSVernon Mauery ledPropertyList.push_back( 173a3702c1fSVernon Mauery LedProperty(SmSignalSet::smSystemReadyLed, "status_green")); 174a3702c1fSVernon Mauery ledPropertyList.push_back( 175a3702c1fSVernon Mauery LedProperty(SmSignalSet::smIdentifyLed, "identify")); 176a3702c1fSVernon Mauery } 177a3702c1fSVernon Mauery 178a3702c1fSVernon Mauery void Manufacturing::revertTimerHandler() 179a3702c1fSVernon Mauery { 180ae13ac62SRichard Marian Thomaiyar 181ae13ac62SRichard Marian Thomaiyar #ifdef BMC_VALIDATION_UNSECURE_FEATURE 182ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::valUnsecure) 183ae13ac62SRichard Marian Thomaiyar { 184ae13ac62SRichard Marian Thomaiyar // Don't revert the behaviour for validation unsecure mode. 185ae13ac62SRichard Marian Thomaiyar return; 186ae13ac62SRichard Marian Thomaiyar } 187ae13ac62SRichard Marian Thomaiyar #endif 188a3702c1fSVernon Mauery if (revertFanPWM) 189a3702c1fSVernon Mauery { 190a3702c1fSVernon Mauery revertFanPWM = false; 191a3702c1fSVernon Mauery disablePidControlService(false); 192a3702c1fSVernon Mauery } 193a3702c1fSVernon Mauery 194d872a4a4SAyushi Smriti if (mtmTestBeepFd != -1) 195d872a4a4SAyushi Smriti { 196d872a4a4SAyushi Smriti ::close(mtmTestBeepFd); 197d872a4a4SAyushi Smriti mtmTestBeepFd = -1; 198d872a4a4SAyushi Smriti } 199d872a4a4SAyushi Smriti 200a3702c1fSVernon Mauery for (const auto& ledProperty : ledPropertyList) 201a3702c1fSVernon Mauery { 202a3702c1fSVernon Mauery const std::string& ledName = ledProperty.getName(); 203a3702c1fSVernon Mauery ledRevert(ledProperty.getSignal()); 204a3702c1fSVernon Mauery } 205a3702c1fSVernon Mauery } 206a3702c1fSVernon Mauery 207a3702c1fSVernon Mauery Manufacturing::Manufacturing() : 208a3702c1fSVernon Mauery revertTimer([&](void) { revertTimerHandler(); }) 209a3702c1fSVernon Mauery { 210a3702c1fSVernon Mauery initData(); 211a3702c1fSVernon Mauery } 212a3702c1fSVernon Mauery 21338d2b5a6SJason M. Bills int8_t Manufacturing::getProperty(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* reply) 218a3702c1fSVernon Mauery { 219a3702c1fSVernon Mauery try 220a3702c1fSVernon Mauery { 22138d2b5a6SJason M. Bills *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface, 22238d2b5a6SJason M. Bills propertyName); 223a3702c1fSVernon Mauery } 224a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& e) 225a3702c1fSVernon Mauery { 226a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 227a3702c1fSVernon Mauery "ERROR: getProperty"); 228a3702c1fSVernon Mauery return -1; 229a3702c1fSVernon Mauery } 230a3702c1fSVernon Mauery 231a3702c1fSVernon Mauery return 0; 232a3702c1fSVernon Mauery } 233a3702c1fSVernon Mauery 23438d2b5a6SJason M. Bills int8_t Manufacturing::setProperty(const std::string& service, 23538d2b5a6SJason M. Bills const std::string& path, 23638d2b5a6SJason M. Bills const std::string& interface, 23738d2b5a6SJason M. Bills const std::string& propertyName, 23838d2b5a6SJason M. Bills ipmi::Value value) 239a3702c1fSVernon Mauery { 240a3702c1fSVernon Mauery try 241a3702c1fSVernon Mauery { 24238d2b5a6SJason M. Bills ipmi::setDbusProperty(*getSdBus(), service, path, interface, 243a3702c1fSVernon Mauery propertyName, value); 244a3702c1fSVernon Mauery } 245a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& e) 246a3702c1fSVernon Mauery { 247a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 248a3702c1fSVernon Mauery "ERROR: setProperty"); 249a3702c1fSVernon Mauery return -1; 250a3702c1fSVernon Mauery } 251a3702c1fSVernon Mauery 252a3702c1fSVernon Mauery return 0; 253a3702c1fSVernon Mauery } 254a3702c1fSVernon Mauery 255a3702c1fSVernon Mauery int8_t Manufacturing::disablePidControlService(const bool disable) 256a3702c1fSVernon Mauery { 257a3702c1fSVernon Mauery try 258a3702c1fSVernon Mauery { 259a3702c1fSVernon Mauery auto dbus = getSdBus(); 260a3702c1fSVernon Mauery auto method = dbus->new_method_call(systemDService, systemDObjPath, 261a3702c1fSVernon Mauery systemDMgrIntf, 262a3702c1fSVernon Mauery disable ? "StopUnit" : "StartUnit"); 263a3702c1fSVernon Mauery method.append(pidControlService, "replace"); 264a3702c1fSVernon Mauery auto reply = dbus->call(method); 265a3702c1fSVernon Mauery } 266a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& e) 267a3702c1fSVernon Mauery { 268a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 269a3702c1fSVernon Mauery "ERROR: phosphor-pid-control service start or stop failed"); 270a3702c1fSVernon Mauery return -1; 271a3702c1fSVernon Mauery } 272a3702c1fSVernon Mauery return 0; 273a3702c1fSVernon Mauery } 274a3702c1fSVernon Mauery 27538d2b5a6SJason M. Bills ipmi::RspType<uint8_t, // Signal value 27638d2b5a6SJason M. Bills std::optional<uint16_t> // Fan tach value 27738d2b5a6SJason M. Bills > 278357ddc74SRichard Marian Thomaiyar appMTMGetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte, 279147daec5SRichard Marian Thomaiyar uint8_t instance, uint8_t actionByte) 280a3702c1fSVernon Mauery { 281e0511e5fSAyushi Smriti // mfg filter logic is used to allow MTM get signal command only in 282e0511e5fSAyushi Smriti // manfacturing mode. 28338d2b5a6SJason M. Bills 28438d2b5a6SJason M. Bills SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte); 28538d2b5a6SJason M. Bills SmActionGet action = static_cast<SmActionGet>(actionByte); 28638d2b5a6SJason M. Bills 28738d2b5a6SJason M. Bills switch (signalType) 28838d2b5a6SJason M. Bills { 28998705b39Sanil kumar appana case SmSignalGet::smChassisIntrusion: 29098705b39Sanil kumar appana { 29198705b39Sanil kumar appana ipmi::Value reply; 29298705b39Sanil kumar appana if (mtm.getProperty(intrusionService, intrusionPath, intrusionIntf, 29398705b39Sanil kumar appana "Status", &reply) < 0) 29498705b39Sanil kumar appana { 29598705b39Sanil kumar appana return ipmi::responseInvalidFieldRequest(); 29698705b39Sanil kumar appana } 29798705b39Sanil kumar appana std::string* intrusionStatus = std::get_if<std::string>(&reply); 29898705b39Sanil kumar appana if (!intrusionStatus) 29998705b39Sanil kumar appana { 30098705b39Sanil kumar appana return ipmi::responseUnspecifiedError(); 30198705b39Sanil kumar appana } 30298705b39Sanil kumar appana 30398705b39Sanil kumar appana uint8_t status = 0; 30498705b39Sanil kumar appana if (!intrusionStatus->compare("Normal")) 30598705b39Sanil kumar appana { 30698705b39Sanil kumar appana status = static_cast<uint8_t>(IntrusionStatus::normal); 30798705b39Sanil kumar appana } 30898705b39Sanil kumar appana else if (!intrusionStatus->compare("HardwareIntrusion")) 30998705b39Sanil kumar appana { 31098705b39Sanil kumar appana status = 31198705b39Sanil kumar appana static_cast<uint8_t>(IntrusionStatus::hardwareIntrusion); 31298705b39Sanil kumar appana } 31398705b39Sanil kumar appana else if (!intrusionStatus->compare("TamperingDetected")) 31498705b39Sanil kumar appana { 31598705b39Sanil kumar appana status = 31698705b39Sanil kumar appana static_cast<uint8_t>(IntrusionStatus::tamperingDetected); 31798705b39Sanil kumar appana } 31898705b39Sanil kumar appana else 31998705b39Sanil kumar appana { 32098705b39Sanil kumar appana return ipmi::responseUnspecifiedError(); 32198705b39Sanil kumar appana } 32298705b39Sanil kumar appana return ipmi::responseSuccess(status, std::nullopt); 32398705b39Sanil kumar appana } 32438d2b5a6SJason M. Bills case SmSignalGet::smFanPwmGet: 32538d2b5a6SJason M. Bills { 326a3702c1fSVernon Mauery ipmi::Value reply; 327147daec5SRichard Marian Thomaiyar std::string fullPath = fanPwmPath + std::to_string(instance + 1); 32838d2b5a6SJason M. Bills if (mtm.getProperty(fanService, fullPath, fanIntf, "Value", 32938d2b5a6SJason M. Bills &reply) < 0) 33038d2b5a6SJason M. Bills { 33138d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 33238d2b5a6SJason M. Bills } 33338d2b5a6SJason M. Bills double* doubleVal = std::get_if<double>(&reply); 33438d2b5a6SJason M. Bills if (doubleVal == nullptr) 33538d2b5a6SJason M. Bills { 33638d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 33738d2b5a6SJason M. Bills } 33838d2b5a6SJason M. Bills uint8_t sensorVal = std::round(*doubleVal); 339357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 34038d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, std::nullopt); 34138d2b5a6SJason M. Bills } 34238d2b5a6SJason M. Bills break; 34338d2b5a6SJason M. Bills case SmSignalGet::smFanTachometerGet: 34438d2b5a6SJason M. Bills { 345147daec5SRichard Marian Thomaiyar boost::system::error_code ec; 346147daec5SRichard Marian Thomaiyar using objFlatMap = boost::container::flat_map< 347147daec5SRichard Marian Thomaiyar std::string, boost::container::flat_map< 348147daec5SRichard Marian Thomaiyar std::string, std::vector<std::string>>>; 349147daec5SRichard Marian Thomaiyar 350357ddc74SRichard Marian Thomaiyar auto flatMap = ctx->bus->yield_method_call<objFlatMap>( 351357ddc74SRichard Marian Thomaiyar ctx->yield, ec, "xyz.openbmc_project.ObjectMapper", 352147daec5SRichard Marian Thomaiyar "/xyz/openbmc_project/object_mapper", 353147daec5SRichard Marian Thomaiyar "xyz.openbmc_project.ObjectMapper", "GetSubTree", 354147daec5SRichard Marian Thomaiyar fanTachBasePath, 0, std::array<const char*, 1>{fanIntf}); 355147daec5SRichard Marian Thomaiyar if (ec) 356147daec5SRichard Marian Thomaiyar { 357147daec5SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 358147daec5SRichard Marian Thomaiyar "Failed to query fan tach sub tree objects"); 359147daec5SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 360147daec5SRichard Marian Thomaiyar } 361147daec5SRichard Marian Thomaiyar if (instance >= flatMap.size()) 36238d2b5a6SJason M. Bills { 36338d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 36438d2b5a6SJason M. Bills } 365147daec5SRichard Marian Thomaiyar auto itr = flatMap.nth(instance); 36638d2b5a6SJason M. Bills ipmi::Value reply; 367147daec5SRichard Marian Thomaiyar if (mtm.getProperty(fanService, itr->first, fanIntf, "Value", 36838d2b5a6SJason M. Bills &reply) < 0) 36938d2b5a6SJason M. Bills { 37038d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 37138d2b5a6SJason M. Bills } 37238d2b5a6SJason M. Bills 37338d2b5a6SJason M. Bills double* doubleVal = std::get_if<double>(&reply); 37438d2b5a6SJason M. Bills if (doubleVal == nullptr) 37538d2b5a6SJason M. Bills { 37638d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 37738d2b5a6SJason M. Bills } 37838d2b5a6SJason M. Bills uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT; 37938d2b5a6SJason M. Bills std::optional<uint16_t> fanTach = std::round(*doubleVal); 38038d2b5a6SJason M. Bills 381357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 38238d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, fanTach); 38338d2b5a6SJason M. Bills } 38438d2b5a6SJason M. Bills break; 3858e5e2b04SRichard Marian Thomaiyar case SmSignalGet::smIdentifyButton: 3868e5e2b04SRichard Marian Thomaiyar { 3878e5e2b04SRichard Marian Thomaiyar if (action == SmActionGet::revert || action == SmActionGet::ignore) 3888e5e2b04SRichard Marian Thomaiyar { 3898e5e2b04SRichard Marian Thomaiyar // ButtonMasked property is not supported for ID button as it is 3908e5e2b04SRichard Marian Thomaiyar // unnecessary. Hence if requested for revert / ignore, override 3918e5e2b04SRichard Marian Thomaiyar // it to sample action to make tools happy. 3928e5e2b04SRichard Marian Thomaiyar action = SmActionGet::sample; 3938e5e2b04SRichard Marian Thomaiyar } 3948e5e2b04SRichard Marian Thomaiyar // fall-through 3958e5e2b04SRichard Marian Thomaiyar } 39638d2b5a6SJason M. Bills case SmSignalGet::smResetButton: 39738d2b5a6SJason M. Bills case SmSignalGet::smPowerButton: 39838d2b5a6SJason M. Bills case SmSignalGet::smNMIButton: 39938d2b5a6SJason M. Bills { 40038d2b5a6SJason M. Bills std::string path; 40138d2b5a6SJason M. Bills if (getGpioPathForSmSignal(signalType, path) < 0) 40238d2b5a6SJason M. Bills { 40338d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 40438d2b5a6SJason M. Bills } 405a3702c1fSVernon Mauery 406a3702c1fSVernon Mauery switch (action) 407a3702c1fSVernon Mauery { 408a3702c1fSVernon Mauery case SmActionGet::sample: 409a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 410a3702c1fSVernon Mauery "case SmActionGet::sample"); 411a3702c1fSVernon Mauery break; 412a3702c1fSVernon Mauery case SmActionGet::ignore: 413a3702c1fSVernon Mauery { 414a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 415a3702c1fSVernon Mauery "case SmActionGet::ignore"); 41638d2b5a6SJason M. Bills if (mtm.setProperty(buttonService, path, buttonIntf, 41738d2b5a6SJason M. Bills "ButtonMasked", true) < 0) 418a3702c1fSVernon Mauery { 41938d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 420a3702c1fSVernon Mauery } 421a3702c1fSVernon Mauery } 422a3702c1fSVernon Mauery break; 423a3702c1fSVernon Mauery case SmActionGet::revert: 424a3702c1fSVernon Mauery { 425a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 426a3702c1fSVernon Mauery "case SmActionGet::revert"); 42738d2b5a6SJason M. Bills if (mtm.setProperty(buttonService, path, buttonIntf, 42838d2b5a6SJason M. Bills "ButtonMasked", false) < 0) 429a3702c1fSVernon Mauery { 43038d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 431a3702c1fSVernon Mauery } 432a3702c1fSVernon Mauery } 433a3702c1fSVernon Mauery break; 434a3702c1fSVernon Mauery 435a3702c1fSVernon Mauery default: 43638d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 437a3702c1fSVernon Mauery break; 438a3702c1fSVernon Mauery } 439a3702c1fSVernon Mauery 440a3702c1fSVernon Mauery ipmi::Value reply; 44138d2b5a6SJason M. Bills if (mtm.getProperty(buttonService, path, buttonIntf, 44238d2b5a6SJason M. Bills "ButtonPressed", &reply) < 0) 443a3702c1fSVernon Mauery { 44438d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 445a3702c1fSVernon Mauery } 44638d2b5a6SJason M. Bills bool* valPtr = std::get_if<bool>(&reply); 44738d2b5a6SJason M. Bills if (valPtr == nullptr) 448a3702c1fSVernon Mauery { 44938d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 450a3702c1fSVernon Mauery } 451357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 45238d2b5a6SJason M. Bills uint8_t sensorVal = *valPtr; 45338d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, std::nullopt); 454a3702c1fSVernon Mauery } 455a3702c1fSVernon Mauery break; 4561b74a210SRichard Marian Thomaiyar case SmSignalGet::smNcsiDiag: 4571b74a210SRichard Marian Thomaiyar { 4581b74a210SRichard Marian Thomaiyar constexpr const char* netBasePath = "/sys/class/net/eth"; 4591b74a210SRichard Marian Thomaiyar constexpr const char* carrierSuffix = "/carrier"; 4601b74a210SRichard Marian Thomaiyar std::ifstream netIfs(netBasePath + std::to_string(instance) + 4611b74a210SRichard Marian Thomaiyar carrierSuffix); 4621b74a210SRichard Marian Thomaiyar if (!netIfs.good()) 4631b74a210SRichard Marian Thomaiyar { 4641b74a210SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 4651b74a210SRichard Marian Thomaiyar } 4661b74a210SRichard Marian Thomaiyar std::string carrier; 4671b74a210SRichard Marian Thomaiyar netIfs >> carrier; 468357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 4691b74a210SRichard Marian Thomaiyar return ipmi::responseSuccess( 4701b74a210SRichard Marian Thomaiyar static_cast<uint8_t>(std::stoi(carrier)), std::nullopt); 4711b74a210SRichard Marian Thomaiyar } 4721b74a210SRichard Marian Thomaiyar break; 473a3702c1fSVernon Mauery default: 47438d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 475a3702c1fSVernon Mauery break; 476a3702c1fSVernon Mauery } 477a3702c1fSVernon Mauery } 478a3702c1fSVernon Mauery 479357ddc74SRichard Marian Thomaiyar ipmi::RspType<> appMTMSetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte, 480357ddc74SRichard Marian Thomaiyar uint8_t instance, uint8_t actionByte, 4815e3bf557SAyushi Smriti std::optional<uint8_t> pwmSpeed) 482a3702c1fSVernon Mauery { 483e0511e5fSAyushi Smriti // mfg filter logic is used to allow MTM set signal command only in 484e0511e5fSAyushi Smriti // manfacturing mode. 4855e3bf557SAyushi Smriti 4865e3bf557SAyushi Smriti SmSignalSet signalType = static_cast<SmSignalSet>(signalTypeByte); 4875e3bf557SAyushi Smriti SmActionSet action = static_cast<SmActionSet>(actionByte); 4885e3bf557SAyushi Smriti Cc retCode = ccSuccess; 48913b0039dSJames Feist int8_t ret = 0; 4905e3bf557SAyushi Smriti 4915e3bf557SAyushi Smriti switch (signalType) 492a3702c1fSVernon Mauery { 493a3702c1fSVernon Mauery case SmSignalSet::smPowerFaultLed: 494a3702c1fSVernon Mauery case SmSignalSet::smSystemReadyLed: 495a3702c1fSVernon Mauery case SmSignalSet::smIdentifyLed: 4965e3bf557SAyushi Smriti switch (action) 497a3702c1fSVernon Mauery { 498a3702c1fSVernon Mauery case SmActionSet::forceDeasserted: 499a3702c1fSVernon Mauery { 500a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 501a3702c1fSVernon Mauery "case SmActionSet::forceDeasserted"); 502a3702c1fSVernon Mauery 5035e3bf557SAyushi Smriti retCode = ledStoreAndSet(signalType, std::string("Off")); 5045e3bf557SAyushi Smriti if (retCode != ccSuccess) 505a3702c1fSVernon Mauery { 5065e3bf557SAyushi Smriti return ipmi::response(retCode); 507a3702c1fSVernon Mauery } 508a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 509a3702c1fSVernon Mauery } 510a3702c1fSVernon Mauery break; 511a3702c1fSVernon Mauery case SmActionSet::forceAsserted: 512a3702c1fSVernon Mauery { 513a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 514a3702c1fSVernon Mauery "case SmActionSet::forceAsserted"); 515a3702c1fSVernon Mauery 5165e3bf557SAyushi Smriti retCode = ledStoreAndSet(signalType, std::string("On")); 5175e3bf557SAyushi Smriti if (retCode != ccSuccess) 518a3702c1fSVernon Mauery { 5195e3bf557SAyushi Smriti return ipmi::response(retCode); 520a3702c1fSVernon Mauery } 521a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 5225e3bf557SAyushi Smriti if (SmSignalSet::smPowerFaultLed == signalType) 523a3702c1fSVernon Mauery { 524a3702c1fSVernon Mauery // Deassert "system ready" 5255e3bf557SAyushi Smriti retCode = ledStoreAndSet(SmSignalSet::smSystemReadyLed, 526a3702c1fSVernon Mauery std::string("Off")); 527a3702c1fSVernon Mauery } 5285e3bf557SAyushi Smriti else if (SmSignalSet::smSystemReadyLed == signalType) 529a3702c1fSVernon Mauery { 530a3702c1fSVernon Mauery // Deassert "fault led" 5315e3bf557SAyushi Smriti retCode = ledStoreAndSet(SmSignalSet::smPowerFaultLed, 532a3702c1fSVernon Mauery std::string("Off")); 533a3702c1fSVernon Mauery } 534a3702c1fSVernon Mauery } 535a3702c1fSVernon Mauery break; 536a3702c1fSVernon Mauery case SmActionSet::revert: 537a3702c1fSVernon Mauery { 538a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 539a3702c1fSVernon Mauery "case SmActionSet::revert"); 5405e3bf557SAyushi Smriti retCode = ledRevert(signalType); 541a3702c1fSVernon Mauery } 542a3702c1fSVernon Mauery break; 543a3702c1fSVernon Mauery default: 544a3702c1fSVernon Mauery { 5455e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 546a3702c1fSVernon Mauery } 547a3702c1fSVernon Mauery } 548a3702c1fSVernon Mauery break; 549a3702c1fSVernon Mauery case SmSignalSet::smFanPowerSpeed: 550a3702c1fSVernon Mauery { 5515e3bf557SAyushi Smriti if ((action == SmActionSet::forceAsserted) && (!pwmSpeed)) 552a3702c1fSVernon Mauery { 5535e3bf557SAyushi Smriti return ipmi::responseReqDataLenInvalid(); 554a3702c1fSVernon Mauery } 5555e3bf557SAyushi Smriti 5565e3bf557SAyushi Smriti if ((action == SmActionSet::forceAsserted) && (*pwmSpeed > 100)) 5575e3bf557SAyushi Smriti { 5585e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 5595e3bf557SAyushi Smriti } 5605e3bf557SAyushi Smriti 561a3702c1fSVernon Mauery uint8_t pwmValue = 0; 5625e3bf557SAyushi Smriti switch (action) 563a3702c1fSVernon Mauery { 564a3702c1fSVernon Mauery case SmActionSet::revert: 565a3702c1fSVernon Mauery { 566a3702c1fSVernon Mauery if (mtm.revertFanPWM) 567a3702c1fSVernon Mauery { 568a3702c1fSVernon Mauery ret = mtm.disablePidControlService(false); 569a3702c1fSVernon Mauery if (ret < 0) 570a3702c1fSVernon Mauery { 5715e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 572a3702c1fSVernon Mauery } 573a3702c1fSVernon Mauery mtm.revertFanPWM = false; 574a3702c1fSVernon Mauery } 575a3702c1fSVernon Mauery } 576a3702c1fSVernon Mauery break; 577a3702c1fSVernon Mauery case SmActionSet::forceAsserted: 578a3702c1fSVernon Mauery { 5795e3bf557SAyushi Smriti pwmValue = *pwmSpeed; 580a3702c1fSVernon Mauery } // fall-through 581a3702c1fSVernon Mauery case SmActionSet::forceDeasserted: 582a3702c1fSVernon Mauery { 583a3702c1fSVernon Mauery if (!mtm.revertFanPWM) 584a3702c1fSVernon Mauery { 585a3702c1fSVernon Mauery ret = mtm.disablePidControlService(true); 586a3702c1fSVernon Mauery if (ret < 0) 587a3702c1fSVernon Mauery { 5885e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 589a3702c1fSVernon Mauery } 590a3702c1fSVernon Mauery mtm.revertFanPWM = true; 591a3702c1fSVernon Mauery } 592a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 593a3702c1fSVernon Mauery std::string fanPwmInstancePath = 5945e3bf557SAyushi Smriti fanPwmPath + std::to_string(instance + 1); 595a3702c1fSVernon Mauery 5965e3bf557SAyushi Smriti ret = 5975e3bf557SAyushi Smriti mtm.setProperty(fanService, fanPwmInstancePath, fanIntf, 5985e3bf557SAyushi Smriti "Value", static_cast<double>(pwmValue)); 599a3702c1fSVernon Mauery if (ret < 0) 600a3702c1fSVernon Mauery { 6015e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 602a3702c1fSVernon Mauery } 603a3702c1fSVernon Mauery } 604a3702c1fSVernon Mauery break; 605a3702c1fSVernon Mauery default: 606a3702c1fSVernon Mauery { 6075e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 608a3702c1fSVernon Mauery } 609a3702c1fSVernon Mauery } 610a3702c1fSVernon Mauery } 611a3702c1fSVernon Mauery break; 612d872a4a4SAyushi Smriti case SmSignalSet::smSpeaker: 613d872a4a4SAyushi Smriti { 614d872a4a4SAyushi Smriti phosphor::logging::log<phosphor::logging::level::INFO>( 615d872a4a4SAyushi Smriti "Performing Speaker SmActionSet", 616d872a4a4SAyushi Smriti phosphor::logging::entry("ACTION=%d", 617d872a4a4SAyushi Smriti static_cast<uint8_t>(action))); 618d872a4a4SAyushi Smriti switch (action) 619d872a4a4SAyushi Smriti { 620d872a4a4SAyushi Smriti case SmActionSet::forceAsserted: 621d872a4a4SAyushi Smriti { 622d872a4a4SAyushi Smriti char beepDevName[] = "/dev/input/event0"; 623d872a4a4SAyushi Smriti if (mtm.mtmTestBeepFd != -1) 624d872a4a4SAyushi Smriti { 625d872a4a4SAyushi Smriti phosphor::logging::log<phosphor::logging::level::INFO>( 626d872a4a4SAyushi Smriti "mtm beep device is opened already!"); 627d872a4a4SAyushi Smriti // returning success as already beep is in progress 628d872a4a4SAyushi Smriti return ipmi::response(retCode); 629d872a4a4SAyushi Smriti } 630d872a4a4SAyushi Smriti 631d872a4a4SAyushi Smriti if ((mtm.mtmTestBeepFd = 632d872a4a4SAyushi Smriti ::open(beepDevName, O_RDWR | O_CLOEXEC)) < 0) 633d872a4a4SAyushi Smriti { 634d872a4a4SAyushi Smriti phosphor::logging::log<phosphor::logging::level::ERR>( 635d872a4a4SAyushi Smriti "Failed to open input device"); 636d872a4a4SAyushi Smriti return ipmi::responseUnspecifiedError(); 637d872a4a4SAyushi Smriti } 638d872a4a4SAyushi Smriti 639d872a4a4SAyushi Smriti struct input_event event; 640d872a4a4SAyushi Smriti event.type = EV_SND; 641d872a4a4SAyushi Smriti event.code = SND_TONE; 642d872a4a4SAyushi Smriti event.value = 2000; 643d872a4a4SAyushi Smriti 644d872a4a4SAyushi Smriti if (::write(mtm.mtmTestBeepFd, &event, 645d872a4a4SAyushi Smriti sizeof(struct input_event)) != 646d872a4a4SAyushi Smriti sizeof(struct input_event)) 647d872a4a4SAyushi Smriti { 648d872a4a4SAyushi Smriti phosphor::logging::log<phosphor::logging::level::ERR>( 649d872a4a4SAyushi Smriti "Failed to write a tone sound event"); 650d872a4a4SAyushi Smriti ::close(mtm.mtmTestBeepFd); 651d872a4a4SAyushi Smriti mtm.mtmTestBeepFd = -1; 652d872a4a4SAyushi Smriti return ipmi::responseUnspecifiedError(); 653d872a4a4SAyushi Smriti } 654d872a4a4SAyushi Smriti mtm.revertTimer.start(revertTimeOut); 655d872a4a4SAyushi Smriti } 656d872a4a4SAyushi Smriti break; 657d872a4a4SAyushi Smriti case SmActionSet::revert: 658d872a4a4SAyushi Smriti case SmActionSet::forceDeasserted: 659d872a4a4SAyushi Smriti { 660d872a4a4SAyushi Smriti if (mtm.mtmTestBeepFd != -1) 661d872a4a4SAyushi Smriti { 662d872a4a4SAyushi Smriti ::close(mtm.mtmTestBeepFd); 663d872a4a4SAyushi Smriti mtm.mtmTestBeepFd = -1; 664d872a4a4SAyushi Smriti } 665d872a4a4SAyushi Smriti } 666d872a4a4SAyushi Smriti break; 667d872a4a4SAyushi Smriti default: 668d872a4a4SAyushi Smriti { 669d872a4a4SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 670d872a4a4SAyushi Smriti } 671d872a4a4SAyushi Smriti } 672d872a4a4SAyushi Smriti } 673d872a4a4SAyushi Smriti break; 6743594c6d6SRichard Marian Thomaiyar case SmSignalSet::smDiskFaultLed: 6753594c6d6SRichard Marian Thomaiyar { 6763594c6d6SRichard Marian Thomaiyar boost::system::error_code ec; 6773594c6d6SRichard Marian Thomaiyar using objPaths = std::vector<std::string>; 6783594c6d6SRichard Marian Thomaiyar std::string driveBasePath = 6793594c6d6SRichard Marian Thomaiyar "/xyz/openbmc_project/inventory/item/drive/"; 6803594c6d6SRichard Marian Thomaiyar static constexpr const char* driveLedIntf = 6813594c6d6SRichard Marian Thomaiyar "xyz.openbmc_project.Led.Group"; 6823594c6d6SRichard Marian Thomaiyar static constexpr const char* hsbpService = 6833594c6d6SRichard Marian Thomaiyar "xyz.openbmc_project.HsbpManager"; 6843594c6d6SRichard Marian Thomaiyar 6853594c6d6SRichard Marian Thomaiyar auto driveList = ctx->bus->yield_method_call<objPaths>( 6863594c6d6SRichard Marian Thomaiyar ctx->yield, ec, "xyz.openbmc_project.ObjectMapper", 6873594c6d6SRichard Marian Thomaiyar "/xyz/openbmc_project/object_mapper", 6883594c6d6SRichard Marian Thomaiyar "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 6893594c6d6SRichard Marian Thomaiyar driveBasePath, 0, std::array<const char*, 1>{driveLedIntf}); 6903594c6d6SRichard Marian Thomaiyar if (ec) 6913594c6d6SRichard Marian Thomaiyar { 6923594c6d6SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 6933594c6d6SRichard Marian Thomaiyar "Failed to query HSBP drive sub tree objects"); 6943594c6d6SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 6953594c6d6SRichard Marian Thomaiyar } 6963594c6d6SRichard Marian Thomaiyar std::string driveObjPath = 6973594c6d6SRichard Marian Thomaiyar driveBasePath + "Drive_" + std::to_string(instance + 1); 6983594c6d6SRichard Marian Thomaiyar if (std::find(driveList.begin(), driveList.end(), driveObjPath) == 6993594c6d6SRichard Marian Thomaiyar driveList.end()) 7003594c6d6SRichard Marian Thomaiyar { 7013594c6d6SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 7023594c6d6SRichard Marian Thomaiyar } 7033594c6d6SRichard Marian Thomaiyar bool driveLedState = false; 7043594c6d6SRichard Marian Thomaiyar switch (action) 7053594c6d6SRichard Marian Thomaiyar { 7063594c6d6SRichard Marian Thomaiyar case SmActionSet::forceAsserted: 7073594c6d6SRichard Marian Thomaiyar { 7083594c6d6SRichard Marian Thomaiyar driveLedState = true; 7093594c6d6SRichard Marian Thomaiyar } 7103594c6d6SRichard Marian Thomaiyar break; 7113594c6d6SRichard Marian Thomaiyar case SmActionSet::revert: 7123594c6d6SRichard Marian Thomaiyar { 7133594c6d6SRichard Marian Thomaiyar driveLedState = false; 7143594c6d6SRichard Marian Thomaiyar } 7153594c6d6SRichard Marian Thomaiyar break; 7163594c6d6SRichard Marian Thomaiyar case SmActionSet::forceDeasserted: 7173594c6d6SRichard Marian Thomaiyar { 7183594c6d6SRichard Marian Thomaiyar driveLedState = false; 7193594c6d6SRichard Marian Thomaiyar } 7203594c6d6SRichard Marian Thomaiyar break; 7213594c6d6SRichard Marian Thomaiyar default: 7223594c6d6SRichard Marian Thomaiyar { 7233594c6d6SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 7243594c6d6SRichard Marian Thomaiyar } 7253594c6d6SRichard Marian Thomaiyar } 7263594c6d6SRichard Marian Thomaiyar ret = mtm.setProperty(hsbpService, driveObjPath, driveLedIntf, 7273594c6d6SRichard Marian Thomaiyar "Asserted", driveLedState); 7283594c6d6SRichard Marian Thomaiyar if (ret < 0) 7293594c6d6SRichard Marian Thomaiyar { 7303594c6d6SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 7313594c6d6SRichard Marian Thomaiyar } 7323594c6d6SRichard Marian Thomaiyar } 7333594c6d6SRichard Marian Thomaiyar break; 734a3702c1fSVernon Mauery default: 735a3702c1fSVernon Mauery { 7365e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 737a3702c1fSVernon Mauery } 738a3702c1fSVernon Mauery } 7394cc10159SRichard Marian Thomaiyar if (retCode == ccSuccess) 7404cc10159SRichard Marian Thomaiyar { 741357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 7424cc10159SRichard Marian Thomaiyar } 7435e3bf557SAyushi Smriti return ipmi::response(retCode); 744a3702c1fSVernon Mauery } 745a3702c1fSVernon Mauery 746357ddc74SRichard Marian Thomaiyar ipmi::RspType<> mtmKeepAlive(ipmi::Context::ptr ctx, uint8_t reserved, 747666dd01cSRichard Marian Thomaiyar const std::array<char, 5>& intentionalSignature) 748666dd01cSRichard Marian Thomaiyar { 749e0511e5fSAyushi Smriti // mfg filter logic is used to allow MTM keep alive command only in 750e0511e5fSAyushi Smriti // manfacturing mode 751e0511e5fSAyushi Smriti 752666dd01cSRichard Marian Thomaiyar constexpr std::array<char, 5> signatureOk = {'I', 'N', 'T', 'E', 'L'}; 753666dd01cSRichard Marian Thomaiyar if (intentionalSignature != signatureOk || reserved != 0) 754666dd01cSRichard Marian Thomaiyar { 755666dd01cSRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 756666dd01cSRichard Marian Thomaiyar } 757357ddc74SRichard Marian Thomaiyar return ipmi::response(resetMtmTimer(ctx)); 758666dd01cSRichard Marian Thomaiyar } 759666dd01cSRichard Marian Thomaiyar 760e0511e5fSAyushi Smriti static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd) 761e0511e5fSAyushi Smriti { 762e0511e5fSAyushi Smriti return (netFn << 8) | cmd; 763e0511e5fSAyushi Smriti } 764e0511e5fSAyushi Smriti 76585feb130SYong Li ipmi::Cc mfgFilterMessage(ipmi::message::Request::ptr request) 76685feb130SYong Li { 767e0511e5fSAyushi Smriti // Restricted commands, must be executed only in Manufacturing mode 768e0511e5fSAyushi Smriti switch (makeCmdKey(request->ctx->netFn, request->ctx->cmd)) 76985feb130SYong Li { 770e0511e5fSAyushi Smriti // i2c master write read command needs additional checking 771e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead): 77285feb130SYong Li if (request->payload.size() > 4) 77385feb130SYong Li { 774ae13ac62SRichard Marian Thomaiyar // Allow write data count > 1 only in Special mode 775ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 77685feb130SYong Li { 77785feb130SYong Li return ipmi::ccInsufficientPrivilege; 77885feb130SYong Li } 77985feb130SYong Li } 7802d4a0198Sjayaprakash Mutyala return ipmi::ccSuccess; 781e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 782e0511e5fSAyushi Smriti ipmi::intel::general::cmdGetSmSignal): 783e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 784e0511e5fSAyushi Smriti ipmi::intel::general::cmdSetSmSignal): 785e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 786e0511e5fSAyushi Smriti ipmi::intel::general::cmdMtmKeepAlive): 787e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 788e0511e5fSAyushi Smriti ipmi::intel::general::cmdSetManufacturingData): 789e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 790e0511e5fSAyushi Smriti ipmi::intel::general::cmdGetManufacturingData): 791e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdWriteFruData): 79285feb130SYong Li 793ae13ac62SRichard Marian Thomaiyar // Check for Special mode 794ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 795e0511e5fSAyushi Smriti { 796e0511e5fSAyushi Smriti return ipmi::ccInvalidCommand; 797e0511e5fSAyushi Smriti } 7982d4a0198Sjayaprakash Mutyala return ipmi::ccSuccess; 7992d4a0198Sjayaprakash Mutyala case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdDeleteSelEntry): 8002d4a0198Sjayaprakash Mutyala { 8012d4a0198Sjayaprakash Mutyala return ipmi::ccInvalidCommand; 8022d4a0198Sjayaprakash Mutyala } 803e0511e5fSAyushi Smriti } 80485feb130SYong Li return ipmi::ccSuccess; 80585feb130SYong Li } 80685feb130SYong Li 8071f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxEthSize = 6; 8081f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxSupportedEth = 3; 8091f0839c2SRichard Marian Thomaiyar static constexpr const char* factoryEthAddrBaseFileName = 8101f0839c2SRichard Marian Thomaiyar "/var/sofs/factory-settings/network/mac/eth"; 8111f0839c2SRichard Marian Thomaiyar 812357ddc74SRichard Marian Thomaiyar ipmi::RspType<> setManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType, 8131f0839c2SRichard Marian Thomaiyar std::array<uint8_t, maxEthSize> ethData) 8141f0839c2SRichard Marian Thomaiyar { 8151f0839c2SRichard Marian Thomaiyar // mfg filter logic will restrict this command executing only in mfg mode. 8161f0839c2SRichard Marian Thomaiyar if (dataType >= maxSupportedEth) 8171f0839c2SRichard Marian Thomaiyar { 8181f0839c2SRichard Marian Thomaiyar return ipmi::responseParmOutOfRange(); 8191f0839c2SRichard Marian Thomaiyar } 8201f0839c2SRichard Marian Thomaiyar 8211f0839c2SRichard Marian Thomaiyar constexpr uint8_t invalidData = 0; 8221f0839c2SRichard Marian Thomaiyar constexpr uint8_t validData = 1; 8231f0839c2SRichard Marian Thomaiyar constexpr uint8_t ethAddrStrSize = 8241f0839c2SRichard Marian Thomaiyar 19; // XX:XX:XX:XX:XX:XX + \n + null termination; 8251f0839c2SRichard Marian Thomaiyar std::vector<uint8_t> buff(ethAddrStrSize); 8261f0839c2SRichard Marian Thomaiyar std::snprintf(reinterpret_cast<char*>(buff.data()), ethAddrStrSize, 8271f0839c2SRichard Marian Thomaiyar "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", ethData.at(0), 8281f0839c2SRichard Marian Thomaiyar ethData.at(1), ethData.at(2), ethData.at(3), ethData.at(4), 8291f0839c2SRichard Marian Thomaiyar ethData.at(5)); 8301f0839c2SRichard Marian Thomaiyar std::ofstream oEthFile(factoryEthAddrBaseFileName + 8311f0839c2SRichard Marian Thomaiyar std::to_string(dataType), 8321f0839c2SRichard Marian Thomaiyar std::ofstream::out); 8331f0839c2SRichard Marian Thomaiyar if (!oEthFile.good()) 8341f0839c2SRichard Marian Thomaiyar { 8351f0839c2SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 8361f0839c2SRichard Marian Thomaiyar } 8371f0839c2SRichard Marian Thomaiyar 8381f0839c2SRichard Marian Thomaiyar oEthFile << reinterpret_cast<char*>(buff.data()); 8396d83e4eeSJohnathan Mantey oEthFile.flush(); 8401f0839c2SRichard Marian Thomaiyar oEthFile.close(); 8411f0839c2SRichard Marian Thomaiyar 842357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 8431f0839c2SRichard Marian Thomaiyar return ipmi::responseSuccess(); 8441f0839c2SRichard Marian Thomaiyar } 8451f0839c2SRichard Marian Thomaiyar 8461f0839c2SRichard Marian Thomaiyar ipmi::RspType<uint8_t, std::array<uint8_t, maxEthSize>> 847357ddc74SRichard Marian Thomaiyar getManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType) 8481f0839c2SRichard Marian Thomaiyar { 8491f0839c2SRichard Marian Thomaiyar // mfg filter logic will restrict this command executing only in mfg mode. 8501f0839c2SRichard Marian Thomaiyar if (dataType >= maxSupportedEth) 8511f0839c2SRichard Marian Thomaiyar { 8521f0839c2SRichard Marian Thomaiyar return ipmi::responseParmOutOfRange(); 8531f0839c2SRichard Marian Thomaiyar } 8541f0839c2SRichard Marian Thomaiyar std::array<uint8_t, maxEthSize> ethData{0}; 8551f0839c2SRichard Marian Thomaiyar constexpr uint8_t invalidData = 0; 8561f0839c2SRichard Marian Thomaiyar constexpr uint8_t validData = 1; 8571f0839c2SRichard Marian Thomaiyar 8581f0839c2SRichard Marian Thomaiyar std::ifstream iEthFile(factoryEthAddrBaseFileName + 8591f0839c2SRichard Marian Thomaiyar std::to_string(dataType), 8601f0839c2SRichard Marian Thomaiyar std::ifstream::in); 8611f0839c2SRichard Marian Thomaiyar if (!iEthFile.good()) 8621f0839c2SRichard Marian Thomaiyar { 8631f0839c2SRichard Marian Thomaiyar return ipmi::responseSuccess(invalidData, ethData); 8641f0839c2SRichard Marian Thomaiyar } 8651f0839c2SRichard Marian Thomaiyar std::string ethStr; 8661f0839c2SRichard Marian Thomaiyar iEthFile >> ethStr; 8671f0839c2SRichard Marian Thomaiyar uint8_t* data = ethData.data(); 8681f0839c2SRichard Marian Thomaiyar std::sscanf(ethStr.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 8691f0839c2SRichard Marian Thomaiyar data, (data + 1), (data + 2), (data + 3), (data + 4), 8701f0839c2SRichard Marian Thomaiyar (data + 5)); 8711f0839c2SRichard Marian Thomaiyar 872357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 8731f0839c2SRichard Marian Thomaiyar return ipmi::responseSuccess(validData, ethData); 8741f0839c2SRichard Marian Thomaiyar } 8751f0839c2SRichard Marian Thomaiyar 876f267a67dSYong Li /** @brief implements slot master write read IPMI command which can be used for 877f267a67dSYong Li * low-level I2C/SMBus write, read or write-read access for PCIE slots 878f267a67dSYong Li * @param reserved - skip 6 bit 879f267a67dSYong Li * @param addressType - address type 880f267a67dSYong Li * @param bbSlotNum - baseboard slot number 881f267a67dSYong Li * @param riserSlotNum - riser slot number 882f267a67dSYong Li * @param reserved2 - skip 2 bit 883f267a67dSYong Li * @param slaveAddr - slave address 884f267a67dSYong Li * @param readCount - number of bytes to be read 885f267a67dSYong Li * @param writeData - data to be written 886f267a67dSYong Li * 887f267a67dSYong Li * @returns IPMI completion code plus response data 888f267a67dSYong Li */ 889f267a67dSYong Li ipmi::RspType<std::vector<uint8_t>> 890f267a67dSYong Li appSlotI2CMasterWriteRead(uint6_t reserved, uint2_t addressType, 891f267a67dSYong Li uint3_t bbSlotNum, uint3_t riserSlotNum, 892f267a67dSYong Li uint2_t resvered2, uint8_t slaveAddr, 893f267a67dSYong Li uint8_t readCount, std::vector<uint8_t> writeData) 894f267a67dSYong Li { 895f267a67dSYong Li const size_t writeCount = writeData.size(); 896f267a67dSYong Li std::string i2cBus; 897f267a67dSYong Li if (addressType == slotAddressTypeBus) 898f267a67dSYong Li { 899f267a67dSYong Li std::string path = "/dev/i2c-mux/Riser_" + 900f267a67dSYong Li std::to_string(static_cast<uint8_t>(bbSlotNum)) + 901f267a67dSYong Li "_Mux/Pcie_Slot_" + 902f267a67dSYong Li std::to_string(static_cast<uint8_t>(riserSlotNum)); 903f267a67dSYong Li 904f267a67dSYong Li if (std::filesystem::exists(path) && std::filesystem::is_symlink(path)) 905f267a67dSYong Li { 906f267a67dSYong Li i2cBus = std::filesystem::read_symlink(path); 907f267a67dSYong Li } 908f267a67dSYong Li else 909f267a67dSYong Li { 910f267a67dSYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 911f267a67dSYong Li "Master write read command: Cannot get BusID"); 912f267a67dSYong Li return ipmi::responseInvalidFieldRequest(); 913f267a67dSYong Li } 914f267a67dSYong Li } 915f267a67dSYong Li else if (addressType == slotAddressTypeUniqueid) 916f267a67dSYong Li { 917f267a67dSYong Li i2cBus = "/dev/i2c-" + 918f267a67dSYong Li std::to_string(static_cast<uint8_t>(bbSlotNum) | 919f267a67dSYong Li (static_cast<uint8_t>(riserSlotNum) << 3)); 920f267a67dSYong Li } 921f267a67dSYong Li else 922f267a67dSYong Li { 923f267a67dSYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 924f267a67dSYong Li "Master write read command: invalid request"); 925f267a67dSYong Li return ipmi::responseInvalidFieldRequest(); 926f267a67dSYong Li } 927f267a67dSYong Li 928f267a67dSYong Li // Allow single byte write as it is offset byte to read the data, rest allow 929ae13ac62SRichard Marian Thomaiyar // only in Special mode. 930f267a67dSYong Li if (writeCount > 1) 931f267a67dSYong Li { 932ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 933f267a67dSYong Li { 934f267a67dSYong Li return ipmi::responseInsufficientPrivilege(); 935f267a67dSYong Li } 936f267a67dSYong Li } 937f267a67dSYong Li 938f267a67dSYong Li if (readCount > slotI2CMaxReadSize) 939f267a67dSYong Li { 940f267a67dSYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 941f267a67dSYong Li "Master write read command: Read count exceeds limit"); 942f267a67dSYong Li return ipmi::responseParmOutOfRange(); 943f267a67dSYong Li } 944f267a67dSYong Li 945f267a67dSYong Li if (!readCount && !writeCount) 946f267a67dSYong Li { 947f267a67dSYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 948f267a67dSYong Li "Master write read command: Read & write count are 0"); 949f267a67dSYong Li return ipmi::responseInvalidFieldRequest(); 950f267a67dSYong Li } 951f267a67dSYong Li 952f267a67dSYong Li std::vector<uint8_t> readBuf(readCount); 953f267a67dSYong Li 954f267a67dSYong Li ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf); 955f267a67dSYong Li if (retI2C != ipmi::ccSuccess) 956f267a67dSYong Li { 957f267a67dSYong Li return ipmi::response(retI2C); 958f267a67dSYong Li } 959f267a67dSYong Li 960f267a67dSYong Li return ipmi::responseSuccess(readBuf); 961f267a67dSYong Li } 962068b4f2cSYong Li 963068b4f2cSYong Li ipmi::RspType<> clearCMOS() 964068b4f2cSYong Li { 965d0d010b7SYong Li // There is an i2c device on bus 4, the slave address is 0x38. Based on the 966eaeb6cb0SYong Li // spec, writing 0x1 to address 0x61 on this device, will trigger the clear 967068b4f2cSYong Li // CMOS action. 968d0d010b7SYong Li constexpr uint8_t slaveAddr = 0x38; 969068b4f2cSYong Li std::string i2cBus = "/dev/i2c-4"; 970eaeb6cb0SYong Li std::vector<uint8_t> writeData = {0x61, 0x1}; 971068b4f2cSYong Li std::vector<uint8_t> readBuf(0); 972068b4f2cSYong Li 973ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 974068b4f2cSYong Li { 975068b4f2cSYong Li return ipmi::responseInsufficientPrivilege(); 976068b4f2cSYong Li } 977068b4f2cSYong Li 978068b4f2cSYong Li ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf); 979068b4f2cSYong Li return ipmi::response(retI2C); 980068b4f2cSYong Li } 981a3702c1fSVernon Mauery } // namespace ipmi 982a3702c1fSVernon Mauery 983a3702c1fSVernon Mauery void register_mtm_commands() __attribute__((constructor)); 984a3702c1fSVernon Mauery void register_mtm_commands() 985a3702c1fSVernon Mauery { 98638d2b5a6SJason M. Bills // <Get SM Signal> 98798bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 98898bbf69aSVernon Mauery ipmi::intel::general::cmdGetSmSignal, 9895e3bf557SAyushi Smriti ipmi::Privilege::Admin, ipmi::appMTMGetSignal); 990a3702c1fSVernon Mauery 99198bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 99298bbf69aSVernon Mauery ipmi::intel::general::cmdSetSmSignal, 9935e3bf557SAyushi Smriti ipmi::Privilege::Admin, ipmi::appMTMSetSignal); 994a3702c1fSVernon Mauery 99598bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 99698bbf69aSVernon Mauery ipmi::intel::general::cmdMtmKeepAlive, 997666dd01cSRichard Marian Thomaiyar ipmi::Privilege::Admin, ipmi::mtmKeepAlive); 998666dd01cSRichard Marian Thomaiyar 99998bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 100098bbf69aSVernon Mauery ipmi::intel::general::cmdSetManufacturingData, 10011f0839c2SRichard Marian Thomaiyar ipmi::Privilege::Admin, ipmi::setManufacturingData); 10021f0839c2SRichard Marian Thomaiyar 100398bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 100498bbf69aSVernon Mauery ipmi::intel::general::cmdGetManufacturingData, 10051f0839c2SRichard Marian Thomaiyar ipmi::Privilege::Admin, ipmi::getManufacturingData); 10061f0839c2SRichard Marian Thomaiyar 100798bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 100898bbf69aSVernon Mauery ipmi::intel::general::cmdSlotI2CMasterWriteRead, 100998bbf69aSVernon Mauery ipmi::Privilege::Admin, 101098bbf69aSVernon Mauery ipmi::appSlotI2CMasterWriteRead); 1011f267a67dSYong Li 1012068b4f2cSYong Li ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnPlatform, 1013068b4f2cSYong Li ipmi::intel::platform::cmdClearCMOS, 1014068b4f2cSYong Li ipmi::Privilege::Admin, ipmi::clearCMOS); 1015068b4f2cSYong Li 101698bbf69aSVernon Mauery ipmi::registerFilter(ipmi::prioOemBase, 101785feb130SYong Li [](ipmi::message::Request::ptr request) { 101885feb130SYong Li return ipmi::mfgFilterMessage(request); 101985feb130SYong Li }); 1020a3702c1fSVernon Mauery } 1021