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 17a3702c1fSVernon Mauery #include <ipmid/api.hpp> 18a3702c1fSVernon Mauery #include <manufacturingcommands.hpp> 19a3702c1fSVernon Mauery #include <oemcommands.hpp> 20a3702c1fSVernon Mauery 21a3702c1fSVernon Mauery namespace ipmi 22a3702c1fSVernon Mauery { 23a3702c1fSVernon Mauery 24a3702c1fSVernon Mauery Manufacturing mtm; 25a3702c1fSVernon Mauery 26a3702c1fSVernon Mauery static auto revertTimeOut = 27a3702c1fSVernon Mauery std::chrono::duration_cast<std::chrono::microseconds>( 28a3702c1fSVernon Mauery std::chrono::seconds(60)); // 1 minute timeout 29a3702c1fSVernon Mauery 30a3702c1fSVernon Mauery static constexpr const char* callbackMgrService = 31a3702c1fSVernon Mauery "xyz.openbmc_project.CallbackManager"; 32a3702c1fSVernon Mauery static constexpr const char* callbackMgrIntf = 33a3702c1fSVernon Mauery "xyz.openbmc_project.CallbackManager"; 34a3702c1fSVernon Mauery static constexpr const char* callbackMgrObjPath = 35a3702c1fSVernon Mauery "/xyz/openbmc_project/CallbackManager"; 36a3702c1fSVernon Mauery static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate"; 37a3702c1fSVernon Mauery 38a3702c1fSVernon Mauery const static constexpr char* systemDService = "org.freedesktop.systemd1"; 39a3702c1fSVernon Mauery const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1"; 40a3702c1fSVernon Mauery const static constexpr char* systemDMgrIntf = 41a3702c1fSVernon Mauery "org.freedesktop.systemd1.Manager"; 42a3702c1fSVernon Mauery const static constexpr char* pidControlService = "phosphor-pid-control.service"; 43a3702c1fSVernon Mauery 4438d2b5a6SJason M. Bills int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path) 45a3702c1fSVernon Mauery { 4638d2b5a6SJason M. Bills switch (signal) 4738d2b5a6SJason M. Bills { 4838d2b5a6SJason M. Bills case SmSignalGet::smPowerButton: 4938d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/power"; 5038d2b5a6SJason M. Bills break; 5138d2b5a6SJason M. Bills case SmSignalGet::smResetButton: 5238d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/reset"; 5338d2b5a6SJason M. Bills break; 5438d2b5a6SJason M. Bills case SmSignalGet::smNMIButton: 5538d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/nmi"; 5638d2b5a6SJason M. Bills break; 57*8e5e2b04SRichard Marian Thomaiyar case SmSignalGet::smIdentifyButton: 58*8e5e2b04SRichard Marian Thomaiyar path = "/xyz/openbmc_project/chassis/buttons/id"; 59*8e5e2b04SRichard Marian Thomaiyar break; 6038d2b5a6SJason M. Bills default: 6138d2b5a6SJason M. Bills return -1; 6238d2b5a6SJason M. Bills break; 6338d2b5a6SJason M. Bills } 6438d2b5a6SJason M. Bills return 0; 65a3702c1fSVernon Mauery } 66a3702c1fSVernon Mauery 67a3702c1fSVernon Mauery ipmi_ret_t ledStoreAndSet(SmSignalSet signal, std::string setState) 68a3702c1fSVernon Mauery { 69a3702c1fSVernon Mauery LedProperty* ledProp = mtm.findLedProperty(signal); 70a3702c1fSVernon Mauery if (ledProp == nullptr) 71a3702c1fSVernon Mauery { 72a3702c1fSVernon Mauery return IPMI_CC_INVALID_FIELD_REQUEST; 73a3702c1fSVernon Mauery } 74a3702c1fSVernon Mauery 75a3702c1fSVernon Mauery std::string ledName = ledProp->getName(); 76a3702c1fSVernon Mauery std::string ledService = ledServicePrefix + ledName; 77a3702c1fSVernon Mauery std::string ledPath = ledPathPrefix + ledName; 78a3702c1fSVernon Mauery ipmi::Value presentState; 79a3702c1fSVernon Mauery 80a3702c1fSVernon Mauery if (false == ledProp->getLock()) 81a3702c1fSVernon Mauery { 82a3702c1fSVernon Mauery if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf, 83a3702c1fSVernon Mauery "State", &presentState) != 0) 84a3702c1fSVernon Mauery { 85a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 86a3702c1fSVernon Mauery } 87a3702c1fSVernon Mauery ledProp->setPrevState(std::get<std::string>(presentState)); 88a3702c1fSVernon Mauery ledProp->setLock(true); 89a3702c1fSVernon Mauery if (signal == SmSignalSet::smPowerFaultLed || 90a3702c1fSVernon Mauery signal == SmSignalSet::smSystemReadyLed) 91a3702c1fSVernon Mauery { 92a3702c1fSVernon Mauery mtm.revertLedCallback = true; 93a3702c1fSVernon Mauery } 94a3702c1fSVernon Mauery } 9538d2b5a6SJason M. Bills if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 96a3702c1fSVernon Mauery ledStateStr + setState) != 0) 97a3702c1fSVernon Mauery { 98a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 99a3702c1fSVernon Mauery } 100a3702c1fSVernon Mauery return IPMI_CC_OK; 101a3702c1fSVernon Mauery } 102a3702c1fSVernon Mauery 103a3702c1fSVernon Mauery ipmi_ret_t ledRevert(SmSignalSet signal) 104a3702c1fSVernon Mauery { 105a3702c1fSVernon Mauery LedProperty* ledProp = mtm.findLedProperty(signal); 106a3702c1fSVernon Mauery if (ledProp == nullptr) 107a3702c1fSVernon Mauery { 108a3702c1fSVernon Mauery return IPMI_CC_INVALID_FIELD_REQUEST; 109a3702c1fSVernon Mauery } 110a3702c1fSVernon Mauery if (true == ledProp->getLock()) 111a3702c1fSVernon Mauery { 112a3702c1fSVernon Mauery ledProp->setLock(false); 113a3702c1fSVernon Mauery if (signal == SmSignalSet::smPowerFaultLed || 114a3702c1fSVernon Mauery signal == SmSignalSet::smSystemReadyLed) 115a3702c1fSVernon Mauery { 116a3702c1fSVernon Mauery try 117a3702c1fSVernon Mauery { 118a3702c1fSVernon Mauery ipmi::method_no_args::callDbusMethod( 119a3702c1fSVernon Mauery *getSdBus(), callbackMgrService, callbackMgrObjPath, 120a3702c1fSVernon Mauery callbackMgrIntf, retriggerLedUpdate); 121a3702c1fSVernon Mauery } 122a3702c1fSVernon Mauery catch (sdbusplus::exception_t& e) 123a3702c1fSVernon Mauery { 124a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 125a3702c1fSVernon Mauery } 126a3702c1fSVernon Mauery mtm.revertLedCallback = false; 127a3702c1fSVernon Mauery } 128a3702c1fSVernon Mauery else 129a3702c1fSVernon Mauery { 130a3702c1fSVernon Mauery std::string ledName = ledProp->getName(); 131a3702c1fSVernon Mauery std::string ledService = ledServicePrefix + ledName; 132a3702c1fSVernon Mauery std::string ledPath = ledPathPrefix + ledName; 13338d2b5a6SJason M. Bills if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 13438d2b5a6SJason M. Bills ledProp->getPrevState()) != 0) 135a3702c1fSVernon Mauery { 136a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 137a3702c1fSVernon Mauery } 138a3702c1fSVernon Mauery } 139a3702c1fSVernon Mauery } 140a3702c1fSVernon Mauery return IPMI_CC_OK; 141a3702c1fSVernon Mauery } 142a3702c1fSVernon Mauery 143a3702c1fSVernon Mauery void Manufacturing::initData() 144a3702c1fSVernon Mauery { 145a3702c1fSVernon Mauery ledPropertyList.push_back( 146a3702c1fSVernon Mauery LedProperty(SmSignalSet::smPowerFaultLed, "status_amber")); 147a3702c1fSVernon Mauery ledPropertyList.push_back( 148a3702c1fSVernon Mauery LedProperty(SmSignalSet::smSystemReadyLed, "status_green")); 149a3702c1fSVernon Mauery ledPropertyList.push_back( 150a3702c1fSVernon Mauery LedProperty(SmSignalSet::smIdentifyLed, "identify")); 151a3702c1fSVernon Mauery } 152a3702c1fSVernon Mauery 153a3702c1fSVernon Mauery void Manufacturing::revertTimerHandler() 154a3702c1fSVernon Mauery { 155a3702c1fSVernon Mauery if (revertFanPWM) 156a3702c1fSVernon Mauery { 157a3702c1fSVernon Mauery revertFanPWM = false; 158a3702c1fSVernon Mauery disablePidControlService(false); 159a3702c1fSVernon Mauery } 160a3702c1fSVernon Mauery 161a3702c1fSVernon Mauery for (const auto& ledProperty : ledPropertyList) 162a3702c1fSVernon Mauery { 163a3702c1fSVernon Mauery const std::string& ledName = ledProperty.getName(); 164a3702c1fSVernon Mauery ledRevert(ledProperty.getSignal()); 165a3702c1fSVernon Mauery } 166a3702c1fSVernon Mauery } 167a3702c1fSVernon Mauery 168a3702c1fSVernon Mauery Manufacturing::Manufacturing() : 169a3702c1fSVernon Mauery revertTimer([&](void) { revertTimerHandler(); }) 170a3702c1fSVernon Mauery { 171a3702c1fSVernon Mauery initData(); 172a3702c1fSVernon Mauery } 173a3702c1fSVernon Mauery 17438d2b5a6SJason M. Bills int8_t Manufacturing::getProperty(const std::string& service, 17538d2b5a6SJason M. Bills const std::string& path, 17638d2b5a6SJason M. Bills const std::string& interface, 17738d2b5a6SJason M. Bills const std::string& propertyName, 17838d2b5a6SJason M. Bills ipmi::Value* reply) 179a3702c1fSVernon Mauery { 180a3702c1fSVernon Mauery try 181a3702c1fSVernon Mauery { 18238d2b5a6SJason M. Bills *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface, 18338d2b5a6SJason M. Bills propertyName); 184a3702c1fSVernon Mauery } 185a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& e) 186a3702c1fSVernon Mauery { 187a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 188a3702c1fSVernon Mauery "ERROR: getProperty"); 189a3702c1fSVernon Mauery return -1; 190a3702c1fSVernon Mauery } 191a3702c1fSVernon Mauery 192a3702c1fSVernon Mauery return 0; 193a3702c1fSVernon Mauery } 194a3702c1fSVernon Mauery 19538d2b5a6SJason M. Bills int8_t Manufacturing::setProperty(const std::string& service, 19638d2b5a6SJason M. Bills const std::string& path, 19738d2b5a6SJason M. Bills const std::string& interface, 19838d2b5a6SJason M. Bills const std::string& propertyName, 19938d2b5a6SJason M. Bills ipmi::Value value) 200a3702c1fSVernon Mauery { 201a3702c1fSVernon Mauery try 202a3702c1fSVernon Mauery { 20338d2b5a6SJason M. Bills ipmi::setDbusProperty(*getSdBus(), service, path, interface, 204a3702c1fSVernon Mauery propertyName, value); 205a3702c1fSVernon Mauery } 206a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& e) 207a3702c1fSVernon Mauery { 208a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 209a3702c1fSVernon Mauery "ERROR: setProperty"); 210a3702c1fSVernon Mauery return -1; 211a3702c1fSVernon Mauery } 212a3702c1fSVernon Mauery 213a3702c1fSVernon Mauery return 0; 214a3702c1fSVernon Mauery } 215a3702c1fSVernon Mauery 216a3702c1fSVernon Mauery int8_t Manufacturing::disablePidControlService(const bool disable) 217a3702c1fSVernon Mauery { 218a3702c1fSVernon Mauery try 219a3702c1fSVernon Mauery { 220a3702c1fSVernon Mauery auto dbus = getSdBus(); 221a3702c1fSVernon Mauery auto method = dbus->new_method_call(systemDService, systemDObjPath, 222a3702c1fSVernon Mauery systemDMgrIntf, 223a3702c1fSVernon Mauery disable ? "StopUnit" : "StartUnit"); 224a3702c1fSVernon Mauery method.append(pidControlService, "replace"); 225a3702c1fSVernon Mauery auto reply = dbus->call(method); 226a3702c1fSVernon Mauery } 227a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& e) 228a3702c1fSVernon Mauery { 229a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 230a3702c1fSVernon Mauery "ERROR: phosphor-pid-control service start or stop failed"); 231a3702c1fSVernon Mauery return -1; 232a3702c1fSVernon Mauery } 233a3702c1fSVernon Mauery return 0; 234a3702c1fSVernon Mauery } 235a3702c1fSVernon Mauery 23638d2b5a6SJason M. Bills ipmi::RspType<uint8_t, // Signal value 23738d2b5a6SJason M. Bills std::optional<uint16_t> // Fan tach value 23838d2b5a6SJason M. Bills > 23938d2b5a6SJason M. Bills appMTMGetSignal(uint8_t signalTypeByte, uint8_t instance, 24038d2b5a6SJason M. Bills uint8_t actionByte) 241a3702c1fSVernon Mauery { 24238d2b5a6SJason M. Bills if (mtm.getAccessLvl() < MtmLvl::mtmAvailable) 24338d2b5a6SJason M. Bills { 24438d2b5a6SJason M. Bills return ipmi::responseInvalidCommand(); 24538d2b5a6SJason M. Bills } 24638d2b5a6SJason M. Bills 24738d2b5a6SJason M. Bills SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte); 24838d2b5a6SJason M. Bills SmActionGet action = static_cast<SmActionGet>(actionByte); 24938d2b5a6SJason M. Bills 25038d2b5a6SJason M. Bills switch (signalType) 25138d2b5a6SJason M. Bills { 25238d2b5a6SJason M. Bills case SmSignalGet::smFanPwmGet: 25338d2b5a6SJason M. Bills { 254a3702c1fSVernon Mauery ipmi::Value reply; 25538d2b5a6SJason M. Bills std::string fullPath = fanPwmPath + std::to_string(instance); 25638d2b5a6SJason M. Bills if (mtm.getProperty(fanService, fullPath, fanIntf, "Value", 25738d2b5a6SJason M. Bills &reply) < 0) 25838d2b5a6SJason M. Bills { 25938d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 26038d2b5a6SJason M. Bills } 26138d2b5a6SJason M. Bills double* doubleVal = std::get_if<double>(&reply); 26238d2b5a6SJason M. Bills if (doubleVal == nullptr) 26338d2b5a6SJason M. Bills { 26438d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 26538d2b5a6SJason M. Bills } 26638d2b5a6SJason M. Bills uint8_t sensorVal = std::round(*doubleVal); 26738d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, std::nullopt); 26838d2b5a6SJason M. Bills } 26938d2b5a6SJason M. Bills break; 27038d2b5a6SJason M. Bills case SmSignalGet::smFanTachometerGet: 27138d2b5a6SJason M. Bills 27238d2b5a6SJason M. Bills { 27338d2b5a6SJason M. Bills // Full path calculation pattern: 27438d2b5a6SJason M. Bills // Instance 1 path is 27538d2b5a6SJason M. Bills // /xyz/openbmc_project/sensors/fan_tach/Fan_1a Instance 2 path 27638d2b5a6SJason M. Bills // is /xyz/openbmc_project/sensors/fan_tach/Fan_1b Instance 3 27738d2b5a6SJason M. Bills // path is /xyz/openbmc_project/sensors/fan_tach/Fan_2a 27838d2b5a6SJason M. Bills // and so on... 27938d2b5a6SJason M. Bills std::string fullPath = fanTachPathPrefix; 28038d2b5a6SJason M. Bills std::string fanAb = (instance % 2) == 0 ? "b" : "a"; 28138d2b5a6SJason M. Bills if (0 == instance) 28238d2b5a6SJason M. Bills { 28338d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 28438d2b5a6SJason M. Bills } 28538d2b5a6SJason M. Bills else if (0 == instance / 2) 28638d2b5a6SJason M. Bills { 28738d2b5a6SJason M. Bills fullPath += std::string("1") + fanAb; 28838d2b5a6SJason M. Bills } 28938d2b5a6SJason M. Bills else 29038d2b5a6SJason M. Bills { 29138d2b5a6SJason M. Bills fullPath += std::to_string(instance / 2) + fanAb; 29238d2b5a6SJason M. Bills } 29338d2b5a6SJason M. Bills 29438d2b5a6SJason M. Bills ipmi::Value reply; 29538d2b5a6SJason M. Bills if (mtm.getProperty(fanService, fullPath, fanIntf, "Value", 29638d2b5a6SJason M. Bills &reply) < 0) 29738d2b5a6SJason M. Bills { 29838d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 29938d2b5a6SJason M. Bills } 30038d2b5a6SJason M. Bills 30138d2b5a6SJason M. Bills double* doubleVal = std::get_if<double>(&reply); 30238d2b5a6SJason M. Bills if (doubleVal == nullptr) 30338d2b5a6SJason M. Bills { 30438d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 30538d2b5a6SJason M. Bills } 30638d2b5a6SJason M. Bills uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT; 30738d2b5a6SJason M. Bills std::optional<uint16_t> fanTach = std::round(*doubleVal); 30838d2b5a6SJason M. Bills 30938d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, fanTach); 31038d2b5a6SJason M. Bills } 31138d2b5a6SJason M. Bills break; 312*8e5e2b04SRichard Marian Thomaiyar case SmSignalGet::smIdentifyButton: 313*8e5e2b04SRichard Marian Thomaiyar { 314*8e5e2b04SRichard Marian Thomaiyar if (action == SmActionGet::revert || action == SmActionGet::ignore) 315*8e5e2b04SRichard Marian Thomaiyar { 316*8e5e2b04SRichard Marian Thomaiyar // ButtonMasked property is not supported for ID button as it is 317*8e5e2b04SRichard Marian Thomaiyar // unnecessary. Hence if requested for revert / ignore, override 318*8e5e2b04SRichard Marian Thomaiyar // it to sample action to make tools happy. 319*8e5e2b04SRichard Marian Thomaiyar action = SmActionGet::sample; 320*8e5e2b04SRichard Marian Thomaiyar } 321*8e5e2b04SRichard Marian Thomaiyar // fall-through 322*8e5e2b04SRichard Marian Thomaiyar } 32338d2b5a6SJason M. Bills case SmSignalGet::smResetButton: 32438d2b5a6SJason M. Bills case SmSignalGet::smPowerButton: 32538d2b5a6SJason M. Bills case SmSignalGet::smNMIButton: 32638d2b5a6SJason M. Bills { 32738d2b5a6SJason M. Bills std::string path; 32838d2b5a6SJason M. Bills if (getGpioPathForSmSignal(signalType, path) < 0) 32938d2b5a6SJason M. Bills { 33038d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 33138d2b5a6SJason M. Bills } 332a3702c1fSVernon Mauery 333a3702c1fSVernon Mauery switch (action) 334a3702c1fSVernon Mauery { 335a3702c1fSVernon Mauery case SmActionGet::sample: 336a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 337a3702c1fSVernon Mauery "case SmActionGet::sample"); 338a3702c1fSVernon Mauery break; 339a3702c1fSVernon Mauery case SmActionGet::ignore: 340a3702c1fSVernon Mauery { 341a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 342a3702c1fSVernon Mauery "case SmActionGet::ignore"); 34338d2b5a6SJason M. Bills if (mtm.setProperty(buttonService, path, buttonIntf, 34438d2b5a6SJason M. Bills "ButtonMasked", true) < 0) 345a3702c1fSVernon Mauery { 34638d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 347a3702c1fSVernon Mauery } 348a3702c1fSVernon Mauery } 349a3702c1fSVernon Mauery break; 350a3702c1fSVernon Mauery case SmActionGet::revert: 351a3702c1fSVernon Mauery { 352a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 353a3702c1fSVernon Mauery "case SmActionGet::revert"); 35438d2b5a6SJason M. Bills if (mtm.setProperty(buttonService, path, buttonIntf, 35538d2b5a6SJason M. Bills "ButtonMasked", false) < 0) 356a3702c1fSVernon Mauery { 35738d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 358a3702c1fSVernon Mauery } 359a3702c1fSVernon Mauery } 360a3702c1fSVernon Mauery break; 361a3702c1fSVernon Mauery 362a3702c1fSVernon Mauery default: 36338d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 364a3702c1fSVernon Mauery break; 365a3702c1fSVernon Mauery } 366a3702c1fSVernon Mauery 367a3702c1fSVernon Mauery ipmi::Value reply; 36838d2b5a6SJason M. Bills if (mtm.getProperty(buttonService, path, buttonIntf, 36938d2b5a6SJason M. Bills "ButtonPressed", &reply) < 0) 370a3702c1fSVernon Mauery { 37138d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 372a3702c1fSVernon Mauery } 37338d2b5a6SJason M. Bills bool* valPtr = std::get_if<bool>(&reply); 37438d2b5a6SJason M. Bills if (valPtr == nullptr) 375a3702c1fSVernon Mauery { 37638d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 377a3702c1fSVernon Mauery } 37838d2b5a6SJason M. Bills uint8_t sensorVal = *valPtr; 37938d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, std::nullopt); 380a3702c1fSVernon Mauery } 381a3702c1fSVernon Mauery break; 382a3702c1fSVernon Mauery default: 38338d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 384a3702c1fSVernon Mauery break; 385a3702c1fSVernon Mauery } 386a3702c1fSVernon Mauery } 387a3702c1fSVernon Mauery 388a3702c1fSVernon Mauery ipmi_ret_t ipmi_app_mtm_set_signal(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 389a3702c1fSVernon Mauery ipmi_request_t request, 390a3702c1fSVernon Mauery ipmi_response_t response, 391a3702c1fSVernon Mauery ipmi_data_len_t data_len, 392a3702c1fSVernon Mauery ipmi_context_t context) 393a3702c1fSVernon Mauery { 394a3702c1fSVernon Mauery uint8_t ret = 0; 395a3702c1fSVernon Mauery ipmi_ret_t retCode = IPMI_CC_OK; 396a3702c1fSVernon Mauery SetSmSignalReq* pReq = static_cast<SetSmSignalReq*>(request); 397a3702c1fSVernon Mauery std::string ledName; 398a3702c1fSVernon Mauery /////////////////// Signal to led configuration //////////////// 399a3702c1fSVernon Mauery // {SM_SYSTEM_READY_LED, STAT_GRN_LED}, GPIOS4 gpio148 400a3702c1fSVernon Mauery // {SM_POWER_FAULT_LED, STAT_AMB_LED}, GPIOS5 gpio149 401a3702c1fSVernon Mauery // {SM_IDENTIFY_LED, IDENTIFY_LED}, GPIOS6 gpio150 402a3702c1fSVernon Mauery // {SM_SPEAKER, SPEAKER}, GPIOAB0 gpio216 403a3702c1fSVernon Mauery ///////////////////////////////////////////////////////////////// 404a3702c1fSVernon Mauery if ((*data_len == sizeof(*pReq)) && 405a3702c1fSVernon Mauery (mtm.getAccessLvl() >= MtmLvl::mtmAvailable)) 406a3702c1fSVernon Mauery { 407a3702c1fSVernon Mauery switch (pReq->Signal) 408a3702c1fSVernon Mauery { 409a3702c1fSVernon Mauery case SmSignalSet::smPowerFaultLed: 410a3702c1fSVernon Mauery case SmSignalSet::smSystemReadyLed: 411a3702c1fSVernon Mauery case SmSignalSet::smIdentifyLed: 412a3702c1fSVernon Mauery switch (pReq->Action) 413a3702c1fSVernon Mauery { 414a3702c1fSVernon Mauery case SmActionSet::forceDeasserted: 415a3702c1fSVernon Mauery { 416a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 417a3702c1fSVernon Mauery "case SmActionSet::forceDeasserted"); 418a3702c1fSVernon Mauery 419a3702c1fSVernon Mauery retCode = 420a3702c1fSVernon Mauery ledStoreAndSet(pReq->Signal, std::string("Off")); 421a3702c1fSVernon Mauery if (retCode != IPMI_CC_OK) 422a3702c1fSVernon Mauery { 423a3702c1fSVernon Mauery break; 424a3702c1fSVernon Mauery } 425a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 426a3702c1fSVernon Mauery } 427a3702c1fSVernon Mauery break; 428a3702c1fSVernon Mauery case SmActionSet::forceAsserted: 429a3702c1fSVernon Mauery { 430a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 431a3702c1fSVernon Mauery "case SmActionSet::forceAsserted"); 432a3702c1fSVernon Mauery 433a3702c1fSVernon Mauery retCode = 434a3702c1fSVernon Mauery ledStoreAndSet(pReq->Signal, std::string("On")); 435a3702c1fSVernon Mauery if (retCode != IPMI_CC_OK) 436a3702c1fSVernon Mauery { 437a3702c1fSVernon Mauery break; 438a3702c1fSVernon Mauery } 439a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 440a3702c1fSVernon Mauery if (SmSignalSet::smPowerFaultLed == pReq->Signal) 441a3702c1fSVernon Mauery { 442a3702c1fSVernon Mauery // Deassert "system ready" 443a3702c1fSVernon Mauery retCode = 444a3702c1fSVernon Mauery ledStoreAndSet(SmSignalSet::smSystemReadyLed, 445a3702c1fSVernon Mauery std::string("Off")); 446a3702c1fSVernon Mauery if (retCode != IPMI_CC_OK) 447a3702c1fSVernon Mauery { 448a3702c1fSVernon Mauery break; 449a3702c1fSVernon Mauery } 450a3702c1fSVernon Mauery } 451a3702c1fSVernon Mauery else if (SmSignalSet::smSystemReadyLed == pReq->Signal) 452a3702c1fSVernon Mauery { 453a3702c1fSVernon Mauery // Deassert "fault led" 454a3702c1fSVernon Mauery retCode = 455a3702c1fSVernon Mauery ledStoreAndSet(SmSignalSet::smPowerFaultLed, 456a3702c1fSVernon Mauery std::string("Off")); 457a3702c1fSVernon Mauery if (retCode != IPMI_CC_OK) 458a3702c1fSVernon Mauery { 459a3702c1fSVernon Mauery break; 460a3702c1fSVernon Mauery } 461a3702c1fSVernon Mauery } 462a3702c1fSVernon Mauery } 463a3702c1fSVernon Mauery break; 464a3702c1fSVernon Mauery case SmActionSet::revert: 465a3702c1fSVernon Mauery { 466a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 467a3702c1fSVernon Mauery "case SmActionSet::revert"); 468a3702c1fSVernon Mauery retCode = ledRevert(pReq->Signal); 469a3702c1fSVernon Mauery if (retCode != IPMI_CC_OK) 470a3702c1fSVernon Mauery { 471a3702c1fSVernon Mauery break; 472a3702c1fSVernon Mauery } 473a3702c1fSVernon Mauery } 474a3702c1fSVernon Mauery break; 475a3702c1fSVernon Mauery default: 476a3702c1fSVernon Mauery { 477a3702c1fSVernon Mauery retCode = IPMI_CC_INVALID_FIELD_REQUEST; 478a3702c1fSVernon Mauery } 479a3702c1fSVernon Mauery break; 480a3702c1fSVernon Mauery } 481a3702c1fSVernon Mauery break; 482a3702c1fSVernon Mauery case SmSignalSet::smFanPowerSpeed: 483a3702c1fSVernon Mauery { 484a3702c1fSVernon Mauery if (((pReq->Action == SmActionSet::forceAsserted) && 485a3702c1fSVernon Mauery (*data_len != sizeof(*pReq)) && (pReq->Value > 100)) || 486a3702c1fSVernon Mauery pReq->Instance == 0) 487a3702c1fSVernon Mauery { 488a3702c1fSVernon Mauery retCode = IPMI_CC_INVALID_FIELD_REQUEST; 489a3702c1fSVernon Mauery break; 490a3702c1fSVernon Mauery } 491a3702c1fSVernon Mauery uint8_t pwmValue = 0; 492a3702c1fSVernon Mauery switch (pReq->Action) 493a3702c1fSVernon Mauery { 494a3702c1fSVernon Mauery case SmActionSet::revert: 495a3702c1fSVernon Mauery { 496a3702c1fSVernon Mauery if (mtm.revertFanPWM) 497a3702c1fSVernon Mauery { 498a3702c1fSVernon Mauery ret = mtm.disablePidControlService(false); 499a3702c1fSVernon Mauery if (ret < 0) 500a3702c1fSVernon Mauery { 501a3702c1fSVernon Mauery retCode = IPMI_CC_UNSPECIFIED_ERROR; 502a3702c1fSVernon Mauery break; 503a3702c1fSVernon Mauery } 504a3702c1fSVernon Mauery mtm.revertFanPWM = false; 505a3702c1fSVernon Mauery } 506a3702c1fSVernon Mauery } 507a3702c1fSVernon Mauery break; 508a3702c1fSVernon Mauery case SmActionSet::forceAsserted: 509a3702c1fSVernon Mauery { 510a3702c1fSVernon Mauery pwmValue = pReq->Value; 511a3702c1fSVernon Mauery } // fall-through 512a3702c1fSVernon Mauery case SmActionSet::forceDeasserted: 513a3702c1fSVernon Mauery { 514a3702c1fSVernon Mauery if (!mtm.revertFanPWM) 515a3702c1fSVernon Mauery { 516a3702c1fSVernon Mauery ret = mtm.disablePidControlService(true); 517a3702c1fSVernon Mauery if (ret < 0) 518a3702c1fSVernon Mauery { 519a3702c1fSVernon Mauery retCode = IPMI_CC_UNSPECIFIED_ERROR; 520a3702c1fSVernon Mauery break; 521a3702c1fSVernon Mauery } 522a3702c1fSVernon Mauery mtm.revertFanPWM = true; 523a3702c1fSVernon Mauery } 524a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 525a3702c1fSVernon Mauery std::string fanPwmInstancePath = 526a3702c1fSVernon Mauery fanPwmPath + std::to_string(pReq->Instance); 527a3702c1fSVernon Mauery 52838d2b5a6SJason M. Bills ret = mtm.setProperty(fanService, fanPwmInstancePath, 52938d2b5a6SJason M. Bills fanIntf, "Value", 53038d2b5a6SJason M. Bills static_cast<double>(pwmValue)); 531a3702c1fSVernon Mauery if (ret < 0) 532a3702c1fSVernon Mauery { 533a3702c1fSVernon Mauery retCode = IPMI_CC_UNSPECIFIED_ERROR; 534a3702c1fSVernon Mauery } 535a3702c1fSVernon Mauery } 536a3702c1fSVernon Mauery break; 537a3702c1fSVernon Mauery default: 538a3702c1fSVernon Mauery { 539a3702c1fSVernon Mauery retCode = IPMI_CC_INVALID_FIELD_REQUEST; 540a3702c1fSVernon Mauery } 541a3702c1fSVernon Mauery break; 542a3702c1fSVernon Mauery } 543a3702c1fSVernon Mauery } 544a3702c1fSVernon Mauery break; 545a3702c1fSVernon Mauery default: 546a3702c1fSVernon Mauery { 547a3702c1fSVernon Mauery retCode = IPMI_CC_INVALID_FIELD_REQUEST; 548a3702c1fSVernon Mauery } 549a3702c1fSVernon Mauery break; 550a3702c1fSVernon Mauery } 551a3702c1fSVernon Mauery } 552a3702c1fSVernon Mauery else 553a3702c1fSVernon Mauery { 55439f64b32SAyushi Smriti retCode = IPMI_CC_INVALID; 555a3702c1fSVernon Mauery } 556a3702c1fSVernon Mauery 557a3702c1fSVernon Mauery *data_len = 0; // Only CC is return for SetSmSignal cmd 558a3702c1fSVernon Mauery return retCode; 559a3702c1fSVernon Mauery } 560a3702c1fSVernon Mauery 561a3702c1fSVernon Mauery } // namespace ipmi 562a3702c1fSVernon Mauery 563a3702c1fSVernon Mauery void register_mtm_commands() __attribute__((constructor)); 564a3702c1fSVernon Mauery void register_mtm_commands() 565a3702c1fSVernon Mauery { 56638d2b5a6SJason M. Bills // <Get SM Signal> 56738d2b5a6SJason M. Bills ipmi::registerHandler( 56838d2b5a6SJason M. Bills ipmi::prioOemBase, ipmi::netFnOemOne, 56938d2b5a6SJason M. Bills static_cast<ipmi::Cmd>(IPMINetFnIntelOemGeneralCmds::GetSmSignal), 57038d2b5a6SJason M. Bills ipmi::Privilege::User, ipmi::appMTMGetSignal); 571a3702c1fSVernon Mauery 572a3702c1fSVernon Mauery ipmi_register_callback( 573a3702c1fSVernon Mauery netfnIntcOEMGeneral, 574a3702c1fSVernon Mauery static_cast<ipmi_cmd_t>(IPMINetFnIntelOemGeneralCmds::SetSmSignal), 575a3702c1fSVernon Mauery NULL, ipmi::ipmi_app_mtm_set_signal, PRIVILEGE_USER); 576a3702c1fSVernon Mauery 577a3702c1fSVernon Mauery return; 578a3702c1fSVernon Mauery } 579