| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | // Copyright (c) 2018 Intel Corporation | 
|  | 3 | // | 
|  | 4 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | // you may not use this file except in compliance with the License. | 
|  | 6 | // You may obtain a copy of the License at | 
|  | 7 | // | 
|  | 8 | //      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | // | 
|  | 10 | // Unless required by applicable law or agreed to in writing, software | 
|  | 11 | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | // See the License for the specific language governing permissions and | 
|  | 14 | // limitations under the License. | 
|  | 15 | */ | 
|  | 16 |  | 
| Richard Marian Thomaiyar | 147daec | 2019-06-15 07:43:48 +0530 | [diff] [blame] | 17 | #include <boost/container/flat_map.hpp> | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 18 | #include <ipmid/api.hpp> | 
|  | 19 | #include <manufacturingcommands.hpp> | 
|  | 20 | #include <oemcommands.hpp> | 
|  | 21 |  | 
|  | 22 | namespace ipmi | 
|  | 23 | { | 
|  | 24 |  | 
|  | 25 | Manufacturing mtm; | 
|  | 26 |  | 
|  | 27 | static auto revertTimeOut = | 
|  | 28 | std::chrono::duration_cast<std::chrono::microseconds>( | 
|  | 29 | std::chrono::seconds(60)); // 1 minute timeout | 
|  | 30 |  | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 31 | static constexpr const char* callbackMgrService = | 
|  | 32 | "xyz.openbmc_project.CallbackManager"; | 
|  | 33 | static constexpr const char* callbackMgrIntf = | 
|  | 34 | "xyz.openbmc_project.CallbackManager"; | 
|  | 35 | static constexpr const char* callbackMgrObjPath = | 
|  | 36 | "/xyz/openbmc_project/CallbackManager"; | 
|  | 37 | static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate"; | 
|  | 38 |  | 
|  | 39 | const static constexpr char* systemDService = "org.freedesktop.systemd1"; | 
|  | 40 | const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1"; | 
|  | 41 | const static constexpr char* systemDMgrIntf = | 
|  | 42 | "org.freedesktop.systemd1.Manager"; | 
|  | 43 | const static constexpr char* pidControlService = "phosphor-pid-control.service"; | 
|  | 44 |  | 
| Richard Marian Thomaiyar | 666dd01 | 2019-08-02 20:55:37 +0530 | [diff] [blame] | 45 | static inline Cc resetMtmTimer(boost::asio::yield_context yield) | 
|  | 46 | { | 
|  | 47 | auto sdbusp = getSdBus(); | 
|  | 48 | boost::system::error_code ec; | 
|  | 49 | sdbusp->yield_method_call<>(yield, ec, specialModeService, | 
|  | 50 | specialModeObjPath, specialModeIntf, | 
|  | 51 | "ResetTimer"); | 
|  | 52 | if (ec) | 
|  | 53 | { | 
|  | 54 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 55 | "Failed to reset the manufacturing mode timer"); | 
|  | 56 | return ccUnspecifiedError; | 
|  | 57 | } | 
|  | 58 | return ccSuccess; | 
|  | 59 | } | 
|  | 60 |  | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 61 | int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 62 | { | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 63 | switch (signal) | 
|  | 64 | { | 
|  | 65 | case SmSignalGet::smPowerButton: | 
|  | 66 | path = "/xyz/openbmc_project/chassis/buttons/power"; | 
|  | 67 | break; | 
|  | 68 | case SmSignalGet::smResetButton: | 
|  | 69 | path = "/xyz/openbmc_project/chassis/buttons/reset"; | 
|  | 70 | break; | 
|  | 71 | case SmSignalGet::smNMIButton: | 
|  | 72 | path = "/xyz/openbmc_project/chassis/buttons/nmi"; | 
|  | 73 | break; | 
| Richard Marian Thomaiyar | 8e5e2b0 | 2019-08-01 07:50:55 +0530 | [diff] [blame] | 74 | case SmSignalGet::smIdentifyButton: | 
|  | 75 | path = "/xyz/openbmc_project/chassis/buttons/id"; | 
|  | 76 | break; | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 77 | default: | 
|  | 78 | return -1; | 
|  | 79 | break; | 
|  | 80 | } | 
|  | 81 | return 0; | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 82 | } | 
|  | 83 |  | 
|  | 84 | ipmi_ret_t ledStoreAndSet(SmSignalSet signal, std::string setState) | 
|  | 85 | { | 
|  | 86 | LedProperty* ledProp = mtm.findLedProperty(signal); | 
|  | 87 | if (ledProp == nullptr) | 
|  | 88 | { | 
|  | 89 | return IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 90 | } | 
|  | 91 |  | 
|  | 92 | std::string ledName = ledProp->getName(); | 
|  | 93 | std::string ledService = ledServicePrefix + ledName; | 
|  | 94 | std::string ledPath = ledPathPrefix + ledName; | 
|  | 95 | ipmi::Value presentState; | 
|  | 96 |  | 
|  | 97 | if (false == ledProp->getLock()) | 
|  | 98 | { | 
|  | 99 | if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf, | 
|  | 100 | "State", &presentState) != 0) | 
|  | 101 | { | 
|  | 102 | return IPMI_CC_UNSPECIFIED_ERROR; | 
|  | 103 | } | 
|  | 104 | ledProp->setPrevState(std::get<std::string>(presentState)); | 
|  | 105 | ledProp->setLock(true); | 
|  | 106 | if (signal == SmSignalSet::smPowerFaultLed || | 
|  | 107 | signal == SmSignalSet::smSystemReadyLed) | 
|  | 108 | { | 
|  | 109 | mtm.revertLedCallback = true; | 
|  | 110 | } | 
|  | 111 | } | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 112 | if (mtm.setProperty(ledService, ledPath, ledIntf, "State", | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 113 | ledStateStr + setState) != 0) | 
|  | 114 | { | 
|  | 115 | return IPMI_CC_UNSPECIFIED_ERROR; | 
|  | 116 | } | 
|  | 117 | return IPMI_CC_OK; | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | ipmi_ret_t ledRevert(SmSignalSet signal) | 
|  | 121 | { | 
|  | 122 | LedProperty* ledProp = mtm.findLedProperty(signal); | 
|  | 123 | if (ledProp == nullptr) | 
|  | 124 | { | 
|  | 125 | return IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 126 | } | 
|  | 127 | if (true == ledProp->getLock()) | 
|  | 128 | { | 
|  | 129 | ledProp->setLock(false); | 
|  | 130 | if (signal == SmSignalSet::smPowerFaultLed || | 
|  | 131 | signal == SmSignalSet::smSystemReadyLed) | 
|  | 132 | { | 
|  | 133 | try | 
|  | 134 | { | 
|  | 135 | ipmi::method_no_args::callDbusMethod( | 
|  | 136 | *getSdBus(), callbackMgrService, callbackMgrObjPath, | 
|  | 137 | callbackMgrIntf, retriggerLedUpdate); | 
|  | 138 | } | 
|  | 139 | catch (sdbusplus::exception_t& e) | 
|  | 140 | { | 
|  | 141 | return IPMI_CC_UNSPECIFIED_ERROR; | 
|  | 142 | } | 
|  | 143 | mtm.revertLedCallback = false; | 
|  | 144 | } | 
|  | 145 | else | 
|  | 146 | { | 
|  | 147 | std::string ledName = ledProp->getName(); | 
|  | 148 | std::string ledService = ledServicePrefix + ledName; | 
|  | 149 | std::string ledPath = ledPathPrefix + ledName; | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 150 | if (mtm.setProperty(ledService, ledPath, ledIntf, "State", | 
|  | 151 | ledProp->getPrevState()) != 0) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 152 | { | 
|  | 153 | return IPMI_CC_UNSPECIFIED_ERROR; | 
|  | 154 | } | 
|  | 155 | } | 
|  | 156 | } | 
|  | 157 | return IPMI_CC_OK; | 
|  | 158 | } | 
|  | 159 |  | 
|  | 160 | void Manufacturing::initData() | 
|  | 161 | { | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 162 | ledPropertyList.push_back( | 
|  | 163 | LedProperty(SmSignalSet::smPowerFaultLed, "status_amber")); | 
|  | 164 | ledPropertyList.push_back( | 
|  | 165 | LedProperty(SmSignalSet::smSystemReadyLed, "status_green")); | 
|  | 166 | ledPropertyList.push_back( | 
|  | 167 | LedProperty(SmSignalSet::smIdentifyLed, "identify")); | 
|  | 168 | } | 
|  | 169 |  | 
|  | 170 | void Manufacturing::revertTimerHandler() | 
|  | 171 | { | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 172 | if (revertFanPWM) | 
|  | 173 | { | 
|  | 174 | revertFanPWM = false; | 
|  | 175 | disablePidControlService(false); | 
|  | 176 | } | 
|  | 177 |  | 
|  | 178 | for (const auto& ledProperty : ledPropertyList) | 
|  | 179 | { | 
|  | 180 | const std::string& ledName = ledProperty.getName(); | 
|  | 181 | ledRevert(ledProperty.getSignal()); | 
|  | 182 | } | 
|  | 183 | } | 
|  | 184 |  | 
|  | 185 | Manufacturing::Manufacturing() : | 
|  | 186 | revertTimer([&](void) { revertTimerHandler(); }) | 
|  | 187 | { | 
|  | 188 | initData(); | 
|  | 189 | } | 
|  | 190 |  | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 191 | int8_t Manufacturing::getProperty(const std::string& service, | 
|  | 192 | const std::string& path, | 
|  | 193 | const std::string& interface, | 
|  | 194 | const std::string& propertyName, | 
|  | 195 | ipmi::Value* reply) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 196 | { | 
|  | 197 | try | 
|  | 198 | { | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 199 | *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface, | 
|  | 200 | propertyName); | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 201 | } | 
|  | 202 | catch (const sdbusplus::exception::SdBusError& e) | 
|  | 203 | { | 
|  | 204 | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | 205 | "ERROR: getProperty"); | 
|  | 206 | return -1; | 
|  | 207 | } | 
|  | 208 |  | 
|  | 209 | return 0; | 
|  | 210 | } | 
|  | 211 |  | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 212 | int8_t Manufacturing::setProperty(const std::string& service, | 
|  | 213 | const std::string& path, | 
|  | 214 | const std::string& interface, | 
|  | 215 | const std::string& propertyName, | 
|  | 216 | ipmi::Value value) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 217 | { | 
|  | 218 | try | 
|  | 219 | { | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 220 | ipmi::setDbusProperty(*getSdBus(), service, path, interface, | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 221 | propertyName, value); | 
|  | 222 | } | 
|  | 223 | catch (const sdbusplus::exception::SdBusError& e) | 
|  | 224 | { | 
|  | 225 | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | 226 | "ERROR: setProperty"); | 
|  | 227 | return -1; | 
|  | 228 | } | 
|  | 229 |  | 
|  | 230 | return 0; | 
|  | 231 | } | 
|  | 232 |  | 
|  | 233 | int8_t Manufacturing::disablePidControlService(const bool disable) | 
|  | 234 | { | 
|  | 235 | try | 
|  | 236 | { | 
|  | 237 | auto dbus = getSdBus(); | 
|  | 238 | auto method = dbus->new_method_call(systemDService, systemDObjPath, | 
|  | 239 | systemDMgrIntf, | 
|  | 240 | disable ? "StopUnit" : "StartUnit"); | 
|  | 241 | method.append(pidControlService, "replace"); | 
|  | 242 | auto reply = dbus->call(method); | 
|  | 243 | } | 
|  | 244 | catch (const sdbusplus::exception::SdBusError& e) | 
|  | 245 | { | 
|  | 246 | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | 247 | "ERROR: phosphor-pid-control service start or stop failed"); | 
|  | 248 | return -1; | 
|  | 249 | } | 
|  | 250 | return 0; | 
|  | 251 | } | 
|  | 252 |  | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 253 | ipmi::RspType<uint8_t,                // Signal value | 
|  | 254 | std::optional<uint16_t> // Fan tach value | 
|  | 255 | > | 
| Richard Marian Thomaiyar | 147daec | 2019-06-15 07:43:48 +0530 | [diff] [blame] | 256 | appMTMGetSignal(boost::asio::yield_context yield, uint8_t signalTypeByte, | 
|  | 257 | uint8_t instance, uint8_t actionByte) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 258 | { | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 259 | if (mtm.getAccessLvl() < MtmLvl::mtmAvailable) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 260 | { | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 261 | return ipmi::responseInvalidCommand(); | 
|  | 262 | } | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 263 |  | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 264 | SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte); | 
|  | 265 | SmActionGet action = static_cast<SmActionGet>(actionByte); | 
|  | 266 |  | 
|  | 267 | switch (signalType) | 
|  | 268 | { | 
|  | 269 | case SmSignalGet::smFanPwmGet: | 
|  | 270 | { | 
|  | 271 | ipmi::Value reply; | 
| Richard Marian Thomaiyar | 147daec | 2019-06-15 07:43:48 +0530 | [diff] [blame] | 272 | std::string fullPath = fanPwmPath + std::to_string(instance + 1); | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 273 | if (mtm.getProperty(fanService, fullPath, fanIntf, "Value", | 
|  | 274 | &reply) < 0) | 
|  | 275 | { | 
|  | 276 | return ipmi::responseInvalidFieldRequest(); | 
|  | 277 | } | 
|  | 278 | double* doubleVal = std::get_if<double>(&reply); | 
|  | 279 | if (doubleVal == nullptr) | 
|  | 280 | { | 
|  | 281 | return ipmi::responseUnspecifiedError(); | 
|  | 282 | } | 
|  | 283 | uint8_t sensorVal = std::round(*doubleVal); | 
|  | 284 | return ipmi::responseSuccess(sensorVal, std::nullopt); | 
|  | 285 | } | 
|  | 286 | break; | 
|  | 287 | case SmSignalGet::smFanTachometerGet: | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 288 | { | 
| Richard Marian Thomaiyar | 147daec | 2019-06-15 07:43:48 +0530 | [diff] [blame] | 289 | auto sdbusp = getSdBus(); | 
|  | 290 | boost::system::error_code ec; | 
|  | 291 | using objFlatMap = boost::container::flat_map< | 
|  | 292 | std::string, boost::container::flat_map< | 
|  | 293 | std::string, std::vector<std::string>>>; | 
|  | 294 |  | 
|  | 295 | auto flatMap = sdbusp->yield_method_call<objFlatMap>( | 
|  | 296 | yield, ec, "xyz.openbmc_project.ObjectMapper", | 
|  | 297 | "/xyz/openbmc_project/object_mapper", | 
|  | 298 | "xyz.openbmc_project.ObjectMapper", "GetSubTree", | 
|  | 299 | fanTachBasePath, 0, std::array<const char*, 1>{fanIntf}); | 
|  | 300 | if (ec) | 
|  | 301 | { | 
|  | 302 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 303 | "Failed to query fan tach sub tree objects"); | 
|  | 304 | return ipmi::responseUnspecifiedError(); | 
|  | 305 | } | 
|  | 306 | if (instance >= flatMap.size()) | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 307 | { | 
|  | 308 | return ipmi::responseInvalidFieldRequest(); | 
|  | 309 | } | 
| Richard Marian Thomaiyar | 147daec | 2019-06-15 07:43:48 +0530 | [diff] [blame] | 310 | auto itr = flatMap.nth(instance); | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 311 | ipmi::Value reply; | 
| Richard Marian Thomaiyar | 147daec | 2019-06-15 07:43:48 +0530 | [diff] [blame] | 312 | if (mtm.getProperty(fanService, itr->first, fanIntf, "Value", | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 313 | &reply) < 0) | 
|  | 314 | { | 
|  | 315 | return ipmi::responseInvalidFieldRequest(); | 
|  | 316 | } | 
|  | 317 |  | 
|  | 318 | double* doubleVal = std::get_if<double>(&reply); | 
|  | 319 | if (doubleVal == nullptr) | 
|  | 320 | { | 
|  | 321 | return ipmi::responseUnspecifiedError(); | 
|  | 322 | } | 
|  | 323 | uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT; | 
|  | 324 | std::optional<uint16_t> fanTach = std::round(*doubleVal); | 
|  | 325 |  | 
|  | 326 | return ipmi::responseSuccess(sensorVal, fanTach); | 
|  | 327 | } | 
|  | 328 | break; | 
| Richard Marian Thomaiyar | 8e5e2b0 | 2019-08-01 07:50:55 +0530 | [diff] [blame] | 329 | case SmSignalGet::smIdentifyButton: | 
|  | 330 | { | 
|  | 331 | if (action == SmActionGet::revert || action == SmActionGet::ignore) | 
|  | 332 | { | 
|  | 333 | // ButtonMasked property is not supported for ID button as it is | 
|  | 334 | // unnecessary. Hence if requested for revert / ignore, override | 
|  | 335 | // it to sample action to make tools happy. | 
|  | 336 | action = SmActionGet::sample; | 
|  | 337 | } | 
|  | 338 | // fall-through | 
|  | 339 | } | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 340 | case SmSignalGet::smResetButton: | 
|  | 341 | case SmSignalGet::smPowerButton: | 
|  | 342 | case SmSignalGet::smNMIButton: | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 343 | { | 
|  | 344 | std::string path; | 
|  | 345 | if (getGpioPathForSmSignal(signalType, path) < 0) | 
|  | 346 | { | 
|  | 347 | return ipmi::responseInvalidFieldRequest(); | 
|  | 348 | } | 
|  | 349 |  | 
|  | 350 | switch (action) | 
|  | 351 | { | 
|  | 352 | case SmActionGet::sample: | 
|  | 353 | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | 354 | "case SmActionGet::sample"); | 
|  | 355 | break; | 
|  | 356 | case SmActionGet::ignore: | 
|  | 357 | { | 
|  | 358 | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | 359 | "case SmActionGet::ignore"); | 
|  | 360 | if (mtm.setProperty(buttonService, path, buttonIntf, | 
|  | 361 | "ButtonMasked", true) < 0) | 
|  | 362 | { | 
|  | 363 | return ipmi::responseUnspecifiedError(); | 
|  | 364 | } | 
|  | 365 | } | 
|  | 366 | break; | 
|  | 367 | case SmActionGet::revert: | 
|  | 368 | { | 
|  | 369 | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | 370 | "case SmActionGet::revert"); | 
|  | 371 | if (mtm.setProperty(buttonService, path, buttonIntf, | 
|  | 372 | "ButtonMasked", false) < 0) | 
|  | 373 | { | 
|  | 374 | return ipmi::responseUnspecifiedError(); | 
|  | 375 | } | 
|  | 376 | } | 
|  | 377 | break; | 
|  | 378 |  | 
|  | 379 | default: | 
|  | 380 | return ipmi::responseInvalidFieldRequest(); | 
|  | 381 | break; | 
|  | 382 | } | 
|  | 383 |  | 
|  | 384 | ipmi::Value reply; | 
|  | 385 | if (mtm.getProperty(buttonService, path, buttonIntf, | 
|  | 386 | "ButtonPressed", &reply) < 0) | 
|  | 387 | { | 
|  | 388 | return ipmi::responseUnspecifiedError(); | 
|  | 389 | } | 
|  | 390 | bool* valPtr = std::get_if<bool>(&reply); | 
|  | 391 | if (valPtr == nullptr) | 
|  | 392 | { | 
|  | 393 | return ipmi::responseUnspecifiedError(); | 
|  | 394 | } | 
|  | 395 | uint8_t sensorVal = *valPtr; | 
|  | 396 | return ipmi::responseSuccess(sensorVal, std::nullopt); | 
|  | 397 | } | 
|  | 398 | break; | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 399 | default: | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 400 | return ipmi::responseInvalidFieldRequest(); | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 401 | break; | 
|  | 402 | } | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 403 | } | 
|  | 404 |  | 
|  | 405 | ipmi_ret_t ipmi_app_mtm_set_signal(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
|  | 406 | ipmi_request_t request, | 
|  | 407 | ipmi_response_t response, | 
|  | 408 | ipmi_data_len_t data_len, | 
|  | 409 | ipmi_context_t context) | 
|  | 410 | { | 
|  | 411 | uint8_t ret = 0; | 
|  | 412 | ipmi_ret_t retCode = IPMI_CC_OK; | 
|  | 413 | SetSmSignalReq* pReq = static_cast<SetSmSignalReq*>(request); | 
|  | 414 | std::string ledName; | 
|  | 415 | ///////////////////  Signal to led configuration //////////////// | 
|  | 416 | //        {SM_SYSTEM_READY_LED, STAT_GRN_LED},    GPIOS4  gpio148 | 
|  | 417 | //        {SM_POWER_FAULT_LED, STAT_AMB_LED},     GPIOS5  gpio149 | 
|  | 418 | //        {SM_IDENTIFY_LED, IDENTIFY_LED},        GPIOS6  gpio150 | 
|  | 419 | //        {SM_SPEAKER, SPEAKER},                  GPIOAB0 gpio216 | 
|  | 420 | ///////////////////////////////////////////////////////////////// | 
|  | 421 | if ((*data_len == sizeof(*pReq)) && | 
|  | 422 | (mtm.getAccessLvl() >= MtmLvl::mtmAvailable)) | 
|  | 423 | { | 
|  | 424 | switch (pReq->Signal) | 
|  | 425 | { | 
|  | 426 | case SmSignalSet::smPowerFaultLed: | 
|  | 427 | case SmSignalSet::smSystemReadyLed: | 
|  | 428 | case SmSignalSet::smIdentifyLed: | 
|  | 429 | switch (pReq->Action) | 
|  | 430 | { | 
|  | 431 | case SmActionSet::forceDeasserted: | 
|  | 432 | { | 
|  | 433 | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | 434 | "case SmActionSet::forceDeasserted"); | 
|  | 435 |  | 
|  | 436 | retCode = | 
|  | 437 | ledStoreAndSet(pReq->Signal, std::string("Off")); | 
|  | 438 | if (retCode != IPMI_CC_OK) | 
|  | 439 | { | 
|  | 440 | break; | 
|  | 441 | } | 
|  | 442 | mtm.revertTimer.start(revertTimeOut); | 
|  | 443 | } | 
|  | 444 | break; | 
|  | 445 | case SmActionSet::forceAsserted: | 
|  | 446 | { | 
|  | 447 | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | 448 | "case SmActionSet::forceAsserted"); | 
|  | 449 |  | 
|  | 450 | retCode = | 
|  | 451 | ledStoreAndSet(pReq->Signal, std::string("On")); | 
|  | 452 | if (retCode != IPMI_CC_OK) | 
|  | 453 | { | 
|  | 454 | break; | 
|  | 455 | } | 
|  | 456 | mtm.revertTimer.start(revertTimeOut); | 
|  | 457 | if (SmSignalSet::smPowerFaultLed == pReq->Signal) | 
|  | 458 | { | 
|  | 459 | // Deassert "system ready" | 
|  | 460 | retCode = | 
|  | 461 | ledStoreAndSet(SmSignalSet::smSystemReadyLed, | 
|  | 462 | std::string("Off")); | 
|  | 463 | if (retCode != IPMI_CC_OK) | 
|  | 464 | { | 
|  | 465 | break; | 
|  | 466 | } | 
|  | 467 | } | 
|  | 468 | else if (SmSignalSet::smSystemReadyLed == pReq->Signal) | 
|  | 469 | { | 
|  | 470 | // Deassert "fault led" | 
|  | 471 | retCode = | 
|  | 472 | ledStoreAndSet(SmSignalSet::smPowerFaultLed, | 
|  | 473 | std::string("Off")); | 
|  | 474 | if (retCode != IPMI_CC_OK) | 
|  | 475 | { | 
|  | 476 | break; | 
|  | 477 | } | 
|  | 478 | } | 
|  | 479 | } | 
|  | 480 | break; | 
|  | 481 | case SmActionSet::revert: | 
|  | 482 | { | 
|  | 483 | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | 484 | "case SmActionSet::revert"); | 
|  | 485 | retCode = ledRevert(pReq->Signal); | 
|  | 486 | if (retCode != IPMI_CC_OK) | 
|  | 487 | { | 
|  | 488 | break; | 
|  | 489 | } | 
|  | 490 | } | 
|  | 491 | break; | 
|  | 492 | default: | 
|  | 493 | { | 
|  | 494 | retCode = IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 495 | } | 
|  | 496 | break; | 
|  | 497 | } | 
|  | 498 | break; | 
|  | 499 | case SmSignalSet::smFanPowerSpeed: | 
|  | 500 | { | 
|  | 501 | if (((pReq->Action == SmActionSet::forceAsserted) && | 
|  | 502 | (*data_len != sizeof(*pReq)) && (pReq->Value > 100)) || | 
|  | 503 | pReq->Instance == 0) | 
|  | 504 | { | 
|  | 505 | retCode = IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 506 | break; | 
|  | 507 | } | 
|  | 508 | uint8_t pwmValue = 0; | 
|  | 509 | switch (pReq->Action) | 
|  | 510 | { | 
|  | 511 | case SmActionSet::revert: | 
|  | 512 | { | 
|  | 513 | if (mtm.revertFanPWM) | 
|  | 514 | { | 
|  | 515 | ret = mtm.disablePidControlService(false); | 
|  | 516 | if (ret < 0) | 
|  | 517 | { | 
|  | 518 | retCode = IPMI_CC_UNSPECIFIED_ERROR; | 
|  | 519 | break; | 
|  | 520 | } | 
|  | 521 | mtm.revertFanPWM = false; | 
|  | 522 | } | 
|  | 523 | } | 
|  | 524 | break; | 
|  | 525 | case SmActionSet::forceAsserted: | 
|  | 526 | { | 
|  | 527 | pwmValue = pReq->Value; | 
|  | 528 | } // fall-through | 
|  | 529 | case SmActionSet::forceDeasserted: | 
|  | 530 | { | 
|  | 531 | if (!mtm.revertFanPWM) | 
|  | 532 | { | 
|  | 533 | ret = mtm.disablePidControlService(true); | 
|  | 534 | if (ret < 0) | 
|  | 535 | { | 
|  | 536 | retCode = IPMI_CC_UNSPECIFIED_ERROR; | 
|  | 537 | break; | 
|  | 538 | } | 
|  | 539 | mtm.revertFanPWM = true; | 
|  | 540 | } | 
|  | 541 | mtm.revertTimer.start(revertTimeOut); | 
|  | 542 | std::string fanPwmInstancePath = | 
|  | 543 | fanPwmPath + std::to_string(pReq->Instance); | 
|  | 544 |  | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 545 | ret = mtm.setProperty(fanService, fanPwmInstancePath, | 
|  | 546 | fanIntf, "Value", | 
|  | 547 | static_cast<double>(pwmValue)); | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 548 | if (ret < 0) | 
|  | 549 | { | 
|  | 550 | retCode = IPMI_CC_UNSPECIFIED_ERROR; | 
|  | 551 | } | 
|  | 552 | } | 
|  | 553 | break; | 
|  | 554 | default: | 
|  | 555 | { | 
|  | 556 | retCode = IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 557 | } | 
|  | 558 | break; | 
|  | 559 | } | 
|  | 560 | } | 
|  | 561 | break; | 
|  | 562 | default: | 
|  | 563 | { | 
|  | 564 | retCode = IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 565 | } | 
|  | 566 | break; | 
|  | 567 | } | 
|  | 568 | } | 
|  | 569 | else | 
|  | 570 | { | 
| Ayushi Smriti | 39f64b3 | 2019-07-04 10:41:22 +0000 | [diff] [blame] | 571 | retCode = IPMI_CC_INVALID; | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 572 | } | 
|  | 573 |  | 
|  | 574 | *data_len = 0; // Only CC is return for SetSmSignal cmd | 
|  | 575 | return retCode; | 
|  | 576 | } | 
|  | 577 |  | 
| Richard Marian Thomaiyar | 666dd01 | 2019-08-02 20:55:37 +0530 | [diff] [blame] | 578 | ipmi::RspType<> mtmKeepAlive(boost::asio::yield_context yield, uint8_t reserved, | 
|  | 579 | const std::array<char, 5>& intentionalSignature) | 
|  | 580 | { | 
|  | 581 | // Allow MTM keep alive command only in manfacturing mode. | 
|  | 582 | if (mtm.getAccessLvl() != MtmLvl::mtmAvailable) | 
|  | 583 | { | 
|  | 584 | return ipmi::responseInvalidCommand(); | 
|  | 585 | } | 
|  | 586 | constexpr std::array<char, 5> signatureOk = {'I', 'N', 'T', 'E', 'L'}; | 
|  | 587 | if (intentionalSignature != signatureOk || reserved != 0) | 
|  | 588 | { | 
|  | 589 | return ipmi::responseInvalidFieldRequest(); | 
|  | 590 | } | 
|  | 591 | return ipmi::response(resetMtmTimer(yield)); | 
|  | 592 | } | 
|  | 593 |  | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 594 | } // namespace ipmi | 
|  | 595 |  | 
|  | 596 | void register_mtm_commands() __attribute__((constructor)); | 
|  | 597 | void register_mtm_commands() | 
|  | 598 | { | 
| Jason M. Bills | 38d2b5a | 2019-06-03 16:26:11 -0700 | [diff] [blame] | 599 | // <Get SM Signal> | 
|  | 600 | ipmi::registerHandler( | 
|  | 601 | ipmi::prioOemBase, ipmi::netFnOemOne, | 
|  | 602 | static_cast<ipmi::Cmd>(IPMINetFnIntelOemGeneralCmds::GetSmSignal), | 
|  | 603 | ipmi::Privilege::User, ipmi::appMTMGetSignal); | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 604 |  | 
|  | 605 | ipmi_register_callback( | 
|  | 606 | netfnIntcOEMGeneral, | 
|  | 607 | static_cast<ipmi_cmd_t>(IPMINetFnIntelOemGeneralCmds::SetSmSignal), | 
|  | 608 | NULL, ipmi::ipmi_app_mtm_set_signal, PRIVILEGE_USER); | 
|  | 609 |  | 
| Richard Marian Thomaiyar | 666dd01 | 2019-08-02 20:55:37 +0530 | [diff] [blame] | 610 | ipmi::registerHandler( | 
|  | 611 | ipmi::prioOemBase, ipmi::netFnOemOne, | 
|  | 612 | static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdMtmKeepAlive), | 
|  | 613 | ipmi::Privilege::Admin, ipmi::mtmKeepAlive); | 
|  | 614 |  | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 615 | return; | 
|  | 616 | } |