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 
17147daec5SRichard Marian Thomaiyar #include <boost/container/flat_map.hpp>
181b74a210SRichard Marian Thomaiyar #include <fstream>
19a3702c1fSVernon Mauery #include <ipmid/api.hpp>
20a3702c1fSVernon Mauery #include <manufacturingcommands.hpp>
21a3702c1fSVernon Mauery #include <oemcommands.hpp>
22a3702c1fSVernon Mauery 
23a3702c1fSVernon Mauery namespace ipmi
24a3702c1fSVernon Mauery {
25a3702c1fSVernon Mauery 
26a3702c1fSVernon Mauery Manufacturing mtm;
27a3702c1fSVernon Mauery 
28a3702c1fSVernon Mauery static auto revertTimeOut =
29a3702c1fSVernon Mauery     std::chrono::duration_cast<std::chrono::microseconds>(
30a3702c1fSVernon Mauery         std::chrono::seconds(60)); // 1 minute timeout
31a3702c1fSVernon Mauery 
32a3702c1fSVernon Mauery static constexpr const char* callbackMgrService =
33a3702c1fSVernon Mauery     "xyz.openbmc_project.CallbackManager";
34a3702c1fSVernon Mauery static constexpr const char* callbackMgrIntf =
35a3702c1fSVernon Mauery     "xyz.openbmc_project.CallbackManager";
36a3702c1fSVernon Mauery static constexpr const char* callbackMgrObjPath =
37a3702c1fSVernon Mauery     "/xyz/openbmc_project/CallbackManager";
38a3702c1fSVernon Mauery static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate";
39a3702c1fSVernon Mauery 
40a3702c1fSVernon Mauery const static constexpr char* systemDService = "org.freedesktop.systemd1";
41a3702c1fSVernon Mauery const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1";
42a3702c1fSVernon Mauery const static constexpr char* systemDMgrIntf =
43a3702c1fSVernon Mauery     "org.freedesktop.systemd1.Manager";
44a3702c1fSVernon Mauery const static constexpr char* pidControlService = "phosphor-pid-control.service";
45a3702c1fSVernon Mauery 
46666dd01cSRichard Marian Thomaiyar static inline Cc resetMtmTimer(boost::asio::yield_context yield)
47666dd01cSRichard Marian Thomaiyar {
48666dd01cSRichard Marian Thomaiyar     auto sdbusp = getSdBus();
49666dd01cSRichard Marian Thomaiyar     boost::system::error_code ec;
50666dd01cSRichard Marian Thomaiyar     sdbusp->yield_method_call<>(yield, ec, specialModeService,
51666dd01cSRichard Marian Thomaiyar                                 specialModeObjPath, specialModeIntf,
52666dd01cSRichard Marian Thomaiyar                                 "ResetTimer");
53666dd01cSRichard Marian Thomaiyar     if (ec)
54666dd01cSRichard Marian Thomaiyar     {
55666dd01cSRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
56666dd01cSRichard Marian Thomaiyar             "Failed to reset the manufacturing mode timer");
57666dd01cSRichard Marian Thomaiyar         return ccUnspecifiedError;
58666dd01cSRichard Marian Thomaiyar     }
59666dd01cSRichard Marian Thomaiyar     return ccSuccess;
60666dd01cSRichard Marian Thomaiyar }
61666dd01cSRichard Marian Thomaiyar 
6238d2b5a6SJason M. Bills int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path)
63a3702c1fSVernon Mauery {
6438d2b5a6SJason M. Bills     switch (signal)
6538d2b5a6SJason M. Bills     {
6638d2b5a6SJason M. Bills         case SmSignalGet::smPowerButton:
6738d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/power";
6838d2b5a6SJason M. Bills             break;
6938d2b5a6SJason M. Bills         case SmSignalGet::smResetButton:
7038d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/reset";
7138d2b5a6SJason M. Bills             break;
7238d2b5a6SJason M. Bills         case SmSignalGet::smNMIButton:
7338d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/nmi";
7438d2b5a6SJason M. Bills             break;
758e5e2b04SRichard Marian Thomaiyar         case SmSignalGet::smIdentifyButton:
768e5e2b04SRichard Marian Thomaiyar             path = "/xyz/openbmc_project/chassis/buttons/id";
778e5e2b04SRichard Marian Thomaiyar             break;
7838d2b5a6SJason M. Bills         default:
7938d2b5a6SJason M. Bills             return -1;
8038d2b5a6SJason M. Bills             break;
8138d2b5a6SJason M. Bills     }
8238d2b5a6SJason M. Bills     return 0;
83a3702c1fSVernon Mauery }
84a3702c1fSVernon Mauery 
85a3702c1fSVernon Mauery ipmi_ret_t ledStoreAndSet(SmSignalSet signal, std::string setState)
86a3702c1fSVernon Mauery {
87a3702c1fSVernon Mauery     LedProperty* ledProp = mtm.findLedProperty(signal);
88a3702c1fSVernon Mauery     if (ledProp == nullptr)
89a3702c1fSVernon Mauery     {
90a3702c1fSVernon Mauery         return IPMI_CC_INVALID_FIELD_REQUEST;
91a3702c1fSVernon Mauery     }
92a3702c1fSVernon Mauery 
93a3702c1fSVernon Mauery     std::string ledName = ledProp->getName();
94a3702c1fSVernon Mauery     std::string ledService = ledServicePrefix + ledName;
95a3702c1fSVernon Mauery     std::string ledPath = ledPathPrefix + ledName;
96a3702c1fSVernon Mauery     ipmi::Value presentState;
97a3702c1fSVernon Mauery 
98a3702c1fSVernon Mauery     if (false == ledProp->getLock())
99a3702c1fSVernon Mauery     {
100a3702c1fSVernon Mauery         if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf,
101a3702c1fSVernon Mauery                             "State", &presentState) != 0)
102a3702c1fSVernon Mauery         {
103a3702c1fSVernon Mauery             return IPMI_CC_UNSPECIFIED_ERROR;
104a3702c1fSVernon Mauery         }
105a3702c1fSVernon Mauery         ledProp->setPrevState(std::get<std::string>(presentState));
106a3702c1fSVernon Mauery         ledProp->setLock(true);
107a3702c1fSVernon Mauery         if (signal == SmSignalSet::smPowerFaultLed ||
108a3702c1fSVernon Mauery             signal == SmSignalSet::smSystemReadyLed)
109a3702c1fSVernon Mauery         {
110a3702c1fSVernon Mauery             mtm.revertLedCallback = true;
111a3702c1fSVernon Mauery         }
112a3702c1fSVernon Mauery     }
11338d2b5a6SJason M. Bills     if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
114a3702c1fSVernon Mauery                         ledStateStr + setState) != 0)
115a3702c1fSVernon Mauery     {
116a3702c1fSVernon Mauery         return IPMI_CC_UNSPECIFIED_ERROR;
117a3702c1fSVernon Mauery     }
118a3702c1fSVernon Mauery     return IPMI_CC_OK;
119a3702c1fSVernon Mauery }
120a3702c1fSVernon Mauery 
121a3702c1fSVernon Mauery ipmi_ret_t ledRevert(SmSignalSet signal)
122a3702c1fSVernon Mauery {
123a3702c1fSVernon Mauery     LedProperty* ledProp = mtm.findLedProperty(signal);
124a3702c1fSVernon Mauery     if (ledProp == nullptr)
125a3702c1fSVernon Mauery     {
126a3702c1fSVernon Mauery         return IPMI_CC_INVALID_FIELD_REQUEST;
127a3702c1fSVernon Mauery     }
128a3702c1fSVernon Mauery     if (true == ledProp->getLock())
129a3702c1fSVernon Mauery     {
130a3702c1fSVernon Mauery         ledProp->setLock(false);
131a3702c1fSVernon Mauery         if (signal == SmSignalSet::smPowerFaultLed ||
132a3702c1fSVernon Mauery             signal == SmSignalSet::smSystemReadyLed)
133a3702c1fSVernon Mauery         {
134a3702c1fSVernon Mauery             try
135a3702c1fSVernon Mauery             {
136a3702c1fSVernon Mauery                 ipmi::method_no_args::callDbusMethod(
137a3702c1fSVernon Mauery                     *getSdBus(), callbackMgrService, callbackMgrObjPath,
138a3702c1fSVernon Mauery                     callbackMgrIntf, retriggerLedUpdate);
139a3702c1fSVernon Mauery             }
140a3702c1fSVernon Mauery             catch (sdbusplus::exception_t& e)
141a3702c1fSVernon Mauery             {
142a3702c1fSVernon Mauery                 return IPMI_CC_UNSPECIFIED_ERROR;
143a3702c1fSVernon Mauery             }
144a3702c1fSVernon Mauery             mtm.revertLedCallback = false;
145a3702c1fSVernon Mauery         }
146a3702c1fSVernon Mauery         else
147a3702c1fSVernon Mauery         {
148a3702c1fSVernon Mauery             std::string ledName = ledProp->getName();
149a3702c1fSVernon Mauery             std::string ledService = ledServicePrefix + ledName;
150a3702c1fSVernon Mauery             std::string ledPath = ledPathPrefix + ledName;
15138d2b5a6SJason M. Bills             if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
15238d2b5a6SJason M. Bills                                 ledProp->getPrevState()) != 0)
153a3702c1fSVernon Mauery             {
154a3702c1fSVernon Mauery                 return IPMI_CC_UNSPECIFIED_ERROR;
155a3702c1fSVernon Mauery             }
156a3702c1fSVernon Mauery         }
157a3702c1fSVernon Mauery     }
158a3702c1fSVernon Mauery     return IPMI_CC_OK;
159a3702c1fSVernon Mauery }
160a3702c1fSVernon Mauery 
161a3702c1fSVernon Mauery void Manufacturing::initData()
162a3702c1fSVernon Mauery {
163a3702c1fSVernon Mauery     ledPropertyList.push_back(
164a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smPowerFaultLed, "status_amber"));
165a3702c1fSVernon Mauery     ledPropertyList.push_back(
166a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smSystemReadyLed, "status_green"));
167a3702c1fSVernon Mauery     ledPropertyList.push_back(
168a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smIdentifyLed, "identify"));
169a3702c1fSVernon Mauery }
170a3702c1fSVernon Mauery 
171a3702c1fSVernon Mauery void Manufacturing::revertTimerHandler()
172a3702c1fSVernon Mauery {
173a3702c1fSVernon Mauery     if (revertFanPWM)
174a3702c1fSVernon Mauery     {
175a3702c1fSVernon Mauery         revertFanPWM = false;
176a3702c1fSVernon Mauery         disablePidControlService(false);
177a3702c1fSVernon Mauery     }
178a3702c1fSVernon Mauery 
179a3702c1fSVernon Mauery     for (const auto& ledProperty : ledPropertyList)
180a3702c1fSVernon Mauery     {
181a3702c1fSVernon Mauery         const std::string& ledName = ledProperty.getName();
182a3702c1fSVernon Mauery         ledRevert(ledProperty.getSignal());
183a3702c1fSVernon Mauery     }
184a3702c1fSVernon Mauery }
185a3702c1fSVernon Mauery 
186a3702c1fSVernon Mauery Manufacturing::Manufacturing() :
187a3702c1fSVernon Mauery     revertTimer([&](void) { revertTimerHandler(); })
188a3702c1fSVernon Mauery {
189a3702c1fSVernon Mauery     initData();
190a3702c1fSVernon Mauery }
191a3702c1fSVernon Mauery 
19238d2b5a6SJason M. Bills int8_t Manufacturing::getProperty(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* reply)
197a3702c1fSVernon Mauery {
198a3702c1fSVernon Mauery     try
199a3702c1fSVernon Mauery     {
20038d2b5a6SJason M. Bills         *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface,
20138d2b5a6SJason M. Bills                                        propertyName);
202a3702c1fSVernon Mauery     }
203a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
204a3702c1fSVernon Mauery     {
205a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
206a3702c1fSVernon Mauery             "ERROR: getProperty");
207a3702c1fSVernon Mauery         return -1;
208a3702c1fSVernon Mauery     }
209a3702c1fSVernon Mauery 
210a3702c1fSVernon Mauery     return 0;
211a3702c1fSVernon Mauery }
212a3702c1fSVernon Mauery 
21338d2b5a6SJason M. Bills int8_t Manufacturing::setProperty(const std::string& service,
21438d2b5a6SJason M. Bills                                   const std::string& path,
21538d2b5a6SJason M. Bills                                   const std::string& interface,
21638d2b5a6SJason M. Bills                                   const std::string& propertyName,
21738d2b5a6SJason M. Bills                                   ipmi::Value value)
218a3702c1fSVernon Mauery {
219a3702c1fSVernon Mauery     try
220a3702c1fSVernon Mauery     {
22138d2b5a6SJason M. Bills         ipmi::setDbusProperty(*getSdBus(), service, path, interface,
222a3702c1fSVernon Mauery                               propertyName, value);
223a3702c1fSVernon Mauery     }
224a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
225a3702c1fSVernon Mauery     {
226a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
227a3702c1fSVernon Mauery             "ERROR: setProperty");
228a3702c1fSVernon Mauery         return -1;
229a3702c1fSVernon Mauery     }
230a3702c1fSVernon Mauery 
231a3702c1fSVernon Mauery     return 0;
232a3702c1fSVernon Mauery }
233a3702c1fSVernon Mauery 
234a3702c1fSVernon Mauery int8_t Manufacturing::disablePidControlService(const bool disable)
235a3702c1fSVernon Mauery {
236a3702c1fSVernon Mauery     try
237a3702c1fSVernon Mauery     {
238a3702c1fSVernon Mauery         auto dbus = getSdBus();
239a3702c1fSVernon Mauery         auto method = dbus->new_method_call(systemDService, systemDObjPath,
240a3702c1fSVernon Mauery                                             systemDMgrIntf,
241a3702c1fSVernon Mauery                                             disable ? "StopUnit" : "StartUnit");
242a3702c1fSVernon Mauery         method.append(pidControlService, "replace");
243a3702c1fSVernon Mauery         auto reply = dbus->call(method);
244a3702c1fSVernon Mauery     }
245a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
246a3702c1fSVernon Mauery     {
247a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
248a3702c1fSVernon Mauery             "ERROR: phosphor-pid-control service start or stop failed");
249a3702c1fSVernon Mauery         return -1;
250a3702c1fSVernon Mauery     }
251a3702c1fSVernon Mauery     return 0;
252a3702c1fSVernon Mauery }
253a3702c1fSVernon Mauery 
25438d2b5a6SJason M. Bills ipmi::RspType<uint8_t,                // Signal value
25538d2b5a6SJason M. Bills               std::optional<uint16_t> // Fan tach value
25638d2b5a6SJason M. Bills               >
257147daec5SRichard Marian Thomaiyar     appMTMGetSignal(boost::asio::yield_context yield, uint8_t signalTypeByte,
258147daec5SRichard Marian Thomaiyar                     uint8_t instance, uint8_t actionByte)
259a3702c1fSVernon Mauery {
26038d2b5a6SJason M. Bills     if (mtm.getAccessLvl() < MtmLvl::mtmAvailable)
26138d2b5a6SJason M. Bills     {
26238d2b5a6SJason M. Bills         return ipmi::responseInvalidCommand();
26338d2b5a6SJason M. Bills     }
26438d2b5a6SJason M. Bills 
26538d2b5a6SJason M. Bills     SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte);
26638d2b5a6SJason M. Bills     SmActionGet action = static_cast<SmActionGet>(actionByte);
26738d2b5a6SJason M. Bills 
26838d2b5a6SJason M. Bills     switch (signalType)
26938d2b5a6SJason M. Bills     {
27038d2b5a6SJason M. Bills         case SmSignalGet::smFanPwmGet:
27138d2b5a6SJason M. Bills         {
272a3702c1fSVernon Mauery             ipmi::Value reply;
273147daec5SRichard Marian Thomaiyar             std::string fullPath = fanPwmPath + std::to_string(instance + 1);
27438d2b5a6SJason M. Bills             if (mtm.getProperty(fanService, fullPath, fanIntf, "Value",
27538d2b5a6SJason M. Bills                                 &reply) < 0)
27638d2b5a6SJason M. Bills             {
27738d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
27838d2b5a6SJason M. Bills             }
27938d2b5a6SJason M. Bills             double* doubleVal = std::get_if<double>(&reply);
28038d2b5a6SJason M. Bills             if (doubleVal == nullptr)
28138d2b5a6SJason M. Bills             {
28238d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
28338d2b5a6SJason M. Bills             }
28438d2b5a6SJason M. Bills             uint8_t sensorVal = std::round(*doubleVal);
2854cc10159SRichard Marian Thomaiyar             resetMtmTimer(yield);
28638d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, std::nullopt);
28738d2b5a6SJason M. Bills         }
28838d2b5a6SJason M. Bills         break;
28938d2b5a6SJason M. Bills         case SmSignalGet::smFanTachometerGet:
29038d2b5a6SJason M. Bills         {
291147daec5SRichard Marian Thomaiyar             auto sdbusp = getSdBus();
292147daec5SRichard Marian Thomaiyar             boost::system::error_code ec;
293147daec5SRichard Marian Thomaiyar             using objFlatMap = boost::container::flat_map<
294147daec5SRichard Marian Thomaiyar                 std::string, boost::container::flat_map<
295147daec5SRichard Marian Thomaiyar                                  std::string, std::vector<std::string>>>;
296147daec5SRichard Marian Thomaiyar 
297147daec5SRichard Marian Thomaiyar             auto flatMap = sdbusp->yield_method_call<objFlatMap>(
298147daec5SRichard Marian Thomaiyar                 yield, ec, "xyz.openbmc_project.ObjectMapper",
299147daec5SRichard Marian Thomaiyar                 "/xyz/openbmc_project/object_mapper",
300147daec5SRichard Marian Thomaiyar                 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
301147daec5SRichard Marian Thomaiyar                 fanTachBasePath, 0, std::array<const char*, 1>{fanIntf});
302147daec5SRichard Marian Thomaiyar             if (ec)
303147daec5SRichard Marian Thomaiyar             {
304147daec5SRichard Marian Thomaiyar                 phosphor::logging::log<phosphor::logging::level::ERR>(
305147daec5SRichard Marian Thomaiyar                     "Failed to query fan tach sub tree objects");
306147daec5SRichard Marian Thomaiyar                 return ipmi::responseUnspecifiedError();
307147daec5SRichard Marian Thomaiyar             }
308147daec5SRichard Marian Thomaiyar             if (instance >= flatMap.size())
30938d2b5a6SJason M. Bills             {
31038d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
31138d2b5a6SJason M. Bills             }
312147daec5SRichard Marian Thomaiyar             auto itr = flatMap.nth(instance);
31338d2b5a6SJason M. Bills             ipmi::Value reply;
314147daec5SRichard Marian Thomaiyar             if (mtm.getProperty(fanService, itr->first, fanIntf, "Value",
31538d2b5a6SJason M. Bills                                 &reply) < 0)
31638d2b5a6SJason M. Bills             {
31738d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
31838d2b5a6SJason M. Bills             }
31938d2b5a6SJason M. Bills 
32038d2b5a6SJason M. Bills             double* doubleVal = std::get_if<double>(&reply);
32138d2b5a6SJason M. Bills             if (doubleVal == nullptr)
32238d2b5a6SJason M. Bills             {
32338d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
32438d2b5a6SJason M. Bills             }
32538d2b5a6SJason M. Bills             uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT;
32638d2b5a6SJason M. Bills             std::optional<uint16_t> fanTach = std::round(*doubleVal);
32738d2b5a6SJason M. Bills 
3284cc10159SRichard Marian Thomaiyar             resetMtmTimer(yield);
32938d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, fanTach);
33038d2b5a6SJason M. Bills         }
33138d2b5a6SJason M. Bills         break;
3328e5e2b04SRichard Marian Thomaiyar         case SmSignalGet::smIdentifyButton:
3338e5e2b04SRichard Marian Thomaiyar         {
3348e5e2b04SRichard Marian Thomaiyar             if (action == SmActionGet::revert || action == SmActionGet::ignore)
3358e5e2b04SRichard Marian Thomaiyar             {
3368e5e2b04SRichard Marian Thomaiyar                 // ButtonMasked property is not supported for ID button as it is
3378e5e2b04SRichard Marian Thomaiyar                 // unnecessary. Hence if requested for revert / ignore, override
3388e5e2b04SRichard Marian Thomaiyar                 // it to sample action to make tools happy.
3398e5e2b04SRichard Marian Thomaiyar                 action = SmActionGet::sample;
3408e5e2b04SRichard Marian Thomaiyar             }
3418e5e2b04SRichard Marian Thomaiyar             // fall-through
3428e5e2b04SRichard Marian Thomaiyar         }
34338d2b5a6SJason M. Bills         case SmSignalGet::smResetButton:
34438d2b5a6SJason M. Bills         case SmSignalGet::smPowerButton:
34538d2b5a6SJason M. Bills         case SmSignalGet::smNMIButton:
34638d2b5a6SJason M. Bills         {
34738d2b5a6SJason M. Bills             std::string path;
34838d2b5a6SJason M. Bills             if (getGpioPathForSmSignal(signalType, path) < 0)
34938d2b5a6SJason M. Bills             {
35038d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
35138d2b5a6SJason M. Bills             }
352a3702c1fSVernon Mauery 
353a3702c1fSVernon Mauery             switch (action)
354a3702c1fSVernon Mauery             {
355a3702c1fSVernon Mauery                 case SmActionGet::sample:
356a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
357a3702c1fSVernon Mauery                         "case SmActionGet::sample");
358a3702c1fSVernon Mauery                     break;
359a3702c1fSVernon Mauery                 case SmActionGet::ignore:
360a3702c1fSVernon Mauery                 {
361a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
362a3702c1fSVernon Mauery                         "case SmActionGet::ignore");
36338d2b5a6SJason M. Bills                     if (mtm.setProperty(buttonService, path, buttonIntf,
36438d2b5a6SJason M. Bills                                         "ButtonMasked", true) < 0)
365a3702c1fSVernon Mauery                     {
36638d2b5a6SJason M. Bills                         return ipmi::responseUnspecifiedError();
367a3702c1fSVernon Mauery                     }
368a3702c1fSVernon Mauery                 }
369a3702c1fSVernon Mauery                 break;
370a3702c1fSVernon Mauery                 case SmActionGet::revert:
371a3702c1fSVernon Mauery                 {
372a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
373a3702c1fSVernon Mauery                         "case SmActionGet::revert");
37438d2b5a6SJason M. Bills                     if (mtm.setProperty(buttonService, path, buttonIntf,
37538d2b5a6SJason M. Bills                                         "ButtonMasked", false) < 0)
376a3702c1fSVernon Mauery                     {
37738d2b5a6SJason M. Bills                         return ipmi::responseUnspecifiedError();
378a3702c1fSVernon Mauery                     }
379a3702c1fSVernon Mauery                 }
380a3702c1fSVernon Mauery                 break;
381a3702c1fSVernon Mauery 
382a3702c1fSVernon Mauery                 default:
38338d2b5a6SJason M. Bills                     return ipmi::responseInvalidFieldRequest();
384a3702c1fSVernon Mauery                     break;
385a3702c1fSVernon Mauery             }
386a3702c1fSVernon Mauery 
387a3702c1fSVernon Mauery             ipmi::Value reply;
38838d2b5a6SJason M. Bills             if (mtm.getProperty(buttonService, path, buttonIntf,
38938d2b5a6SJason M. Bills                                 "ButtonPressed", &reply) < 0)
390a3702c1fSVernon Mauery             {
39138d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
392a3702c1fSVernon Mauery             }
39338d2b5a6SJason M. Bills             bool* valPtr = std::get_if<bool>(&reply);
39438d2b5a6SJason M. Bills             if (valPtr == nullptr)
395a3702c1fSVernon Mauery             {
39638d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
397a3702c1fSVernon Mauery             }
3984cc10159SRichard Marian Thomaiyar             resetMtmTimer(yield);
39938d2b5a6SJason M. Bills             uint8_t sensorVal = *valPtr;
40038d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, std::nullopt);
401a3702c1fSVernon Mauery         }
402a3702c1fSVernon Mauery         break;
4031b74a210SRichard Marian Thomaiyar         case SmSignalGet::smNcsiDiag:
4041b74a210SRichard Marian Thomaiyar         {
4051b74a210SRichard Marian Thomaiyar             constexpr const char* netBasePath = "/sys/class/net/eth";
4061b74a210SRichard Marian Thomaiyar             constexpr const char* carrierSuffix = "/carrier";
4071b74a210SRichard Marian Thomaiyar             std::ifstream netIfs(netBasePath + std::to_string(instance) +
4081b74a210SRichard Marian Thomaiyar                                  carrierSuffix);
4091b74a210SRichard Marian Thomaiyar             if (!netIfs.good())
4101b74a210SRichard Marian Thomaiyar             {
4111b74a210SRichard Marian Thomaiyar                 return ipmi::responseInvalidFieldRequest();
4121b74a210SRichard Marian Thomaiyar             }
4131b74a210SRichard Marian Thomaiyar             std::string carrier;
4141b74a210SRichard Marian Thomaiyar             netIfs >> carrier;
4151b74a210SRichard Marian Thomaiyar             resetMtmTimer(yield);
4161b74a210SRichard Marian Thomaiyar             return ipmi::responseSuccess(
4171b74a210SRichard Marian Thomaiyar                 static_cast<uint8_t>(std::stoi(carrier)), std::nullopt);
4181b74a210SRichard Marian Thomaiyar         }
4191b74a210SRichard Marian Thomaiyar         break;
420a3702c1fSVernon Mauery         default:
42138d2b5a6SJason M. Bills             return ipmi::responseInvalidFieldRequest();
422a3702c1fSVernon Mauery             break;
423a3702c1fSVernon Mauery     }
424a3702c1fSVernon Mauery }
425a3702c1fSVernon Mauery 
4264cc10159SRichard Marian Thomaiyar ipmi::RspType<> appMTMSetSignal(boost::asio::yield_context yield,
4274cc10159SRichard Marian Thomaiyar                                 uint8_t signalTypeByte, uint8_t instance,
4285e3bf557SAyushi Smriti                                 uint8_t actionByte,
4295e3bf557SAyushi Smriti                                 std::optional<uint8_t> pwmSpeed)
430a3702c1fSVernon Mauery {
4315e3bf557SAyushi Smriti     if (mtm.getAccessLvl() < MtmLvl::mtmAvailable)
4325e3bf557SAyushi Smriti     {
4335e3bf557SAyushi Smriti         return ipmi::responseInvalidCommand();
4345e3bf557SAyushi Smriti     }
4355e3bf557SAyushi Smriti 
4365e3bf557SAyushi Smriti     SmSignalSet signalType = static_cast<SmSignalSet>(signalTypeByte);
4375e3bf557SAyushi Smriti     SmActionSet action = static_cast<SmActionSet>(actionByte);
4385e3bf557SAyushi Smriti     Cc retCode = ccSuccess;
43913b0039dSJames Feist     int8_t ret = 0;
4405e3bf557SAyushi Smriti 
4415e3bf557SAyushi Smriti     switch (signalType)
442a3702c1fSVernon Mauery     {
443a3702c1fSVernon Mauery         case SmSignalSet::smPowerFaultLed:
444a3702c1fSVernon Mauery         case SmSignalSet::smSystemReadyLed:
445a3702c1fSVernon Mauery         case SmSignalSet::smIdentifyLed:
4465e3bf557SAyushi Smriti             switch (action)
447a3702c1fSVernon Mauery             {
448a3702c1fSVernon Mauery                 case SmActionSet::forceDeasserted:
449a3702c1fSVernon Mauery                 {
450a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
451a3702c1fSVernon Mauery                         "case SmActionSet::forceDeasserted");
452a3702c1fSVernon Mauery 
4535e3bf557SAyushi Smriti                     retCode = ledStoreAndSet(signalType, std::string("Off"));
4545e3bf557SAyushi Smriti                     if (retCode != ccSuccess)
455a3702c1fSVernon Mauery                     {
4565e3bf557SAyushi Smriti                         return ipmi::response(retCode);
457a3702c1fSVernon Mauery                     }
458a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
459a3702c1fSVernon Mauery                 }
460a3702c1fSVernon Mauery                 break;
461a3702c1fSVernon Mauery                 case SmActionSet::forceAsserted:
462a3702c1fSVernon Mauery                 {
463a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
464a3702c1fSVernon Mauery                         "case SmActionSet::forceAsserted");
465a3702c1fSVernon Mauery 
4665e3bf557SAyushi Smriti                     retCode = ledStoreAndSet(signalType, std::string("On"));
4675e3bf557SAyushi Smriti                     if (retCode != ccSuccess)
468a3702c1fSVernon Mauery                     {
4695e3bf557SAyushi Smriti                         return ipmi::response(retCode);
470a3702c1fSVernon Mauery                     }
471a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
4725e3bf557SAyushi Smriti                     if (SmSignalSet::smPowerFaultLed == signalType)
473a3702c1fSVernon Mauery                     {
474a3702c1fSVernon Mauery                         // Deassert "system ready"
4755e3bf557SAyushi Smriti                         retCode = ledStoreAndSet(SmSignalSet::smSystemReadyLed,
476a3702c1fSVernon Mauery                                                  std::string("Off"));
477a3702c1fSVernon Mauery                     }
4785e3bf557SAyushi Smriti                     else if (SmSignalSet::smSystemReadyLed == signalType)
479a3702c1fSVernon Mauery                     {
480a3702c1fSVernon Mauery                         // Deassert "fault led"
4815e3bf557SAyushi Smriti                         retCode = ledStoreAndSet(SmSignalSet::smPowerFaultLed,
482a3702c1fSVernon Mauery                                                  std::string("Off"));
483a3702c1fSVernon Mauery                     }
484a3702c1fSVernon Mauery                 }
485a3702c1fSVernon Mauery                 break;
486a3702c1fSVernon Mauery                 case SmActionSet::revert:
487a3702c1fSVernon Mauery                 {
488a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
489a3702c1fSVernon Mauery                         "case SmActionSet::revert");
4905e3bf557SAyushi Smriti                     retCode = ledRevert(signalType);
491a3702c1fSVernon Mauery                 }
492a3702c1fSVernon Mauery                 break;
493a3702c1fSVernon Mauery                 default:
494a3702c1fSVernon Mauery                 {
4955e3bf557SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
496a3702c1fSVernon Mauery                 }
497a3702c1fSVernon Mauery             }
498a3702c1fSVernon Mauery             break;
499a3702c1fSVernon Mauery         case SmSignalSet::smFanPowerSpeed:
500a3702c1fSVernon Mauery         {
5015e3bf557SAyushi Smriti             if ((action == SmActionSet::forceAsserted) && (!pwmSpeed))
502a3702c1fSVernon Mauery             {
5035e3bf557SAyushi Smriti                 return ipmi::responseReqDataLenInvalid();
504a3702c1fSVernon Mauery             }
5055e3bf557SAyushi Smriti 
5065e3bf557SAyushi Smriti             if ((action == SmActionSet::forceAsserted) && (*pwmSpeed > 100))
5075e3bf557SAyushi Smriti             {
5085e3bf557SAyushi Smriti                 return ipmi::responseInvalidFieldRequest();
5095e3bf557SAyushi Smriti             }
5105e3bf557SAyushi Smriti 
511a3702c1fSVernon Mauery             uint8_t pwmValue = 0;
5125e3bf557SAyushi Smriti             switch (action)
513a3702c1fSVernon Mauery             {
514a3702c1fSVernon Mauery                 case SmActionSet::revert:
515a3702c1fSVernon Mauery                 {
516a3702c1fSVernon Mauery                     if (mtm.revertFanPWM)
517a3702c1fSVernon Mauery                     {
518a3702c1fSVernon Mauery                         ret = mtm.disablePidControlService(false);
519a3702c1fSVernon Mauery                         if (ret < 0)
520a3702c1fSVernon Mauery                         {
5215e3bf557SAyushi Smriti                             return ipmi::responseUnspecifiedError();
522a3702c1fSVernon Mauery                         }
523a3702c1fSVernon Mauery                         mtm.revertFanPWM = false;
524a3702c1fSVernon Mauery                     }
525a3702c1fSVernon Mauery                 }
526a3702c1fSVernon Mauery                 break;
527a3702c1fSVernon Mauery                 case SmActionSet::forceAsserted:
528a3702c1fSVernon Mauery                 {
5295e3bf557SAyushi Smriti                     pwmValue = *pwmSpeed;
530a3702c1fSVernon Mauery                 } // fall-through
531a3702c1fSVernon Mauery                 case SmActionSet::forceDeasserted:
532a3702c1fSVernon Mauery                 {
533a3702c1fSVernon Mauery                     if (!mtm.revertFanPWM)
534a3702c1fSVernon Mauery                     {
535a3702c1fSVernon Mauery                         ret = mtm.disablePidControlService(true);
536a3702c1fSVernon Mauery                         if (ret < 0)
537a3702c1fSVernon Mauery                         {
5385e3bf557SAyushi Smriti                             return ipmi::responseUnspecifiedError();
539a3702c1fSVernon Mauery                         }
540a3702c1fSVernon Mauery                         mtm.revertFanPWM = true;
541a3702c1fSVernon Mauery                     }
542a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
543a3702c1fSVernon Mauery                     std::string fanPwmInstancePath =
5445e3bf557SAyushi Smriti                         fanPwmPath + std::to_string(instance + 1);
545a3702c1fSVernon Mauery 
5465e3bf557SAyushi Smriti                     ret =
5475e3bf557SAyushi Smriti                         mtm.setProperty(fanService, fanPwmInstancePath, fanIntf,
5485e3bf557SAyushi Smriti                                         "Value", static_cast<double>(pwmValue));
549a3702c1fSVernon Mauery                     if (ret < 0)
550a3702c1fSVernon Mauery                     {
5515e3bf557SAyushi Smriti                         return ipmi::responseUnspecifiedError();
552a3702c1fSVernon Mauery                     }
553a3702c1fSVernon Mauery                 }
554a3702c1fSVernon Mauery                 break;
555a3702c1fSVernon Mauery                 default:
556a3702c1fSVernon Mauery                 {
5575e3bf557SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
558a3702c1fSVernon Mauery                 }
559a3702c1fSVernon Mauery             }
560a3702c1fSVernon Mauery         }
561a3702c1fSVernon Mauery         break;
562a3702c1fSVernon Mauery         default:
563a3702c1fSVernon Mauery         {
5645e3bf557SAyushi Smriti             return ipmi::responseInvalidFieldRequest();
565a3702c1fSVernon Mauery         }
566a3702c1fSVernon Mauery     }
5674cc10159SRichard Marian Thomaiyar     if (retCode == ccSuccess)
5684cc10159SRichard Marian Thomaiyar     {
5694cc10159SRichard Marian Thomaiyar         resetMtmTimer(yield);
5704cc10159SRichard Marian Thomaiyar     }
5715e3bf557SAyushi Smriti     return ipmi::response(retCode);
572a3702c1fSVernon Mauery }
573a3702c1fSVernon Mauery 
574666dd01cSRichard Marian Thomaiyar ipmi::RspType<> mtmKeepAlive(boost::asio::yield_context yield, uint8_t reserved,
575666dd01cSRichard Marian Thomaiyar                              const std::array<char, 5>& intentionalSignature)
576666dd01cSRichard Marian Thomaiyar {
577666dd01cSRichard Marian Thomaiyar     // Allow MTM keep alive command only in manfacturing mode.
578666dd01cSRichard Marian Thomaiyar     if (mtm.getAccessLvl() != MtmLvl::mtmAvailable)
579666dd01cSRichard Marian Thomaiyar     {
580666dd01cSRichard Marian Thomaiyar         return ipmi::responseInvalidCommand();
581666dd01cSRichard Marian Thomaiyar     }
582666dd01cSRichard Marian Thomaiyar     constexpr std::array<char, 5> signatureOk = {'I', 'N', 'T', 'E', 'L'};
583666dd01cSRichard Marian Thomaiyar     if (intentionalSignature != signatureOk || reserved != 0)
584666dd01cSRichard Marian Thomaiyar     {
585666dd01cSRichard Marian Thomaiyar         return ipmi::responseInvalidFieldRequest();
586666dd01cSRichard Marian Thomaiyar     }
587666dd01cSRichard Marian Thomaiyar     return ipmi::response(resetMtmTimer(yield));
588666dd01cSRichard Marian Thomaiyar }
589666dd01cSRichard Marian Thomaiyar 
590*85feb130SYong Li ipmi::Cc mfgFilterMessage(ipmi::message::Request::ptr request)
591*85feb130SYong Li {
592*85feb130SYong Li     // i2c master write read command needs additional checking
593*85feb130SYong Li     if ((request->ctx->netFn == ipmi::netFnApp) &&
594*85feb130SYong Li         (request->ctx->cmd == ipmi::app::cmdMasterWriteRead))
595*85feb130SYong Li     {
596*85feb130SYong Li         if (request->payload.size() > 4)
597*85feb130SYong Li         {
598*85feb130SYong Li             // Allow write data count > 1, only if it is in MFG mode
599*85feb130SYong Li             if (mtm.getAccessLvl() != MtmLvl::mtmAvailable)
600*85feb130SYong Li             {
601*85feb130SYong Li                 return ipmi::ccInsufficientPrivilege;
602*85feb130SYong Li             }
603*85feb130SYong Li         }
604*85feb130SYong Li     }
605*85feb130SYong Li 
606*85feb130SYong Li     return ipmi::ccSuccess;
607*85feb130SYong Li }
608*85feb130SYong Li 
609a3702c1fSVernon Mauery } // namespace ipmi
610a3702c1fSVernon Mauery 
611a3702c1fSVernon Mauery void register_mtm_commands() __attribute__((constructor));
612a3702c1fSVernon Mauery void register_mtm_commands()
613a3702c1fSVernon Mauery {
61438d2b5a6SJason M. Bills     // <Get SM Signal>
61538d2b5a6SJason M. Bills     ipmi::registerHandler(
61638d2b5a6SJason M. Bills         ipmi::prioOemBase, ipmi::netFnOemOne,
617390b4354SRichard Marian Thomaiyar         static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetSmSignal),
6185e3bf557SAyushi Smriti         ipmi::Privilege::Admin, ipmi::appMTMGetSignal);
619a3702c1fSVernon Mauery 
6205e3bf557SAyushi Smriti     ipmi::registerHandler(
6215e3bf557SAyushi Smriti         ipmi::prioOemBase, ipmi::netFnOemOne,
622390b4354SRichard Marian Thomaiyar         static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetSmSignal),
6235e3bf557SAyushi Smriti         ipmi::Privilege::Admin, ipmi::appMTMSetSignal);
624a3702c1fSVernon Mauery 
625666dd01cSRichard Marian Thomaiyar     ipmi::registerHandler(
626666dd01cSRichard Marian Thomaiyar         ipmi::prioOemBase, ipmi::netFnOemOne,
627666dd01cSRichard Marian Thomaiyar         static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdMtmKeepAlive),
628666dd01cSRichard Marian Thomaiyar         ipmi::Privilege::Admin, ipmi::mtmKeepAlive);
629666dd01cSRichard Marian Thomaiyar 
630*85feb130SYong Li     ipmi::registerFilter(ipmi::netFnOemOne,
631*85feb130SYong Li                          [](ipmi::message::Request::ptr request) {
632*85feb130SYong Li                              return ipmi::mfgFilterMessage(request);
633*85feb130SYong Li                          });
634*85feb130SYong Li 
635a3702c1fSVernon Mauery     return;
636a3702c1fSVernon Mauery }
637