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 
19*06584cd0SArun P. Mohanan #include <boost/algorithm/string.hpp>
20147daec5SRichard Marian Thomaiyar #include <boost/container/flat_map.hpp>
21a3702c1fSVernon Mauery #include <ipmid/api.hpp>
22a3702c1fSVernon Mauery #include <manufacturingcommands.hpp>
23a3702c1fSVernon Mauery #include <oemcommands.hpp>
24a3702c1fSVernon Mauery 
25fcd2d3a9SJames Feist #include <filesystem>
26fcd2d3a9SJames Feist #include <fstream>
27fcd2d3a9SJames Feist 
28a3702c1fSVernon Mauery namespace ipmi
29a3702c1fSVernon Mauery {
30a3702c1fSVernon Mauery 
31a3702c1fSVernon Mauery Manufacturing mtm;
32a3702c1fSVernon Mauery 
33a3702c1fSVernon Mauery static auto revertTimeOut =
34a3702c1fSVernon Mauery     std::chrono::duration_cast<std::chrono::microseconds>(
35a3702c1fSVernon Mauery         std::chrono::seconds(60)); // 1 minute timeout
36a3702c1fSVernon Mauery 
37f267a67dSYong Li static constexpr uint8_t slotAddressTypeBus = 0;
38f267a67dSYong Li static constexpr uint8_t slotAddressTypeUniqueid = 1;
39f267a67dSYong Li static constexpr uint8_t slotI2CMaxReadSize = 35;
40f267a67dSYong Li 
41a3702c1fSVernon Mauery static constexpr const char* callbackMgrService =
42a3702c1fSVernon Mauery     "xyz.openbmc_project.CallbackManager";
43a3702c1fSVernon Mauery static constexpr const char* callbackMgrIntf =
44a3702c1fSVernon Mauery     "xyz.openbmc_project.CallbackManager";
45a3702c1fSVernon Mauery static constexpr const char* callbackMgrObjPath =
46a3702c1fSVernon Mauery     "/xyz/openbmc_project/CallbackManager";
47a3702c1fSVernon Mauery static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate";
48a3702c1fSVernon Mauery 
49a3702c1fSVernon Mauery const static constexpr char* systemDService = "org.freedesktop.systemd1";
50a3702c1fSVernon Mauery const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1";
51a3702c1fSVernon Mauery const static constexpr char* systemDMgrIntf =
52a3702c1fSVernon Mauery     "org.freedesktop.systemd1.Manager";
53a3702c1fSVernon Mauery const static constexpr char* pidControlService = "phosphor-pid-control.service";
54a3702c1fSVernon Mauery 
55357ddc74SRichard Marian Thomaiyar static inline Cc resetMtmTimer(ipmi::Context::ptr ctx)
56666dd01cSRichard Marian Thomaiyar {
57666dd01cSRichard Marian Thomaiyar     boost::system::error_code ec;
58357ddc74SRichard Marian Thomaiyar     ctx->bus->yield_method_call<>(ctx->yield, ec, specialModeService,
59666dd01cSRichard Marian Thomaiyar                                   specialModeObjPath, specialModeIntf,
60666dd01cSRichard Marian Thomaiyar                                   "ResetTimer");
61666dd01cSRichard Marian Thomaiyar     if (ec)
62666dd01cSRichard Marian Thomaiyar     {
63666dd01cSRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
64666dd01cSRichard Marian Thomaiyar             "Failed to reset the manufacturing mode timer");
65666dd01cSRichard Marian Thomaiyar         return ccUnspecifiedError;
66666dd01cSRichard Marian Thomaiyar     }
67666dd01cSRichard Marian Thomaiyar     return ccSuccess;
68666dd01cSRichard Marian Thomaiyar }
69666dd01cSRichard Marian Thomaiyar 
7038d2b5a6SJason M. Bills int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path)
71a3702c1fSVernon Mauery {
7238d2b5a6SJason M. Bills     switch (signal)
7338d2b5a6SJason M. Bills     {
7438d2b5a6SJason M. Bills         case SmSignalGet::smPowerButton:
7538d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/power";
7638d2b5a6SJason M. Bills             break;
7738d2b5a6SJason M. Bills         case SmSignalGet::smResetButton:
7838d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/reset";
7938d2b5a6SJason M. Bills             break;
8038d2b5a6SJason M. Bills         case SmSignalGet::smNMIButton:
8138d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/nmi";
8238d2b5a6SJason M. Bills             break;
838e5e2b04SRichard Marian Thomaiyar         case SmSignalGet::smIdentifyButton:
848e5e2b04SRichard Marian Thomaiyar             path = "/xyz/openbmc_project/chassis/buttons/id";
858e5e2b04SRichard Marian Thomaiyar             break;
8638d2b5a6SJason M. Bills         default:
8738d2b5a6SJason M. Bills             return -1;
8838d2b5a6SJason M. Bills             break;
8938d2b5a6SJason M. Bills     }
9038d2b5a6SJason M. Bills     return 0;
91a3702c1fSVernon Mauery }
92a3702c1fSVernon Mauery 
9337890392SPatrick Venture ipmi_ret_t ledStoreAndSet(SmSignalSet signal, const std::string& setState)
94a3702c1fSVernon Mauery {
95a3702c1fSVernon Mauery     LedProperty* ledProp = mtm.findLedProperty(signal);
96a3702c1fSVernon Mauery     if (ledProp == nullptr)
97a3702c1fSVernon Mauery     {
98a3702c1fSVernon Mauery         return IPMI_CC_INVALID_FIELD_REQUEST;
99a3702c1fSVernon Mauery     }
100a3702c1fSVernon Mauery 
101a3702c1fSVernon Mauery     std::string ledName = ledProp->getName();
102a3702c1fSVernon Mauery     std::string ledService = ledServicePrefix + ledName;
103a3702c1fSVernon Mauery     std::string ledPath = ledPathPrefix + ledName;
104a3702c1fSVernon Mauery     ipmi::Value presentState;
105a3702c1fSVernon Mauery 
106a3702c1fSVernon Mauery     if (false == ledProp->getLock())
107a3702c1fSVernon Mauery     {
108a3702c1fSVernon Mauery         if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf,
109a3702c1fSVernon Mauery                             "State", &presentState) != 0)
110a3702c1fSVernon Mauery         {
111a3702c1fSVernon Mauery             return IPMI_CC_UNSPECIFIED_ERROR;
112a3702c1fSVernon Mauery         }
113a3702c1fSVernon Mauery         ledProp->setPrevState(std::get<std::string>(presentState));
114a3702c1fSVernon Mauery         ledProp->setLock(true);
115a3702c1fSVernon Mauery         if (signal == SmSignalSet::smPowerFaultLed ||
116a3702c1fSVernon Mauery             signal == SmSignalSet::smSystemReadyLed)
117a3702c1fSVernon Mauery         {
118a3702c1fSVernon Mauery             mtm.revertLedCallback = true;
119a3702c1fSVernon Mauery         }
120a3702c1fSVernon Mauery     }
12138d2b5a6SJason M. Bills     if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
122a3702c1fSVernon Mauery                         ledStateStr + setState) != 0)
123a3702c1fSVernon Mauery     {
124a3702c1fSVernon Mauery         return IPMI_CC_UNSPECIFIED_ERROR;
125a3702c1fSVernon Mauery     }
126a3702c1fSVernon Mauery     return IPMI_CC_OK;
127a3702c1fSVernon Mauery }
128a3702c1fSVernon Mauery 
129a3702c1fSVernon Mauery ipmi_ret_t ledRevert(SmSignalSet signal)
130a3702c1fSVernon Mauery {
131a3702c1fSVernon Mauery     LedProperty* ledProp = mtm.findLedProperty(signal);
132a3702c1fSVernon Mauery     if (ledProp == nullptr)
133a3702c1fSVernon Mauery     {
134a3702c1fSVernon Mauery         return IPMI_CC_INVALID_FIELD_REQUEST;
135a3702c1fSVernon Mauery     }
136a3702c1fSVernon Mauery     if (true == ledProp->getLock())
137a3702c1fSVernon Mauery     {
138a3702c1fSVernon Mauery         ledProp->setLock(false);
139a3702c1fSVernon Mauery         if (signal == SmSignalSet::smPowerFaultLed ||
140a3702c1fSVernon Mauery             signal == SmSignalSet::smSystemReadyLed)
141a3702c1fSVernon Mauery         {
142a3702c1fSVernon Mauery             try
143a3702c1fSVernon Mauery             {
144a3702c1fSVernon Mauery                 ipmi::method_no_args::callDbusMethod(
145a3702c1fSVernon Mauery                     *getSdBus(), callbackMgrService, callbackMgrObjPath,
146a3702c1fSVernon Mauery                     callbackMgrIntf, retriggerLedUpdate);
147a3702c1fSVernon Mauery             }
148a3702c1fSVernon Mauery             catch (sdbusplus::exception_t& e)
149a3702c1fSVernon Mauery             {
150a3702c1fSVernon Mauery                 return IPMI_CC_UNSPECIFIED_ERROR;
151a3702c1fSVernon Mauery             }
152a3702c1fSVernon Mauery             mtm.revertLedCallback = false;
153a3702c1fSVernon Mauery         }
154a3702c1fSVernon Mauery         else
155a3702c1fSVernon Mauery         {
156a3702c1fSVernon Mauery             std::string ledName = ledProp->getName();
157a3702c1fSVernon Mauery             std::string ledService = ledServicePrefix + ledName;
158a3702c1fSVernon Mauery             std::string ledPath = ledPathPrefix + ledName;
15938d2b5a6SJason M. Bills             if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
16038d2b5a6SJason M. Bills                                 ledProp->getPrevState()) != 0)
161a3702c1fSVernon Mauery             {
162a3702c1fSVernon Mauery                 return IPMI_CC_UNSPECIFIED_ERROR;
163a3702c1fSVernon Mauery             }
164a3702c1fSVernon Mauery         }
165a3702c1fSVernon Mauery     }
166a3702c1fSVernon Mauery     return IPMI_CC_OK;
167a3702c1fSVernon Mauery }
168a3702c1fSVernon Mauery 
169a3702c1fSVernon Mauery void Manufacturing::initData()
170a3702c1fSVernon Mauery {
171a3702c1fSVernon Mauery     ledPropertyList.push_back(
172a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smPowerFaultLed, "status_amber"));
173a3702c1fSVernon Mauery     ledPropertyList.push_back(
174a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smSystemReadyLed, "status_green"));
175a3702c1fSVernon Mauery     ledPropertyList.push_back(
176a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smIdentifyLed, "identify"));
177a3702c1fSVernon Mauery }
178a3702c1fSVernon Mauery 
179a3702c1fSVernon Mauery void Manufacturing::revertTimerHandler()
180a3702c1fSVernon Mauery {
181ae13ac62SRichard Marian Thomaiyar 
182ae13ac62SRichard Marian Thomaiyar #ifdef BMC_VALIDATION_UNSECURE_FEATURE
183ae13ac62SRichard Marian Thomaiyar     if (mtm.getMfgMode() == SpecialMode::valUnsecure)
184ae13ac62SRichard Marian Thomaiyar     {
185ae13ac62SRichard Marian Thomaiyar         // Don't revert the behaviour for validation unsecure mode.
186ae13ac62SRichard Marian Thomaiyar         return;
187ae13ac62SRichard Marian Thomaiyar     }
188ae13ac62SRichard Marian Thomaiyar #endif
189a3702c1fSVernon Mauery     if (revertFanPWM)
190a3702c1fSVernon Mauery     {
191a3702c1fSVernon Mauery         revertFanPWM = false;
192a3702c1fSVernon Mauery         disablePidControlService(false);
193a3702c1fSVernon Mauery     }
194a3702c1fSVernon Mauery 
195d872a4a4SAyushi Smriti     if (mtmTestBeepFd != -1)
196d872a4a4SAyushi Smriti     {
197d872a4a4SAyushi Smriti         ::close(mtmTestBeepFd);
198d872a4a4SAyushi Smriti         mtmTestBeepFd = -1;
199d872a4a4SAyushi Smriti     }
200d872a4a4SAyushi Smriti 
201a3702c1fSVernon Mauery     for (const auto& ledProperty : ledPropertyList)
202a3702c1fSVernon Mauery     {
203a3702c1fSVernon Mauery         const std::string& ledName = ledProperty.getName();
204f365614cSJayaprakash Mutyala         if (ledName == "identify" && mtm.getMfgMode() == SpecialMode::mfg)
205f365614cSJayaprakash Mutyala         {
206f365614cSJayaprakash Mutyala             // Don't revert the behaviour for manufacturing mode
207f365614cSJayaprakash Mutyala             continue;
208f365614cSJayaprakash Mutyala         }
209a3702c1fSVernon Mauery         ledRevert(ledProperty.getSignal());
210a3702c1fSVernon Mauery     }
211a3702c1fSVernon Mauery }
212a3702c1fSVernon Mauery 
213a3702c1fSVernon Mauery Manufacturing::Manufacturing() :
214a3702c1fSVernon Mauery     revertTimer([&](void) { revertTimerHandler(); })
215a3702c1fSVernon Mauery {
216a3702c1fSVernon Mauery     initData();
217a3702c1fSVernon Mauery }
218a3702c1fSVernon Mauery 
21938d2b5a6SJason M. Bills int8_t Manufacturing::getProperty(const std::string& service,
22038d2b5a6SJason M. Bills                                   const std::string& path,
22138d2b5a6SJason M. Bills                                   const std::string& interface,
22238d2b5a6SJason M. Bills                                   const std::string& propertyName,
22338d2b5a6SJason M. Bills                                   ipmi::Value* reply)
224a3702c1fSVernon Mauery {
225a3702c1fSVernon Mauery     try
226a3702c1fSVernon Mauery     {
22738d2b5a6SJason M. Bills         *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface,
22838d2b5a6SJason M. Bills                                        propertyName);
229a3702c1fSVernon Mauery     }
230a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
231a3702c1fSVernon Mauery     {
232a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
233a3702c1fSVernon Mauery             "ERROR: getProperty");
234a3702c1fSVernon Mauery         return -1;
235a3702c1fSVernon Mauery     }
236a3702c1fSVernon Mauery 
237a3702c1fSVernon Mauery     return 0;
238a3702c1fSVernon Mauery }
239a3702c1fSVernon Mauery 
24038d2b5a6SJason M. Bills int8_t Manufacturing::setProperty(const std::string& service,
24138d2b5a6SJason M. Bills                                   const std::string& path,
24238d2b5a6SJason M. Bills                                   const std::string& interface,
24338d2b5a6SJason M. Bills                                   const std::string& propertyName,
24438d2b5a6SJason M. Bills                                   ipmi::Value value)
245a3702c1fSVernon Mauery {
246a3702c1fSVernon Mauery     try
247a3702c1fSVernon Mauery     {
24838d2b5a6SJason M. Bills         ipmi::setDbusProperty(*getSdBus(), service, path, interface,
249a3702c1fSVernon Mauery                               propertyName, value);
250a3702c1fSVernon Mauery     }
251a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
252a3702c1fSVernon Mauery     {
253a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
254a3702c1fSVernon Mauery             "ERROR: setProperty");
255a3702c1fSVernon Mauery         return -1;
256a3702c1fSVernon Mauery     }
257a3702c1fSVernon Mauery 
258a3702c1fSVernon Mauery     return 0;
259a3702c1fSVernon Mauery }
260a3702c1fSVernon Mauery 
261a3702c1fSVernon Mauery int8_t Manufacturing::disablePidControlService(const bool disable)
262a3702c1fSVernon Mauery {
263a3702c1fSVernon Mauery     try
264a3702c1fSVernon Mauery     {
265a3702c1fSVernon Mauery         auto dbus = getSdBus();
266a3702c1fSVernon Mauery         auto method = dbus->new_method_call(systemDService, systemDObjPath,
267a3702c1fSVernon Mauery                                             systemDMgrIntf,
268a3702c1fSVernon Mauery                                             disable ? "StopUnit" : "StartUnit");
269a3702c1fSVernon Mauery         method.append(pidControlService, "replace");
270a3702c1fSVernon Mauery         auto reply = dbus->call(method);
271a3702c1fSVernon Mauery     }
272a3702c1fSVernon Mauery     catch (const sdbusplus::exception::SdBusError& e)
273a3702c1fSVernon Mauery     {
274a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
275a3702c1fSVernon Mauery             "ERROR: phosphor-pid-control service start or stop failed");
276a3702c1fSVernon Mauery         return -1;
277a3702c1fSVernon Mauery     }
278a3702c1fSVernon Mauery     return 0;
279a3702c1fSVernon Mauery }
280a3702c1fSVernon Mauery 
28138d2b5a6SJason M. Bills ipmi::RspType<uint8_t,                // Signal value
28238d2b5a6SJason M. Bills               std::optional<uint16_t> // Fan tach value
28338d2b5a6SJason M. Bills               >
284357ddc74SRichard Marian Thomaiyar     appMTMGetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte,
285147daec5SRichard Marian Thomaiyar                     uint8_t instance, uint8_t actionByte)
286a3702c1fSVernon Mauery {
287e0511e5fSAyushi Smriti     // mfg filter logic is used to allow MTM get signal command only in
288e0511e5fSAyushi Smriti     // manfacturing mode.
28938d2b5a6SJason M. Bills 
29038d2b5a6SJason M. Bills     SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte);
29138d2b5a6SJason M. Bills     SmActionGet action = static_cast<SmActionGet>(actionByte);
29238d2b5a6SJason M. Bills 
29338d2b5a6SJason M. Bills     switch (signalType)
29438d2b5a6SJason M. Bills     {
29598705b39Sanil kumar appana         case SmSignalGet::smChassisIntrusion:
29698705b39Sanil kumar appana         {
29798705b39Sanil kumar appana             ipmi::Value reply;
29898705b39Sanil kumar appana             if (mtm.getProperty(intrusionService, intrusionPath, intrusionIntf,
29998705b39Sanil kumar appana                                 "Status", &reply) < 0)
30098705b39Sanil kumar appana             {
30198705b39Sanil kumar appana                 return ipmi::responseInvalidFieldRequest();
30298705b39Sanil kumar appana             }
30398705b39Sanil kumar appana             std::string* intrusionStatus = std::get_if<std::string>(&reply);
30498705b39Sanil kumar appana             if (!intrusionStatus)
30598705b39Sanil kumar appana             {
30698705b39Sanil kumar appana                 return ipmi::responseUnspecifiedError();
30798705b39Sanil kumar appana             }
30898705b39Sanil kumar appana 
30998705b39Sanil kumar appana             uint8_t status = 0;
31098705b39Sanil kumar appana             if (!intrusionStatus->compare("Normal"))
31198705b39Sanil kumar appana             {
31298705b39Sanil kumar appana                 status = static_cast<uint8_t>(IntrusionStatus::normal);
31398705b39Sanil kumar appana             }
31498705b39Sanil kumar appana             else if (!intrusionStatus->compare("HardwareIntrusion"))
31598705b39Sanil kumar appana             {
31698705b39Sanil kumar appana                 status =
31798705b39Sanil kumar appana                     static_cast<uint8_t>(IntrusionStatus::hardwareIntrusion);
31898705b39Sanil kumar appana             }
31998705b39Sanil kumar appana             else if (!intrusionStatus->compare("TamperingDetected"))
32098705b39Sanil kumar appana             {
32198705b39Sanil kumar appana                 status =
32298705b39Sanil kumar appana                     static_cast<uint8_t>(IntrusionStatus::tamperingDetected);
32398705b39Sanil kumar appana             }
32498705b39Sanil kumar appana             else
32598705b39Sanil kumar appana             {
32698705b39Sanil kumar appana                 return ipmi::responseUnspecifiedError();
32798705b39Sanil kumar appana             }
32898705b39Sanil kumar appana             return ipmi::responseSuccess(status, std::nullopt);
32998705b39Sanil kumar appana         }
33038d2b5a6SJason M. Bills         case SmSignalGet::smFanPwmGet:
33138d2b5a6SJason M. Bills         {
332a3702c1fSVernon Mauery             ipmi::Value reply;
333147daec5SRichard Marian Thomaiyar             std::string fullPath = fanPwmPath + std::to_string(instance + 1);
33438d2b5a6SJason M. Bills             if (mtm.getProperty(fanService, fullPath, fanIntf, "Value",
33538d2b5a6SJason M. Bills                                 &reply) < 0)
33638d2b5a6SJason M. Bills             {
33738d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
33838d2b5a6SJason M. Bills             }
33938d2b5a6SJason M. Bills             double* doubleVal = std::get_if<double>(&reply);
34038d2b5a6SJason M. Bills             if (doubleVal == nullptr)
34138d2b5a6SJason M. Bills             {
34238d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
34338d2b5a6SJason M. Bills             }
34438d2b5a6SJason M. Bills             uint8_t sensorVal = std::round(*doubleVal);
345357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
34638d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, std::nullopt);
34738d2b5a6SJason M. Bills         }
34838d2b5a6SJason M. Bills         break;
34938d2b5a6SJason M. Bills         case SmSignalGet::smFanTachometerGet:
35038d2b5a6SJason M. Bills         {
351147daec5SRichard Marian Thomaiyar             boost::system::error_code ec;
352147daec5SRichard Marian Thomaiyar             using objFlatMap = boost::container::flat_map<
353147daec5SRichard Marian Thomaiyar                 std::string, boost::container::flat_map<
354147daec5SRichard Marian Thomaiyar                                  std::string, std::vector<std::string>>>;
355147daec5SRichard Marian Thomaiyar 
356357ddc74SRichard Marian Thomaiyar             auto flatMap = ctx->bus->yield_method_call<objFlatMap>(
357357ddc74SRichard Marian Thomaiyar                 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
358147daec5SRichard Marian Thomaiyar                 "/xyz/openbmc_project/object_mapper",
359147daec5SRichard Marian Thomaiyar                 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
360147daec5SRichard Marian Thomaiyar                 fanTachBasePath, 0, std::array<const char*, 1>{fanIntf});
361147daec5SRichard Marian Thomaiyar             if (ec)
362147daec5SRichard Marian Thomaiyar             {
363147daec5SRichard Marian Thomaiyar                 phosphor::logging::log<phosphor::logging::level::ERR>(
364147daec5SRichard Marian Thomaiyar                     "Failed to query fan tach sub tree objects");
365147daec5SRichard Marian Thomaiyar                 return ipmi::responseUnspecifiedError();
366147daec5SRichard Marian Thomaiyar             }
367147daec5SRichard Marian Thomaiyar             if (instance >= flatMap.size())
36838d2b5a6SJason M. Bills             {
36938d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
37038d2b5a6SJason M. Bills             }
371147daec5SRichard Marian Thomaiyar             auto itr = flatMap.nth(instance);
37238d2b5a6SJason M. Bills             ipmi::Value reply;
373147daec5SRichard Marian Thomaiyar             if (mtm.getProperty(fanService, itr->first, fanIntf, "Value",
37438d2b5a6SJason M. Bills                                 &reply) < 0)
37538d2b5a6SJason M. Bills             {
37638d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
37738d2b5a6SJason M. Bills             }
37838d2b5a6SJason M. Bills 
37938d2b5a6SJason M. Bills             double* doubleVal = std::get_if<double>(&reply);
38038d2b5a6SJason M. Bills             if (doubleVal == nullptr)
38138d2b5a6SJason M. Bills             {
38238d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
38338d2b5a6SJason M. Bills             }
38438d2b5a6SJason M. Bills             uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT;
38538d2b5a6SJason M. Bills             std::optional<uint16_t> fanTach = std::round(*doubleVal);
38638d2b5a6SJason M. Bills 
387357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
38838d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, fanTach);
38938d2b5a6SJason M. Bills         }
39038d2b5a6SJason M. Bills         break;
3918e5e2b04SRichard Marian Thomaiyar         case SmSignalGet::smIdentifyButton:
3928e5e2b04SRichard Marian Thomaiyar         {
3938e5e2b04SRichard Marian Thomaiyar             if (action == SmActionGet::revert || action == SmActionGet::ignore)
3948e5e2b04SRichard Marian Thomaiyar             {
3958e5e2b04SRichard Marian Thomaiyar                 // ButtonMasked property is not supported for ID button as it is
3968e5e2b04SRichard Marian Thomaiyar                 // unnecessary. Hence if requested for revert / ignore, override
3978e5e2b04SRichard Marian Thomaiyar                 // it to sample action to make tools happy.
3988e5e2b04SRichard Marian Thomaiyar                 action = SmActionGet::sample;
3998e5e2b04SRichard Marian Thomaiyar             }
4008e5e2b04SRichard Marian Thomaiyar             // fall-through
4018e5e2b04SRichard Marian Thomaiyar         }
40238d2b5a6SJason M. Bills         case SmSignalGet::smResetButton:
40338d2b5a6SJason M. Bills         case SmSignalGet::smPowerButton:
40438d2b5a6SJason M. Bills         case SmSignalGet::smNMIButton:
40538d2b5a6SJason M. Bills         {
40638d2b5a6SJason M. Bills             std::string path;
40738d2b5a6SJason M. Bills             if (getGpioPathForSmSignal(signalType, path) < 0)
40838d2b5a6SJason M. Bills             {
40938d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
41038d2b5a6SJason M. Bills             }
411a3702c1fSVernon Mauery 
412a3702c1fSVernon Mauery             switch (action)
413a3702c1fSVernon Mauery             {
414a3702c1fSVernon Mauery                 case SmActionGet::sample:
415a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
416a3702c1fSVernon Mauery                         "case SmActionGet::sample");
417a3702c1fSVernon Mauery                     break;
418a3702c1fSVernon Mauery                 case SmActionGet::ignore:
419a3702c1fSVernon Mauery                 {
420a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
421a3702c1fSVernon Mauery                         "case SmActionGet::ignore");
42238d2b5a6SJason M. Bills                     if (mtm.setProperty(buttonService, path, buttonIntf,
42338d2b5a6SJason M. Bills                                         "ButtonMasked", true) < 0)
424a3702c1fSVernon Mauery                     {
42538d2b5a6SJason M. Bills                         return ipmi::responseUnspecifiedError();
426a3702c1fSVernon Mauery                     }
427a3702c1fSVernon Mauery                 }
428a3702c1fSVernon Mauery                 break;
429a3702c1fSVernon Mauery                 case SmActionGet::revert:
430a3702c1fSVernon Mauery                 {
431a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
432a3702c1fSVernon Mauery                         "case SmActionGet::revert");
43338d2b5a6SJason M. Bills                     if (mtm.setProperty(buttonService, path, buttonIntf,
43438d2b5a6SJason M. Bills                                         "ButtonMasked", false) < 0)
435a3702c1fSVernon Mauery                     {
43638d2b5a6SJason M. Bills                         return ipmi::responseUnspecifiedError();
437a3702c1fSVernon Mauery                     }
438a3702c1fSVernon Mauery                 }
439a3702c1fSVernon Mauery                 break;
440a3702c1fSVernon Mauery 
441a3702c1fSVernon Mauery                 default:
44238d2b5a6SJason M. Bills                     return ipmi::responseInvalidFieldRequest();
443a3702c1fSVernon Mauery                     break;
444a3702c1fSVernon Mauery             }
445a3702c1fSVernon Mauery 
446a3702c1fSVernon Mauery             ipmi::Value reply;
44738d2b5a6SJason M. Bills             if (mtm.getProperty(buttonService, path, buttonIntf,
44838d2b5a6SJason M. Bills                                 "ButtonPressed", &reply) < 0)
449a3702c1fSVernon Mauery             {
45038d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
451a3702c1fSVernon Mauery             }
45238d2b5a6SJason M. Bills             bool* valPtr = std::get_if<bool>(&reply);
45338d2b5a6SJason M. Bills             if (valPtr == nullptr)
454a3702c1fSVernon Mauery             {
45538d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
456a3702c1fSVernon Mauery             }
457357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
45838d2b5a6SJason M. Bills             uint8_t sensorVal = *valPtr;
45938d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, std::nullopt);
460a3702c1fSVernon Mauery         }
461a3702c1fSVernon Mauery         break;
4621b74a210SRichard Marian Thomaiyar         case SmSignalGet::smNcsiDiag:
4631b74a210SRichard Marian Thomaiyar         {
4641b74a210SRichard Marian Thomaiyar             constexpr const char* netBasePath = "/sys/class/net/eth";
4651b74a210SRichard Marian Thomaiyar             constexpr const char* carrierSuffix = "/carrier";
4661b74a210SRichard Marian Thomaiyar             std::ifstream netIfs(netBasePath + std::to_string(instance) +
4671b74a210SRichard Marian Thomaiyar                                  carrierSuffix);
4681b74a210SRichard Marian Thomaiyar             if (!netIfs.good())
4691b74a210SRichard Marian Thomaiyar             {
4701b74a210SRichard Marian Thomaiyar                 return ipmi::responseInvalidFieldRequest();
4711b74a210SRichard Marian Thomaiyar             }
4721b74a210SRichard Marian Thomaiyar             std::string carrier;
4731b74a210SRichard Marian Thomaiyar             netIfs >> carrier;
474357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
4751b74a210SRichard Marian Thomaiyar             return ipmi::responseSuccess(
4761b74a210SRichard Marian Thomaiyar                 static_cast<uint8_t>(std::stoi(carrier)), std::nullopt);
4771b74a210SRichard Marian Thomaiyar         }
4781b74a210SRichard Marian Thomaiyar         break;
479a3702c1fSVernon Mauery         default:
48038d2b5a6SJason M. Bills             return ipmi::responseInvalidFieldRequest();
481a3702c1fSVernon Mauery             break;
482a3702c1fSVernon Mauery     }
483a3702c1fSVernon Mauery }
484a3702c1fSVernon Mauery 
485357ddc74SRichard Marian Thomaiyar ipmi::RspType<> appMTMSetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte,
486357ddc74SRichard Marian Thomaiyar                                 uint8_t instance, uint8_t actionByte,
4875e3bf557SAyushi Smriti                                 std::optional<uint8_t> pwmSpeed)
488a3702c1fSVernon Mauery {
489e0511e5fSAyushi Smriti     // mfg filter logic is used to allow MTM set signal command only in
490e0511e5fSAyushi Smriti     // manfacturing mode.
4915e3bf557SAyushi Smriti 
4925e3bf557SAyushi Smriti     SmSignalSet signalType = static_cast<SmSignalSet>(signalTypeByte);
4935e3bf557SAyushi Smriti     SmActionSet action = static_cast<SmActionSet>(actionByte);
4945e3bf557SAyushi Smriti     Cc retCode = ccSuccess;
49513b0039dSJames Feist     int8_t ret = 0;
4965e3bf557SAyushi Smriti 
4975e3bf557SAyushi Smriti     switch (signalType)
498a3702c1fSVernon Mauery     {
499a3702c1fSVernon Mauery         case SmSignalSet::smPowerFaultLed:
500a3702c1fSVernon Mauery         case SmSignalSet::smSystemReadyLed:
501a3702c1fSVernon Mauery         case SmSignalSet::smIdentifyLed:
5025e3bf557SAyushi Smriti             switch (action)
503a3702c1fSVernon Mauery             {
504a3702c1fSVernon Mauery                 case SmActionSet::forceDeasserted:
505a3702c1fSVernon Mauery                 {
506a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
507a3702c1fSVernon Mauery                         "case SmActionSet::forceDeasserted");
508a3702c1fSVernon Mauery 
5095e3bf557SAyushi Smriti                     retCode = ledStoreAndSet(signalType, std::string("Off"));
5105e3bf557SAyushi Smriti                     if (retCode != ccSuccess)
511a3702c1fSVernon Mauery                     {
5125e3bf557SAyushi Smriti                         return ipmi::response(retCode);
513a3702c1fSVernon Mauery                     }
514a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
515a3702c1fSVernon Mauery                 }
516a3702c1fSVernon Mauery                 break;
517a3702c1fSVernon Mauery                 case SmActionSet::forceAsserted:
518a3702c1fSVernon Mauery                 {
519a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
520a3702c1fSVernon Mauery                         "case SmActionSet::forceAsserted");
521a3702c1fSVernon Mauery 
5225e3bf557SAyushi Smriti                     retCode = ledStoreAndSet(signalType, std::string("On"));
5235e3bf557SAyushi Smriti                     if (retCode != ccSuccess)
524a3702c1fSVernon Mauery                     {
5255e3bf557SAyushi Smriti                         return ipmi::response(retCode);
526a3702c1fSVernon Mauery                     }
527a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
5285e3bf557SAyushi Smriti                     if (SmSignalSet::smPowerFaultLed == signalType)
529a3702c1fSVernon Mauery                     {
530a3702c1fSVernon Mauery                         // Deassert "system ready"
5315e3bf557SAyushi Smriti                         retCode = ledStoreAndSet(SmSignalSet::smSystemReadyLed,
532a3702c1fSVernon Mauery                                                  std::string("Off"));
533a3702c1fSVernon Mauery                     }
5345e3bf557SAyushi Smriti                     else if (SmSignalSet::smSystemReadyLed == signalType)
535a3702c1fSVernon Mauery                     {
536a3702c1fSVernon Mauery                         // Deassert "fault led"
5375e3bf557SAyushi Smriti                         retCode = ledStoreAndSet(SmSignalSet::smPowerFaultLed,
538a3702c1fSVernon Mauery                                                  std::string("Off"));
539a3702c1fSVernon Mauery                     }
540a3702c1fSVernon Mauery                 }
541a3702c1fSVernon Mauery                 break;
542a3702c1fSVernon Mauery                 case SmActionSet::revert:
543a3702c1fSVernon Mauery                 {
544a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
545a3702c1fSVernon Mauery                         "case SmActionSet::revert");
5465e3bf557SAyushi Smriti                     retCode = ledRevert(signalType);
547a3702c1fSVernon Mauery                 }
548a3702c1fSVernon Mauery                 break;
549a3702c1fSVernon Mauery                 default:
550a3702c1fSVernon Mauery                 {
5515e3bf557SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
552a3702c1fSVernon Mauery                 }
553a3702c1fSVernon Mauery             }
554a3702c1fSVernon Mauery             break;
555a3702c1fSVernon Mauery         case SmSignalSet::smFanPowerSpeed:
556a3702c1fSVernon Mauery         {
5575e3bf557SAyushi Smriti             if ((action == SmActionSet::forceAsserted) && (!pwmSpeed))
558a3702c1fSVernon Mauery             {
5595e3bf557SAyushi Smriti                 return ipmi::responseReqDataLenInvalid();
560a3702c1fSVernon Mauery             }
5615e3bf557SAyushi Smriti 
5625e3bf557SAyushi Smriti             if ((action == SmActionSet::forceAsserted) && (*pwmSpeed > 100))
5635e3bf557SAyushi Smriti             {
5645e3bf557SAyushi Smriti                 return ipmi::responseInvalidFieldRequest();
5655e3bf557SAyushi Smriti             }
5665e3bf557SAyushi Smriti 
567a3702c1fSVernon Mauery             uint8_t pwmValue = 0;
5685e3bf557SAyushi Smriti             switch (action)
569a3702c1fSVernon Mauery             {
570a3702c1fSVernon Mauery                 case SmActionSet::revert:
571a3702c1fSVernon Mauery                 {
572a3702c1fSVernon Mauery                     if (mtm.revertFanPWM)
573a3702c1fSVernon Mauery                     {
574a3702c1fSVernon Mauery                         ret = mtm.disablePidControlService(false);
575a3702c1fSVernon Mauery                         if (ret < 0)
576a3702c1fSVernon Mauery                         {
5775e3bf557SAyushi Smriti                             return ipmi::responseUnspecifiedError();
578a3702c1fSVernon Mauery                         }
579a3702c1fSVernon Mauery                         mtm.revertFanPWM = false;
580a3702c1fSVernon Mauery                     }
581a3702c1fSVernon Mauery                 }
582a3702c1fSVernon Mauery                 break;
583a3702c1fSVernon Mauery                 case SmActionSet::forceAsserted:
584a3702c1fSVernon Mauery                 {
5855e3bf557SAyushi Smriti                     pwmValue = *pwmSpeed;
586a3702c1fSVernon Mauery                 } // fall-through
587a3702c1fSVernon Mauery                 case SmActionSet::forceDeasserted:
588a3702c1fSVernon Mauery                 {
589a3702c1fSVernon Mauery                     if (!mtm.revertFanPWM)
590a3702c1fSVernon Mauery                     {
591a3702c1fSVernon Mauery                         ret = mtm.disablePidControlService(true);
592a3702c1fSVernon Mauery                         if (ret < 0)
593a3702c1fSVernon Mauery                         {
5945e3bf557SAyushi Smriti                             return ipmi::responseUnspecifiedError();
595a3702c1fSVernon Mauery                         }
596a3702c1fSVernon Mauery                         mtm.revertFanPWM = true;
597a3702c1fSVernon Mauery                     }
598a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
599a3702c1fSVernon Mauery                     std::string fanPwmInstancePath =
6005e3bf557SAyushi Smriti                         fanPwmPath + std::to_string(instance + 1);
601a3702c1fSVernon Mauery 
6025e3bf557SAyushi Smriti                     ret =
6035e3bf557SAyushi Smriti                         mtm.setProperty(fanService, fanPwmInstancePath, fanIntf,
6045e3bf557SAyushi Smriti                                         "Value", static_cast<double>(pwmValue));
605a3702c1fSVernon Mauery                     if (ret < 0)
606a3702c1fSVernon Mauery                     {
6075e3bf557SAyushi Smriti                         return ipmi::responseUnspecifiedError();
608a3702c1fSVernon Mauery                     }
609a3702c1fSVernon Mauery                 }
610a3702c1fSVernon Mauery                 break;
611a3702c1fSVernon Mauery                 default:
612a3702c1fSVernon Mauery                 {
6135e3bf557SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
614a3702c1fSVernon Mauery                 }
615a3702c1fSVernon Mauery             }
616a3702c1fSVernon Mauery         }
617a3702c1fSVernon Mauery         break;
618d872a4a4SAyushi Smriti         case SmSignalSet::smSpeaker:
619d872a4a4SAyushi Smriti         {
620d872a4a4SAyushi Smriti             phosphor::logging::log<phosphor::logging::level::INFO>(
621d872a4a4SAyushi Smriti                 "Performing Speaker SmActionSet",
622d872a4a4SAyushi Smriti                 phosphor::logging::entry("ACTION=%d",
623d872a4a4SAyushi Smriti                                          static_cast<uint8_t>(action)));
624d872a4a4SAyushi Smriti             switch (action)
625d872a4a4SAyushi Smriti             {
626d872a4a4SAyushi Smriti                 case SmActionSet::forceAsserted:
627d872a4a4SAyushi Smriti                 {
628d872a4a4SAyushi Smriti                     char beepDevName[] = "/dev/input/event0";
629d872a4a4SAyushi Smriti                     if (mtm.mtmTestBeepFd != -1)
630d872a4a4SAyushi Smriti                     {
631d872a4a4SAyushi Smriti                         phosphor::logging::log<phosphor::logging::level::INFO>(
632d872a4a4SAyushi Smriti                             "mtm beep device is opened already!");
633d872a4a4SAyushi Smriti                         // returning success as already beep is in progress
634d872a4a4SAyushi Smriti                         return ipmi::response(retCode);
635d872a4a4SAyushi Smriti                     }
636d872a4a4SAyushi Smriti 
637d872a4a4SAyushi Smriti                     if ((mtm.mtmTestBeepFd =
638d872a4a4SAyushi Smriti                              ::open(beepDevName, O_RDWR | O_CLOEXEC)) < 0)
639d872a4a4SAyushi Smriti                     {
640d872a4a4SAyushi Smriti                         phosphor::logging::log<phosphor::logging::level::ERR>(
641d872a4a4SAyushi Smriti                             "Failed to open input device");
642d872a4a4SAyushi Smriti                         return ipmi::responseUnspecifiedError();
643d872a4a4SAyushi Smriti                     }
644d872a4a4SAyushi Smriti 
645d872a4a4SAyushi Smriti                     struct input_event event;
646d872a4a4SAyushi Smriti                     event.type = EV_SND;
647d872a4a4SAyushi Smriti                     event.code = SND_TONE;
648d872a4a4SAyushi Smriti                     event.value = 2000;
649d872a4a4SAyushi Smriti 
650d872a4a4SAyushi Smriti                     if (::write(mtm.mtmTestBeepFd, &event,
651d872a4a4SAyushi Smriti                                 sizeof(struct input_event)) !=
652d872a4a4SAyushi Smriti                         sizeof(struct input_event))
653d872a4a4SAyushi Smriti                     {
654d872a4a4SAyushi Smriti                         phosphor::logging::log<phosphor::logging::level::ERR>(
655d872a4a4SAyushi Smriti                             "Failed to write a tone sound event");
656d872a4a4SAyushi Smriti                         ::close(mtm.mtmTestBeepFd);
657d872a4a4SAyushi Smriti                         mtm.mtmTestBeepFd = -1;
658d872a4a4SAyushi Smriti                         return ipmi::responseUnspecifiedError();
659d872a4a4SAyushi Smriti                     }
660d872a4a4SAyushi Smriti                     mtm.revertTimer.start(revertTimeOut);
661d872a4a4SAyushi Smriti                 }
662d872a4a4SAyushi Smriti                 break;
663d872a4a4SAyushi Smriti                 case SmActionSet::revert:
664d872a4a4SAyushi Smriti                 case SmActionSet::forceDeasserted:
665d872a4a4SAyushi Smriti                 {
666d872a4a4SAyushi Smriti                     if (mtm.mtmTestBeepFd != -1)
667d872a4a4SAyushi Smriti                     {
668d872a4a4SAyushi Smriti                         ::close(mtm.mtmTestBeepFd);
669d872a4a4SAyushi Smriti                         mtm.mtmTestBeepFd = -1;
670d872a4a4SAyushi Smriti                     }
671d872a4a4SAyushi Smriti                 }
672d872a4a4SAyushi Smriti                 break;
673d872a4a4SAyushi Smriti                 default:
674d872a4a4SAyushi Smriti                 {
675d872a4a4SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
676d872a4a4SAyushi Smriti                 }
677d872a4a4SAyushi Smriti             }
678d872a4a4SAyushi Smriti         }
679d872a4a4SAyushi Smriti         break;
6803594c6d6SRichard Marian Thomaiyar         case SmSignalSet::smDiskFaultLed:
6813594c6d6SRichard Marian Thomaiyar         {
6823594c6d6SRichard Marian Thomaiyar             boost::system::error_code ec;
6833594c6d6SRichard Marian Thomaiyar             using objPaths = std::vector<std::string>;
6843594c6d6SRichard Marian Thomaiyar             std::string driveBasePath =
6853594c6d6SRichard Marian Thomaiyar                 "/xyz/openbmc_project/inventory/item/drive/";
6863594c6d6SRichard Marian Thomaiyar             static constexpr const char* driveLedIntf =
6873594c6d6SRichard Marian Thomaiyar                 "xyz.openbmc_project.Led.Group";
6883594c6d6SRichard Marian Thomaiyar             static constexpr const char* hsbpService =
6893594c6d6SRichard Marian Thomaiyar                 "xyz.openbmc_project.HsbpManager";
6903594c6d6SRichard Marian Thomaiyar 
6913594c6d6SRichard Marian Thomaiyar             auto driveList = ctx->bus->yield_method_call<objPaths>(
6923594c6d6SRichard Marian Thomaiyar                 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
6933594c6d6SRichard Marian Thomaiyar                 "/xyz/openbmc_project/object_mapper",
6943594c6d6SRichard Marian Thomaiyar                 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
6953594c6d6SRichard Marian Thomaiyar                 driveBasePath, 0, std::array<const char*, 1>{driveLedIntf});
6963594c6d6SRichard Marian Thomaiyar             if (ec)
6973594c6d6SRichard Marian Thomaiyar             {
6983594c6d6SRichard Marian Thomaiyar                 phosphor::logging::log<phosphor::logging::level::ERR>(
6993594c6d6SRichard Marian Thomaiyar                     "Failed to query HSBP drive sub tree objects");
7003594c6d6SRichard Marian Thomaiyar                 return ipmi::responseUnspecifiedError();
7013594c6d6SRichard Marian Thomaiyar             }
7023594c6d6SRichard Marian Thomaiyar             std::string driveObjPath =
7033594c6d6SRichard Marian Thomaiyar                 driveBasePath + "Drive_" + std::to_string(instance + 1);
7043594c6d6SRichard Marian Thomaiyar             if (std::find(driveList.begin(), driveList.end(), driveObjPath) ==
7053594c6d6SRichard Marian Thomaiyar                 driveList.end())
7063594c6d6SRichard Marian Thomaiyar             {
7073594c6d6SRichard Marian Thomaiyar                 return ipmi::responseInvalidFieldRequest();
7083594c6d6SRichard Marian Thomaiyar             }
7093594c6d6SRichard Marian Thomaiyar             bool driveLedState = false;
7103594c6d6SRichard Marian Thomaiyar             switch (action)
7113594c6d6SRichard Marian Thomaiyar             {
7123594c6d6SRichard Marian Thomaiyar                 case SmActionSet::forceAsserted:
7133594c6d6SRichard Marian Thomaiyar                 {
7143594c6d6SRichard Marian Thomaiyar                     driveLedState = true;
7153594c6d6SRichard Marian Thomaiyar                 }
7163594c6d6SRichard Marian Thomaiyar                 break;
7173594c6d6SRichard Marian Thomaiyar                 case SmActionSet::revert:
7183594c6d6SRichard Marian Thomaiyar                 {
7193594c6d6SRichard Marian Thomaiyar                     driveLedState = false;
7203594c6d6SRichard Marian Thomaiyar                 }
7213594c6d6SRichard Marian Thomaiyar                 break;
7223594c6d6SRichard Marian Thomaiyar                 case SmActionSet::forceDeasserted:
7233594c6d6SRichard Marian Thomaiyar                 {
7243594c6d6SRichard Marian Thomaiyar                     driveLedState = false;
7253594c6d6SRichard Marian Thomaiyar                 }
7263594c6d6SRichard Marian Thomaiyar                 break;
7273594c6d6SRichard Marian Thomaiyar                 default:
7283594c6d6SRichard Marian Thomaiyar                 {
7293594c6d6SRichard Marian Thomaiyar                     return ipmi::responseInvalidFieldRequest();
7303594c6d6SRichard Marian Thomaiyar                 }
7313594c6d6SRichard Marian Thomaiyar             }
7323594c6d6SRichard Marian Thomaiyar             ret = mtm.setProperty(hsbpService, driveObjPath, driveLedIntf,
7333594c6d6SRichard Marian Thomaiyar                                   "Asserted", driveLedState);
7343594c6d6SRichard Marian Thomaiyar             if (ret < 0)
7353594c6d6SRichard Marian Thomaiyar             {
7363594c6d6SRichard Marian Thomaiyar                 return ipmi::responseUnspecifiedError();
7373594c6d6SRichard Marian Thomaiyar             }
7383594c6d6SRichard Marian Thomaiyar         }
7393594c6d6SRichard Marian Thomaiyar         break;
740a3702c1fSVernon Mauery         default:
741a3702c1fSVernon Mauery         {
7425e3bf557SAyushi Smriti             return ipmi::responseInvalidFieldRequest();
743a3702c1fSVernon Mauery         }
744a3702c1fSVernon Mauery     }
7454cc10159SRichard Marian Thomaiyar     if (retCode == ccSuccess)
7464cc10159SRichard Marian Thomaiyar     {
747357ddc74SRichard Marian Thomaiyar         resetMtmTimer(ctx);
7484cc10159SRichard Marian Thomaiyar     }
7495e3bf557SAyushi Smriti     return ipmi::response(retCode);
750a3702c1fSVernon Mauery }
751a3702c1fSVernon Mauery 
752357ddc74SRichard Marian Thomaiyar ipmi::RspType<> mtmKeepAlive(ipmi::Context::ptr ctx, uint8_t reserved,
753666dd01cSRichard Marian Thomaiyar                              const std::array<char, 5>& intentionalSignature)
754666dd01cSRichard Marian Thomaiyar {
755e0511e5fSAyushi Smriti     // mfg filter logic is used to allow MTM keep alive command only in
756e0511e5fSAyushi Smriti     // manfacturing mode
757e0511e5fSAyushi Smriti 
758666dd01cSRichard Marian Thomaiyar     constexpr std::array<char, 5> signatureOk = {'I', 'N', 'T', 'E', 'L'};
759666dd01cSRichard Marian Thomaiyar     if (intentionalSignature != signatureOk || reserved != 0)
760666dd01cSRichard Marian Thomaiyar     {
761666dd01cSRichard Marian Thomaiyar         return ipmi::responseInvalidFieldRequest();
762666dd01cSRichard Marian Thomaiyar     }
763357ddc74SRichard Marian Thomaiyar     return ipmi::response(resetMtmTimer(ctx));
764666dd01cSRichard Marian Thomaiyar }
765666dd01cSRichard Marian Thomaiyar 
766e0511e5fSAyushi Smriti static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd)
767e0511e5fSAyushi Smriti {
768e0511e5fSAyushi Smriti     return (netFn << 8) | cmd;
769e0511e5fSAyushi Smriti }
770e0511e5fSAyushi Smriti 
77185feb130SYong Li ipmi::Cc mfgFilterMessage(ipmi::message::Request::ptr request)
77285feb130SYong Li {
773e0511e5fSAyushi Smriti     // Restricted commands, must be executed only in Manufacturing mode
774e0511e5fSAyushi Smriti     switch (makeCmdKey(request->ctx->netFn, request->ctx->cmd))
77585feb130SYong Li     {
776e0511e5fSAyushi Smriti         // i2c master write read command needs additional checking
777e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead):
77885feb130SYong Li             if (request->payload.size() > 4)
77985feb130SYong Li             {
780ae13ac62SRichard Marian Thomaiyar                 // Allow write data count > 1 only in Special mode
781ae13ac62SRichard Marian Thomaiyar                 if (mtm.getMfgMode() == SpecialMode::none)
78285feb130SYong Li                 {
78385feb130SYong Li                     return ipmi::ccInsufficientPrivilege;
78485feb130SYong Li                 }
78585feb130SYong Li             }
7862d4a0198Sjayaprakash Mutyala             return ipmi::ccSuccess;
787e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
788e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdGetSmSignal):
789e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
790e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdSetSmSignal):
791e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
792e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdMtmKeepAlive):
793e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
794e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdSetManufacturingData):
795e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
796e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdGetManufacturingData):
79727d2356eSVernon Mauery         case makeCmdKey(ipmi::intel::netFnGeneral,
79827d2356eSVernon Mauery                         ipmi::intel::general::cmdSetFITcLayout):
799*06584cd0SArun P. Mohanan         case makeCmdKey(ipmi::netFnOemOne,
800*06584cd0SArun P. Mohanan                         ipmi::intel::general::cmdMTMBMCFeatureControl):
801e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdWriteFruData):
8029a13daaeSAppaRao Puli         case makeCmdKey(ipmi::netFnOemTwo, ipmi::intel::platform::cmdClearCMOS):
80385feb130SYong Li 
804ae13ac62SRichard Marian Thomaiyar             // Check for Special mode
805ae13ac62SRichard Marian Thomaiyar             if (mtm.getMfgMode() == SpecialMode::none)
806e0511e5fSAyushi Smriti             {
807e0511e5fSAyushi Smriti                 return ipmi::ccInvalidCommand;
808e0511e5fSAyushi Smriti             }
8092d4a0198Sjayaprakash Mutyala             return ipmi::ccSuccess;
8102d4a0198Sjayaprakash Mutyala         case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdDeleteSelEntry):
8112d4a0198Sjayaprakash Mutyala         {
8122d4a0198Sjayaprakash Mutyala             return ipmi::ccInvalidCommand;
8132d4a0198Sjayaprakash Mutyala         }
814e0511e5fSAyushi Smriti     }
81585feb130SYong Li     return ipmi::ccSuccess;
81685feb130SYong Li }
81785feb130SYong Li 
8181f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxEthSize = 6;
8191f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxSupportedEth = 3;
8201f0839c2SRichard Marian Thomaiyar static constexpr const char* factoryEthAddrBaseFileName =
8211f0839c2SRichard Marian Thomaiyar     "/var/sofs/factory-settings/network/mac/eth";
8221f0839c2SRichard Marian Thomaiyar 
823357ddc74SRichard Marian Thomaiyar ipmi::RspType<> setManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType,
8241f0839c2SRichard Marian Thomaiyar                                      std::array<uint8_t, maxEthSize> ethData)
8251f0839c2SRichard Marian Thomaiyar {
8261f0839c2SRichard Marian Thomaiyar     // mfg filter logic will restrict this command executing only in mfg mode.
8271f0839c2SRichard Marian Thomaiyar     if (dataType >= maxSupportedEth)
8281f0839c2SRichard Marian Thomaiyar     {
8291f0839c2SRichard Marian Thomaiyar         return ipmi::responseParmOutOfRange();
8301f0839c2SRichard Marian Thomaiyar     }
8311f0839c2SRichard Marian Thomaiyar 
8321f0839c2SRichard Marian Thomaiyar     constexpr uint8_t invalidData = 0;
8331f0839c2SRichard Marian Thomaiyar     constexpr uint8_t validData = 1;
8341f0839c2SRichard Marian Thomaiyar     constexpr uint8_t ethAddrStrSize =
8351f0839c2SRichard Marian Thomaiyar         19; // XX:XX:XX:XX:XX:XX + \n + null termination;
8361f0839c2SRichard Marian Thomaiyar     std::vector<uint8_t> buff(ethAddrStrSize);
8371f0839c2SRichard Marian Thomaiyar     std::snprintf(reinterpret_cast<char*>(buff.data()), ethAddrStrSize,
8381f0839c2SRichard Marian Thomaiyar                   "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", ethData.at(0),
8391f0839c2SRichard Marian Thomaiyar                   ethData.at(1), ethData.at(2), ethData.at(3), ethData.at(4),
8401f0839c2SRichard Marian Thomaiyar                   ethData.at(5));
8411f0839c2SRichard Marian Thomaiyar     std::ofstream oEthFile(factoryEthAddrBaseFileName +
8421f0839c2SRichard Marian Thomaiyar                                std::to_string(dataType),
8431f0839c2SRichard Marian Thomaiyar                            std::ofstream::out);
8441f0839c2SRichard Marian Thomaiyar     if (!oEthFile.good())
8451f0839c2SRichard Marian Thomaiyar     {
8461f0839c2SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
8471f0839c2SRichard Marian Thomaiyar     }
8481f0839c2SRichard Marian Thomaiyar 
8491f0839c2SRichard Marian Thomaiyar     oEthFile << reinterpret_cast<char*>(buff.data());
8506d83e4eeSJohnathan Mantey     oEthFile.flush();
8511f0839c2SRichard Marian Thomaiyar     oEthFile.close();
8521f0839c2SRichard Marian Thomaiyar 
853357ddc74SRichard Marian Thomaiyar     resetMtmTimer(ctx);
8541f0839c2SRichard Marian Thomaiyar     return ipmi::responseSuccess();
8551f0839c2SRichard Marian Thomaiyar }
8561f0839c2SRichard Marian Thomaiyar 
8571f0839c2SRichard Marian Thomaiyar ipmi::RspType<uint8_t, std::array<uint8_t, maxEthSize>>
858357ddc74SRichard Marian Thomaiyar     getManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType)
8591f0839c2SRichard Marian Thomaiyar {
8601f0839c2SRichard Marian Thomaiyar     // mfg filter logic will restrict this command executing only in mfg mode.
8611f0839c2SRichard Marian Thomaiyar     if (dataType >= maxSupportedEth)
8621f0839c2SRichard Marian Thomaiyar     {
8631f0839c2SRichard Marian Thomaiyar         return ipmi::responseParmOutOfRange();
8641f0839c2SRichard Marian Thomaiyar     }
8651f0839c2SRichard Marian Thomaiyar     std::array<uint8_t, maxEthSize> ethData{0};
8661f0839c2SRichard Marian Thomaiyar     constexpr uint8_t invalidData = 0;
8671f0839c2SRichard Marian Thomaiyar     constexpr uint8_t validData = 1;
8681f0839c2SRichard Marian Thomaiyar 
8691f0839c2SRichard Marian Thomaiyar     std::ifstream iEthFile(factoryEthAddrBaseFileName +
8701f0839c2SRichard Marian Thomaiyar                                std::to_string(dataType),
8711f0839c2SRichard Marian Thomaiyar                            std::ifstream::in);
8721f0839c2SRichard Marian Thomaiyar     if (!iEthFile.good())
8731f0839c2SRichard Marian Thomaiyar     {
8741f0839c2SRichard Marian Thomaiyar         return ipmi::responseSuccess(invalidData, ethData);
8751f0839c2SRichard Marian Thomaiyar     }
8761f0839c2SRichard Marian Thomaiyar     std::string ethStr;
8771f0839c2SRichard Marian Thomaiyar     iEthFile >> ethStr;
8781f0839c2SRichard Marian Thomaiyar     uint8_t* data = ethData.data();
8791f0839c2SRichard Marian Thomaiyar     std::sscanf(ethStr.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
8801f0839c2SRichard Marian Thomaiyar                 data, (data + 1), (data + 2), (data + 3), (data + 4),
8811f0839c2SRichard Marian Thomaiyar                 (data + 5));
8821f0839c2SRichard Marian Thomaiyar 
883357ddc74SRichard Marian Thomaiyar     resetMtmTimer(ctx);
8841f0839c2SRichard Marian Thomaiyar     return ipmi::responseSuccess(validData, ethData);
8851f0839c2SRichard Marian Thomaiyar }
8861f0839c2SRichard Marian Thomaiyar 
887f267a67dSYong Li /** @brief implements slot master write read IPMI command which can be used for
888f267a67dSYong Li  * low-level I2C/SMBus write, read or write-read access for PCIE slots
889f267a67dSYong Li  * @param reserved - skip 6 bit
890f267a67dSYong Li  * @param addressType - address type
891f267a67dSYong Li  * @param bbSlotNum - baseboard slot number
892f267a67dSYong Li  * @param riserSlotNum - riser slot number
893f267a67dSYong Li  * @param reserved2 - skip 2 bit
894f267a67dSYong Li  * @param slaveAddr - slave address
895f267a67dSYong Li  * @param readCount - number of bytes to be read
896f267a67dSYong Li  * @param writeData - data to be written
897f267a67dSYong Li  *
898f267a67dSYong Li  * @returns IPMI completion code plus response data
899f267a67dSYong Li  */
900f267a67dSYong Li ipmi::RspType<std::vector<uint8_t>>
901f267a67dSYong Li     appSlotI2CMasterWriteRead(uint6_t reserved, uint2_t addressType,
902f267a67dSYong Li                               uint3_t bbSlotNum, uint3_t riserSlotNum,
903f267a67dSYong Li                               uint2_t resvered2, uint8_t slaveAddr,
904f267a67dSYong Li                               uint8_t readCount, std::vector<uint8_t> writeData)
905f267a67dSYong Li {
906f267a67dSYong Li     const size_t writeCount = writeData.size();
907f267a67dSYong Li     std::string i2cBus;
908f267a67dSYong Li     if (addressType == slotAddressTypeBus)
909f267a67dSYong Li     {
910f267a67dSYong Li         std::string path = "/dev/i2c-mux/Riser_" +
911f267a67dSYong Li                            std::to_string(static_cast<uint8_t>(bbSlotNum)) +
912f267a67dSYong Li                            "_Mux/Pcie_Slot_" +
913f267a67dSYong Li                            std::to_string(static_cast<uint8_t>(riserSlotNum));
914f267a67dSYong Li 
915f267a67dSYong Li         if (std::filesystem::exists(path) && std::filesystem::is_symlink(path))
916f267a67dSYong Li         {
917f267a67dSYong Li             i2cBus = std::filesystem::read_symlink(path);
918f267a67dSYong Li         }
919f267a67dSYong Li         else
920f267a67dSYong Li         {
921f267a67dSYong Li             phosphor::logging::log<phosphor::logging::level::ERR>(
922f267a67dSYong Li                 "Master write read command: Cannot get BusID");
923f267a67dSYong Li             return ipmi::responseInvalidFieldRequest();
924f267a67dSYong Li         }
925f267a67dSYong Li     }
926f267a67dSYong Li     else if (addressType == slotAddressTypeUniqueid)
927f267a67dSYong Li     {
928f267a67dSYong Li         i2cBus = "/dev/i2c-" +
929f267a67dSYong Li                  std::to_string(static_cast<uint8_t>(bbSlotNum) |
930f267a67dSYong Li                                 (static_cast<uint8_t>(riserSlotNum) << 3));
931f267a67dSYong Li     }
932f267a67dSYong Li     else
933f267a67dSYong Li     {
934f267a67dSYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
935f267a67dSYong Li             "Master write read command: invalid request");
936f267a67dSYong Li         return ipmi::responseInvalidFieldRequest();
937f267a67dSYong Li     }
938f267a67dSYong Li 
939f267a67dSYong Li     // Allow single byte write as it is offset byte to read the data, rest allow
940ae13ac62SRichard Marian Thomaiyar     // only in Special mode.
941f267a67dSYong Li     if (writeCount > 1)
942f267a67dSYong Li     {
943ae13ac62SRichard Marian Thomaiyar         if (mtm.getMfgMode() == SpecialMode::none)
944f267a67dSYong Li         {
945f267a67dSYong Li             return ipmi::responseInsufficientPrivilege();
946f267a67dSYong Li         }
947f267a67dSYong Li     }
948f267a67dSYong Li 
949f267a67dSYong Li     if (readCount > slotI2CMaxReadSize)
950f267a67dSYong Li     {
951f267a67dSYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
952f267a67dSYong Li             "Master write read command: Read count exceeds limit");
953f267a67dSYong Li         return ipmi::responseParmOutOfRange();
954f267a67dSYong Li     }
955f267a67dSYong Li 
956f267a67dSYong Li     if (!readCount && !writeCount)
957f267a67dSYong Li     {
958f267a67dSYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
959f267a67dSYong Li             "Master write read command: Read & write count are 0");
960f267a67dSYong Li         return ipmi::responseInvalidFieldRequest();
961f267a67dSYong Li     }
962f267a67dSYong Li 
963f267a67dSYong Li     std::vector<uint8_t> readBuf(readCount);
964f267a67dSYong Li 
965f267a67dSYong Li     ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf);
966f267a67dSYong Li     if (retI2C != ipmi::ccSuccess)
967f267a67dSYong Li     {
968f267a67dSYong Li         return ipmi::response(retI2C);
969f267a67dSYong Li     }
970f267a67dSYong Li 
971f267a67dSYong Li     return ipmi::responseSuccess(readBuf);
972f267a67dSYong Li }
973068b4f2cSYong Li 
974068b4f2cSYong Li ipmi::RspType<> clearCMOS()
975068b4f2cSYong Li {
976d0d010b7SYong Li     // There is an i2c device on bus 4, the slave address is 0x38. Based on the
977eaeb6cb0SYong Li     // spec, writing 0x1 to address 0x61 on this device, will trigger the clear
978068b4f2cSYong Li     // CMOS action.
979d0d010b7SYong Li     constexpr uint8_t slaveAddr = 0x38;
980068b4f2cSYong Li     std::string i2cBus = "/dev/i2c-4";
981eaeb6cb0SYong Li     std::vector<uint8_t> writeData = {0x61, 0x1};
982068b4f2cSYong Li     std::vector<uint8_t> readBuf(0);
983068b4f2cSYong Li 
984068b4f2cSYong Li     ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf);
985068b4f2cSYong Li     return ipmi::response(retI2C);
986068b4f2cSYong Li }
98727d2356eSVernon Mauery 
98827d2356eSVernon Mauery ipmi::RspType<> setFITcLayout(uint32_t layout)
98927d2356eSVernon Mauery {
99027d2356eSVernon Mauery     static constexpr const char* factoryFITcLayout =
99127d2356eSVernon Mauery         "/var/sofs/factory-settings/layout/fitc";
99227d2356eSVernon Mauery     std::filesystem::path fitcDir =
99327d2356eSVernon Mauery         std::filesystem::path(factoryFITcLayout).parent_path();
99427d2356eSVernon Mauery     std::error_code ec;
99527d2356eSVernon Mauery     std::filesystem::create_directories(fitcDir, ec);
99627d2356eSVernon Mauery     if (ec)
99727d2356eSVernon Mauery     {
99827d2356eSVernon Mauery         return ipmi::responseUnspecifiedError();
99927d2356eSVernon Mauery     }
100027d2356eSVernon Mauery     try
100127d2356eSVernon Mauery     {
100227d2356eSVernon Mauery         std::ofstream file(factoryFITcLayout);
100327d2356eSVernon Mauery         file << layout;
100427d2356eSVernon Mauery         file.flush();
100527d2356eSVernon Mauery         file.close();
100627d2356eSVernon Mauery     }
100727d2356eSVernon Mauery     catch (const std::exception& e)
100827d2356eSVernon Mauery     {
100927d2356eSVernon Mauery         return ipmi::responseUnspecifiedError();
101027d2356eSVernon Mauery     }
101127d2356eSVernon Mauery 
101227d2356eSVernon Mauery     return ipmi::responseSuccess();
101327d2356eSVernon Mauery }
101427d2356eSVernon Mauery 
1015*06584cd0SArun P. Mohanan static std::vector<std::string>
1016*06584cd0SArun P. Mohanan     getMCTPServiceConfigPaths(ipmi::Context::ptr& ctx)
1017*06584cd0SArun P. Mohanan {
1018*06584cd0SArun P. Mohanan     boost::system::error_code ec;
1019*06584cd0SArun P. Mohanan     auto configPaths = ctx->bus->yield_method_call<std::vector<std::string>>(
1020*06584cd0SArun P. Mohanan         ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
1021*06584cd0SArun P. Mohanan         "/xyz/openbmc_project/object_mapper",
1022*06584cd0SArun P. Mohanan         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
1023*06584cd0SArun P. Mohanan         "/xyz/openbmc_project/inventory/system/board", 2,
1024*06584cd0SArun P. Mohanan         std::array<const char*, 1>{
1025*06584cd0SArun P. Mohanan             "xyz.openbmc_project.Configuration.MctpConfiguration"});
1026*06584cd0SArun P. Mohanan     if (ec)
1027*06584cd0SArun P. Mohanan     {
1028*06584cd0SArun P. Mohanan         throw std::runtime_error(
1029*06584cd0SArun P. Mohanan             "Failed to query configuration sub tree objects");
1030*06584cd0SArun P. Mohanan     }
1031*06584cd0SArun P. Mohanan     return configPaths;
1032*06584cd0SArun P. Mohanan }
1033*06584cd0SArun P. Mohanan 
1034*06584cd0SArun P. Mohanan static ipmi::RspType<> startOrStopService(ipmi::Context::ptr& ctx,
1035*06584cd0SArun P. Mohanan                                           const uint8_t enable,
1036*06584cd0SArun P. Mohanan                                           const std::string& serviceName)
1037*06584cd0SArun P. Mohanan {
1038*06584cd0SArun P. Mohanan     constexpr bool runtimeOnly = false;
1039*06584cd0SArun P. Mohanan     constexpr bool force = false;
1040*06584cd0SArun P. Mohanan 
1041*06584cd0SArun P. Mohanan     boost::system::error_code ec;
1042*06584cd0SArun P. Mohanan     switch (enable)
1043*06584cd0SArun P. Mohanan     {
1044*06584cd0SArun P. Mohanan         case ipmi::SupportedFeatureActions::stop:
1045*06584cd0SArun P. Mohanan             ctx->bus->yield_method_call(ctx->yield, ec, systemDService,
1046*06584cd0SArun P. Mohanan                                         systemDObjPath, systemDMgrIntf,
1047*06584cd0SArun P. Mohanan                                         "StopUnit", serviceName, "replace");
1048*06584cd0SArun P. Mohanan             break;
1049*06584cd0SArun P. Mohanan         case ipmi::SupportedFeatureActions::start:
1050*06584cd0SArun P. Mohanan             ctx->bus->yield_method_call(ctx->yield, ec, systemDService,
1051*06584cd0SArun P. Mohanan                                         systemDObjPath, systemDMgrIntf,
1052*06584cd0SArun P. Mohanan                                         "StartUnit", serviceName, "replace");
1053*06584cd0SArun P. Mohanan             break;
1054*06584cd0SArun P. Mohanan         case ipmi::SupportedFeatureActions::disable:
1055*06584cd0SArun P. Mohanan             ctx->bus->yield_method_call(
1056*06584cd0SArun P. Mohanan                 ctx->yield, ec, systemDService, systemDObjPath, systemDMgrIntf,
1057*06584cd0SArun P. Mohanan                 "MaskUnitFiles",
1058*06584cd0SArun P. Mohanan                 std::array<const char*, 1>{serviceName.c_str()}, runtimeOnly,
1059*06584cd0SArun P. Mohanan                 force);
1060*06584cd0SArun P. Mohanan             ctx->bus->yield_method_call(
1061*06584cd0SArun P. Mohanan                 ctx->yield, ec, systemDService, systemDObjPath, systemDMgrIntf,
1062*06584cd0SArun P. Mohanan                 "DisableUnitFiles",
1063*06584cd0SArun P. Mohanan                 std::array<const char*, 1>{serviceName.c_str()}, runtimeOnly);
1064*06584cd0SArun P. Mohanan             break;
1065*06584cd0SArun P. Mohanan         case ipmi::SupportedFeatureActions::enable:
1066*06584cd0SArun P. Mohanan             ctx->bus->yield_method_call(
1067*06584cd0SArun P. Mohanan                 ctx->yield, ec, systemDService, systemDObjPath, systemDMgrIntf,
1068*06584cd0SArun P. Mohanan                 "UnmaskUnitFiles",
1069*06584cd0SArun P. Mohanan                 std::array<const char*, 1>{serviceName.c_str()}, runtimeOnly);
1070*06584cd0SArun P. Mohanan             ctx->bus->yield_method_call(
1071*06584cd0SArun P. Mohanan                 ctx->yield, ec, systemDService, systemDObjPath, systemDMgrIntf,
1072*06584cd0SArun P. Mohanan                 "EnableUnitFiles",
1073*06584cd0SArun P. Mohanan                 std::array<const char*, 1>{serviceName.c_str()}, runtimeOnly,
1074*06584cd0SArun P. Mohanan                 force);
1075*06584cd0SArun P. Mohanan             break;
1076*06584cd0SArun P. Mohanan         default:
1077*06584cd0SArun P. Mohanan             phosphor::logging::log<phosphor::logging::level::WARNING>(
1078*06584cd0SArun P. Mohanan                 "ERROR: Invalid feature action selected",
1079*06584cd0SArun P. Mohanan                 phosphor::logging::entry("ACTION=%d", enable));
1080*06584cd0SArun P. Mohanan             return ipmi::responseInvalidFieldRequest();
1081*06584cd0SArun P. Mohanan     }
1082*06584cd0SArun P. Mohanan     if (ec)
1083*06584cd0SArun P. Mohanan     {
1084*06584cd0SArun P. Mohanan         phosphor::logging::log<phosphor::logging::level::WARNING>(
1085*06584cd0SArun P. Mohanan             "ERROR: Service start or stop failed",
1086*06584cd0SArun P. Mohanan             phosphor::logging::entry("SERVICE=%s", serviceName.c_str()));
1087*06584cd0SArun P. Mohanan         return ipmi::responseUnspecifiedError();
1088*06584cd0SArun P. Mohanan     }
1089*06584cd0SArun P. Mohanan     return ipmi::responseSuccess();
1090*06584cd0SArun P. Mohanan }
1091*06584cd0SArun P. Mohanan 
1092*06584cd0SArun P. Mohanan static std::string getMCTPServiceName(const std::string& objectPath)
1093*06584cd0SArun P. Mohanan {
1094*06584cd0SArun P. Mohanan     const auto serviceArgument = boost::algorithm::replace_all_copy(
1095*06584cd0SArun P. Mohanan         boost::algorithm::replace_first_copy(
1096*06584cd0SArun P. Mohanan             objectPath, "/xyz/openbmc_project/inventory/system/board/", ""),
1097*06584cd0SArun P. Mohanan         "/", "_2f");
1098*06584cd0SArun P. Mohanan     std::string unitName =
1099*06584cd0SArun P. Mohanan         "xyz.openbmc_project.mctpd@" + serviceArgument + ".service";
1100*06584cd0SArun P. Mohanan     return unitName;
1101*06584cd0SArun P. Mohanan }
1102*06584cd0SArun P. Mohanan 
1103*06584cd0SArun P. Mohanan static ipmi::RspType<> handleMCTPFeature(ipmi::Context::ptr& ctx,
1104*06584cd0SArun P. Mohanan                                          const uint8_t enable,
1105*06584cd0SArun P. Mohanan                                          const std::string& binding)
1106*06584cd0SArun P. Mohanan {
1107*06584cd0SArun P. Mohanan     std::vector<std::string> configPaths;
1108*06584cd0SArun P. Mohanan     try
1109*06584cd0SArun P. Mohanan     {
1110*06584cd0SArun P. Mohanan         configPaths = getMCTPServiceConfigPaths(ctx);
1111*06584cd0SArun P. Mohanan     }
1112*06584cd0SArun P. Mohanan     catch (const std::exception& e)
1113*06584cd0SArun P. Mohanan     {
1114*06584cd0SArun P. Mohanan         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1115*06584cd0SArun P. Mohanan         return ipmi::responseUnspecifiedError();
1116*06584cd0SArun P. Mohanan     }
1117*06584cd0SArun P. Mohanan 
1118*06584cd0SArun P. Mohanan     for (const auto& objectPath : configPaths)
1119*06584cd0SArun P. Mohanan     {
1120*06584cd0SArun P. Mohanan         auto const pos = objectPath.find_last_of('/');
1121*06584cd0SArun P. Mohanan         if (binding == objectPath.substr(pos + 1))
1122*06584cd0SArun P. Mohanan         {
1123*06584cd0SArun P. Mohanan             return startOrStopService(ctx, enable,
1124*06584cd0SArun P. Mohanan                                       getMCTPServiceName(objectPath));
1125*06584cd0SArun P. Mohanan         }
1126*06584cd0SArun P. Mohanan     }
1127*06584cd0SArun P. Mohanan     return ipmi::responseSuccess();
1128*06584cd0SArun P. Mohanan }
1129*06584cd0SArun P. Mohanan 
1130*06584cd0SArun P. Mohanan /** @brief implements MTM BMC Feature Control IPMI command which can be
1131*06584cd0SArun P. Mohanan  * used to enable or disable the supported BMC features.
1132*06584cd0SArun P. Mohanan  * @param yield - context object that represents the currently executing
1133*06584cd0SArun P. Mohanan  * coroutine
1134*06584cd0SArun P. Mohanan  * @param feature - feature enum to enable or disable
1135*06584cd0SArun P. Mohanan  * @param enable - enable or disable the feature
1136*06584cd0SArun P. Mohanan  * @param featureArg - custom arguments for that feature
1137*06584cd0SArun P. Mohanan  * @param reserved - reserved for future use
1138*06584cd0SArun P. Mohanan  *
1139*06584cd0SArun P. Mohanan  * @returns IPMI completion code
1140*06584cd0SArun P. Mohanan  */
1141*06584cd0SArun P. Mohanan ipmi::RspType<> mtmBMCFeatureControl(ipmi::Context::ptr ctx,
1142*06584cd0SArun P. Mohanan                                      const uint8_t feature,
1143*06584cd0SArun P. Mohanan                                      const uint8_t enable,
1144*06584cd0SArun P. Mohanan                                      const uint8_t featureArg,
1145*06584cd0SArun P. Mohanan                                      const uint16_t reserved)
1146*06584cd0SArun P. Mohanan {
1147*06584cd0SArun P. Mohanan     if (reserved != 0)
1148*06584cd0SArun P. Mohanan     {
1149*06584cd0SArun P. Mohanan         return ipmi::responseInvalidFieldRequest();
1150*06584cd0SArun P. Mohanan     }
1151*06584cd0SArun P. Mohanan 
1152*06584cd0SArun P. Mohanan     switch (feature)
1153*06584cd0SArun P. Mohanan     {
1154*06584cd0SArun P. Mohanan         case ipmi::SupportedFeatureControls::mctp:
1155*06584cd0SArun P. Mohanan             switch (featureArg)
1156*06584cd0SArun P. Mohanan             {
1157*06584cd0SArun P. Mohanan                 case ipmi::SupportedMCTPBindings::mctpPCIe:
1158*06584cd0SArun P. Mohanan                     return handleMCTPFeature(ctx, enable, "MCTP_PCIe");
1159*06584cd0SArun P. Mohanan                 case ipmi::SupportedMCTPBindings::mctpSMBusHSBP:
1160*06584cd0SArun P. Mohanan                     return handleMCTPFeature(ctx, enable, "MCTP_SMBus_HSBP");
1161*06584cd0SArun P. Mohanan                 case ipmi::SupportedMCTPBindings::mctpSMBusPCIeSlot:
1162*06584cd0SArun P. Mohanan                     return handleMCTPFeature(ctx, enable,
1163*06584cd0SArun P. Mohanan                                              "MCTP_SMBus_PCIe_slot");
1164*06584cd0SArun P. Mohanan                 default:
1165*06584cd0SArun P. Mohanan                     return ipmi::responseInvalidFieldRequest();
1166*06584cd0SArun P. Mohanan             }
1167*06584cd0SArun P. Mohanan             break;
1168*06584cd0SArun P. Mohanan         default:
1169*06584cd0SArun P. Mohanan             return ipmi::responseInvalidFieldRequest();
1170*06584cd0SArun P. Mohanan     }
1171*06584cd0SArun P. Mohanan     return ipmi::responseSuccess();
1172*06584cd0SArun P. Mohanan }
1173a3702c1fSVernon Mauery } // namespace ipmi
1174a3702c1fSVernon Mauery 
1175a3702c1fSVernon Mauery void register_mtm_commands() __attribute__((constructor));
1176a3702c1fSVernon Mauery void register_mtm_commands()
1177a3702c1fSVernon Mauery {
117838d2b5a6SJason M. Bills     // <Get SM Signal>
117998bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
118098bbf69aSVernon Mauery                           ipmi::intel::general::cmdGetSmSignal,
11815e3bf557SAyushi Smriti                           ipmi::Privilege::Admin, ipmi::appMTMGetSignal);
1182a3702c1fSVernon Mauery 
118398bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
118498bbf69aSVernon Mauery                           ipmi::intel::general::cmdSetSmSignal,
11855e3bf557SAyushi Smriti                           ipmi::Privilege::Admin, ipmi::appMTMSetSignal);
1186a3702c1fSVernon Mauery 
118798bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
118898bbf69aSVernon Mauery                           ipmi::intel::general::cmdMtmKeepAlive,
1189666dd01cSRichard Marian Thomaiyar                           ipmi::Privilege::Admin, ipmi::mtmKeepAlive);
1190666dd01cSRichard Marian Thomaiyar 
119198bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
119298bbf69aSVernon Mauery                           ipmi::intel::general::cmdSetManufacturingData,
11931f0839c2SRichard Marian Thomaiyar                           ipmi::Privilege::Admin, ipmi::setManufacturingData);
11941f0839c2SRichard Marian Thomaiyar 
119598bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
119698bbf69aSVernon Mauery                           ipmi::intel::general::cmdGetManufacturingData,
11971f0839c2SRichard Marian Thomaiyar                           ipmi::Privilege::Admin, ipmi::getManufacturingData);
11981f0839c2SRichard Marian Thomaiyar 
119927d2356eSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
120027d2356eSVernon Mauery                           ipmi::intel::general::cmdSetFITcLayout,
120127d2356eSVernon Mauery                           ipmi::Privilege::Admin, ipmi::setFITcLayout);
120227d2356eSVernon Mauery 
1203*06584cd0SArun P. Mohanan     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
1204*06584cd0SArun P. Mohanan                           ipmi::intel::general::cmdMTMBMCFeatureControl,
1205*06584cd0SArun P. Mohanan                           ipmi::Privilege::Admin, ipmi::mtmBMCFeatureControl);
1206*06584cd0SArun P. Mohanan 
120798bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
120898bbf69aSVernon Mauery                           ipmi::intel::general::cmdSlotI2CMasterWriteRead,
120998bbf69aSVernon Mauery                           ipmi::Privilege::Admin,
121098bbf69aSVernon Mauery                           ipmi::appSlotI2CMasterWriteRead);
1211f267a67dSYong Li 
1212068b4f2cSYong Li     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnPlatform,
1213068b4f2cSYong Li                           ipmi::intel::platform::cmdClearCMOS,
1214068b4f2cSYong Li                           ipmi::Privilege::Admin, ipmi::clearCMOS);
1215068b4f2cSYong Li 
121698bbf69aSVernon Mauery     ipmi::registerFilter(ipmi::prioOemBase,
121785feb130SYong Li                          [](ipmi::message::Request::ptr request) {
121885feb130SYong Li                              return ipmi::mfgFilterMessage(request);
121985feb130SYong Li                          });
1220a3702c1fSVernon Mauery }
1221