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