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;
5738d2b5a6SJason M. Bills         default:
5838d2b5a6SJason M. Bills             return -1;
5938d2b5a6SJason M. Bills             break;
6038d2b5a6SJason M. Bills     }
6138d2b5a6SJason M. Bills     return 0;
62a3702c1fSVernon Mauery }
63a3702c1fSVernon Mauery 
64a3702c1fSVernon Mauery ipmi_ret_t ledStoreAndSet(SmSignalSet signal, std::string setState)
65a3702c1fSVernon Mauery {
66a3702c1fSVernon Mauery     LedProperty* ledProp = mtm.findLedProperty(signal);
67a3702c1fSVernon Mauery     if (ledProp == nullptr)
68a3702c1fSVernon Mauery     {
69a3702c1fSVernon Mauery         return IPMI_CC_INVALID_FIELD_REQUEST;
70a3702c1fSVernon Mauery     }
71a3702c1fSVernon Mauery 
72a3702c1fSVernon Mauery     std::string ledName = ledProp->getName();
73a3702c1fSVernon Mauery     std::string ledService = ledServicePrefix + ledName;
74a3702c1fSVernon Mauery     std::string ledPath = ledPathPrefix + ledName;
75a3702c1fSVernon Mauery     ipmi::Value presentState;
76a3702c1fSVernon Mauery 
77a3702c1fSVernon Mauery     if (false == ledProp->getLock())
78a3702c1fSVernon Mauery     {
79a3702c1fSVernon Mauery         if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf,
80a3702c1fSVernon Mauery                             "State", &presentState) != 0)
81a3702c1fSVernon Mauery         {
82a3702c1fSVernon Mauery             return IPMI_CC_UNSPECIFIED_ERROR;
83a3702c1fSVernon Mauery         }
84a3702c1fSVernon Mauery         ledProp->setPrevState(std::get<std::string>(presentState));
85a3702c1fSVernon Mauery         ledProp->setLock(true);
86a3702c1fSVernon Mauery         if (signal == SmSignalSet::smPowerFaultLed ||
87a3702c1fSVernon Mauery             signal == SmSignalSet::smSystemReadyLed)
88a3702c1fSVernon Mauery         {
89a3702c1fSVernon Mauery             mtm.revertLedCallback = true;
90a3702c1fSVernon Mauery         }
91a3702c1fSVernon Mauery     }
9238d2b5a6SJason M. Bills     if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
93a3702c1fSVernon Mauery                         ledStateStr + setState) != 0)
94a3702c1fSVernon Mauery     {
95a3702c1fSVernon Mauery         return IPMI_CC_UNSPECIFIED_ERROR;
96a3702c1fSVernon Mauery     }
97a3702c1fSVernon Mauery     return IPMI_CC_OK;
98a3702c1fSVernon Mauery }
99a3702c1fSVernon Mauery 
100a3702c1fSVernon Mauery ipmi_ret_t ledRevert(SmSignalSet signal)
101a3702c1fSVernon Mauery {
102a3702c1fSVernon Mauery     LedProperty* ledProp = mtm.findLedProperty(signal);
103a3702c1fSVernon Mauery     if (ledProp == nullptr)
104a3702c1fSVernon Mauery     {
105a3702c1fSVernon Mauery         return IPMI_CC_INVALID_FIELD_REQUEST;
106a3702c1fSVernon Mauery     }
107a3702c1fSVernon Mauery     if (true == ledProp->getLock())
108a3702c1fSVernon Mauery     {
109a3702c1fSVernon Mauery         ledProp->setLock(false);
110a3702c1fSVernon Mauery         if (signal == SmSignalSet::smPowerFaultLed ||
111a3702c1fSVernon Mauery             signal == SmSignalSet::smSystemReadyLed)
112a3702c1fSVernon Mauery         {
113a3702c1fSVernon Mauery             try
114a3702c1fSVernon Mauery             {
115a3702c1fSVernon Mauery                 ipmi::method_no_args::callDbusMethod(
116a3702c1fSVernon Mauery                     *getSdBus(), callbackMgrService, callbackMgrObjPath,
117a3702c1fSVernon Mauery                     callbackMgrIntf, retriggerLedUpdate);
118a3702c1fSVernon Mauery             }
119a3702c1fSVernon Mauery             catch (sdbusplus::exception_t& e)
120a3702c1fSVernon Mauery             {
121a3702c1fSVernon Mauery                 return IPMI_CC_UNSPECIFIED_ERROR;
122a3702c1fSVernon Mauery             }
123a3702c1fSVernon Mauery             mtm.revertLedCallback = false;
124a3702c1fSVernon Mauery         }
125a3702c1fSVernon Mauery         else
126a3702c1fSVernon Mauery         {
127a3702c1fSVernon Mauery             std::string ledName = ledProp->getName();
128a3702c1fSVernon Mauery             std::string ledService = ledServicePrefix + ledName;
129a3702c1fSVernon Mauery             std::string ledPath = ledPathPrefix + ledName;
13038d2b5a6SJason M. Bills             if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
13138d2b5a6SJason M. Bills                                 ledProp->getPrevState()) != 0)
132a3702c1fSVernon Mauery             {
133a3702c1fSVernon Mauery                 return IPMI_CC_UNSPECIFIED_ERROR;
134a3702c1fSVernon Mauery             }
135a3702c1fSVernon Mauery         }
136a3702c1fSVernon Mauery     }
137a3702c1fSVernon Mauery     return IPMI_CC_OK;
138a3702c1fSVernon Mauery }
139a3702c1fSVernon Mauery 
140a3702c1fSVernon Mauery void Manufacturing::initData()
141a3702c1fSVernon Mauery {
142a3702c1fSVernon Mauery     ledPropertyList.push_back(
143a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smPowerFaultLed, "status_amber"));
144a3702c1fSVernon Mauery     ledPropertyList.push_back(
145a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smSystemReadyLed, "status_green"));
146a3702c1fSVernon Mauery     ledPropertyList.push_back(
147a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smIdentifyLed, "identify"));
148a3702c1fSVernon Mauery }
149a3702c1fSVernon Mauery 
150a3702c1fSVernon Mauery void Manufacturing::revertTimerHandler()
151a3702c1fSVernon Mauery {
152a3702c1fSVernon Mauery     if (revertFanPWM)
153a3702c1fSVernon Mauery     {
154a3702c1fSVernon Mauery         revertFanPWM = false;
155a3702c1fSVernon Mauery         disablePidControlService(false);
156a3702c1fSVernon Mauery     }
157a3702c1fSVernon Mauery 
158a3702c1fSVernon Mauery     for (const auto& ledProperty : ledPropertyList)
159a3702c1fSVernon Mauery     {
160a3702c1fSVernon Mauery         const std::string& ledName = ledProperty.getName();
161a3702c1fSVernon Mauery         ledRevert(ledProperty.getSignal());
162a3702c1fSVernon Mauery     }
163a3702c1fSVernon Mauery }
164a3702c1fSVernon Mauery 
165a3702c1fSVernon Mauery Manufacturing::Manufacturing() :
166a3702c1fSVernon Mauery     revertTimer([&](void) { revertTimerHandler(); })
167a3702c1fSVernon Mauery {
168a3702c1fSVernon Mauery     initData();
169a3702c1fSVernon Mauery }
170a3702c1fSVernon Mauery 
17138d2b5a6SJason M. Bills int8_t Manufacturing::getProperty(const std::string& service,
17238d2b5a6SJason M. Bills                                   const std::string& path,
17338d2b5a6SJason M. Bills                                   const std::string& interface,
17438d2b5a6SJason M. Bills                                   const std::string& propertyName,
17538d2b5a6SJason M. Bills                                   ipmi::Value* reply)
176a3702c1fSVernon Mauery {
177a3702c1fSVernon Mauery     try
178a3702c1fSVernon Mauery     {
17938d2b5a6SJason M. Bills         *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface,
18038d2b5a6SJason M. Bills                                        propertyName);
181a3702c1fSVernon Mauery     }
182a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
183a3702c1fSVernon Mauery     {
184a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
185a3702c1fSVernon Mauery             "ERROR: getProperty");
186a3702c1fSVernon Mauery         return -1;
187a3702c1fSVernon Mauery     }
188a3702c1fSVernon Mauery 
189a3702c1fSVernon Mauery     return 0;
190a3702c1fSVernon Mauery }
191a3702c1fSVernon Mauery 
19238d2b5a6SJason M. Bills int8_t Manufacturing::setProperty(const std::string& service,
19338d2b5a6SJason M. Bills                                   const std::string& path,
19438d2b5a6SJason M. Bills                                   const std::string& interface,
19538d2b5a6SJason M. Bills                                   const std::string& propertyName,
19638d2b5a6SJason M. Bills                                   ipmi::Value value)
197a3702c1fSVernon Mauery {
198a3702c1fSVernon Mauery     try
199a3702c1fSVernon Mauery     {
20038d2b5a6SJason M. Bills         ipmi::setDbusProperty(*getSdBus(), service, path, interface,
201a3702c1fSVernon Mauery                               propertyName, value);
202a3702c1fSVernon Mauery     }
203a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
204a3702c1fSVernon Mauery     {
205a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
206a3702c1fSVernon Mauery             "ERROR: setProperty");
207a3702c1fSVernon Mauery         return -1;
208a3702c1fSVernon Mauery     }
209a3702c1fSVernon Mauery 
210a3702c1fSVernon Mauery     return 0;
211a3702c1fSVernon Mauery }
212a3702c1fSVernon Mauery 
213a3702c1fSVernon Mauery int8_t Manufacturing::disablePidControlService(const bool disable)
214a3702c1fSVernon Mauery {
215a3702c1fSVernon Mauery     try
216a3702c1fSVernon Mauery     {
217a3702c1fSVernon Mauery         auto dbus = getSdBus();
218a3702c1fSVernon Mauery         auto method = dbus->new_method_call(systemDService, systemDObjPath,
219a3702c1fSVernon Mauery                                             systemDMgrIntf,
220a3702c1fSVernon Mauery                                             disable ? "StopUnit" : "StartUnit");
221a3702c1fSVernon Mauery         method.append(pidControlService, "replace");
222a3702c1fSVernon Mauery         auto reply = dbus->call(method);
223a3702c1fSVernon Mauery     }
224a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
225a3702c1fSVernon Mauery     {
226a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
227a3702c1fSVernon Mauery             "ERROR: phosphor-pid-control service start or stop failed");
228a3702c1fSVernon Mauery         return -1;
229a3702c1fSVernon Mauery     }
230a3702c1fSVernon Mauery     return 0;
231a3702c1fSVernon Mauery }
232a3702c1fSVernon Mauery 
23338d2b5a6SJason M. Bills ipmi::RspType<uint8_t,                // Signal value
23438d2b5a6SJason M. Bills               std::optional<uint16_t> // Fan tach value
23538d2b5a6SJason M. Bills               >
23638d2b5a6SJason M. Bills     appMTMGetSignal(uint8_t signalTypeByte, uint8_t instance,
23738d2b5a6SJason M. Bills                     uint8_t actionByte)
238a3702c1fSVernon Mauery {
23938d2b5a6SJason M. Bills     if (mtm.getAccessLvl() < MtmLvl::mtmAvailable)
24038d2b5a6SJason M. Bills     {
24138d2b5a6SJason M. Bills         return ipmi::responseInvalidCommand();
24238d2b5a6SJason M. Bills     }
24338d2b5a6SJason M. Bills 
24438d2b5a6SJason M. Bills     SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte);
24538d2b5a6SJason M. Bills     SmActionGet action = static_cast<SmActionGet>(actionByte);
24638d2b5a6SJason M. Bills 
24738d2b5a6SJason M. Bills     switch (signalType)
24838d2b5a6SJason M. Bills     {
24938d2b5a6SJason M. Bills         case SmSignalGet::smFanPwmGet:
25038d2b5a6SJason M. Bills         {
251a3702c1fSVernon Mauery             ipmi::Value reply;
25238d2b5a6SJason M. Bills             std::string fullPath = fanPwmPath + std::to_string(instance);
25338d2b5a6SJason M. Bills             if (mtm.getProperty(fanService, fullPath, fanIntf, "Value",
25438d2b5a6SJason M. Bills                                 &reply) < 0)
25538d2b5a6SJason M. Bills             {
25638d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
25738d2b5a6SJason M. Bills             }
25838d2b5a6SJason M. Bills             double* doubleVal = std::get_if<double>(&reply);
25938d2b5a6SJason M. Bills             if (doubleVal == nullptr)
26038d2b5a6SJason M. Bills             {
26138d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
26238d2b5a6SJason M. Bills             }
26338d2b5a6SJason M. Bills             uint8_t sensorVal = std::round(*doubleVal);
26438d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, std::nullopt);
26538d2b5a6SJason M. Bills         }
26638d2b5a6SJason M. Bills         break;
26738d2b5a6SJason M. Bills         case SmSignalGet::smFanTachometerGet:
26838d2b5a6SJason M. Bills 
26938d2b5a6SJason M. Bills         {
27038d2b5a6SJason M. Bills             // Full path calculation pattern:
27138d2b5a6SJason M. Bills             // Instance 1 path is
27238d2b5a6SJason M. Bills             // /xyz/openbmc_project/sensors/fan_tach/Fan_1a Instance 2 path
27338d2b5a6SJason M. Bills             // is /xyz/openbmc_project/sensors/fan_tach/Fan_1b Instance 3
27438d2b5a6SJason M. Bills             // path is /xyz/openbmc_project/sensors/fan_tach/Fan_2a
27538d2b5a6SJason M. Bills             // and so on...
27638d2b5a6SJason M. Bills             std::string fullPath = fanTachPathPrefix;
27738d2b5a6SJason M. Bills             std::string fanAb = (instance % 2) == 0 ? "b" : "a";
27838d2b5a6SJason M. Bills             if (0 == instance)
27938d2b5a6SJason M. Bills             {
28038d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
28138d2b5a6SJason M. Bills             }
28238d2b5a6SJason M. Bills             else if (0 == instance / 2)
28338d2b5a6SJason M. Bills             {
28438d2b5a6SJason M. Bills                 fullPath += std::string("1") + fanAb;
28538d2b5a6SJason M. Bills             }
28638d2b5a6SJason M. Bills             else
28738d2b5a6SJason M. Bills             {
28838d2b5a6SJason M. Bills                 fullPath += std::to_string(instance / 2) + fanAb;
28938d2b5a6SJason M. Bills             }
29038d2b5a6SJason M. Bills 
29138d2b5a6SJason M. Bills             ipmi::Value reply;
29238d2b5a6SJason M. Bills             if (mtm.getProperty(fanService, fullPath, fanIntf, "Value",
29338d2b5a6SJason M. Bills                                 &reply) < 0)
29438d2b5a6SJason M. Bills             {
29538d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
29638d2b5a6SJason M. Bills             }
29738d2b5a6SJason M. Bills 
29838d2b5a6SJason M. Bills             double* doubleVal = std::get_if<double>(&reply);
29938d2b5a6SJason M. Bills             if (doubleVal == nullptr)
30038d2b5a6SJason M. Bills             {
30138d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
30238d2b5a6SJason M. Bills             }
30338d2b5a6SJason M. Bills             uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT;
30438d2b5a6SJason M. Bills             std::optional<uint16_t> fanTach = std::round(*doubleVal);
30538d2b5a6SJason M. Bills 
30638d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, fanTach);
30738d2b5a6SJason M. Bills         }
30838d2b5a6SJason M. Bills         break;
30938d2b5a6SJason M. Bills         case SmSignalGet::smResetButton:
31038d2b5a6SJason M. Bills         case SmSignalGet::smPowerButton:
31138d2b5a6SJason M. Bills         case SmSignalGet::smNMIButton:
31238d2b5a6SJason M. Bills         case SmSignalGet::smIdentifyButton:
31338d2b5a6SJason M. Bills         {
31438d2b5a6SJason M. Bills             std::string path;
31538d2b5a6SJason M. Bills             if (getGpioPathForSmSignal(signalType, path) < 0)
31638d2b5a6SJason M. Bills             {
31738d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
31838d2b5a6SJason M. Bills             }
319a3702c1fSVernon Mauery 
320a3702c1fSVernon Mauery             switch (action)
321a3702c1fSVernon Mauery             {
322a3702c1fSVernon Mauery                 case SmActionGet::sample:
323a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
324a3702c1fSVernon Mauery                         "case SmActionGet::sample");
325a3702c1fSVernon Mauery                     break;
326a3702c1fSVernon Mauery                 case SmActionGet::ignore:
327a3702c1fSVernon Mauery                 {
328a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
329a3702c1fSVernon Mauery                         "case SmActionGet::ignore");
33038d2b5a6SJason M. Bills                     if (mtm.setProperty(buttonService, path, buttonIntf,
33138d2b5a6SJason M. Bills                                         "ButtonMasked", true) < 0)
332a3702c1fSVernon Mauery                     {
33338d2b5a6SJason M. Bills                         return ipmi::responseUnspecifiedError();
334a3702c1fSVernon Mauery                     }
335a3702c1fSVernon Mauery                 }
336a3702c1fSVernon Mauery                 break;
337a3702c1fSVernon Mauery                 case SmActionGet::revert:
338a3702c1fSVernon Mauery                 {
339a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
340a3702c1fSVernon Mauery                         "case SmActionGet::revert");
34138d2b5a6SJason M. Bills                     if (mtm.setProperty(buttonService, path, buttonIntf,
34238d2b5a6SJason M. Bills                                         "ButtonMasked", false) < 0)
343a3702c1fSVernon Mauery                     {
34438d2b5a6SJason M. Bills                         return ipmi::responseUnspecifiedError();
345a3702c1fSVernon Mauery                     }
346a3702c1fSVernon Mauery                 }
347a3702c1fSVernon Mauery                 break;
348a3702c1fSVernon Mauery 
349a3702c1fSVernon Mauery                 default:
35038d2b5a6SJason M. Bills                     return ipmi::responseInvalidFieldRequest();
351a3702c1fSVernon Mauery                     break;
352a3702c1fSVernon Mauery             }
353a3702c1fSVernon Mauery 
354a3702c1fSVernon Mauery             ipmi::Value reply;
35538d2b5a6SJason M. Bills             if (mtm.getProperty(buttonService, path, buttonIntf,
35638d2b5a6SJason M. Bills                                 "ButtonPressed", &reply) < 0)
357a3702c1fSVernon Mauery             {
35838d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
359a3702c1fSVernon Mauery             }
36038d2b5a6SJason M. Bills             bool* valPtr = std::get_if<bool>(&reply);
36138d2b5a6SJason M. Bills             if (valPtr == nullptr)
362a3702c1fSVernon Mauery             {
36338d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
364a3702c1fSVernon Mauery             }
36538d2b5a6SJason M. Bills             uint8_t sensorVal = *valPtr;
36638d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, std::nullopt);
367a3702c1fSVernon Mauery         }
368a3702c1fSVernon Mauery         break;
369a3702c1fSVernon Mauery         default:
37038d2b5a6SJason M. Bills             return ipmi::responseInvalidFieldRequest();
371a3702c1fSVernon Mauery             break;
372a3702c1fSVernon Mauery     }
373a3702c1fSVernon Mauery }
374a3702c1fSVernon Mauery 
375a3702c1fSVernon Mauery ipmi_ret_t ipmi_app_mtm_set_signal(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
376a3702c1fSVernon Mauery                                    ipmi_request_t request,
377a3702c1fSVernon Mauery                                    ipmi_response_t response,
378a3702c1fSVernon Mauery                                    ipmi_data_len_t data_len,
379a3702c1fSVernon Mauery                                    ipmi_context_t context)
380a3702c1fSVernon Mauery {
381a3702c1fSVernon Mauery     uint8_t ret = 0;
382a3702c1fSVernon Mauery     ipmi_ret_t retCode = IPMI_CC_OK;
383a3702c1fSVernon Mauery     SetSmSignalReq* pReq = static_cast<SetSmSignalReq*>(request);
384a3702c1fSVernon Mauery     std::string ledName;
385a3702c1fSVernon Mauery     ///////////////////  Signal to led configuration ////////////////
386a3702c1fSVernon Mauery     //        {SM_SYSTEM_READY_LED, STAT_GRN_LED},    GPIOS4  gpio148
387a3702c1fSVernon Mauery     //        {SM_POWER_FAULT_LED, STAT_AMB_LED},     GPIOS5  gpio149
388a3702c1fSVernon Mauery     //        {SM_IDENTIFY_LED, IDENTIFY_LED},        GPIOS6  gpio150
389a3702c1fSVernon Mauery     //        {SM_SPEAKER, SPEAKER},                  GPIOAB0 gpio216
390a3702c1fSVernon Mauery     /////////////////////////////////////////////////////////////////
391a3702c1fSVernon Mauery     if ((*data_len == sizeof(*pReq)) &&
392a3702c1fSVernon Mauery         (mtm.getAccessLvl() >= MtmLvl::mtmAvailable))
393a3702c1fSVernon Mauery     {
394a3702c1fSVernon Mauery         switch (pReq->Signal)
395a3702c1fSVernon Mauery         {
396a3702c1fSVernon Mauery             case SmSignalSet::smPowerFaultLed:
397a3702c1fSVernon Mauery             case SmSignalSet::smSystemReadyLed:
398a3702c1fSVernon Mauery             case SmSignalSet::smIdentifyLed:
399a3702c1fSVernon Mauery                 switch (pReq->Action)
400a3702c1fSVernon Mauery                 {
401a3702c1fSVernon Mauery                     case SmActionSet::forceDeasserted:
402a3702c1fSVernon Mauery                     {
403a3702c1fSVernon Mauery                         phosphor::logging::log<phosphor::logging::level::INFO>(
404a3702c1fSVernon Mauery                             "case SmActionSet::forceDeasserted");
405a3702c1fSVernon Mauery 
406a3702c1fSVernon Mauery                         retCode =
407a3702c1fSVernon Mauery                             ledStoreAndSet(pReq->Signal, std::string("Off"));
408a3702c1fSVernon Mauery                         if (retCode != IPMI_CC_OK)
409a3702c1fSVernon Mauery                         {
410a3702c1fSVernon Mauery                             break;
411a3702c1fSVernon Mauery                         }
412a3702c1fSVernon Mauery                         mtm.revertTimer.start(revertTimeOut);
413a3702c1fSVernon Mauery                     }
414a3702c1fSVernon Mauery                     break;
415a3702c1fSVernon Mauery                     case SmActionSet::forceAsserted:
416a3702c1fSVernon Mauery                     {
417a3702c1fSVernon Mauery                         phosphor::logging::log<phosphor::logging::level::INFO>(
418a3702c1fSVernon Mauery                             "case SmActionSet::forceAsserted");
419a3702c1fSVernon Mauery 
420a3702c1fSVernon Mauery                         retCode =
421a3702c1fSVernon Mauery                             ledStoreAndSet(pReq->Signal, std::string("On"));
422a3702c1fSVernon Mauery                         if (retCode != IPMI_CC_OK)
423a3702c1fSVernon Mauery                         {
424a3702c1fSVernon Mauery                             break;
425a3702c1fSVernon Mauery                         }
426a3702c1fSVernon Mauery                         mtm.revertTimer.start(revertTimeOut);
427a3702c1fSVernon Mauery                         if (SmSignalSet::smPowerFaultLed == pReq->Signal)
428a3702c1fSVernon Mauery                         {
429a3702c1fSVernon Mauery                             // Deassert "system ready"
430a3702c1fSVernon Mauery                             retCode =
431a3702c1fSVernon Mauery                                 ledStoreAndSet(SmSignalSet::smSystemReadyLed,
432a3702c1fSVernon Mauery                                                std::string("Off"));
433a3702c1fSVernon Mauery                             if (retCode != IPMI_CC_OK)
434a3702c1fSVernon Mauery                             {
435a3702c1fSVernon Mauery                                 break;
436a3702c1fSVernon Mauery                             }
437a3702c1fSVernon Mauery                         }
438a3702c1fSVernon Mauery                         else if (SmSignalSet::smSystemReadyLed == pReq->Signal)
439a3702c1fSVernon Mauery                         {
440a3702c1fSVernon Mauery                             // Deassert "fault led"
441a3702c1fSVernon Mauery                             retCode =
442a3702c1fSVernon Mauery                                 ledStoreAndSet(SmSignalSet::smPowerFaultLed,
443a3702c1fSVernon Mauery                                                std::string("Off"));
444a3702c1fSVernon Mauery                             if (retCode != IPMI_CC_OK)
445a3702c1fSVernon Mauery                             {
446a3702c1fSVernon Mauery                                 break;
447a3702c1fSVernon Mauery                             }
448a3702c1fSVernon Mauery                         }
449a3702c1fSVernon Mauery                     }
450a3702c1fSVernon Mauery                     break;
451a3702c1fSVernon Mauery                     case SmActionSet::revert:
452a3702c1fSVernon Mauery                     {
453a3702c1fSVernon Mauery                         phosphor::logging::log<phosphor::logging::level::INFO>(
454a3702c1fSVernon Mauery                             "case SmActionSet::revert");
455a3702c1fSVernon Mauery                         retCode = ledRevert(pReq->Signal);
456a3702c1fSVernon Mauery                         if (retCode != IPMI_CC_OK)
457a3702c1fSVernon Mauery                         {
458a3702c1fSVernon Mauery                             break;
459a3702c1fSVernon Mauery                         }
460a3702c1fSVernon Mauery                     }
461a3702c1fSVernon Mauery                     break;
462a3702c1fSVernon Mauery                     default:
463a3702c1fSVernon Mauery                     {
464a3702c1fSVernon Mauery                         retCode = IPMI_CC_INVALID_FIELD_REQUEST;
465a3702c1fSVernon Mauery                     }
466a3702c1fSVernon Mauery                     break;
467a3702c1fSVernon Mauery                 }
468a3702c1fSVernon Mauery                 break;
469a3702c1fSVernon Mauery             case SmSignalSet::smFanPowerSpeed:
470a3702c1fSVernon Mauery             {
471a3702c1fSVernon Mauery                 if (((pReq->Action == SmActionSet::forceAsserted) &&
472a3702c1fSVernon Mauery                      (*data_len != sizeof(*pReq)) && (pReq->Value > 100)) ||
473a3702c1fSVernon Mauery                     pReq->Instance == 0)
474a3702c1fSVernon Mauery                 {
475a3702c1fSVernon Mauery                     retCode = IPMI_CC_INVALID_FIELD_REQUEST;
476a3702c1fSVernon Mauery                     break;
477a3702c1fSVernon Mauery                 }
478a3702c1fSVernon Mauery                 uint8_t pwmValue = 0;
479a3702c1fSVernon Mauery                 switch (pReq->Action)
480a3702c1fSVernon Mauery                 {
481a3702c1fSVernon Mauery                     case SmActionSet::revert:
482a3702c1fSVernon Mauery                     {
483a3702c1fSVernon Mauery                         if (mtm.revertFanPWM)
484a3702c1fSVernon Mauery                         {
485a3702c1fSVernon Mauery                             ret = mtm.disablePidControlService(false);
486a3702c1fSVernon Mauery                             if (ret < 0)
487a3702c1fSVernon Mauery                             {
488a3702c1fSVernon Mauery                                 retCode = IPMI_CC_UNSPECIFIED_ERROR;
489a3702c1fSVernon Mauery                                 break;
490a3702c1fSVernon Mauery                             }
491a3702c1fSVernon Mauery                             mtm.revertFanPWM = false;
492a3702c1fSVernon Mauery                         }
493a3702c1fSVernon Mauery                     }
494a3702c1fSVernon Mauery                     break;
495a3702c1fSVernon Mauery                     case SmActionSet::forceAsserted:
496a3702c1fSVernon Mauery                     {
497a3702c1fSVernon Mauery                         pwmValue = pReq->Value;
498a3702c1fSVernon Mauery                     } // fall-through
499a3702c1fSVernon Mauery                     case SmActionSet::forceDeasserted:
500a3702c1fSVernon Mauery                     {
501a3702c1fSVernon Mauery                         if (!mtm.revertFanPWM)
502a3702c1fSVernon Mauery                         {
503a3702c1fSVernon Mauery                             ret = mtm.disablePidControlService(true);
504a3702c1fSVernon Mauery                             if (ret < 0)
505a3702c1fSVernon Mauery                             {
506a3702c1fSVernon Mauery                                 retCode = IPMI_CC_UNSPECIFIED_ERROR;
507a3702c1fSVernon Mauery                                 break;
508a3702c1fSVernon Mauery                             }
509a3702c1fSVernon Mauery                             mtm.revertFanPWM = true;
510a3702c1fSVernon Mauery                         }
511a3702c1fSVernon Mauery                         mtm.revertTimer.start(revertTimeOut);
512a3702c1fSVernon Mauery                         std::string fanPwmInstancePath =
513a3702c1fSVernon Mauery                             fanPwmPath + std::to_string(pReq->Instance);
514a3702c1fSVernon Mauery 
51538d2b5a6SJason M. Bills                         ret = mtm.setProperty(fanService, fanPwmInstancePath,
51638d2b5a6SJason M. Bills                                               fanIntf, "Value",
51738d2b5a6SJason M. Bills                                               static_cast<double>(pwmValue));
518a3702c1fSVernon Mauery                         if (ret < 0)
519a3702c1fSVernon Mauery                         {
520a3702c1fSVernon Mauery                             retCode = IPMI_CC_UNSPECIFIED_ERROR;
521a3702c1fSVernon Mauery                         }
522a3702c1fSVernon Mauery                     }
523a3702c1fSVernon Mauery                     break;
524a3702c1fSVernon Mauery                     default:
525a3702c1fSVernon Mauery                     {
526a3702c1fSVernon Mauery                         retCode = IPMI_CC_INVALID_FIELD_REQUEST;
527a3702c1fSVernon Mauery                     }
528a3702c1fSVernon Mauery                     break;
529a3702c1fSVernon Mauery                 }
530a3702c1fSVernon Mauery             }
531a3702c1fSVernon Mauery             break;
532a3702c1fSVernon Mauery             default:
533a3702c1fSVernon Mauery             {
534a3702c1fSVernon Mauery                 retCode = IPMI_CC_INVALID_FIELD_REQUEST;
535a3702c1fSVernon Mauery             }
536a3702c1fSVernon Mauery             break;
537a3702c1fSVernon Mauery         }
538a3702c1fSVernon Mauery     }
539a3702c1fSVernon Mauery     else
540a3702c1fSVernon Mauery     {
541*39f64b32SAyushi Smriti         retCode = IPMI_CC_INVALID;
542a3702c1fSVernon Mauery     }
543a3702c1fSVernon Mauery 
544a3702c1fSVernon Mauery     *data_len = 0; // Only CC is return for SetSmSignal cmd
545a3702c1fSVernon Mauery     return retCode;
546a3702c1fSVernon Mauery }
547a3702c1fSVernon Mauery 
548a3702c1fSVernon Mauery } // namespace ipmi
549a3702c1fSVernon Mauery 
550a3702c1fSVernon Mauery void register_mtm_commands() __attribute__((constructor));
551a3702c1fSVernon Mauery void register_mtm_commands()
552a3702c1fSVernon Mauery {
55338d2b5a6SJason M. Bills     // <Get SM Signal>
55438d2b5a6SJason M. Bills     ipmi::registerHandler(
55538d2b5a6SJason M. Bills         ipmi::prioOemBase, ipmi::netFnOemOne,
55638d2b5a6SJason M. Bills         static_cast<ipmi::Cmd>(IPMINetFnIntelOemGeneralCmds::GetSmSignal),
55738d2b5a6SJason M. Bills         ipmi::Privilege::User, ipmi::appMTMGetSignal);
558a3702c1fSVernon Mauery 
559a3702c1fSVernon Mauery     ipmi_register_callback(
560a3702c1fSVernon Mauery         netfnIntcOEMGeneral,
561a3702c1fSVernon Mauery         static_cast<ipmi_cmd_t>(IPMINetFnIntelOemGeneralCmds::SetSmSignal),
562a3702c1fSVernon Mauery         NULL, ipmi::ipmi_app_mtm_set_signal, PRIVILEGE_USER);
563a3702c1fSVernon Mauery 
564a3702c1fSVernon Mauery     return;
565a3702c1fSVernon Mauery }
566