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 
17d872a4a4SAyushi Smriti #include <linux/input.h>
18d872a4a4SAyushi Smriti 
19147daec5SRichard Marian Thomaiyar #include <boost/container/flat_map.hpp>
20a3702c1fSVernon Mauery #include <ipmid/api.hpp>
21a3702c1fSVernon Mauery #include <manufacturingcommands.hpp>
22a3702c1fSVernon Mauery #include <oemcommands.hpp>
23a3702c1fSVernon Mauery 
24*fcd2d3a9SJames Feist #include <filesystem>
25*fcd2d3a9SJames Feist #include <fstream>
26*fcd2d3a9SJames Feist 
27a3702c1fSVernon Mauery namespace ipmi
28a3702c1fSVernon Mauery {
29a3702c1fSVernon Mauery 
30a3702c1fSVernon Mauery Manufacturing mtm;
31a3702c1fSVernon Mauery 
32a3702c1fSVernon Mauery static auto revertTimeOut =
33a3702c1fSVernon Mauery     std::chrono::duration_cast<std::chrono::microseconds>(
34a3702c1fSVernon Mauery         std::chrono::seconds(60)); // 1 minute timeout
35a3702c1fSVernon Mauery 
36f267a67dSYong Li static constexpr uint8_t slotAddressTypeBus = 0;
37f267a67dSYong Li static constexpr uint8_t slotAddressTypeUniqueid = 1;
38f267a67dSYong Li static constexpr uint8_t slotI2CMaxReadSize = 35;
39f267a67dSYong Li 
40a3702c1fSVernon Mauery static constexpr const char* callbackMgrService =
41a3702c1fSVernon Mauery     "xyz.openbmc_project.CallbackManager";
42a3702c1fSVernon Mauery static constexpr const char* callbackMgrIntf =
43a3702c1fSVernon Mauery     "xyz.openbmc_project.CallbackManager";
44a3702c1fSVernon Mauery static constexpr const char* callbackMgrObjPath =
45a3702c1fSVernon Mauery     "/xyz/openbmc_project/CallbackManager";
46a3702c1fSVernon Mauery static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate";
47a3702c1fSVernon Mauery 
48a3702c1fSVernon Mauery const static constexpr char* systemDService = "org.freedesktop.systemd1";
49a3702c1fSVernon Mauery const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1";
50a3702c1fSVernon Mauery const static constexpr char* systemDMgrIntf =
51a3702c1fSVernon Mauery     "org.freedesktop.systemd1.Manager";
52a3702c1fSVernon Mauery const static constexpr char* pidControlService = "phosphor-pid-control.service";
53a3702c1fSVernon Mauery 
54357ddc74SRichard Marian Thomaiyar static inline Cc resetMtmTimer(ipmi::Context::ptr ctx)
55666dd01cSRichard Marian Thomaiyar {
56666dd01cSRichard Marian Thomaiyar     boost::system::error_code ec;
57357ddc74SRichard Marian Thomaiyar     ctx->bus->yield_method_call<>(ctx->yield, ec, specialModeService,
58666dd01cSRichard Marian Thomaiyar                                   specialModeObjPath, specialModeIntf,
59666dd01cSRichard Marian Thomaiyar                                   "ResetTimer");
60666dd01cSRichard Marian Thomaiyar     if (ec)
61666dd01cSRichard Marian Thomaiyar     {
62666dd01cSRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
63666dd01cSRichard Marian Thomaiyar             "Failed to reset the manufacturing mode timer");
64666dd01cSRichard Marian Thomaiyar         return ccUnspecifiedError;
65666dd01cSRichard Marian Thomaiyar     }
66666dd01cSRichard Marian Thomaiyar     return ccSuccess;
67666dd01cSRichard Marian Thomaiyar }
68666dd01cSRichard Marian Thomaiyar 
6938d2b5a6SJason M. Bills int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path)
70a3702c1fSVernon Mauery {
7138d2b5a6SJason M. Bills     switch (signal)
7238d2b5a6SJason M. Bills     {
7338d2b5a6SJason M. Bills         case SmSignalGet::smPowerButton:
7438d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/power";
7538d2b5a6SJason M. Bills             break;
7638d2b5a6SJason M. Bills         case SmSignalGet::smResetButton:
7738d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/reset";
7838d2b5a6SJason M. Bills             break;
7938d2b5a6SJason M. Bills         case SmSignalGet::smNMIButton:
8038d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/nmi";
8138d2b5a6SJason M. Bills             break;
828e5e2b04SRichard Marian Thomaiyar         case SmSignalGet::smIdentifyButton:
838e5e2b04SRichard Marian Thomaiyar             path = "/xyz/openbmc_project/chassis/buttons/id";
848e5e2b04SRichard Marian Thomaiyar             break;
8538d2b5a6SJason M. Bills         default:
8638d2b5a6SJason M. Bills             return -1;
8738d2b5a6SJason M. Bills             break;
8838d2b5a6SJason M. Bills     }
8938d2b5a6SJason M. Bills     return 0;
90a3702c1fSVernon Mauery }
91a3702c1fSVernon Mauery 
9237890392SPatrick Venture ipmi_ret_t ledStoreAndSet(SmSignalSet signal, const std::string& setState)
93a3702c1fSVernon Mauery {
94a3702c1fSVernon Mauery     LedProperty* ledProp = mtm.findLedProperty(signal);
95a3702c1fSVernon Mauery     if (ledProp == nullptr)
96a3702c1fSVernon Mauery     {
97a3702c1fSVernon Mauery         return IPMI_CC_INVALID_FIELD_REQUEST;
98a3702c1fSVernon Mauery     }
99a3702c1fSVernon Mauery 
100a3702c1fSVernon Mauery     std::string ledName = ledProp->getName();
101a3702c1fSVernon Mauery     std::string ledService = ledServicePrefix + ledName;
102a3702c1fSVernon Mauery     std::string ledPath = ledPathPrefix + ledName;
103a3702c1fSVernon Mauery     ipmi::Value presentState;
104a3702c1fSVernon Mauery 
105a3702c1fSVernon Mauery     if (false == ledProp->getLock())
106a3702c1fSVernon Mauery     {
107a3702c1fSVernon Mauery         if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf,
108a3702c1fSVernon Mauery                             "State", &presentState) != 0)
109a3702c1fSVernon Mauery         {
110a3702c1fSVernon Mauery             return IPMI_CC_UNSPECIFIED_ERROR;
111a3702c1fSVernon Mauery         }
112a3702c1fSVernon Mauery         ledProp->setPrevState(std::get<std::string>(presentState));
113a3702c1fSVernon Mauery         ledProp->setLock(true);
114a3702c1fSVernon Mauery         if (signal == SmSignalSet::smPowerFaultLed ||
115a3702c1fSVernon Mauery             signal == SmSignalSet::smSystemReadyLed)
116a3702c1fSVernon Mauery         {
117a3702c1fSVernon Mauery             mtm.revertLedCallback = true;
118a3702c1fSVernon Mauery         }
119a3702c1fSVernon Mauery     }
12038d2b5a6SJason M. Bills     if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
121a3702c1fSVernon Mauery                         ledStateStr + setState) != 0)
122a3702c1fSVernon Mauery     {
123a3702c1fSVernon Mauery         return IPMI_CC_UNSPECIFIED_ERROR;
124a3702c1fSVernon Mauery     }
125a3702c1fSVernon Mauery     return IPMI_CC_OK;
126a3702c1fSVernon Mauery }
127a3702c1fSVernon Mauery 
128a3702c1fSVernon Mauery ipmi_ret_t ledRevert(SmSignalSet signal)
129a3702c1fSVernon Mauery {
130a3702c1fSVernon Mauery     LedProperty* ledProp = mtm.findLedProperty(signal);
131a3702c1fSVernon Mauery     if (ledProp == nullptr)
132a3702c1fSVernon Mauery     {
133a3702c1fSVernon Mauery         return IPMI_CC_INVALID_FIELD_REQUEST;
134a3702c1fSVernon Mauery     }
135a3702c1fSVernon Mauery     if (true == ledProp->getLock())
136a3702c1fSVernon Mauery     {
137a3702c1fSVernon Mauery         ledProp->setLock(false);
138a3702c1fSVernon Mauery         if (signal == SmSignalSet::smPowerFaultLed ||
139a3702c1fSVernon Mauery             signal == SmSignalSet::smSystemReadyLed)
140a3702c1fSVernon Mauery         {
141a3702c1fSVernon Mauery             try
142a3702c1fSVernon Mauery             {
143a3702c1fSVernon Mauery                 ipmi::method_no_args::callDbusMethod(
144a3702c1fSVernon Mauery                     *getSdBus(), callbackMgrService, callbackMgrObjPath,
145a3702c1fSVernon Mauery                     callbackMgrIntf, retriggerLedUpdate);
146a3702c1fSVernon Mauery             }
147a3702c1fSVernon Mauery             catch (sdbusplus::exception_t& e)
148a3702c1fSVernon Mauery             {
149a3702c1fSVernon Mauery                 return IPMI_CC_UNSPECIFIED_ERROR;
150a3702c1fSVernon Mauery             }
151a3702c1fSVernon Mauery             mtm.revertLedCallback = false;
152a3702c1fSVernon Mauery         }
153a3702c1fSVernon Mauery         else
154a3702c1fSVernon Mauery         {
155a3702c1fSVernon Mauery             std::string ledName = ledProp->getName();
156a3702c1fSVernon Mauery             std::string ledService = ledServicePrefix + ledName;
157a3702c1fSVernon Mauery             std::string ledPath = ledPathPrefix + ledName;
15838d2b5a6SJason M. Bills             if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
15938d2b5a6SJason M. Bills                                 ledProp->getPrevState()) != 0)
160a3702c1fSVernon Mauery             {
161a3702c1fSVernon Mauery                 return IPMI_CC_UNSPECIFIED_ERROR;
162a3702c1fSVernon Mauery             }
163a3702c1fSVernon Mauery         }
164a3702c1fSVernon Mauery     }
165a3702c1fSVernon Mauery     return IPMI_CC_OK;
166a3702c1fSVernon Mauery }
167a3702c1fSVernon Mauery 
168a3702c1fSVernon Mauery void Manufacturing::initData()
169a3702c1fSVernon Mauery {
170a3702c1fSVernon Mauery     ledPropertyList.push_back(
171a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smPowerFaultLed, "status_amber"));
172a3702c1fSVernon Mauery     ledPropertyList.push_back(
173a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smSystemReadyLed, "status_green"));
174a3702c1fSVernon Mauery     ledPropertyList.push_back(
175a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smIdentifyLed, "identify"));
176a3702c1fSVernon Mauery }
177a3702c1fSVernon Mauery 
178a3702c1fSVernon Mauery void Manufacturing::revertTimerHandler()
179a3702c1fSVernon Mauery {
180ae13ac62SRichard Marian Thomaiyar 
181ae13ac62SRichard Marian Thomaiyar #ifdef BMC_VALIDATION_UNSECURE_FEATURE
182ae13ac62SRichard Marian Thomaiyar     if (mtm.getMfgMode() == SpecialMode::valUnsecure)
183ae13ac62SRichard Marian Thomaiyar     {
184ae13ac62SRichard Marian Thomaiyar         // Don't revert the behaviour for validation unsecure mode.
185ae13ac62SRichard Marian Thomaiyar         return;
186ae13ac62SRichard Marian Thomaiyar     }
187ae13ac62SRichard Marian Thomaiyar #endif
188a3702c1fSVernon Mauery     if (revertFanPWM)
189a3702c1fSVernon Mauery     {
190a3702c1fSVernon Mauery         revertFanPWM = false;
191a3702c1fSVernon Mauery         disablePidControlService(false);
192a3702c1fSVernon Mauery     }
193a3702c1fSVernon Mauery 
194d872a4a4SAyushi Smriti     if (mtmTestBeepFd != -1)
195d872a4a4SAyushi Smriti     {
196d872a4a4SAyushi Smriti         ::close(mtmTestBeepFd);
197d872a4a4SAyushi Smriti         mtmTestBeepFd = -1;
198d872a4a4SAyushi Smriti     }
199d872a4a4SAyushi Smriti 
200a3702c1fSVernon Mauery     for (const auto& ledProperty : ledPropertyList)
201a3702c1fSVernon Mauery     {
202a3702c1fSVernon Mauery         const std::string& ledName = ledProperty.getName();
203a3702c1fSVernon Mauery         ledRevert(ledProperty.getSignal());
204a3702c1fSVernon Mauery     }
205a3702c1fSVernon Mauery }
206a3702c1fSVernon Mauery 
207a3702c1fSVernon Mauery Manufacturing::Manufacturing() :
208a3702c1fSVernon Mauery     revertTimer([&](void) { revertTimerHandler(); })
209a3702c1fSVernon Mauery {
210a3702c1fSVernon Mauery     initData();
211a3702c1fSVernon Mauery }
212a3702c1fSVernon Mauery 
21338d2b5a6SJason M. Bills int8_t Manufacturing::getProperty(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* reply)
218a3702c1fSVernon Mauery {
219a3702c1fSVernon Mauery     try
220a3702c1fSVernon Mauery     {
22138d2b5a6SJason M. Bills         *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface,
22238d2b5a6SJason M. Bills                                        propertyName);
223a3702c1fSVernon Mauery     }
224a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
225a3702c1fSVernon Mauery     {
226a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
227a3702c1fSVernon Mauery             "ERROR: getProperty");
228a3702c1fSVernon Mauery         return -1;
229a3702c1fSVernon Mauery     }
230a3702c1fSVernon Mauery 
231a3702c1fSVernon Mauery     return 0;
232a3702c1fSVernon Mauery }
233a3702c1fSVernon Mauery 
23438d2b5a6SJason M. Bills int8_t Manufacturing::setProperty(const std::string& service,
23538d2b5a6SJason M. Bills                                   const std::string& path,
23638d2b5a6SJason M. Bills                                   const std::string& interface,
23738d2b5a6SJason M. Bills                                   const std::string& propertyName,
23838d2b5a6SJason M. Bills                                   ipmi::Value value)
239a3702c1fSVernon Mauery {
240a3702c1fSVernon Mauery     try
241a3702c1fSVernon Mauery     {
24238d2b5a6SJason M. Bills         ipmi::setDbusProperty(*getSdBus(), service, path, interface,
243a3702c1fSVernon Mauery                               propertyName, value);
244a3702c1fSVernon Mauery     }
245a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
246a3702c1fSVernon Mauery     {
247a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
248a3702c1fSVernon Mauery             "ERROR: setProperty");
249a3702c1fSVernon Mauery         return -1;
250a3702c1fSVernon Mauery     }
251a3702c1fSVernon Mauery 
252a3702c1fSVernon Mauery     return 0;
253a3702c1fSVernon Mauery }
254a3702c1fSVernon Mauery 
255a3702c1fSVernon Mauery int8_t Manufacturing::disablePidControlService(const bool disable)
256a3702c1fSVernon Mauery {
257a3702c1fSVernon Mauery     try
258a3702c1fSVernon Mauery     {
259a3702c1fSVernon Mauery         auto dbus = getSdBus();
260a3702c1fSVernon Mauery         auto method = dbus->new_method_call(systemDService, systemDObjPath,
261a3702c1fSVernon Mauery                                             systemDMgrIntf,
262a3702c1fSVernon Mauery                                             disable ? "StopUnit" : "StartUnit");
263a3702c1fSVernon Mauery         method.append(pidControlService, "replace");
264a3702c1fSVernon Mauery         auto reply = dbus->call(method);
265a3702c1fSVernon Mauery     }
266a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
267a3702c1fSVernon Mauery     {
268a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
269a3702c1fSVernon Mauery             "ERROR: phosphor-pid-control service start or stop failed");
270a3702c1fSVernon Mauery         return -1;
271a3702c1fSVernon Mauery     }
272a3702c1fSVernon Mauery     return 0;
273a3702c1fSVernon Mauery }
274a3702c1fSVernon Mauery 
27538d2b5a6SJason M. Bills ipmi::RspType<uint8_t,                // Signal value
27638d2b5a6SJason M. Bills               std::optional<uint16_t> // Fan tach value
27738d2b5a6SJason M. Bills               >
278357ddc74SRichard Marian Thomaiyar     appMTMGetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte,
279147daec5SRichard Marian Thomaiyar                     uint8_t instance, uint8_t actionByte)
280a3702c1fSVernon Mauery {
281e0511e5fSAyushi Smriti     // mfg filter logic is used to allow MTM get signal command only in
282e0511e5fSAyushi Smriti     // manfacturing mode.
28338d2b5a6SJason M. Bills 
28438d2b5a6SJason M. Bills     SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte);
28538d2b5a6SJason M. Bills     SmActionGet action = static_cast<SmActionGet>(actionByte);
28638d2b5a6SJason M. Bills 
28738d2b5a6SJason M. Bills     switch (signalType)
28838d2b5a6SJason M. Bills     {
28998705b39Sanil kumar appana         case SmSignalGet::smChassisIntrusion:
29098705b39Sanil kumar appana         {
29198705b39Sanil kumar appana             ipmi::Value reply;
29298705b39Sanil kumar appana             if (mtm.getProperty(intrusionService, intrusionPath, intrusionIntf,
29398705b39Sanil kumar appana                                 "Status", &reply) < 0)
29498705b39Sanil kumar appana             {
29598705b39Sanil kumar appana                 return ipmi::responseInvalidFieldRequest();
29698705b39Sanil kumar appana             }
29798705b39Sanil kumar appana             std::string* intrusionStatus = std::get_if<std::string>(&reply);
29898705b39Sanil kumar appana             if (!intrusionStatus)
29998705b39Sanil kumar appana             {
30098705b39Sanil kumar appana                 return ipmi::responseUnspecifiedError();
30198705b39Sanil kumar appana             }
30298705b39Sanil kumar appana 
30398705b39Sanil kumar appana             uint8_t status = 0;
30498705b39Sanil kumar appana             if (!intrusionStatus->compare("Normal"))
30598705b39Sanil kumar appana             {
30698705b39Sanil kumar appana                 status = static_cast<uint8_t>(IntrusionStatus::normal);
30798705b39Sanil kumar appana             }
30898705b39Sanil kumar appana             else if (!intrusionStatus->compare("HardwareIntrusion"))
30998705b39Sanil kumar appana             {
31098705b39Sanil kumar appana                 status =
31198705b39Sanil kumar appana                     static_cast<uint8_t>(IntrusionStatus::hardwareIntrusion);
31298705b39Sanil kumar appana             }
31398705b39Sanil kumar appana             else if (!intrusionStatus->compare("TamperingDetected"))
31498705b39Sanil kumar appana             {
31598705b39Sanil kumar appana                 status =
31698705b39Sanil kumar appana                     static_cast<uint8_t>(IntrusionStatus::tamperingDetected);
31798705b39Sanil kumar appana             }
31898705b39Sanil kumar appana             else
31998705b39Sanil kumar appana             {
32098705b39Sanil kumar appana                 return ipmi::responseUnspecifiedError();
32198705b39Sanil kumar appana             }
32298705b39Sanil kumar appana             return ipmi::responseSuccess(status, std::nullopt);
32398705b39Sanil kumar appana         }
32438d2b5a6SJason M. Bills         case SmSignalGet::smFanPwmGet:
32538d2b5a6SJason M. Bills         {
326a3702c1fSVernon Mauery             ipmi::Value reply;
327147daec5SRichard Marian Thomaiyar             std::string fullPath = fanPwmPath + std::to_string(instance + 1);
32838d2b5a6SJason M. Bills             if (mtm.getProperty(fanService, fullPath, fanIntf, "Value",
32938d2b5a6SJason M. Bills                                 &reply) < 0)
33038d2b5a6SJason M. Bills             {
33138d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
33238d2b5a6SJason M. Bills             }
33338d2b5a6SJason M. Bills             double* doubleVal = std::get_if<double>(&reply);
33438d2b5a6SJason M. Bills             if (doubleVal == nullptr)
33538d2b5a6SJason M. Bills             {
33638d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
33738d2b5a6SJason M. Bills             }
33838d2b5a6SJason M. Bills             uint8_t sensorVal = std::round(*doubleVal);
339357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
34038d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, std::nullopt);
34138d2b5a6SJason M. Bills         }
34238d2b5a6SJason M. Bills         break;
34338d2b5a6SJason M. Bills         case SmSignalGet::smFanTachometerGet:
34438d2b5a6SJason M. Bills         {
345147daec5SRichard Marian Thomaiyar             boost::system::error_code ec;
346147daec5SRichard Marian Thomaiyar             using objFlatMap = boost::container::flat_map<
347147daec5SRichard Marian Thomaiyar                 std::string, boost::container::flat_map<
348147daec5SRichard Marian Thomaiyar                                  std::string, std::vector<std::string>>>;
349147daec5SRichard Marian Thomaiyar 
350357ddc74SRichard Marian Thomaiyar             auto flatMap = ctx->bus->yield_method_call<objFlatMap>(
351357ddc74SRichard Marian Thomaiyar                 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
352147daec5SRichard Marian Thomaiyar                 "/xyz/openbmc_project/object_mapper",
353147daec5SRichard Marian Thomaiyar                 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
354147daec5SRichard Marian Thomaiyar                 fanTachBasePath, 0, std::array<const char*, 1>{fanIntf});
355147daec5SRichard Marian Thomaiyar             if (ec)
356147daec5SRichard Marian Thomaiyar             {
357147daec5SRichard Marian Thomaiyar                 phosphor::logging::log<phosphor::logging::level::ERR>(
358147daec5SRichard Marian Thomaiyar                     "Failed to query fan tach sub tree objects");
359147daec5SRichard Marian Thomaiyar                 return ipmi::responseUnspecifiedError();
360147daec5SRichard Marian Thomaiyar             }
361147daec5SRichard Marian Thomaiyar             if (instance >= flatMap.size())
36238d2b5a6SJason M. Bills             {
36338d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
36438d2b5a6SJason M. Bills             }
365147daec5SRichard Marian Thomaiyar             auto itr = flatMap.nth(instance);
36638d2b5a6SJason M. Bills             ipmi::Value reply;
367147daec5SRichard Marian Thomaiyar             if (mtm.getProperty(fanService, itr->first, fanIntf, "Value",
36838d2b5a6SJason M. Bills                                 &reply) < 0)
36938d2b5a6SJason M. Bills             {
37038d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
37138d2b5a6SJason M. Bills             }
37238d2b5a6SJason M. Bills 
37338d2b5a6SJason M. Bills             double* doubleVal = std::get_if<double>(&reply);
37438d2b5a6SJason M. Bills             if (doubleVal == nullptr)
37538d2b5a6SJason M. Bills             {
37638d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
37738d2b5a6SJason M. Bills             }
37838d2b5a6SJason M. Bills             uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT;
37938d2b5a6SJason M. Bills             std::optional<uint16_t> fanTach = std::round(*doubleVal);
38038d2b5a6SJason M. Bills 
381357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
38238d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, fanTach);
38338d2b5a6SJason M. Bills         }
38438d2b5a6SJason M. Bills         break;
3858e5e2b04SRichard Marian Thomaiyar         case SmSignalGet::smIdentifyButton:
3868e5e2b04SRichard Marian Thomaiyar         {
3878e5e2b04SRichard Marian Thomaiyar             if (action == SmActionGet::revert || action == SmActionGet::ignore)
3888e5e2b04SRichard Marian Thomaiyar             {
3898e5e2b04SRichard Marian Thomaiyar                 // ButtonMasked property is not supported for ID button as it is
3908e5e2b04SRichard Marian Thomaiyar                 // unnecessary. Hence if requested for revert / ignore, override
3918e5e2b04SRichard Marian Thomaiyar                 // it to sample action to make tools happy.
3928e5e2b04SRichard Marian Thomaiyar                 action = SmActionGet::sample;
3938e5e2b04SRichard Marian Thomaiyar             }
3948e5e2b04SRichard Marian Thomaiyar             // fall-through
3958e5e2b04SRichard Marian Thomaiyar         }
39638d2b5a6SJason M. Bills         case SmSignalGet::smResetButton:
39738d2b5a6SJason M. Bills         case SmSignalGet::smPowerButton:
39838d2b5a6SJason M. Bills         case SmSignalGet::smNMIButton:
39938d2b5a6SJason M. Bills         {
40038d2b5a6SJason M. Bills             std::string path;
40138d2b5a6SJason M. Bills             if (getGpioPathForSmSignal(signalType, path) < 0)
40238d2b5a6SJason M. Bills             {
40338d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
40438d2b5a6SJason M. Bills             }
405a3702c1fSVernon Mauery 
406a3702c1fSVernon Mauery             switch (action)
407a3702c1fSVernon Mauery             {
408a3702c1fSVernon Mauery                 case SmActionGet::sample:
409a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
410a3702c1fSVernon Mauery                         "case SmActionGet::sample");
411a3702c1fSVernon Mauery                     break;
412a3702c1fSVernon Mauery                 case SmActionGet::ignore:
413a3702c1fSVernon Mauery                 {
414a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
415a3702c1fSVernon Mauery                         "case SmActionGet::ignore");
41638d2b5a6SJason M. Bills                     if (mtm.setProperty(buttonService, path, buttonIntf,
41738d2b5a6SJason M. Bills                                         "ButtonMasked", true) < 0)
418a3702c1fSVernon Mauery                     {
41938d2b5a6SJason M. Bills                         return ipmi::responseUnspecifiedError();
420a3702c1fSVernon Mauery                     }
421a3702c1fSVernon Mauery                 }
422a3702c1fSVernon Mauery                 break;
423a3702c1fSVernon Mauery                 case SmActionGet::revert:
424a3702c1fSVernon Mauery                 {
425a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
426a3702c1fSVernon Mauery                         "case SmActionGet::revert");
42738d2b5a6SJason M. Bills                     if (mtm.setProperty(buttonService, path, buttonIntf,
42838d2b5a6SJason M. Bills                                         "ButtonMasked", false) < 0)
429a3702c1fSVernon Mauery                     {
43038d2b5a6SJason M. Bills                         return ipmi::responseUnspecifiedError();
431a3702c1fSVernon Mauery                     }
432a3702c1fSVernon Mauery                 }
433a3702c1fSVernon Mauery                 break;
434a3702c1fSVernon Mauery 
435a3702c1fSVernon Mauery                 default:
43638d2b5a6SJason M. Bills                     return ipmi::responseInvalidFieldRequest();
437a3702c1fSVernon Mauery                     break;
438a3702c1fSVernon Mauery             }
439a3702c1fSVernon Mauery 
440a3702c1fSVernon Mauery             ipmi::Value reply;
44138d2b5a6SJason M. Bills             if (mtm.getProperty(buttonService, path, buttonIntf,
44238d2b5a6SJason M. Bills                                 "ButtonPressed", &reply) < 0)
443a3702c1fSVernon Mauery             {
44438d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
445a3702c1fSVernon Mauery             }
44638d2b5a6SJason M. Bills             bool* valPtr = std::get_if<bool>(&reply);
44738d2b5a6SJason M. Bills             if (valPtr == nullptr)
448a3702c1fSVernon Mauery             {
44938d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
450a3702c1fSVernon Mauery             }
451357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
45238d2b5a6SJason M. Bills             uint8_t sensorVal = *valPtr;
45338d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, std::nullopt);
454a3702c1fSVernon Mauery         }
455a3702c1fSVernon Mauery         break;
4561b74a210SRichard Marian Thomaiyar         case SmSignalGet::smNcsiDiag:
4571b74a210SRichard Marian Thomaiyar         {
4581b74a210SRichard Marian Thomaiyar             constexpr const char* netBasePath = "/sys/class/net/eth";
4591b74a210SRichard Marian Thomaiyar             constexpr const char* carrierSuffix = "/carrier";
4601b74a210SRichard Marian Thomaiyar             std::ifstream netIfs(netBasePath + std::to_string(instance) +
4611b74a210SRichard Marian Thomaiyar                                  carrierSuffix);
4621b74a210SRichard Marian Thomaiyar             if (!netIfs.good())
4631b74a210SRichard Marian Thomaiyar             {
4641b74a210SRichard Marian Thomaiyar                 return ipmi::responseInvalidFieldRequest();
4651b74a210SRichard Marian Thomaiyar             }
4661b74a210SRichard Marian Thomaiyar             std::string carrier;
4671b74a210SRichard Marian Thomaiyar             netIfs >> carrier;
468357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
4691b74a210SRichard Marian Thomaiyar             return ipmi::responseSuccess(
4701b74a210SRichard Marian Thomaiyar                 static_cast<uint8_t>(std::stoi(carrier)), std::nullopt);
4711b74a210SRichard Marian Thomaiyar         }
4721b74a210SRichard Marian Thomaiyar         break;
473a3702c1fSVernon Mauery         default:
47438d2b5a6SJason M. Bills             return ipmi::responseInvalidFieldRequest();
475a3702c1fSVernon Mauery             break;
476a3702c1fSVernon Mauery     }
477a3702c1fSVernon Mauery }
478a3702c1fSVernon Mauery 
479357ddc74SRichard Marian Thomaiyar ipmi::RspType<> appMTMSetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte,
480357ddc74SRichard Marian Thomaiyar                                 uint8_t instance, uint8_t actionByte,
4815e3bf557SAyushi Smriti                                 std::optional<uint8_t> pwmSpeed)
482a3702c1fSVernon Mauery {
483e0511e5fSAyushi Smriti     // mfg filter logic is used to allow MTM set signal command only in
484e0511e5fSAyushi Smriti     // manfacturing mode.
4855e3bf557SAyushi Smriti 
4865e3bf557SAyushi Smriti     SmSignalSet signalType = static_cast<SmSignalSet>(signalTypeByte);
4875e3bf557SAyushi Smriti     SmActionSet action = static_cast<SmActionSet>(actionByte);
4885e3bf557SAyushi Smriti     Cc retCode = ccSuccess;
48913b0039dSJames Feist     int8_t ret = 0;
4905e3bf557SAyushi Smriti 
4915e3bf557SAyushi Smriti     switch (signalType)
492a3702c1fSVernon Mauery     {
493a3702c1fSVernon Mauery         case SmSignalSet::smPowerFaultLed:
494a3702c1fSVernon Mauery         case SmSignalSet::smSystemReadyLed:
495a3702c1fSVernon Mauery         case SmSignalSet::smIdentifyLed:
4965e3bf557SAyushi Smriti             switch (action)
497a3702c1fSVernon Mauery             {
498a3702c1fSVernon Mauery                 case SmActionSet::forceDeasserted:
499a3702c1fSVernon Mauery                 {
500a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
501a3702c1fSVernon Mauery                         "case SmActionSet::forceDeasserted");
502a3702c1fSVernon Mauery 
5035e3bf557SAyushi Smriti                     retCode = ledStoreAndSet(signalType, std::string("Off"));
5045e3bf557SAyushi Smriti                     if (retCode != ccSuccess)
505a3702c1fSVernon Mauery                     {
5065e3bf557SAyushi Smriti                         return ipmi::response(retCode);
507a3702c1fSVernon Mauery                     }
508a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
509a3702c1fSVernon Mauery                 }
510a3702c1fSVernon Mauery                 break;
511a3702c1fSVernon Mauery                 case SmActionSet::forceAsserted:
512a3702c1fSVernon Mauery                 {
513a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
514a3702c1fSVernon Mauery                         "case SmActionSet::forceAsserted");
515a3702c1fSVernon Mauery 
5165e3bf557SAyushi Smriti                     retCode = ledStoreAndSet(signalType, std::string("On"));
5175e3bf557SAyushi Smriti                     if (retCode != ccSuccess)
518a3702c1fSVernon Mauery                     {
5195e3bf557SAyushi Smriti                         return ipmi::response(retCode);
520a3702c1fSVernon Mauery                     }
521a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
5225e3bf557SAyushi Smriti                     if (SmSignalSet::smPowerFaultLed == signalType)
523a3702c1fSVernon Mauery                     {
524a3702c1fSVernon Mauery                         // Deassert "system ready"
5255e3bf557SAyushi Smriti                         retCode = ledStoreAndSet(SmSignalSet::smSystemReadyLed,
526a3702c1fSVernon Mauery                                                  std::string("Off"));
527a3702c1fSVernon Mauery                     }
5285e3bf557SAyushi Smriti                     else if (SmSignalSet::smSystemReadyLed == signalType)
529a3702c1fSVernon Mauery                     {
530a3702c1fSVernon Mauery                         // Deassert "fault led"
5315e3bf557SAyushi Smriti                         retCode = ledStoreAndSet(SmSignalSet::smPowerFaultLed,
532a3702c1fSVernon Mauery                                                  std::string("Off"));
533a3702c1fSVernon Mauery                     }
534a3702c1fSVernon Mauery                 }
535a3702c1fSVernon Mauery                 break;
536a3702c1fSVernon Mauery                 case SmActionSet::revert:
537a3702c1fSVernon Mauery                 {
538a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
539a3702c1fSVernon Mauery                         "case SmActionSet::revert");
5405e3bf557SAyushi Smriti                     retCode = ledRevert(signalType);
541a3702c1fSVernon Mauery                 }
542a3702c1fSVernon Mauery                 break;
543a3702c1fSVernon Mauery                 default:
544a3702c1fSVernon Mauery                 {
5455e3bf557SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
546a3702c1fSVernon Mauery                 }
547a3702c1fSVernon Mauery             }
548a3702c1fSVernon Mauery             break;
549a3702c1fSVernon Mauery         case SmSignalSet::smFanPowerSpeed:
550a3702c1fSVernon Mauery         {
5515e3bf557SAyushi Smriti             if ((action == SmActionSet::forceAsserted) && (!pwmSpeed))
552a3702c1fSVernon Mauery             {
5535e3bf557SAyushi Smriti                 return ipmi::responseReqDataLenInvalid();
554a3702c1fSVernon Mauery             }
5555e3bf557SAyushi Smriti 
5565e3bf557SAyushi Smriti             if ((action == SmActionSet::forceAsserted) && (*pwmSpeed > 100))
5575e3bf557SAyushi Smriti             {
5585e3bf557SAyushi Smriti                 return ipmi::responseInvalidFieldRequest();
5595e3bf557SAyushi Smriti             }
5605e3bf557SAyushi Smriti 
561a3702c1fSVernon Mauery             uint8_t pwmValue = 0;
5625e3bf557SAyushi Smriti             switch (action)
563a3702c1fSVernon Mauery             {
564a3702c1fSVernon Mauery                 case SmActionSet::revert:
565a3702c1fSVernon Mauery                 {
566a3702c1fSVernon Mauery                     if (mtm.revertFanPWM)
567a3702c1fSVernon Mauery                     {
568a3702c1fSVernon Mauery                         ret = mtm.disablePidControlService(false);
569a3702c1fSVernon Mauery                         if (ret < 0)
570a3702c1fSVernon Mauery                         {
5715e3bf557SAyushi Smriti                             return ipmi::responseUnspecifiedError();
572a3702c1fSVernon Mauery                         }
573a3702c1fSVernon Mauery                         mtm.revertFanPWM = false;
574a3702c1fSVernon Mauery                     }
575a3702c1fSVernon Mauery                 }
576a3702c1fSVernon Mauery                 break;
577a3702c1fSVernon Mauery                 case SmActionSet::forceAsserted:
578a3702c1fSVernon Mauery                 {
5795e3bf557SAyushi Smriti                     pwmValue = *pwmSpeed;
580a3702c1fSVernon Mauery                 } // fall-through
581a3702c1fSVernon Mauery                 case SmActionSet::forceDeasserted:
582a3702c1fSVernon Mauery                 {
583a3702c1fSVernon Mauery                     if (!mtm.revertFanPWM)
584a3702c1fSVernon Mauery                     {
585a3702c1fSVernon Mauery                         ret = mtm.disablePidControlService(true);
586a3702c1fSVernon Mauery                         if (ret < 0)
587a3702c1fSVernon Mauery                         {
5885e3bf557SAyushi Smriti                             return ipmi::responseUnspecifiedError();
589a3702c1fSVernon Mauery                         }
590a3702c1fSVernon Mauery                         mtm.revertFanPWM = true;
591a3702c1fSVernon Mauery                     }
592a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
593a3702c1fSVernon Mauery                     std::string fanPwmInstancePath =
5945e3bf557SAyushi Smriti                         fanPwmPath + std::to_string(instance + 1);
595a3702c1fSVernon Mauery 
5965e3bf557SAyushi Smriti                     ret =
5975e3bf557SAyushi Smriti                         mtm.setProperty(fanService, fanPwmInstancePath, fanIntf,
5985e3bf557SAyushi Smriti                                         "Value", static_cast<double>(pwmValue));
599a3702c1fSVernon Mauery                     if (ret < 0)
600a3702c1fSVernon Mauery                     {
6015e3bf557SAyushi Smriti                         return ipmi::responseUnspecifiedError();
602a3702c1fSVernon Mauery                     }
603a3702c1fSVernon Mauery                 }
604a3702c1fSVernon Mauery                 break;
605a3702c1fSVernon Mauery                 default:
606a3702c1fSVernon Mauery                 {
6075e3bf557SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
608a3702c1fSVernon Mauery                 }
609a3702c1fSVernon Mauery             }
610a3702c1fSVernon Mauery         }
611a3702c1fSVernon Mauery         break;
612d872a4a4SAyushi Smriti         case SmSignalSet::smSpeaker:
613d872a4a4SAyushi Smriti         {
614d872a4a4SAyushi Smriti             phosphor::logging::log<phosphor::logging::level::INFO>(
615d872a4a4SAyushi Smriti                 "Performing Speaker SmActionSet",
616d872a4a4SAyushi Smriti                 phosphor::logging::entry("ACTION=%d",
617d872a4a4SAyushi Smriti                                          static_cast<uint8_t>(action)));
618d872a4a4SAyushi Smriti             switch (action)
619d872a4a4SAyushi Smriti             {
620d872a4a4SAyushi Smriti                 case SmActionSet::forceAsserted:
621d872a4a4SAyushi Smriti                 {
622d872a4a4SAyushi Smriti                     char beepDevName[] = "/dev/input/event0";
623d872a4a4SAyushi Smriti                     if (mtm.mtmTestBeepFd != -1)
624d872a4a4SAyushi Smriti                     {
625d872a4a4SAyushi Smriti                         phosphor::logging::log<phosphor::logging::level::INFO>(
626d872a4a4SAyushi Smriti                             "mtm beep device is opened already!");
627d872a4a4SAyushi Smriti                         // returning success as already beep is in progress
628d872a4a4SAyushi Smriti                         return ipmi::response(retCode);
629d872a4a4SAyushi Smriti                     }
630d872a4a4SAyushi Smriti 
631d872a4a4SAyushi Smriti                     if ((mtm.mtmTestBeepFd =
632d872a4a4SAyushi Smriti                              ::open(beepDevName, O_RDWR | O_CLOEXEC)) < 0)
633d872a4a4SAyushi Smriti                     {
634d872a4a4SAyushi Smriti                         phosphor::logging::log<phosphor::logging::level::ERR>(
635d872a4a4SAyushi Smriti                             "Failed to open input device");
636d872a4a4SAyushi Smriti                         return ipmi::responseUnspecifiedError();
637d872a4a4SAyushi Smriti                     }
638d872a4a4SAyushi Smriti 
639d872a4a4SAyushi Smriti                     struct input_event event;
640d872a4a4SAyushi Smriti                     event.type = EV_SND;
641d872a4a4SAyushi Smriti                     event.code = SND_TONE;
642d872a4a4SAyushi Smriti                     event.value = 2000;
643d872a4a4SAyushi Smriti 
644d872a4a4SAyushi Smriti                     if (::write(mtm.mtmTestBeepFd, &event,
645d872a4a4SAyushi Smriti                                 sizeof(struct input_event)) !=
646d872a4a4SAyushi Smriti                         sizeof(struct input_event))
647d872a4a4SAyushi Smriti                     {
648d872a4a4SAyushi Smriti                         phosphor::logging::log<phosphor::logging::level::ERR>(
649d872a4a4SAyushi Smriti                             "Failed to write a tone sound event");
650d872a4a4SAyushi Smriti                         ::close(mtm.mtmTestBeepFd);
651d872a4a4SAyushi Smriti                         mtm.mtmTestBeepFd = -1;
652d872a4a4SAyushi Smriti                         return ipmi::responseUnspecifiedError();
653d872a4a4SAyushi Smriti                     }
654d872a4a4SAyushi Smriti                     mtm.revertTimer.start(revertTimeOut);
655d872a4a4SAyushi Smriti                 }
656d872a4a4SAyushi Smriti                 break;
657d872a4a4SAyushi Smriti                 case SmActionSet::revert:
658d872a4a4SAyushi Smriti                 case SmActionSet::forceDeasserted:
659d872a4a4SAyushi Smriti                 {
660d872a4a4SAyushi Smriti                     if (mtm.mtmTestBeepFd != -1)
661d872a4a4SAyushi Smriti                     {
662d872a4a4SAyushi Smriti                         ::close(mtm.mtmTestBeepFd);
663d872a4a4SAyushi Smriti                         mtm.mtmTestBeepFd = -1;
664d872a4a4SAyushi Smriti                     }
665d872a4a4SAyushi Smriti                 }
666d872a4a4SAyushi Smriti                 break;
667d872a4a4SAyushi Smriti                 default:
668d872a4a4SAyushi Smriti                 {
669d872a4a4SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
670d872a4a4SAyushi Smriti                 }
671d872a4a4SAyushi Smriti             }
672d872a4a4SAyushi Smriti         }
673d872a4a4SAyushi Smriti         break;
6743594c6d6SRichard Marian Thomaiyar         case SmSignalSet::smDiskFaultLed:
6753594c6d6SRichard Marian Thomaiyar         {
6763594c6d6SRichard Marian Thomaiyar             boost::system::error_code ec;
6773594c6d6SRichard Marian Thomaiyar             using objPaths = std::vector<std::string>;
6783594c6d6SRichard Marian Thomaiyar             std::string driveBasePath =
6793594c6d6SRichard Marian Thomaiyar                 "/xyz/openbmc_project/inventory/item/drive/";
6803594c6d6SRichard Marian Thomaiyar             static constexpr const char* driveLedIntf =
6813594c6d6SRichard Marian Thomaiyar                 "xyz.openbmc_project.Led.Group";
6823594c6d6SRichard Marian Thomaiyar             static constexpr const char* hsbpService =
6833594c6d6SRichard Marian Thomaiyar                 "xyz.openbmc_project.HsbpManager";
6843594c6d6SRichard Marian Thomaiyar 
6853594c6d6SRichard Marian Thomaiyar             auto driveList = ctx->bus->yield_method_call<objPaths>(
6863594c6d6SRichard Marian Thomaiyar                 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
6873594c6d6SRichard Marian Thomaiyar                 "/xyz/openbmc_project/object_mapper",
6883594c6d6SRichard Marian Thomaiyar                 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
6893594c6d6SRichard Marian Thomaiyar                 driveBasePath, 0, std::array<const char*, 1>{driveLedIntf});
6903594c6d6SRichard Marian Thomaiyar             if (ec)
6913594c6d6SRichard Marian Thomaiyar             {
6923594c6d6SRichard Marian Thomaiyar                 phosphor::logging::log<phosphor::logging::level::ERR>(
6933594c6d6SRichard Marian Thomaiyar                     "Failed to query HSBP drive sub tree objects");
6943594c6d6SRichard Marian Thomaiyar                 return ipmi::responseUnspecifiedError();
6953594c6d6SRichard Marian Thomaiyar             }
6963594c6d6SRichard Marian Thomaiyar             std::string driveObjPath =
6973594c6d6SRichard Marian Thomaiyar                 driveBasePath + "Drive_" + std::to_string(instance + 1);
6983594c6d6SRichard Marian Thomaiyar             if (std::find(driveList.begin(), driveList.end(), driveObjPath) ==
6993594c6d6SRichard Marian Thomaiyar                 driveList.end())
7003594c6d6SRichard Marian Thomaiyar             {
7013594c6d6SRichard Marian Thomaiyar                 return ipmi::responseInvalidFieldRequest();
7023594c6d6SRichard Marian Thomaiyar             }
7033594c6d6SRichard Marian Thomaiyar             bool driveLedState = false;
7043594c6d6SRichard Marian Thomaiyar             switch (action)
7053594c6d6SRichard Marian Thomaiyar             {
7063594c6d6SRichard Marian Thomaiyar                 case SmActionSet::forceAsserted:
7073594c6d6SRichard Marian Thomaiyar                 {
7083594c6d6SRichard Marian Thomaiyar                     driveLedState = true;
7093594c6d6SRichard Marian Thomaiyar                 }
7103594c6d6SRichard Marian Thomaiyar                 break;
7113594c6d6SRichard Marian Thomaiyar                 case SmActionSet::revert:
7123594c6d6SRichard Marian Thomaiyar                 {
7133594c6d6SRichard Marian Thomaiyar                     driveLedState = false;
7143594c6d6SRichard Marian Thomaiyar                 }
7153594c6d6SRichard Marian Thomaiyar                 break;
7163594c6d6SRichard Marian Thomaiyar                 case SmActionSet::forceDeasserted:
7173594c6d6SRichard Marian Thomaiyar                 {
7183594c6d6SRichard Marian Thomaiyar                     driveLedState = false;
7193594c6d6SRichard Marian Thomaiyar                 }
7203594c6d6SRichard Marian Thomaiyar                 break;
7213594c6d6SRichard Marian Thomaiyar                 default:
7223594c6d6SRichard Marian Thomaiyar                 {
7233594c6d6SRichard Marian Thomaiyar                     return ipmi::responseInvalidFieldRequest();
7243594c6d6SRichard Marian Thomaiyar                 }
7253594c6d6SRichard Marian Thomaiyar             }
7263594c6d6SRichard Marian Thomaiyar             ret = mtm.setProperty(hsbpService, driveObjPath, driveLedIntf,
7273594c6d6SRichard Marian Thomaiyar                                   "Asserted", driveLedState);
7283594c6d6SRichard Marian Thomaiyar             if (ret < 0)
7293594c6d6SRichard Marian Thomaiyar             {
7303594c6d6SRichard Marian Thomaiyar                 return ipmi::responseUnspecifiedError();
7313594c6d6SRichard Marian Thomaiyar             }
7323594c6d6SRichard Marian Thomaiyar         }
7333594c6d6SRichard Marian Thomaiyar         break;
734a3702c1fSVernon Mauery         default:
735a3702c1fSVernon Mauery         {
7365e3bf557SAyushi Smriti             return ipmi::responseInvalidFieldRequest();
737a3702c1fSVernon Mauery         }
738a3702c1fSVernon Mauery     }
7394cc10159SRichard Marian Thomaiyar     if (retCode == ccSuccess)
7404cc10159SRichard Marian Thomaiyar     {
741357ddc74SRichard Marian Thomaiyar         resetMtmTimer(ctx);
7424cc10159SRichard Marian Thomaiyar     }
7435e3bf557SAyushi Smriti     return ipmi::response(retCode);
744a3702c1fSVernon Mauery }
745a3702c1fSVernon Mauery 
746357ddc74SRichard Marian Thomaiyar ipmi::RspType<> mtmKeepAlive(ipmi::Context::ptr ctx, uint8_t reserved,
747666dd01cSRichard Marian Thomaiyar                              const std::array<char, 5>& intentionalSignature)
748666dd01cSRichard Marian Thomaiyar {
749e0511e5fSAyushi Smriti     // mfg filter logic is used to allow MTM keep alive command only in
750e0511e5fSAyushi Smriti     // manfacturing mode
751e0511e5fSAyushi Smriti 
752666dd01cSRichard Marian Thomaiyar     constexpr std::array<char, 5> signatureOk = {'I', 'N', 'T', 'E', 'L'};
753666dd01cSRichard Marian Thomaiyar     if (intentionalSignature != signatureOk || reserved != 0)
754666dd01cSRichard Marian Thomaiyar     {
755666dd01cSRichard Marian Thomaiyar         return ipmi::responseInvalidFieldRequest();
756666dd01cSRichard Marian Thomaiyar     }
757357ddc74SRichard Marian Thomaiyar     return ipmi::response(resetMtmTimer(ctx));
758666dd01cSRichard Marian Thomaiyar }
759666dd01cSRichard Marian Thomaiyar 
760e0511e5fSAyushi Smriti static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd)
761e0511e5fSAyushi Smriti {
762e0511e5fSAyushi Smriti     return (netFn << 8) | cmd;
763e0511e5fSAyushi Smriti }
764e0511e5fSAyushi Smriti 
76585feb130SYong Li ipmi::Cc mfgFilterMessage(ipmi::message::Request::ptr request)
76685feb130SYong Li {
767e0511e5fSAyushi Smriti     // Restricted commands, must be executed only in Manufacturing mode
768e0511e5fSAyushi Smriti     switch (makeCmdKey(request->ctx->netFn, request->ctx->cmd))
76985feb130SYong Li     {
770e0511e5fSAyushi Smriti         // i2c master write read command needs additional checking
771e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead):
77285feb130SYong Li             if (request->payload.size() > 4)
77385feb130SYong Li             {
774ae13ac62SRichard Marian Thomaiyar                 // Allow write data count > 1 only in Special mode
775ae13ac62SRichard Marian Thomaiyar                 if (mtm.getMfgMode() == SpecialMode::none)
77685feb130SYong Li                 {
77785feb130SYong Li                     return ipmi::ccInsufficientPrivilege;
77885feb130SYong Li                 }
77985feb130SYong Li             }
7802d4a0198Sjayaprakash Mutyala             return ipmi::ccSuccess;
781e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
782e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdGetSmSignal):
783e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
784e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdSetSmSignal):
785e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
786e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdMtmKeepAlive):
787e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
788e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdSetManufacturingData):
789e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
790e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdGetManufacturingData):
791e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdWriteFruData):
79285feb130SYong Li 
793ae13ac62SRichard Marian Thomaiyar             // Check for Special mode
794ae13ac62SRichard Marian Thomaiyar             if (mtm.getMfgMode() == SpecialMode::none)
795e0511e5fSAyushi Smriti             {
796e0511e5fSAyushi Smriti                 return ipmi::ccInvalidCommand;
797e0511e5fSAyushi Smriti             }
7982d4a0198Sjayaprakash Mutyala             return ipmi::ccSuccess;
7992d4a0198Sjayaprakash Mutyala         case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdDeleteSelEntry):
8002d4a0198Sjayaprakash Mutyala         {
8012d4a0198Sjayaprakash Mutyala             return ipmi::ccInvalidCommand;
8022d4a0198Sjayaprakash Mutyala         }
803e0511e5fSAyushi Smriti     }
80485feb130SYong Li     return ipmi::ccSuccess;
80585feb130SYong Li }
80685feb130SYong Li 
8071f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxEthSize = 6;
8081f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxSupportedEth = 3;
8091f0839c2SRichard Marian Thomaiyar static constexpr const char* factoryEthAddrBaseFileName =
8101f0839c2SRichard Marian Thomaiyar     "/var/sofs/factory-settings/network/mac/eth";
8111f0839c2SRichard Marian Thomaiyar 
812357ddc74SRichard Marian Thomaiyar ipmi::RspType<> setManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType,
8131f0839c2SRichard Marian Thomaiyar                                      std::array<uint8_t, maxEthSize> ethData)
8141f0839c2SRichard Marian Thomaiyar {
8151f0839c2SRichard Marian Thomaiyar     // mfg filter logic will restrict this command executing only in mfg mode.
8161f0839c2SRichard Marian Thomaiyar     if (dataType >= maxSupportedEth)
8171f0839c2SRichard Marian Thomaiyar     {
8181f0839c2SRichard Marian Thomaiyar         return ipmi::responseParmOutOfRange();
8191f0839c2SRichard Marian Thomaiyar     }
8201f0839c2SRichard Marian Thomaiyar 
8211f0839c2SRichard Marian Thomaiyar     constexpr uint8_t invalidData = 0;
8221f0839c2SRichard Marian Thomaiyar     constexpr uint8_t validData = 1;
8231f0839c2SRichard Marian Thomaiyar     constexpr uint8_t ethAddrStrSize =
8241f0839c2SRichard Marian Thomaiyar         19; // XX:XX:XX:XX:XX:XX + \n + null termination;
8251f0839c2SRichard Marian Thomaiyar     std::vector<uint8_t> buff(ethAddrStrSize);
8261f0839c2SRichard Marian Thomaiyar     std::snprintf(reinterpret_cast<char*>(buff.data()), ethAddrStrSize,
8271f0839c2SRichard Marian Thomaiyar                   "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", ethData.at(0),
8281f0839c2SRichard Marian Thomaiyar                   ethData.at(1), ethData.at(2), ethData.at(3), ethData.at(4),
8291f0839c2SRichard Marian Thomaiyar                   ethData.at(5));
8301f0839c2SRichard Marian Thomaiyar     std::ofstream oEthFile(factoryEthAddrBaseFileName +
8311f0839c2SRichard Marian Thomaiyar                                std::to_string(dataType),
8321f0839c2SRichard Marian Thomaiyar                            std::ofstream::out);
8331f0839c2SRichard Marian Thomaiyar     if (!oEthFile.good())
8341f0839c2SRichard Marian Thomaiyar     {
8351f0839c2SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
8361f0839c2SRichard Marian Thomaiyar     }
8371f0839c2SRichard Marian Thomaiyar 
8381f0839c2SRichard Marian Thomaiyar     oEthFile << reinterpret_cast<char*>(buff.data());
8396d83e4eeSJohnathan Mantey     oEthFile.flush();
8401f0839c2SRichard Marian Thomaiyar     oEthFile.close();
8411f0839c2SRichard Marian Thomaiyar 
842357ddc74SRichard Marian Thomaiyar     resetMtmTimer(ctx);
8431f0839c2SRichard Marian Thomaiyar     return ipmi::responseSuccess();
8441f0839c2SRichard Marian Thomaiyar }
8451f0839c2SRichard Marian Thomaiyar 
8461f0839c2SRichard Marian Thomaiyar ipmi::RspType<uint8_t, std::array<uint8_t, maxEthSize>>
847357ddc74SRichard Marian Thomaiyar     getManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType)
8481f0839c2SRichard Marian Thomaiyar {
8491f0839c2SRichard Marian Thomaiyar     // mfg filter logic will restrict this command executing only in mfg mode.
8501f0839c2SRichard Marian Thomaiyar     if (dataType >= maxSupportedEth)
8511f0839c2SRichard Marian Thomaiyar     {
8521f0839c2SRichard Marian Thomaiyar         return ipmi::responseParmOutOfRange();
8531f0839c2SRichard Marian Thomaiyar     }
8541f0839c2SRichard Marian Thomaiyar     std::array<uint8_t, maxEthSize> ethData{0};
8551f0839c2SRichard Marian Thomaiyar     constexpr uint8_t invalidData = 0;
8561f0839c2SRichard Marian Thomaiyar     constexpr uint8_t validData = 1;
8571f0839c2SRichard Marian Thomaiyar 
8581f0839c2SRichard Marian Thomaiyar     std::ifstream iEthFile(factoryEthAddrBaseFileName +
8591f0839c2SRichard Marian Thomaiyar                                std::to_string(dataType),
8601f0839c2SRichard Marian Thomaiyar                            std::ifstream::in);
8611f0839c2SRichard Marian Thomaiyar     if (!iEthFile.good())
8621f0839c2SRichard Marian Thomaiyar     {
8631f0839c2SRichard Marian Thomaiyar         return ipmi::responseSuccess(invalidData, ethData);
8641f0839c2SRichard Marian Thomaiyar     }
8651f0839c2SRichard Marian Thomaiyar     std::string ethStr;
8661f0839c2SRichard Marian Thomaiyar     iEthFile >> ethStr;
8671f0839c2SRichard Marian Thomaiyar     uint8_t* data = ethData.data();
8681f0839c2SRichard Marian Thomaiyar     std::sscanf(ethStr.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
8691f0839c2SRichard Marian Thomaiyar                 data, (data + 1), (data + 2), (data + 3), (data + 4),
8701f0839c2SRichard Marian Thomaiyar                 (data + 5));
8711f0839c2SRichard Marian Thomaiyar 
872357ddc74SRichard Marian Thomaiyar     resetMtmTimer(ctx);
8731f0839c2SRichard Marian Thomaiyar     return ipmi::responseSuccess(validData, ethData);
8741f0839c2SRichard Marian Thomaiyar }
8751f0839c2SRichard Marian Thomaiyar 
876f267a67dSYong Li /** @brief implements slot master write read IPMI command which can be used for
877f267a67dSYong Li  * low-level I2C/SMBus write, read or write-read access for PCIE slots
878f267a67dSYong Li  * @param reserved - skip 6 bit
879f267a67dSYong Li  * @param addressType - address type
880f267a67dSYong Li  * @param bbSlotNum - baseboard slot number
881f267a67dSYong Li  * @param riserSlotNum - riser slot number
882f267a67dSYong Li  * @param reserved2 - skip 2 bit
883f267a67dSYong Li  * @param slaveAddr - slave address
884f267a67dSYong Li  * @param readCount - number of bytes to be read
885f267a67dSYong Li  * @param writeData - data to be written
886f267a67dSYong Li  *
887f267a67dSYong Li  * @returns IPMI completion code plus response data
888f267a67dSYong Li  */
889f267a67dSYong Li ipmi::RspType<std::vector<uint8_t>>
890f267a67dSYong Li     appSlotI2CMasterWriteRead(uint6_t reserved, uint2_t addressType,
891f267a67dSYong Li                               uint3_t bbSlotNum, uint3_t riserSlotNum,
892f267a67dSYong Li                               uint2_t resvered2, uint8_t slaveAddr,
893f267a67dSYong Li                               uint8_t readCount, std::vector<uint8_t> writeData)
894f267a67dSYong Li {
895f267a67dSYong Li     const size_t writeCount = writeData.size();
896f267a67dSYong Li     std::string i2cBus;
897f267a67dSYong Li     if (addressType == slotAddressTypeBus)
898f267a67dSYong Li     {
899f267a67dSYong Li         std::string path = "/dev/i2c-mux/Riser_" +
900f267a67dSYong Li                            std::to_string(static_cast<uint8_t>(bbSlotNum)) +
901f267a67dSYong Li                            "_Mux/Pcie_Slot_" +
902f267a67dSYong Li                            std::to_string(static_cast<uint8_t>(riserSlotNum));
903f267a67dSYong Li 
904f267a67dSYong Li         if (std::filesystem::exists(path) && std::filesystem::is_symlink(path))
905f267a67dSYong Li         {
906f267a67dSYong Li             i2cBus = std::filesystem::read_symlink(path);
907f267a67dSYong Li         }
908f267a67dSYong Li         else
909f267a67dSYong Li         {
910f267a67dSYong Li             phosphor::logging::log<phosphor::logging::level::ERR>(
911f267a67dSYong Li                 "Master write read command: Cannot get BusID");
912f267a67dSYong Li             return ipmi::responseInvalidFieldRequest();
913f267a67dSYong Li         }
914f267a67dSYong Li     }
915f267a67dSYong Li     else if (addressType == slotAddressTypeUniqueid)
916f267a67dSYong Li     {
917f267a67dSYong Li         i2cBus = "/dev/i2c-" +
918f267a67dSYong Li                  std::to_string(static_cast<uint8_t>(bbSlotNum) |
919f267a67dSYong Li                                 (static_cast<uint8_t>(riserSlotNum) << 3));
920f267a67dSYong Li     }
921f267a67dSYong Li     else
922f267a67dSYong Li     {
923f267a67dSYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
924f267a67dSYong Li             "Master write read command: invalid request");
925f267a67dSYong Li         return ipmi::responseInvalidFieldRequest();
926f267a67dSYong Li     }
927f267a67dSYong Li 
928f267a67dSYong Li     // Allow single byte write as it is offset byte to read the data, rest allow
929ae13ac62SRichard Marian Thomaiyar     // only in Special mode.
930f267a67dSYong Li     if (writeCount > 1)
931f267a67dSYong Li     {
932ae13ac62SRichard Marian Thomaiyar         if (mtm.getMfgMode() == SpecialMode::none)
933f267a67dSYong Li         {
934f267a67dSYong Li             return ipmi::responseInsufficientPrivilege();
935f267a67dSYong Li         }
936f267a67dSYong Li     }
937f267a67dSYong Li 
938f267a67dSYong Li     if (readCount > slotI2CMaxReadSize)
939f267a67dSYong Li     {
940f267a67dSYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
941f267a67dSYong Li             "Master write read command: Read count exceeds limit");
942f267a67dSYong Li         return ipmi::responseParmOutOfRange();
943f267a67dSYong Li     }
944f267a67dSYong Li 
945f267a67dSYong Li     if (!readCount && !writeCount)
946f267a67dSYong Li     {
947f267a67dSYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
948f267a67dSYong Li             "Master write read command: Read & write count are 0");
949f267a67dSYong Li         return ipmi::responseInvalidFieldRequest();
950f267a67dSYong Li     }
951f267a67dSYong Li 
952f267a67dSYong Li     std::vector<uint8_t> readBuf(readCount);
953f267a67dSYong Li 
954f267a67dSYong Li     ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf);
955f267a67dSYong Li     if (retI2C != ipmi::ccSuccess)
956f267a67dSYong Li     {
957f267a67dSYong Li         return ipmi::response(retI2C);
958f267a67dSYong Li     }
959f267a67dSYong Li 
960f267a67dSYong Li     return ipmi::responseSuccess(readBuf);
961f267a67dSYong Li }
962068b4f2cSYong Li 
963068b4f2cSYong Li ipmi::RspType<> clearCMOS()
964068b4f2cSYong Li {
965d0d010b7SYong Li     // There is an i2c device on bus 4, the slave address is 0x38. Based on the
966eaeb6cb0SYong Li     // spec, writing 0x1 to address 0x61 on this device, will trigger the clear
967068b4f2cSYong Li     // CMOS action.
968d0d010b7SYong Li     constexpr uint8_t slaveAddr = 0x38;
969068b4f2cSYong Li     std::string i2cBus = "/dev/i2c-4";
970eaeb6cb0SYong Li     std::vector<uint8_t> writeData = {0x61, 0x1};
971068b4f2cSYong Li     std::vector<uint8_t> readBuf(0);
972068b4f2cSYong Li 
973ae13ac62SRichard Marian Thomaiyar     if (mtm.getMfgMode() == SpecialMode::none)
974068b4f2cSYong Li     {
975068b4f2cSYong Li         return ipmi::responseInsufficientPrivilege();
976068b4f2cSYong Li     }
977068b4f2cSYong Li 
978068b4f2cSYong Li     ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf);
979068b4f2cSYong Li     return ipmi::response(retI2C);
980068b4f2cSYong Li }
981a3702c1fSVernon Mauery } // namespace ipmi
982a3702c1fSVernon Mauery 
983a3702c1fSVernon Mauery void register_mtm_commands() __attribute__((constructor));
984a3702c1fSVernon Mauery void register_mtm_commands()
985a3702c1fSVernon Mauery {
98638d2b5a6SJason M. Bills     // <Get SM Signal>
98798bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
98898bbf69aSVernon Mauery                           ipmi::intel::general::cmdGetSmSignal,
9895e3bf557SAyushi Smriti                           ipmi::Privilege::Admin, ipmi::appMTMGetSignal);
990a3702c1fSVernon Mauery 
99198bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
99298bbf69aSVernon Mauery                           ipmi::intel::general::cmdSetSmSignal,
9935e3bf557SAyushi Smriti                           ipmi::Privilege::Admin, ipmi::appMTMSetSignal);
994a3702c1fSVernon Mauery 
99598bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
99698bbf69aSVernon Mauery                           ipmi::intel::general::cmdMtmKeepAlive,
997666dd01cSRichard Marian Thomaiyar                           ipmi::Privilege::Admin, ipmi::mtmKeepAlive);
998666dd01cSRichard Marian Thomaiyar 
99998bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
100098bbf69aSVernon Mauery                           ipmi::intel::general::cmdSetManufacturingData,
10011f0839c2SRichard Marian Thomaiyar                           ipmi::Privilege::Admin, ipmi::setManufacturingData);
10021f0839c2SRichard Marian Thomaiyar 
100398bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
100498bbf69aSVernon Mauery                           ipmi::intel::general::cmdGetManufacturingData,
10051f0839c2SRichard Marian Thomaiyar                           ipmi::Privilege::Admin, ipmi::getManufacturingData);
10061f0839c2SRichard Marian Thomaiyar 
100798bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
100898bbf69aSVernon Mauery                           ipmi::intel::general::cmdSlotI2CMasterWriteRead,
100998bbf69aSVernon Mauery                           ipmi::Privilege::Admin,
101098bbf69aSVernon Mauery                           ipmi::appSlotI2CMasterWriteRead);
1011f267a67dSYong Li 
1012068b4f2cSYong Li     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnPlatform,
1013068b4f2cSYong Li                           ipmi::intel::platform::cmdClearCMOS,
1014068b4f2cSYong Li                           ipmi::Privilege::Admin, ipmi::clearCMOS);
1015068b4f2cSYong Li 
101698bbf69aSVernon Mauery     ipmi::registerFilter(ipmi::prioOemBase,
101785feb130SYong Li                          [](ipmi::message::Request::ptr request) {
101885feb130SYong Li                              return ipmi::mfgFilterMessage(request);
101985feb130SYong Li                          });
1020a3702c1fSVernon Mauery }
1021