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>
20f267a67dSYong Li #include <filesystem>
211b74a210SRichard Marian Thomaiyar #include <fstream>
22a3702c1fSVernon Mauery #include <ipmid/api.hpp>
23a3702c1fSVernon Mauery #include <manufacturingcommands.hpp>
24a3702c1fSVernon Mauery #include <oemcommands.hpp>
25a3702c1fSVernon Mauery 
26a3702c1fSVernon Mauery namespace ipmi
27a3702c1fSVernon Mauery {
28a3702c1fSVernon Mauery 
29a3702c1fSVernon Mauery Manufacturing mtm;
30a3702c1fSVernon Mauery 
31a3702c1fSVernon Mauery static auto revertTimeOut =
32a3702c1fSVernon Mauery     std::chrono::duration_cast<std::chrono::microseconds>(
33a3702c1fSVernon Mauery         std::chrono::seconds(60)); // 1 minute timeout
34a3702c1fSVernon Mauery 
35f267a67dSYong Li static constexpr uint8_t slotAddressTypeBus = 0;
36f267a67dSYong Li static constexpr uint8_t slotAddressTypeUniqueid = 1;
37f267a67dSYong Li static constexpr uint8_t slotI2CMaxReadSize = 35;
38f267a67dSYong Li 
39a3702c1fSVernon Mauery static constexpr const char* callbackMgrService =
40a3702c1fSVernon Mauery     "xyz.openbmc_project.CallbackManager";
41a3702c1fSVernon Mauery static constexpr const char* callbackMgrIntf =
42a3702c1fSVernon Mauery     "xyz.openbmc_project.CallbackManager";
43a3702c1fSVernon Mauery static constexpr const char* callbackMgrObjPath =
44a3702c1fSVernon Mauery     "/xyz/openbmc_project/CallbackManager";
45a3702c1fSVernon Mauery static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate";
46a3702c1fSVernon Mauery 
47a3702c1fSVernon Mauery const static constexpr char* systemDService = "org.freedesktop.systemd1";
48a3702c1fSVernon Mauery const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1";
49a3702c1fSVernon Mauery const static constexpr char* systemDMgrIntf =
50a3702c1fSVernon Mauery     "org.freedesktop.systemd1.Manager";
51a3702c1fSVernon Mauery const static constexpr char* pidControlService = "phosphor-pid-control.service";
52a3702c1fSVernon Mauery 
53357ddc74SRichard Marian Thomaiyar static inline Cc resetMtmTimer(ipmi::Context::ptr ctx)
54666dd01cSRichard Marian Thomaiyar {
55666dd01cSRichard Marian Thomaiyar     boost::system::error_code ec;
56357ddc74SRichard Marian Thomaiyar     ctx->bus->yield_method_call<>(ctx->yield, ec, specialModeService,
57666dd01cSRichard Marian Thomaiyar                                   specialModeObjPath, specialModeIntf,
58666dd01cSRichard Marian Thomaiyar                                   "ResetTimer");
59666dd01cSRichard Marian Thomaiyar     if (ec)
60666dd01cSRichard Marian Thomaiyar     {
61666dd01cSRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
62666dd01cSRichard Marian Thomaiyar             "Failed to reset the manufacturing mode timer");
63666dd01cSRichard Marian Thomaiyar         return ccUnspecifiedError;
64666dd01cSRichard Marian Thomaiyar     }
65666dd01cSRichard Marian Thomaiyar     return ccSuccess;
66666dd01cSRichard Marian Thomaiyar }
67666dd01cSRichard Marian Thomaiyar 
6838d2b5a6SJason M. Bills int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path)
69a3702c1fSVernon Mauery {
7038d2b5a6SJason M. Bills     switch (signal)
7138d2b5a6SJason M. Bills     {
7238d2b5a6SJason M. Bills         case SmSignalGet::smPowerButton:
7338d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/power";
7438d2b5a6SJason M. Bills             break;
7538d2b5a6SJason M. Bills         case SmSignalGet::smResetButton:
7638d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/reset";
7738d2b5a6SJason M. Bills             break;
7838d2b5a6SJason M. Bills         case SmSignalGet::smNMIButton:
7938d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/nmi";
8038d2b5a6SJason M. Bills             break;
818e5e2b04SRichard Marian Thomaiyar         case SmSignalGet::smIdentifyButton:
828e5e2b04SRichard Marian Thomaiyar             path = "/xyz/openbmc_project/chassis/buttons/id";
838e5e2b04SRichard Marian Thomaiyar             break;
8438d2b5a6SJason M. Bills         default:
8538d2b5a6SJason M. Bills             return -1;
8638d2b5a6SJason M. Bills             break;
8738d2b5a6SJason M. Bills     }
8838d2b5a6SJason M. Bills     return 0;
89a3702c1fSVernon Mauery }
90a3702c1fSVernon Mauery 
9137890392SPatrick Venture ipmi_ret_t ledStoreAndSet(SmSignalSet signal, const std::string& setState)
92a3702c1fSVernon Mauery {
93a3702c1fSVernon Mauery     LedProperty* ledProp = mtm.findLedProperty(signal);
94a3702c1fSVernon Mauery     if (ledProp == nullptr)
95a3702c1fSVernon Mauery     {
96a3702c1fSVernon Mauery         return IPMI_CC_INVALID_FIELD_REQUEST;
97a3702c1fSVernon Mauery     }
98a3702c1fSVernon Mauery 
99a3702c1fSVernon Mauery     std::string ledName = ledProp->getName();
100a3702c1fSVernon Mauery     std::string ledService = ledServicePrefix + ledName;
101a3702c1fSVernon Mauery     std::string ledPath = ledPathPrefix + ledName;
102a3702c1fSVernon Mauery     ipmi::Value presentState;
103a3702c1fSVernon Mauery 
104a3702c1fSVernon Mauery     if (false == ledProp->getLock())
105a3702c1fSVernon Mauery     {
106a3702c1fSVernon Mauery         if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf,
107a3702c1fSVernon Mauery                             "State", &presentState) != 0)
108a3702c1fSVernon Mauery         {
109a3702c1fSVernon Mauery             return IPMI_CC_UNSPECIFIED_ERROR;
110a3702c1fSVernon Mauery         }
111a3702c1fSVernon Mauery         ledProp->setPrevState(std::get<std::string>(presentState));
112a3702c1fSVernon Mauery         ledProp->setLock(true);
113a3702c1fSVernon Mauery         if (signal == SmSignalSet::smPowerFaultLed ||
114a3702c1fSVernon Mauery             signal == SmSignalSet::smSystemReadyLed)
115a3702c1fSVernon Mauery         {
116a3702c1fSVernon Mauery             mtm.revertLedCallback = true;
117a3702c1fSVernon Mauery         }
118a3702c1fSVernon Mauery     }
11938d2b5a6SJason M. Bills     if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
120a3702c1fSVernon Mauery                         ledStateStr + setState) != 0)
121a3702c1fSVernon Mauery     {
122a3702c1fSVernon Mauery         return IPMI_CC_UNSPECIFIED_ERROR;
123a3702c1fSVernon Mauery     }
124a3702c1fSVernon Mauery     return IPMI_CC_OK;
125a3702c1fSVernon Mauery }
126a3702c1fSVernon Mauery 
127a3702c1fSVernon Mauery ipmi_ret_t ledRevert(SmSignalSet signal)
128a3702c1fSVernon Mauery {
129a3702c1fSVernon Mauery     LedProperty* ledProp = mtm.findLedProperty(signal);
130a3702c1fSVernon Mauery     if (ledProp == nullptr)
131a3702c1fSVernon Mauery     {
132a3702c1fSVernon Mauery         return IPMI_CC_INVALID_FIELD_REQUEST;
133a3702c1fSVernon Mauery     }
134a3702c1fSVernon Mauery     if (true == ledProp->getLock())
135a3702c1fSVernon Mauery     {
136a3702c1fSVernon Mauery         ledProp->setLock(false);
137a3702c1fSVernon Mauery         if (signal == SmSignalSet::smPowerFaultLed ||
138a3702c1fSVernon Mauery             signal == SmSignalSet::smSystemReadyLed)
139a3702c1fSVernon Mauery         {
140a3702c1fSVernon Mauery             try
141a3702c1fSVernon Mauery             {
142a3702c1fSVernon Mauery                 ipmi::method_no_args::callDbusMethod(
143a3702c1fSVernon Mauery                     *getSdBus(), callbackMgrService, callbackMgrObjPath,
144a3702c1fSVernon Mauery                     callbackMgrIntf, retriggerLedUpdate);
145a3702c1fSVernon Mauery             }
146a3702c1fSVernon Mauery             catch (sdbusplus::exception_t& e)
147a3702c1fSVernon Mauery             {
148a3702c1fSVernon Mauery                 return IPMI_CC_UNSPECIFIED_ERROR;
149a3702c1fSVernon Mauery             }
150a3702c1fSVernon Mauery             mtm.revertLedCallback = false;
151a3702c1fSVernon Mauery         }
152a3702c1fSVernon Mauery         else
153a3702c1fSVernon Mauery         {
154a3702c1fSVernon Mauery             std::string ledName = ledProp->getName();
155a3702c1fSVernon Mauery             std::string ledService = ledServicePrefix + ledName;
156a3702c1fSVernon Mauery             std::string ledPath = ledPathPrefix + ledName;
15738d2b5a6SJason M. Bills             if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
15838d2b5a6SJason M. Bills                                 ledProp->getPrevState()) != 0)
159a3702c1fSVernon Mauery             {
160a3702c1fSVernon Mauery                 return IPMI_CC_UNSPECIFIED_ERROR;
161a3702c1fSVernon Mauery             }
162a3702c1fSVernon Mauery         }
163a3702c1fSVernon Mauery     }
164a3702c1fSVernon Mauery     return IPMI_CC_OK;
165a3702c1fSVernon Mauery }
166a3702c1fSVernon Mauery 
167a3702c1fSVernon Mauery void Manufacturing::initData()
168a3702c1fSVernon Mauery {
169a3702c1fSVernon Mauery     ledPropertyList.push_back(
170a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smPowerFaultLed, "status_amber"));
171a3702c1fSVernon Mauery     ledPropertyList.push_back(
172a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smSystemReadyLed, "status_green"));
173a3702c1fSVernon Mauery     ledPropertyList.push_back(
174a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smIdentifyLed, "identify"));
175a3702c1fSVernon Mauery }
176a3702c1fSVernon Mauery 
177a3702c1fSVernon Mauery void Manufacturing::revertTimerHandler()
178a3702c1fSVernon Mauery {
179ae13ac62SRichard Marian Thomaiyar 
180ae13ac62SRichard Marian Thomaiyar #ifdef BMC_VALIDATION_UNSECURE_FEATURE
181ae13ac62SRichard Marian Thomaiyar     if (mtm.getMfgMode() == SpecialMode::valUnsecure)
182ae13ac62SRichard Marian Thomaiyar     {
183ae13ac62SRichard Marian Thomaiyar         // Don't revert the behaviour for validation unsecure mode.
184ae13ac62SRichard Marian Thomaiyar         return;
185ae13ac62SRichard Marian Thomaiyar     }
186ae13ac62SRichard Marian Thomaiyar #endif
187a3702c1fSVernon Mauery     if (revertFanPWM)
188a3702c1fSVernon Mauery     {
189a3702c1fSVernon Mauery         revertFanPWM = false;
190a3702c1fSVernon Mauery         disablePidControlService(false);
191a3702c1fSVernon Mauery     }
192a3702c1fSVernon Mauery 
193d872a4a4SAyushi Smriti     if (mtmTestBeepFd != -1)
194d872a4a4SAyushi Smriti     {
195d872a4a4SAyushi Smriti         ::close(mtmTestBeepFd);
196d872a4a4SAyushi Smriti         mtmTestBeepFd = -1;
197d872a4a4SAyushi Smriti     }
198d872a4a4SAyushi Smriti 
199a3702c1fSVernon Mauery     for (const auto& ledProperty : ledPropertyList)
200a3702c1fSVernon Mauery     {
201a3702c1fSVernon Mauery         const std::string& ledName = ledProperty.getName();
202a3702c1fSVernon Mauery         ledRevert(ledProperty.getSignal());
203a3702c1fSVernon Mauery     }
204a3702c1fSVernon Mauery }
205a3702c1fSVernon Mauery 
206a3702c1fSVernon Mauery Manufacturing::Manufacturing() :
207a3702c1fSVernon Mauery     revertTimer([&](void) { revertTimerHandler(); })
208a3702c1fSVernon Mauery {
209a3702c1fSVernon Mauery     initData();
210a3702c1fSVernon Mauery }
211a3702c1fSVernon Mauery 
21238d2b5a6SJason M. Bills int8_t Manufacturing::getProperty(const std::string& service,
21338d2b5a6SJason M. Bills                                   const std::string& path,
21438d2b5a6SJason M. Bills                                   const std::string& interface,
21538d2b5a6SJason M. Bills                                   const std::string& propertyName,
21638d2b5a6SJason M. Bills                                   ipmi::Value* reply)
217a3702c1fSVernon Mauery {
218a3702c1fSVernon Mauery     try
219a3702c1fSVernon Mauery     {
22038d2b5a6SJason M. Bills         *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface,
22138d2b5a6SJason M. Bills                                        propertyName);
222a3702c1fSVernon Mauery     }
223a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
224a3702c1fSVernon Mauery     {
225a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
226a3702c1fSVernon Mauery             "ERROR: getProperty");
227a3702c1fSVernon Mauery         return -1;
228a3702c1fSVernon Mauery     }
229a3702c1fSVernon Mauery 
230a3702c1fSVernon Mauery     return 0;
231a3702c1fSVernon Mauery }
232a3702c1fSVernon Mauery 
23338d2b5a6SJason M. Bills int8_t Manufacturing::setProperty(const std::string& service,
23438d2b5a6SJason M. Bills                                   const std::string& path,
23538d2b5a6SJason M. Bills                                   const std::string& interface,
23638d2b5a6SJason M. Bills                                   const std::string& propertyName,
23738d2b5a6SJason M. Bills                                   ipmi::Value value)
238a3702c1fSVernon Mauery {
239a3702c1fSVernon Mauery     try
240a3702c1fSVernon Mauery     {
24138d2b5a6SJason M. Bills         ipmi::setDbusProperty(*getSdBus(), service, path, interface,
242a3702c1fSVernon Mauery                               propertyName, value);
243a3702c1fSVernon Mauery     }
244a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
245a3702c1fSVernon Mauery     {
246a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
247a3702c1fSVernon Mauery             "ERROR: setProperty");
248a3702c1fSVernon Mauery         return -1;
249a3702c1fSVernon Mauery     }
250a3702c1fSVernon Mauery 
251a3702c1fSVernon Mauery     return 0;
252a3702c1fSVernon Mauery }
253a3702c1fSVernon Mauery 
254a3702c1fSVernon Mauery int8_t Manufacturing::disablePidControlService(const bool disable)
255a3702c1fSVernon Mauery {
256a3702c1fSVernon Mauery     try
257a3702c1fSVernon Mauery     {
258a3702c1fSVernon Mauery         auto dbus = getSdBus();
259a3702c1fSVernon Mauery         auto method = dbus->new_method_call(systemDService, systemDObjPath,
260a3702c1fSVernon Mauery                                             systemDMgrIntf,
261a3702c1fSVernon Mauery                                             disable ? "StopUnit" : "StartUnit");
262a3702c1fSVernon Mauery         method.append(pidControlService, "replace");
263a3702c1fSVernon Mauery         auto reply = dbus->call(method);
264a3702c1fSVernon Mauery     }
265a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
266a3702c1fSVernon Mauery     {
267a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
268a3702c1fSVernon Mauery             "ERROR: phosphor-pid-control service start or stop failed");
269a3702c1fSVernon Mauery         return -1;
270a3702c1fSVernon Mauery     }
271a3702c1fSVernon Mauery     return 0;
272a3702c1fSVernon Mauery }
273a3702c1fSVernon Mauery 
27438d2b5a6SJason M. Bills ipmi::RspType<uint8_t,                // Signal value
27538d2b5a6SJason M. Bills               std::optional<uint16_t> // Fan tach value
27638d2b5a6SJason M. Bills               >
277357ddc74SRichard Marian Thomaiyar     appMTMGetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte,
278147daec5SRichard Marian Thomaiyar                     uint8_t instance, uint8_t actionByte)
279a3702c1fSVernon Mauery {
280e0511e5fSAyushi Smriti     // mfg filter logic is used to allow MTM get signal command only in
281e0511e5fSAyushi Smriti     // manfacturing mode.
28238d2b5a6SJason M. Bills 
28338d2b5a6SJason M. Bills     SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte);
28438d2b5a6SJason M. Bills     SmActionGet action = static_cast<SmActionGet>(actionByte);
28538d2b5a6SJason M. Bills 
28638d2b5a6SJason M. Bills     switch (signalType)
28738d2b5a6SJason M. Bills     {
28898705b39Sanil kumar appana         case SmSignalGet::smChassisIntrusion:
28998705b39Sanil kumar appana         {
29098705b39Sanil kumar appana             ipmi::Value reply;
29198705b39Sanil kumar appana             if (mtm.getProperty(intrusionService, intrusionPath, intrusionIntf,
29298705b39Sanil kumar appana                                 "Status", &reply) < 0)
29398705b39Sanil kumar appana             {
29498705b39Sanil kumar appana                 return ipmi::responseInvalidFieldRequest();
29598705b39Sanil kumar appana             }
29698705b39Sanil kumar appana             std::string* intrusionStatus = std::get_if<std::string>(&reply);
29798705b39Sanil kumar appana             if (!intrusionStatus)
29898705b39Sanil kumar appana             {
29998705b39Sanil kumar appana                 return ipmi::responseUnspecifiedError();
30098705b39Sanil kumar appana             }
30198705b39Sanil kumar appana 
30298705b39Sanil kumar appana             uint8_t status = 0;
30398705b39Sanil kumar appana             if (!intrusionStatus->compare("Normal"))
30498705b39Sanil kumar appana             {
30598705b39Sanil kumar appana                 status = static_cast<uint8_t>(IntrusionStatus::normal);
30698705b39Sanil kumar appana             }
30798705b39Sanil kumar appana             else if (!intrusionStatus->compare("HardwareIntrusion"))
30898705b39Sanil kumar appana             {
30998705b39Sanil kumar appana                 status =
31098705b39Sanil kumar appana                     static_cast<uint8_t>(IntrusionStatus::hardwareIntrusion);
31198705b39Sanil kumar appana             }
31298705b39Sanil kumar appana             else if (!intrusionStatus->compare("TamperingDetected"))
31398705b39Sanil kumar appana             {
31498705b39Sanil kumar appana                 status =
31598705b39Sanil kumar appana                     static_cast<uint8_t>(IntrusionStatus::tamperingDetected);
31698705b39Sanil kumar appana             }
31798705b39Sanil kumar appana             else
31898705b39Sanil kumar appana             {
31998705b39Sanil kumar appana                 return ipmi::responseUnspecifiedError();
32098705b39Sanil kumar appana             }
32198705b39Sanil kumar appana             return ipmi::responseSuccess(status, std::nullopt);
32298705b39Sanil kumar appana         }
32338d2b5a6SJason M. Bills         case SmSignalGet::smFanPwmGet:
32438d2b5a6SJason M. Bills         {
325a3702c1fSVernon Mauery             ipmi::Value reply;
326147daec5SRichard Marian Thomaiyar             std::string fullPath = fanPwmPath + std::to_string(instance + 1);
32738d2b5a6SJason M. Bills             if (mtm.getProperty(fanService, fullPath, fanIntf, "Value",
32838d2b5a6SJason M. Bills                                 &reply) < 0)
32938d2b5a6SJason M. Bills             {
33038d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
33138d2b5a6SJason M. Bills             }
33238d2b5a6SJason M. Bills             double* doubleVal = std::get_if<double>(&reply);
33338d2b5a6SJason M. Bills             if (doubleVal == nullptr)
33438d2b5a6SJason M. Bills             {
33538d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
33638d2b5a6SJason M. Bills             }
33738d2b5a6SJason M. Bills             uint8_t sensorVal = std::round(*doubleVal);
338357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
33938d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, std::nullopt);
34038d2b5a6SJason M. Bills         }
34138d2b5a6SJason M. Bills         break;
34238d2b5a6SJason M. Bills         case SmSignalGet::smFanTachometerGet:
34338d2b5a6SJason M. Bills         {
344147daec5SRichard Marian Thomaiyar             boost::system::error_code ec;
345147daec5SRichard Marian Thomaiyar             using objFlatMap = boost::container::flat_map<
346147daec5SRichard Marian Thomaiyar                 std::string, boost::container::flat_map<
347147daec5SRichard Marian Thomaiyar                                  std::string, std::vector<std::string>>>;
348147daec5SRichard Marian Thomaiyar 
349357ddc74SRichard Marian Thomaiyar             auto flatMap = ctx->bus->yield_method_call<objFlatMap>(
350357ddc74SRichard Marian Thomaiyar                 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
351147daec5SRichard Marian Thomaiyar                 "/xyz/openbmc_project/object_mapper",
352147daec5SRichard Marian Thomaiyar                 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
353147daec5SRichard Marian Thomaiyar                 fanTachBasePath, 0, std::array<const char*, 1>{fanIntf});
354147daec5SRichard Marian Thomaiyar             if (ec)
355147daec5SRichard Marian Thomaiyar             {
356147daec5SRichard Marian Thomaiyar                 phosphor::logging::log<phosphor::logging::level::ERR>(
357147daec5SRichard Marian Thomaiyar                     "Failed to query fan tach sub tree objects");
358147daec5SRichard Marian Thomaiyar                 return ipmi::responseUnspecifiedError();
359147daec5SRichard Marian Thomaiyar             }
360147daec5SRichard Marian Thomaiyar             if (instance >= flatMap.size())
36138d2b5a6SJason M. Bills             {
36238d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
36338d2b5a6SJason M. Bills             }
364147daec5SRichard Marian Thomaiyar             auto itr = flatMap.nth(instance);
36538d2b5a6SJason M. Bills             ipmi::Value reply;
366147daec5SRichard Marian Thomaiyar             if (mtm.getProperty(fanService, itr->first, fanIntf, "Value",
36738d2b5a6SJason M. Bills                                 &reply) < 0)
36838d2b5a6SJason M. Bills             {
36938d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
37038d2b5a6SJason M. Bills             }
37138d2b5a6SJason M. Bills 
37238d2b5a6SJason M. Bills             double* doubleVal = std::get_if<double>(&reply);
37338d2b5a6SJason M. Bills             if (doubleVal == nullptr)
37438d2b5a6SJason M. Bills             {
37538d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
37638d2b5a6SJason M. Bills             }
37738d2b5a6SJason M. Bills             uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT;
37838d2b5a6SJason M. Bills             std::optional<uint16_t> fanTach = std::round(*doubleVal);
37938d2b5a6SJason M. Bills 
380357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
38138d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, fanTach);
38238d2b5a6SJason M. Bills         }
38338d2b5a6SJason M. Bills         break;
3848e5e2b04SRichard Marian Thomaiyar         case SmSignalGet::smIdentifyButton:
3858e5e2b04SRichard Marian Thomaiyar         {
3868e5e2b04SRichard Marian Thomaiyar             if (action == SmActionGet::revert || action == SmActionGet::ignore)
3878e5e2b04SRichard Marian Thomaiyar             {
3888e5e2b04SRichard Marian Thomaiyar                 // ButtonMasked property is not supported for ID button as it is
3898e5e2b04SRichard Marian Thomaiyar                 // unnecessary. Hence if requested for revert / ignore, override
3908e5e2b04SRichard Marian Thomaiyar                 // it to sample action to make tools happy.
3918e5e2b04SRichard Marian Thomaiyar                 action = SmActionGet::sample;
3928e5e2b04SRichard Marian Thomaiyar             }
3938e5e2b04SRichard Marian Thomaiyar             // fall-through
3948e5e2b04SRichard Marian Thomaiyar         }
39538d2b5a6SJason M. Bills         case SmSignalGet::smResetButton:
39638d2b5a6SJason M. Bills         case SmSignalGet::smPowerButton:
39738d2b5a6SJason M. Bills         case SmSignalGet::smNMIButton:
39838d2b5a6SJason M. Bills         {
39938d2b5a6SJason M. Bills             std::string path;
40038d2b5a6SJason M. Bills             if (getGpioPathForSmSignal(signalType, path) < 0)
40138d2b5a6SJason M. Bills             {
40238d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
40338d2b5a6SJason M. Bills             }
404a3702c1fSVernon Mauery 
405a3702c1fSVernon Mauery             switch (action)
406a3702c1fSVernon Mauery             {
407a3702c1fSVernon Mauery                 case SmActionGet::sample:
408a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
409a3702c1fSVernon Mauery                         "case SmActionGet::sample");
410a3702c1fSVernon Mauery                     break;
411a3702c1fSVernon Mauery                 case SmActionGet::ignore:
412a3702c1fSVernon Mauery                 {
413a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
414a3702c1fSVernon Mauery                         "case SmActionGet::ignore");
41538d2b5a6SJason M. Bills                     if (mtm.setProperty(buttonService, path, buttonIntf,
41638d2b5a6SJason M. Bills                                         "ButtonMasked", true) < 0)
417a3702c1fSVernon Mauery                     {
41838d2b5a6SJason M. Bills                         return ipmi::responseUnspecifiedError();
419a3702c1fSVernon Mauery                     }
420a3702c1fSVernon Mauery                 }
421a3702c1fSVernon Mauery                 break;
422a3702c1fSVernon Mauery                 case SmActionGet::revert:
423a3702c1fSVernon Mauery                 {
424a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
425a3702c1fSVernon Mauery                         "case SmActionGet::revert");
42638d2b5a6SJason M. Bills                     if (mtm.setProperty(buttonService, path, buttonIntf,
42738d2b5a6SJason M. Bills                                         "ButtonMasked", false) < 0)
428a3702c1fSVernon Mauery                     {
42938d2b5a6SJason M. Bills                         return ipmi::responseUnspecifiedError();
430a3702c1fSVernon Mauery                     }
431a3702c1fSVernon Mauery                 }
432a3702c1fSVernon Mauery                 break;
433a3702c1fSVernon Mauery 
434a3702c1fSVernon Mauery                 default:
43538d2b5a6SJason M. Bills                     return ipmi::responseInvalidFieldRequest();
436a3702c1fSVernon Mauery                     break;
437a3702c1fSVernon Mauery             }
438a3702c1fSVernon Mauery 
439a3702c1fSVernon Mauery             ipmi::Value reply;
44038d2b5a6SJason M. Bills             if (mtm.getProperty(buttonService, path, buttonIntf,
44138d2b5a6SJason M. Bills                                 "ButtonPressed", &reply) < 0)
442a3702c1fSVernon Mauery             {
44338d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
444a3702c1fSVernon Mauery             }
44538d2b5a6SJason M. Bills             bool* valPtr = std::get_if<bool>(&reply);
44638d2b5a6SJason M. Bills             if (valPtr == nullptr)
447a3702c1fSVernon Mauery             {
44838d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
449a3702c1fSVernon Mauery             }
450357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
45138d2b5a6SJason M. Bills             uint8_t sensorVal = *valPtr;
45238d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, std::nullopt);
453a3702c1fSVernon Mauery         }
454a3702c1fSVernon Mauery         break;
4551b74a210SRichard Marian Thomaiyar         case SmSignalGet::smNcsiDiag:
4561b74a210SRichard Marian Thomaiyar         {
4571b74a210SRichard Marian Thomaiyar             constexpr const char* netBasePath = "/sys/class/net/eth";
4581b74a210SRichard Marian Thomaiyar             constexpr const char* carrierSuffix = "/carrier";
4591b74a210SRichard Marian Thomaiyar             std::ifstream netIfs(netBasePath + std::to_string(instance) +
4601b74a210SRichard Marian Thomaiyar                                  carrierSuffix);
4611b74a210SRichard Marian Thomaiyar             if (!netIfs.good())
4621b74a210SRichard Marian Thomaiyar             {
4631b74a210SRichard Marian Thomaiyar                 return ipmi::responseInvalidFieldRequest();
4641b74a210SRichard Marian Thomaiyar             }
4651b74a210SRichard Marian Thomaiyar             std::string carrier;
4661b74a210SRichard Marian Thomaiyar             netIfs >> carrier;
467357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
4681b74a210SRichard Marian Thomaiyar             return ipmi::responseSuccess(
4691b74a210SRichard Marian Thomaiyar                 static_cast<uint8_t>(std::stoi(carrier)), std::nullopt);
4701b74a210SRichard Marian Thomaiyar         }
4711b74a210SRichard Marian Thomaiyar         break;
472a3702c1fSVernon Mauery         default:
47338d2b5a6SJason M. Bills             return ipmi::responseInvalidFieldRequest();
474a3702c1fSVernon Mauery             break;
475a3702c1fSVernon Mauery     }
476a3702c1fSVernon Mauery }
477a3702c1fSVernon Mauery 
478357ddc74SRichard Marian Thomaiyar ipmi::RspType<> appMTMSetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte,
479357ddc74SRichard Marian Thomaiyar                                 uint8_t instance, uint8_t actionByte,
4805e3bf557SAyushi Smriti                                 std::optional<uint8_t> pwmSpeed)
481a3702c1fSVernon Mauery {
482e0511e5fSAyushi Smriti     // mfg filter logic is used to allow MTM set signal command only in
483e0511e5fSAyushi Smriti     // manfacturing mode.
4845e3bf557SAyushi Smriti 
4855e3bf557SAyushi Smriti     SmSignalSet signalType = static_cast<SmSignalSet>(signalTypeByte);
4865e3bf557SAyushi Smriti     SmActionSet action = static_cast<SmActionSet>(actionByte);
4875e3bf557SAyushi Smriti     Cc retCode = ccSuccess;
48813b0039dSJames Feist     int8_t ret = 0;
4895e3bf557SAyushi Smriti 
4905e3bf557SAyushi Smriti     switch (signalType)
491a3702c1fSVernon Mauery     {
492a3702c1fSVernon Mauery         case SmSignalSet::smPowerFaultLed:
493a3702c1fSVernon Mauery         case SmSignalSet::smSystemReadyLed:
494a3702c1fSVernon Mauery         case SmSignalSet::smIdentifyLed:
4955e3bf557SAyushi Smriti             switch (action)
496a3702c1fSVernon Mauery             {
497a3702c1fSVernon Mauery                 case SmActionSet::forceDeasserted:
498a3702c1fSVernon Mauery                 {
499a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
500a3702c1fSVernon Mauery                         "case SmActionSet::forceDeasserted");
501a3702c1fSVernon Mauery 
5025e3bf557SAyushi Smriti                     retCode = ledStoreAndSet(signalType, std::string("Off"));
5035e3bf557SAyushi Smriti                     if (retCode != ccSuccess)
504a3702c1fSVernon Mauery                     {
5055e3bf557SAyushi Smriti                         return ipmi::response(retCode);
506a3702c1fSVernon Mauery                     }
507a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
508a3702c1fSVernon Mauery                 }
509a3702c1fSVernon Mauery                 break;
510a3702c1fSVernon Mauery                 case SmActionSet::forceAsserted:
511a3702c1fSVernon Mauery                 {
512a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
513a3702c1fSVernon Mauery                         "case SmActionSet::forceAsserted");
514a3702c1fSVernon Mauery 
5155e3bf557SAyushi Smriti                     retCode = ledStoreAndSet(signalType, std::string("On"));
5165e3bf557SAyushi Smriti                     if (retCode != ccSuccess)
517a3702c1fSVernon Mauery                     {
5185e3bf557SAyushi Smriti                         return ipmi::response(retCode);
519a3702c1fSVernon Mauery                     }
520a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
5215e3bf557SAyushi Smriti                     if (SmSignalSet::smPowerFaultLed == signalType)
522a3702c1fSVernon Mauery                     {
523a3702c1fSVernon Mauery                         // Deassert "system ready"
5245e3bf557SAyushi Smriti                         retCode = ledStoreAndSet(SmSignalSet::smSystemReadyLed,
525a3702c1fSVernon Mauery                                                  std::string("Off"));
526a3702c1fSVernon Mauery                     }
5275e3bf557SAyushi Smriti                     else if (SmSignalSet::smSystemReadyLed == signalType)
528a3702c1fSVernon Mauery                     {
529a3702c1fSVernon Mauery                         // Deassert "fault led"
5305e3bf557SAyushi Smriti                         retCode = ledStoreAndSet(SmSignalSet::smPowerFaultLed,
531a3702c1fSVernon Mauery                                                  std::string("Off"));
532a3702c1fSVernon Mauery                     }
533a3702c1fSVernon Mauery                 }
534a3702c1fSVernon Mauery                 break;
535a3702c1fSVernon Mauery                 case SmActionSet::revert:
536a3702c1fSVernon Mauery                 {
537a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
538a3702c1fSVernon Mauery                         "case SmActionSet::revert");
5395e3bf557SAyushi Smriti                     retCode = ledRevert(signalType);
540a3702c1fSVernon Mauery                 }
541a3702c1fSVernon Mauery                 break;
542a3702c1fSVernon Mauery                 default:
543a3702c1fSVernon Mauery                 {
5445e3bf557SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
545a3702c1fSVernon Mauery                 }
546a3702c1fSVernon Mauery             }
547a3702c1fSVernon Mauery             break;
548a3702c1fSVernon Mauery         case SmSignalSet::smFanPowerSpeed:
549a3702c1fSVernon Mauery         {
5505e3bf557SAyushi Smriti             if ((action == SmActionSet::forceAsserted) && (!pwmSpeed))
551a3702c1fSVernon Mauery             {
5525e3bf557SAyushi Smriti                 return ipmi::responseReqDataLenInvalid();
553a3702c1fSVernon Mauery             }
5545e3bf557SAyushi Smriti 
5555e3bf557SAyushi Smriti             if ((action == SmActionSet::forceAsserted) && (*pwmSpeed > 100))
5565e3bf557SAyushi Smriti             {
5575e3bf557SAyushi Smriti                 return ipmi::responseInvalidFieldRequest();
5585e3bf557SAyushi Smriti             }
5595e3bf557SAyushi Smriti 
560a3702c1fSVernon Mauery             uint8_t pwmValue = 0;
5615e3bf557SAyushi Smriti             switch (action)
562a3702c1fSVernon Mauery             {
563a3702c1fSVernon Mauery                 case SmActionSet::revert:
564a3702c1fSVernon Mauery                 {
565a3702c1fSVernon Mauery                     if (mtm.revertFanPWM)
566a3702c1fSVernon Mauery                     {
567a3702c1fSVernon Mauery                         ret = mtm.disablePidControlService(false);
568a3702c1fSVernon Mauery                         if (ret < 0)
569a3702c1fSVernon Mauery                         {
5705e3bf557SAyushi Smriti                             return ipmi::responseUnspecifiedError();
571a3702c1fSVernon Mauery                         }
572a3702c1fSVernon Mauery                         mtm.revertFanPWM = false;
573a3702c1fSVernon Mauery                     }
574a3702c1fSVernon Mauery                 }
575a3702c1fSVernon Mauery                 break;
576a3702c1fSVernon Mauery                 case SmActionSet::forceAsserted:
577a3702c1fSVernon Mauery                 {
5785e3bf557SAyushi Smriti                     pwmValue = *pwmSpeed;
579a3702c1fSVernon Mauery                 } // fall-through
580a3702c1fSVernon Mauery                 case SmActionSet::forceDeasserted:
581a3702c1fSVernon Mauery                 {
582a3702c1fSVernon Mauery                     if (!mtm.revertFanPWM)
583a3702c1fSVernon Mauery                     {
584a3702c1fSVernon Mauery                         ret = mtm.disablePidControlService(true);
585a3702c1fSVernon Mauery                         if (ret < 0)
586a3702c1fSVernon Mauery                         {
5875e3bf557SAyushi Smriti                             return ipmi::responseUnspecifiedError();
588a3702c1fSVernon Mauery                         }
589a3702c1fSVernon Mauery                         mtm.revertFanPWM = true;
590a3702c1fSVernon Mauery                     }
591a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
592a3702c1fSVernon Mauery                     std::string fanPwmInstancePath =
5935e3bf557SAyushi Smriti                         fanPwmPath + std::to_string(instance + 1);
594a3702c1fSVernon Mauery 
5955e3bf557SAyushi Smriti                     ret =
5965e3bf557SAyushi Smriti                         mtm.setProperty(fanService, fanPwmInstancePath, fanIntf,
5975e3bf557SAyushi Smriti                                         "Value", static_cast<double>(pwmValue));
598a3702c1fSVernon Mauery                     if (ret < 0)
599a3702c1fSVernon Mauery                     {
6005e3bf557SAyushi Smriti                         return ipmi::responseUnspecifiedError();
601a3702c1fSVernon Mauery                     }
602a3702c1fSVernon Mauery                 }
603a3702c1fSVernon Mauery                 break;
604a3702c1fSVernon Mauery                 default:
605a3702c1fSVernon Mauery                 {
6065e3bf557SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
607a3702c1fSVernon Mauery                 }
608a3702c1fSVernon Mauery             }
609a3702c1fSVernon Mauery         }
610a3702c1fSVernon Mauery         break;
611d872a4a4SAyushi Smriti         case SmSignalSet::smSpeaker:
612d872a4a4SAyushi Smriti         {
613d872a4a4SAyushi Smriti             phosphor::logging::log<phosphor::logging::level::INFO>(
614d872a4a4SAyushi Smriti                 "Performing Speaker SmActionSet",
615d872a4a4SAyushi Smriti                 phosphor::logging::entry("ACTION=%d",
616d872a4a4SAyushi Smriti                                          static_cast<uint8_t>(action)));
617d872a4a4SAyushi Smriti             switch (action)
618d872a4a4SAyushi Smriti             {
619d872a4a4SAyushi Smriti                 case SmActionSet::forceAsserted:
620d872a4a4SAyushi Smriti                 {
621d872a4a4SAyushi Smriti                     char beepDevName[] = "/dev/input/event0";
622d872a4a4SAyushi Smriti                     if (mtm.mtmTestBeepFd != -1)
623d872a4a4SAyushi Smriti                     {
624d872a4a4SAyushi Smriti                         phosphor::logging::log<phosphor::logging::level::INFO>(
625d872a4a4SAyushi Smriti                             "mtm beep device is opened already!");
626d872a4a4SAyushi Smriti                         // returning success as already beep is in progress
627d872a4a4SAyushi Smriti                         return ipmi::response(retCode);
628d872a4a4SAyushi Smriti                     }
629d872a4a4SAyushi Smriti 
630d872a4a4SAyushi Smriti                     if ((mtm.mtmTestBeepFd =
631d872a4a4SAyushi Smriti                              ::open(beepDevName, O_RDWR | O_CLOEXEC)) < 0)
632d872a4a4SAyushi Smriti                     {
633d872a4a4SAyushi Smriti                         phosphor::logging::log<phosphor::logging::level::ERR>(
634d872a4a4SAyushi Smriti                             "Failed to open input device");
635d872a4a4SAyushi Smriti                         return ipmi::responseUnspecifiedError();
636d872a4a4SAyushi Smriti                     }
637d872a4a4SAyushi Smriti 
638d872a4a4SAyushi Smriti                     struct input_event event;
639d872a4a4SAyushi Smriti                     event.type = EV_SND;
640d872a4a4SAyushi Smriti                     event.code = SND_TONE;
641d872a4a4SAyushi Smriti                     event.value = 2000;
642d872a4a4SAyushi Smriti 
643d872a4a4SAyushi Smriti                     if (::write(mtm.mtmTestBeepFd, &event,
644d872a4a4SAyushi Smriti                                 sizeof(struct input_event)) !=
645d872a4a4SAyushi Smriti                         sizeof(struct input_event))
646d872a4a4SAyushi Smriti                     {
647d872a4a4SAyushi Smriti                         phosphor::logging::log<phosphor::logging::level::ERR>(
648d872a4a4SAyushi Smriti                             "Failed to write a tone sound event");
649d872a4a4SAyushi Smriti                         ::close(mtm.mtmTestBeepFd);
650d872a4a4SAyushi Smriti                         mtm.mtmTestBeepFd = -1;
651d872a4a4SAyushi Smriti                         return ipmi::responseUnspecifiedError();
652d872a4a4SAyushi Smriti                     }
653d872a4a4SAyushi Smriti                     mtm.revertTimer.start(revertTimeOut);
654d872a4a4SAyushi Smriti                 }
655d872a4a4SAyushi Smriti                 break;
656d872a4a4SAyushi Smriti                 case SmActionSet::revert:
657d872a4a4SAyushi Smriti                 case SmActionSet::forceDeasserted:
658d872a4a4SAyushi Smriti                 {
659d872a4a4SAyushi Smriti                     if (mtm.mtmTestBeepFd != -1)
660d872a4a4SAyushi Smriti                     {
661d872a4a4SAyushi Smriti                         ::close(mtm.mtmTestBeepFd);
662d872a4a4SAyushi Smriti                         mtm.mtmTestBeepFd = -1;
663d872a4a4SAyushi Smriti                     }
664d872a4a4SAyushi Smriti                 }
665d872a4a4SAyushi Smriti                 break;
666d872a4a4SAyushi Smriti                 default:
667d872a4a4SAyushi Smriti                 {
668d872a4a4SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
669d872a4a4SAyushi Smriti                 }
670d872a4a4SAyushi Smriti             }
671d872a4a4SAyushi Smriti         }
672d872a4a4SAyushi Smriti         break;
6733594c6d6SRichard Marian Thomaiyar         case SmSignalSet::smDiskFaultLed:
6743594c6d6SRichard Marian Thomaiyar         {
6753594c6d6SRichard Marian Thomaiyar             boost::system::error_code ec;
6763594c6d6SRichard Marian Thomaiyar             using objPaths = std::vector<std::string>;
6773594c6d6SRichard Marian Thomaiyar             std::string driveBasePath =
6783594c6d6SRichard Marian Thomaiyar                 "/xyz/openbmc_project/inventory/item/drive/";
6793594c6d6SRichard Marian Thomaiyar             static constexpr const char* driveLedIntf =
6803594c6d6SRichard Marian Thomaiyar                 "xyz.openbmc_project.Led.Group";
6813594c6d6SRichard Marian Thomaiyar             static constexpr const char* hsbpService =
6823594c6d6SRichard Marian Thomaiyar                 "xyz.openbmc_project.HsbpManager";
6833594c6d6SRichard Marian Thomaiyar 
6843594c6d6SRichard Marian Thomaiyar             auto driveList = ctx->bus->yield_method_call<objPaths>(
6853594c6d6SRichard Marian Thomaiyar                 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
6863594c6d6SRichard Marian Thomaiyar                 "/xyz/openbmc_project/object_mapper",
6873594c6d6SRichard Marian Thomaiyar                 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
6883594c6d6SRichard Marian Thomaiyar                 driveBasePath, 0, std::array<const char*, 1>{driveLedIntf});
6893594c6d6SRichard Marian Thomaiyar             if (ec)
6903594c6d6SRichard Marian Thomaiyar             {
6913594c6d6SRichard Marian Thomaiyar                 phosphor::logging::log<phosphor::logging::level::ERR>(
6923594c6d6SRichard Marian Thomaiyar                     "Failed to query HSBP drive sub tree objects");
6933594c6d6SRichard Marian Thomaiyar                 return ipmi::responseUnspecifiedError();
6943594c6d6SRichard Marian Thomaiyar             }
6953594c6d6SRichard Marian Thomaiyar             std::string driveObjPath =
6963594c6d6SRichard Marian Thomaiyar                 driveBasePath + "Drive_" + std::to_string(instance + 1);
6973594c6d6SRichard Marian Thomaiyar             if (std::find(driveList.begin(), driveList.end(), driveObjPath) ==
6983594c6d6SRichard Marian Thomaiyar                 driveList.end())
6993594c6d6SRichard Marian Thomaiyar             {
7003594c6d6SRichard Marian Thomaiyar                 return ipmi::responseInvalidFieldRequest();
7013594c6d6SRichard Marian Thomaiyar             }
7023594c6d6SRichard Marian Thomaiyar             bool driveLedState = false;
7033594c6d6SRichard Marian Thomaiyar             switch (action)
7043594c6d6SRichard Marian Thomaiyar             {
7053594c6d6SRichard Marian Thomaiyar                 case SmActionSet::forceAsserted:
7063594c6d6SRichard Marian Thomaiyar                 {
7073594c6d6SRichard Marian Thomaiyar                     driveLedState = true;
7083594c6d6SRichard Marian Thomaiyar                 }
7093594c6d6SRichard Marian Thomaiyar                 break;
7103594c6d6SRichard Marian Thomaiyar                 case SmActionSet::revert:
7113594c6d6SRichard Marian Thomaiyar                 {
7123594c6d6SRichard Marian Thomaiyar                     driveLedState = false;
7133594c6d6SRichard Marian Thomaiyar                 }
7143594c6d6SRichard Marian Thomaiyar                 break;
7153594c6d6SRichard Marian Thomaiyar                 case SmActionSet::forceDeasserted:
7163594c6d6SRichard Marian Thomaiyar                 {
7173594c6d6SRichard Marian Thomaiyar                     driveLedState = false;
7183594c6d6SRichard Marian Thomaiyar                 }
7193594c6d6SRichard Marian Thomaiyar                 break;
7203594c6d6SRichard Marian Thomaiyar                 default:
7213594c6d6SRichard Marian Thomaiyar                 {
7223594c6d6SRichard Marian Thomaiyar                     return ipmi::responseInvalidFieldRequest();
7233594c6d6SRichard Marian Thomaiyar                 }
7243594c6d6SRichard Marian Thomaiyar             }
7253594c6d6SRichard Marian Thomaiyar             ret = mtm.setProperty(hsbpService, driveObjPath, driveLedIntf,
7263594c6d6SRichard Marian Thomaiyar                                   "Asserted", driveLedState);
7273594c6d6SRichard Marian Thomaiyar             if (ret < 0)
7283594c6d6SRichard Marian Thomaiyar             {
7293594c6d6SRichard Marian Thomaiyar                 return ipmi::responseUnspecifiedError();
7303594c6d6SRichard Marian Thomaiyar             }
7313594c6d6SRichard Marian Thomaiyar         }
7323594c6d6SRichard Marian Thomaiyar         break;
733a3702c1fSVernon Mauery         default:
734a3702c1fSVernon Mauery         {
7355e3bf557SAyushi Smriti             return ipmi::responseInvalidFieldRequest();
736a3702c1fSVernon Mauery         }
737a3702c1fSVernon Mauery     }
7384cc10159SRichard Marian Thomaiyar     if (retCode == ccSuccess)
7394cc10159SRichard Marian Thomaiyar     {
740357ddc74SRichard Marian Thomaiyar         resetMtmTimer(ctx);
7414cc10159SRichard Marian Thomaiyar     }
7425e3bf557SAyushi Smriti     return ipmi::response(retCode);
743a3702c1fSVernon Mauery }
744a3702c1fSVernon Mauery 
745357ddc74SRichard Marian Thomaiyar ipmi::RspType<> mtmKeepAlive(ipmi::Context::ptr ctx, uint8_t reserved,
746666dd01cSRichard Marian Thomaiyar                              const std::array<char, 5>& intentionalSignature)
747666dd01cSRichard Marian Thomaiyar {
748e0511e5fSAyushi Smriti     // mfg filter logic is used to allow MTM keep alive command only in
749e0511e5fSAyushi Smriti     // manfacturing mode
750e0511e5fSAyushi Smriti 
751666dd01cSRichard Marian Thomaiyar     constexpr std::array<char, 5> signatureOk = {'I', 'N', 'T', 'E', 'L'};
752666dd01cSRichard Marian Thomaiyar     if (intentionalSignature != signatureOk || reserved != 0)
753666dd01cSRichard Marian Thomaiyar     {
754666dd01cSRichard Marian Thomaiyar         return ipmi::responseInvalidFieldRequest();
755666dd01cSRichard Marian Thomaiyar     }
756357ddc74SRichard Marian Thomaiyar     return ipmi::response(resetMtmTimer(ctx));
757666dd01cSRichard Marian Thomaiyar }
758666dd01cSRichard Marian Thomaiyar 
759e0511e5fSAyushi Smriti static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd)
760e0511e5fSAyushi Smriti {
761e0511e5fSAyushi Smriti     return (netFn << 8) | cmd;
762e0511e5fSAyushi Smriti }
763e0511e5fSAyushi Smriti 
76485feb130SYong Li ipmi::Cc mfgFilterMessage(ipmi::message::Request::ptr request)
76585feb130SYong Li {
766e0511e5fSAyushi Smriti     // Restricted commands, must be executed only in Manufacturing mode
767e0511e5fSAyushi Smriti     switch (makeCmdKey(request->ctx->netFn, request->ctx->cmd))
76885feb130SYong Li     {
769e0511e5fSAyushi Smriti         // i2c master write read command needs additional checking
770e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead):
77185feb130SYong Li             if (request->payload.size() > 4)
77285feb130SYong Li             {
773ae13ac62SRichard Marian Thomaiyar                 // Allow write data count > 1 only in Special mode
774ae13ac62SRichard Marian Thomaiyar                 if (mtm.getMfgMode() == SpecialMode::none)
77585feb130SYong Li                 {
77685feb130SYong Li                     return ipmi::ccInsufficientPrivilege;
77785feb130SYong Li                 }
77885feb130SYong Li             }
7792d4a0198Sjayaprakash Mutyala             return ipmi::ccSuccess;
780e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
781e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdGetSmSignal):
782e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
783e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdSetSmSignal):
784e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
785e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdMtmKeepAlive):
786e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
787e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdSetManufacturingData):
788e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
789e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdGetManufacturingData):
790e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdWriteFruData):
79185feb130SYong Li 
792ae13ac62SRichard Marian Thomaiyar             // Check for Special mode
793ae13ac62SRichard Marian Thomaiyar             if (mtm.getMfgMode() == SpecialMode::none)
794e0511e5fSAyushi Smriti             {
795e0511e5fSAyushi Smriti                 return ipmi::ccInvalidCommand;
796e0511e5fSAyushi Smriti             }
7972d4a0198Sjayaprakash Mutyala             return ipmi::ccSuccess;
7982d4a0198Sjayaprakash Mutyala         case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdDeleteSelEntry):
7992d4a0198Sjayaprakash Mutyala         {
8002d4a0198Sjayaprakash Mutyala             return ipmi::ccInvalidCommand;
8012d4a0198Sjayaprakash Mutyala         }
802e0511e5fSAyushi Smriti     }
80385feb130SYong Li     return ipmi::ccSuccess;
80485feb130SYong Li }
80585feb130SYong Li 
8061f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxEthSize = 6;
8071f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxSupportedEth = 3;
8081f0839c2SRichard Marian Thomaiyar static constexpr const char* factoryEthAddrBaseFileName =
8091f0839c2SRichard Marian Thomaiyar     "/var/sofs/factory-settings/network/mac/eth";
8101f0839c2SRichard Marian Thomaiyar 
811357ddc74SRichard Marian Thomaiyar ipmi::RspType<> setManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType,
8121f0839c2SRichard Marian Thomaiyar                                      std::array<uint8_t, maxEthSize> ethData)
8131f0839c2SRichard Marian Thomaiyar {
8141f0839c2SRichard Marian Thomaiyar     // mfg filter logic will restrict this command executing only in mfg mode.
8151f0839c2SRichard Marian Thomaiyar     if (dataType >= maxSupportedEth)
8161f0839c2SRichard Marian Thomaiyar     {
8171f0839c2SRichard Marian Thomaiyar         return ipmi::responseParmOutOfRange();
8181f0839c2SRichard Marian Thomaiyar     }
8191f0839c2SRichard Marian Thomaiyar 
8201f0839c2SRichard Marian Thomaiyar     constexpr uint8_t invalidData = 0;
8211f0839c2SRichard Marian Thomaiyar     constexpr uint8_t validData = 1;
8221f0839c2SRichard Marian Thomaiyar     constexpr uint8_t ethAddrStrSize =
8231f0839c2SRichard Marian Thomaiyar         19; // XX:XX:XX:XX:XX:XX + \n + null termination;
8241f0839c2SRichard Marian Thomaiyar     std::vector<uint8_t> buff(ethAddrStrSize);
8251f0839c2SRichard Marian Thomaiyar     std::snprintf(reinterpret_cast<char*>(buff.data()), ethAddrStrSize,
8261f0839c2SRichard Marian Thomaiyar                   "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", ethData.at(0),
8271f0839c2SRichard Marian Thomaiyar                   ethData.at(1), ethData.at(2), ethData.at(3), ethData.at(4),
8281f0839c2SRichard Marian Thomaiyar                   ethData.at(5));
8291f0839c2SRichard Marian Thomaiyar     std::ofstream oEthFile(factoryEthAddrBaseFileName +
8301f0839c2SRichard Marian Thomaiyar                                std::to_string(dataType),
8311f0839c2SRichard Marian Thomaiyar                            std::ofstream::out);
8321f0839c2SRichard Marian Thomaiyar     if (!oEthFile.good())
8331f0839c2SRichard Marian Thomaiyar     {
8341f0839c2SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
8351f0839c2SRichard Marian Thomaiyar     }
8361f0839c2SRichard Marian Thomaiyar 
8371f0839c2SRichard Marian Thomaiyar     oEthFile << reinterpret_cast<char*>(buff.data());
8381f0839c2SRichard Marian Thomaiyar     oEthFile << fflush;
8391f0839c2SRichard Marian Thomaiyar     oEthFile.close();
8401f0839c2SRichard Marian Thomaiyar 
841357ddc74SRichard Marian Thomaiyar     resetMtmTimer(ctx);
8421f0839c2SRichard Marian Thomaiyar     return ipmi::responseSuccess();
8431f0839c2SRichard Marian Thomaiyar }
8441f0839c2SRichard Marian Thomaiyar 
8451f0839c2SRichard Marian Thomaiyar ipmi::RspType<uint8_t, std::array<uint8_t, maxEthSize>>
846357ddc74SRichard Marian Thomaiyar     getManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType)
8471f0839c2SRichard Marian Thomaiyar {
8481f0839c2SRichard Marian Thomaiyar     // mfg filter logic will restrict this command executing only in mfg mode.
8491f0839c2SRichard Marian Thomaiyar     if (dataType >= maxSupportedEth)
8501f0839c2SRichard Marian Thomaiyar     {
8511f0839c2SRichard Marian Thomaiyar         return ipmi::responseParmOutOfRange();
8521f0839c2SRichard Marian Thomaiyar     }
8531f0839c2SRichard Marian Thomaiyar     std::array<uint8_t, maxEthSize> ethData{0};
8541f0839c2SRichard Marian Thomaiyar     constexpr uint8_t invalidData = 0;
8551f0839c2SRichard Marian Thomaiyar     constexpr uint8_t validData = 1;
8561f0839c2SRichard Marian Thomaiyar 
8571f0839c2SRichard Marian Thomaiyar     std::ifstream iEthFile(factoryEthAddrBaseFileName +
8581f0839c2SRichard Marian Thomaiyar                                std::to_string(dataType),
8591f0839c2SRichard Marian Thomaiyar                            std::ifstream::in);
8601f0839c2SRichard Marian Thomaiyar     if (!iEthFile.good())
8611f0839c2SRichard Marian Thomaiyar     {
8621f0839c2SRichard Marian Thomaiyar         return ipmi::responseSuccess(invalidData, ethData);
8631f0839c2SRichard Marian Thomaiyar     }
8641f0839c2SRichard Marian Thomaiyar     std::string ethStr;
8651f0839c2SRichard Marian Thomaiyar     iEthFile >> ethStr;
8661f0839c2SRichard Marian Thomaiyar     uint8_t* data = ethData.data();
8671f0839c2SRichard Marian Thomaiyar     std::sscanf(ethStr.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
8681f0839c2SRichard Marian Thomaiyar                 data, (data + 1), (data + 2), (data + 3), (data + 4),
8691f0839c2SRichard Marian Thomaiyar                 (data + 5));
8701f0839c2SRichard Marian Thomaiyar 
871357ddc74SRichard Marian Thomaiyar     resetMtmTimer(ctx);
8721f0839c2SRichard Marian Thomaiyar     return ipmi::responseSuccess(validData, ethData);
8731f0839c2SRichard Marian Thomaiyar }
8741f0839c2SRichard Marian Thomaiyar 
875f267a67dSYong Li /** @brief implements slot master write read IPMI command which can be used for
876f267a67dSYong Li  * low-level I2C/SMBus write, read or write-read access for PCIE slots
877f267a67dSYong Li  * @param reserved - skip 6 bit
878f267a67dSYong Li  * @param addressType - address type
879f267a67dSYong Li  * @param bbSlotNum - baseboard slot number
880f267a67dSYong Li  * @param riserSlotNum - riser slot number
881f267a67dSYong Li  * @param reserved2 - skip 2 bit
882f267a67dSYong Li  * @param slaveAddr - slave address
883f267a67dSYong Li  * @param readCount - number of bytes to be read
884f267a67dSYong Li  * @param writeData - data to be written
885f267a67dSYong Li  *
886f267a67dSYong Li  * @returns IPMI completion code plus response data
887f267a67dSYong Li  */
888f267a67dSYong Li ipmi::RspType<std::vector<uint8_t>>
889f267a67dSYong Li     appSlotI2CMasterWriteRead(uint6_t reserved, uint2_t addressType,
890f267a67dSYong Li                               uint3_t bbSlotNum, uint3_t riserSlotNum,
891f267a67dSYong Li                               uint2_t resvered2, uint8_t slaveAddr,
892f267a67dSYong Li                               uint8_t readCount, std::vector<uint8_t> writeData)
893f267a67dSYong Li {
894f267a67dSYong Li     const size_t writeCount = writeData.size();
895f267a67dSYong Li     std::string i2cBus;
896f267a67dSYong Li     if (addressType == slotAddressTypeBus)
897f267a67dSYong Li     {
898f267a67dSYong Li         std::string path = "/dev/i2c-mux/Riser_" +
899f267a67dSYong Li                            std::to_string(static_cast<uint8_t>(bbSlotNum)) +
900f267a67dSYong Li                            "_Mux/Pcie_Slot_" +
901f267a67dSYong Li                            std::to_string(static_cast<uint8_t>(riserSlotNum));
902f267a67dSYong Li 
903f267a67dSYong Li         if (std::filesystem::exists(path) && std::filesystem::is_symlink(path))
904f267a67dSYong Li         {
905f267a67dSYong Li             i2cBus = std::filesystem::read_symlink(path);
906f267a67dSYong Li         }
907f267a67dSYong Li         else
908f267a67dSYong Li         {
909f267a67dSYong Li             phosphor::logging::log<phosphor::logging::level::ERR>(
910f267a67dSYong Li                 "Master write read command: Cannot get BusID");
911f267a67dSYong Li             return ipmi::responseInvalidFieldRequest();
912f267a67dSYong Li         }
913f267a67dSYong Li     }
914f267a67dSYong Li     else if (addressType == slotAddressTypeUniqueid)
915f267a67dSYong Li     {
916f267a67dSYong Li         i2cBus = "/dev/i2c-" +
917f267a67dSYong Li                  std::to_string(static_cast<uint8_t>(bbSlotNum) |
918f267a67dSYong Li                                 (static_cast<uint8_t>(riserSlotNum) << 3));
919f267a67dSYong Li     }
920f267a67dSYong Li     else
921f267a67dSYong Li     {
922f267a67dSYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
923f267a67dSYong Li             "Master write read command: invalid request");
924f267a67dSYong Li         return ipmi::responseInvalidFieldRequest();
925f267a67dSYong Li     }
926f267a67dSYong Li 
927f267a67dSYong Li     // Allow single byte write as it is offset byte to read the data, rest allow
928ae13ac62SRichard Marian Thomaiyar     // only in Special mode.
929f267a67dSYong Li     if (writeCount > 1)
930f267a67dSYong Li     {
931ae13ac62SRichard Marian Thomaiyar         if (mtm.getMfgMode() == SpecialMode::none)
932f267a67dSYong Li         {
933f267a67dSYong Li             return ipmi::responseInsufficientPrivilege();
934f267a67dSYong Li         }
935f267a67dSYong Li     }
936f267a67dSYong Li 
937f267a67dSYong Li     if (readCount > slotI2CMaxReadSize)
938f267a67dSYong Li     {
939f267a67dSYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
940f267a67dSYong Li             "Master write read command: Read count exceeds limit");
941f267a67dSYong Li         return ipmi::responseParmOutOfRange();
942f267a67dSYong Li     }
943f267a67dSYong Li 
944f267a67dSYong Li     if (!readCount && !writeCount)
945f267a67dSYong Li     {
946f267a67dSYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
947f267a67dSYong Li             "Master write read command: Read & write count are 0");
948f267a67dSYong Li         return ipmi::responseInvalidFieldRequest();
949f267a67dSYong Li     }
950f267a67dSYong Li 
951f267a67dSYong Li     std::vector<uint8_t> readBuf(readCount);
952f267a67dSYong Li 
953f267a67dSYong Li     ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf);
954f267a67dSYong Li     if (retI2C != ipmi::ccSuccess)
955f267a67dSYong Li     {
956f267a67dSYong Li         return ipmi::response(retI2C);
957f267a67dSYong Li     }
958f267a67dSYong Li 
959f267a67dSYong Li     return ipmi::responseSuccess(readBuf);
960f267a67dSYong Li }
961068b4f2cSYong Li 
962068b4f2cSYong Li ipmi::RspType<> clearCMOS()
963068b4f2cSYong Li {
964d0d010b7SYong Li     // There is an i2c device on bus 4, the slave address is 0x38. Based on the
965*eaeb6cb0SYong Li     // spec, writing 0x1 to address 0x61 on this device, will trigger the clear
966068b4f2cSYong Li     // CMOS action.
967d0d010b7SYong Li     constexpr uint8_t slaveAddr = 0x38;
968068b4f2cSYong Li     std::string i2cBus = "/dev/i2c-4";
969*eaeb6cb0SYong Li     std::vector<uint8_t> writeData = {0x61, 0x1};
970068b4f2cSYong Li     std::vector<uint8_t> readBuf(0);
971068b4f2cSYong Li 
972ae13ac62SRichard Marian Thomaiyar     if (mtm.getMfgMode() == SpecialMode::none)
973068b4f2cSYong Li     {
974068b4f2cSYong Li         return ipmi::responseInsufficientPrivilege();
975068b4f2cSYong Li     }
976068b4f2cSYong Li 
977068b4f2cSYong Li     ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf);
978068b4f2cSYong Li     return ipmi::response(retI2C);
979068b4f2cSYong Li }
980a3702c1fSVernon Mauery } // namespace ipmi
981a3702c1fSVernon Mauery 
982a3702c1fSVernon Mauery void register_mtm_commands() __attribute__((constructor));
983a3702c1fSVernon Mauery void register_mtm_commands()
984a3702c1fSVernon Mauery {
98538d2b5a6SJason M. Bills     // <Get SM Signal>
98698bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
98798bbf69aSVernon Mauery                           ipmi::intel::general::cmdGetSmSignal,
9885e3bf557SAyushi Smriti                           ipmi::Privilege::Admin, ipmi::appMTMGetSignal);
989a3702c1fSVernon Mauery 
99098bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
99198bbf69aSVernon Mauery                           ipmi::intel::general::cmdSetSmSignal,
9925e3bf557SAyushi Smriti                           ipmi::Privilege::Admin, ipmi::appMTMSetSignal);
993a3702c1fSVernon Mauery 
99498bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
99598bbf69aSVernon Mauery                           ipmi::intel::general::cmdMtmKeepAlive,
996666dd01cSRichard Marian Thomaiyar                           ipmi::Privilege::Admin, ipmi::mtmKeepAlive);
997666dd01cSRichard Marian Thomaiyar 
99898bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
99998bbf69aSVernon Mauery                           ipmi::intel::general::cmdSetManufacturingData,
10001f0839c2SRichard Marian Thomaiyar                           ipmi::Privilege::Admin, ipmi::setManufacturingData);
10011f0839c2SRichard Marian Thomaiyar 
100298bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
100398bbf69aSVernon Mauery                           ipmi::intel::general::cmdGetManufacturingData,
10041f0839c2SRichard Marian Thomaiyar                           ipmi::Privilege::Admin, ipmi::getManufacturingData);
10051f0839c2SRichard Marian Thomaiyar 
100698bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
100798bbf69aSVernon Mauery                           ipmi::intel::general::cmdSlotI2CMasterWriteRead,
100898bbf69aSVernon Mauery                           ipmi::Privilege::Admin,
100998bbf69aSVernon Mauery                           ipmi::appSlotI2CMasterWriteRead);
1010f267a67dSYong Li 
1011068b4f2cSYong Li     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnPlatform,
1012068b4f2cSYong Li                           ipmi::intel::platform::cmdClearCMOS,
1013068b4f2cSYong Li                           ipmi::Privilege::Admin, ipmi::clearCMOS);
1014068b4f2cSYong Li 
101598bbf69aSVernon Mauery     ipmi::registerFilter(ipmi::prioOemBase,
101685feb130SYong Li                          [](ipmi::message::Request::ptr request) {
101785feb130SYong Li                              return ipmi::mfgFilterMessage(request);
101885feb130SYong Li                          });
1019a3702c1fSVernon Mauery }
1020