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 
1906584cd0SArun 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>
240748c69dSJason M. Bills #include <types.hpp>
25a3702c1fSVernon Mauery 
26fcd2d3a9SJames Feist #include <filesystem>
27fcd2d3a9SJames Feist #include <fstream>
28fcd2d3a9SJames Feist 
29a3702c1fSVernon Mauery namespace ipmi
30a3702c1fSVernon Mauery {
31a3702c1fSVernon Mauery 
32a3702c1fSVernon Mauery Manufacturing mtm;
33a3702c1fSVernon Mauery 
34a3702c1fSVernon Mauery static auto revertTimeOut =
35a3702c1fSVernon Mauery     std::chrono::duration_cast<std::chrono::microseconds>(
36a3702c1fSVernon Mauery         std::chrono::seconds(60)); // 1 minute timeout
37a3702c1fSVernon Mauery 
38f267a67dSYong Li static constexpr uint8_t slotAddressTypeBus = 0;
39f267a67dSYong Li static constexpr uint8_t slotAddressTypeUniqueid = 1;
40f267a67dSYong Li static constexpr uint8_t slotI2CMaxReadSize = 35;
41f267a67dSYong Li 
42a3702c1fSVernon Mauery static constexpr const char* callbackMgrService =
43a3702c1fSVernon Mauery     "xyz.openbmc_project.CallbackManager";
44a3702c1fSVernon Mauery static constexpr const char* callbackMgrIntf =
45a3702c1fSVernon Mauery     "xyz.openbmc_project.CallbackManager";
46a3702c1fSVernon Mauery static constexpr const char* callbackMgrObjPath =
47a3702c1fSVernon Mauery     "/xyz/openbmc_project/CallbackManager";
48a3702c1fSVernon Mauery static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate";
49a3702c1fSVernon Mauery 
50a3702c1fSVernon Mauery const static constexpr char* systemDService = "org.freedesktop.systemd1";
51a3702c1fSVernon Mauery const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1";
52a3702c1fSVernon Mauery const static constexpr char* systemDMgrIntf =
53a3702c1fSVernon Mauery     "org.freedesktop.systemd1.Manager";
54a3702c1fSVernon Mauery const static constexpr char* pidControlService = "phosphor-pid-control.service";
55a3702c1fSVernon Mauery 
56357ddc74SRichard Marian Thomaiyar static inline Cc resetMtmTimer(ipmi::Context::ptr ctx)
57666dd01cSRichard Marian Thomaiyar {
58666dd01cSRichard Marian Thomaiyar     boost::system::error_code ec;
59357ddc74SRichard Marian Thomaiyar     ctx->bus->yield_method_call<>(ctx->yield, ec, specialModeService,
60666dd01cSRichard Marian Thomaiyar                                   specialModeObjPath, specialModeIntf,
61666dd01cSRichard Marian Thomaiyar                                   "ResetTimer");
62666dd01cSRichard Marian Thomaiyar     if (ec)
63666dd01cSRichard Marian Thomaiyar     {
64666dd01cSRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
65666dd01cSRichard Marian Thomaiyar             "Failed to reset the manufacturing mode timer");
66666dd01cSRichard Marian Thomaiyar         return ccUnspecifiedError;
67666dd01cSRichard Marian Thomaiyar     }
68666dd01cSRichard Marian Thomaiyar     return ccSuccess;
69666dd01cSRichard Marian Thomaiyar }
70666dd01cSRichard Marian Thomaiyar 
7138d2b5a6SJason M. Bills int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path)
72a3702c1fSVernon Mauery {
7338d2b5a6SJason M. Bills     switch (signal)
7438d2b5a6SJason M. Bills     {
7538d2b5a6SJason M. Bills         case SmSignalGet::smPowerButton:
7638d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/power";
7738d2b5a6SJason M. Bills             break;
7838d2b5a6SJason M. Bills         case SmSignalGet::smResetButton:
7938d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/reset";
8038d2b5a6SJason M. Bills             break;
8138d2b5a6SJason M. Bills         case SmSignalGet::smNMIButton:
8238d2b5a6SJason M. Bills             path = "/xyz/openbmc_project/chassis/buttons/nmi";
8338d2b5a6SJason M. Bills             break;
848e5e2b04SRichard Marian Thomaiyar         case SmSignalGet::smIdentifyButton:
858e5e2b04SRichard Marian Thomaiyar             path = "/xyz/openbmc_project/chassis/buttons/id";
868e5e2b04SRichard Marian Thomaiyar             break;
8738d2b5a6SJason M. Bills         default:
8838d2b5a6SJason M. Bills             return -1;
8938d2b5a6SJason M. Bills             break;
9038d2b5a6SJason M. Bills     }
9138d2b5a6SJason M. Bills     return 0;
92a3702c1fSVernon Mauery }
93a3702c1fSVernon Mauery 
9437890392SPatrick Venture ipmi_ret_t ledStoreAndSet(SmSignalSet signal, const std::string& setState)
95a3702c1fSVernon Mauery {
96a3702c1fSVernon Mauery     LedProperty* ledProp = mtm.findLedProperty(signal);
97a3702c1fSVernon Mauery     if (ledProp == nullptr)
98a3702c1fSVernon Mauery     {
99a3702c1fSVernon Mauery         return IPMI_CC_INVALID_FIELD_REQUEST;
100a3702c1fSVernon Mauery     }
101a3702c1fSVernon Mauery 
102a3702c1fSVernon Mauery     std::string ledName = ledProp->getName();
103a3702c1fSVernon Mauery     std::string ledService = ledServicePrefix + ledName;
104a3702c1fSVernon Mauery     std::string ledPath = ledPathPrefix + ledName;
105a3702c1fSVernon Mauery     ipmi::Value presentState;
106a3702c1fSVernon Mauery 
107a3702c1fSVernon Mauery     if (false == ledProp->getLock())
108a3702c1fSVernon Mauery     {
109a3702c1fSVernon Mauery         if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf,
110a3702c1fSVernon Mauery                             "State", &presentState) != 0)
111a3702c1fSVernon Mauery         {
112a3702c1fSVernon Mauery             return IPMI_CC_UNSPECIFIED_ERROR;
113a3702c1fSVernon Mauery         }
114a3702c1fSVernon Mauery         ledProp->setPrevState(std::get<std::string>(presentState));
115a3702c1fSVernon Mauery         ledProp->setLock(true);
116a3702c1fSVernon Mauery         if (signal == SmSignalSet::smPowerFaultLed ||
117a3702c1fSVernon Mauery             signal == SmSignalSet::smSystemReadyLed)
118a3702c1fSVernon Mauery         {
119a3702c1fSVernon Mauery             mtm.revertLedCallback = true;
120a3702c1fSVernon Mauery         }
121a3702c1fSVernon Mauery     }
12238d2b5a6SJason M. Bills     if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
123a3702c1fSVernon Mauery                         ledStateStr + setState) != 0)
124a3702c1fSVernon Mauery     {
125a3702c1fSVernon Mauery         return IPMI_CC_UNSPECIFIED_ERROR;
126a3702c1fSVernon Mauery     }
127a3702c1fSVernon Mauery     return IPMI_CC_OK;
128a3702c1fSVernon Mauery }
129a3702c1fSVernon Mauery 
130a3702c1fSVernon Mauery ipmi_ret_t ledRevert(SmSignalSet signal)
131a3702c1fSVernon Mauery {
132a3702c1fSVernon Mauery     LedProperty* ledProp = mtm.findLedProperty(signal);
133a3702c1fSVernon Mauery     if (ledProp == nullptr)
134a3702c1fSVernon Mauery     {
135a3702c1fSVernon Mauery         return IPMI_CC_INVALID_FIELD_REQUEST;
136a3702c1fSVernon Mauery     }
137a3702c1fSVernon Mauery     if (true == ledProp->getLock())
138a3702c1fSVernon Mauery     {
139a3702c1fSVernon Mauery         ledProp->setLock(false);
140a3702c1fSVernon Mauery         if (signal == SmSignalSet::smPowerFaultLed ||
141a3702c1fSVernon Mauery             signal == SmSignalSet::smSystemReadyLed)
142a3702c1fSVernon Mauery         {
143a3702c1fSVernon Mauery             try
144a3702c1fSVernon Mauery             {
145a3702c1fSVernon Mauery                 ipmi::method_no_args::callDbusMethod(
146a3702c1fSVernon Mauery                     *getSdBus(), callbackMgrService, callbackMgrObjPath,
147a3702c1fSVernon Mauery                     callbackMgrIntf, retriggerLedUpdate);
148a3702c1fSVernon Mauery             }
149bd51e6a9SPatrick Williams             catch (const sdbusplus::exception_t& e)
150a3702c1fSVernon Mauery             {
151a3702c1fSVernon Mauery                 return IPMI_CC_UNSPECIFIED_ERROR;
152a3702c1fSVernon Mauery             }
153a3702c1fSVernon Mauery             mtm.revertLedCallback = false;
154a3702c1fSVernon Mauery         }
155a3702c1fSVernon Mauery         else
156a3702c1fSVernon Mauery         {
157a3702c1fSVernon Mauery             std::string ledName = ledProp->getName();
158a3702c1fSVernon Mauery             std::string ledService = ledServicePrefix + ledName;
159a3702c1fSVernon Mauery             std::string ledPath = ledPathPrefix + ledName;
16038d2b5a6SJason M. Bills             if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
16138d2b5a6SJason M. Bills                                 ledProp->getPrevState()) != 0)
162a3702c1fSVernon Mauery             {
163a3702c1fSVernon Mauery                 return IPMI_CC_UNSPECIFIED_ERROR;
164a3702c1fSVernon Mauery             }
165a3702c1fSVernon Mauery         }
166a3702c1fSVernon Mauery     }
167a3702c1fSVernon Mauery     return IPMI_CC_OK;
168a3702c1fSVernon Mauery }
169a3702c1fSVernon Mauery 
170a3702c1fSVernon Mauery void Manufacturing::initData()
171a3702c1fSVernon Mauery {
172a3702c1fSVernon Mauery     ledPropertyList.push_back(
173a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smPowerFaultLed, "status_amber"));
174a3702c1fSVernon Mauery     ledPropertyList.push_back(
175a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smSystemReadyLed, "status_green"));
176a3702c1fSVernon Mauery     ledPropertyList.push_back(
177a3702c1fSVernon Mauery         LedProperty(SmSignalSet::smIdentifyLed, "identify"));
178a3702c1fSVernon Mauery }
179a3702c1fSVernon Mauery 
180a3702c1fSVernon Mauery void Manufacturing::revertTimerHandler()
181a3702c1fSVernon Mauery {
182ae13ac62SRichard Marian Thomaiyar 
183ae13ac62SRichard Marian Thomaiyar #ifdef BMC_VALIDATION_UNSECURE_FEATURE
184ae13ac62SRichard Marian Thomaiyar     if (mtm.getMfgMode() == SpecialMode::valUnsecure)
185ae13ac62SRichard Marian Thomaiyar     {
186ae13ac62SRichard Marian Thomaiyar         // Don't revert the behaviour for validation unsecure mode.
187ae13ac62SRichard Marian Thomaiyar         return;
188ae13ac62SRichard Marian Thomaiyar     }
189ae13ac62SRichard Marian Thomaiyar #endif
190a3702c1fSVernon Mauery     if (revertFanPWM)
191a3702c1fSVernon Mauery     {
192a3702c1fSVernon Mauery         revertFanPWM = false;
193a3702c1fSVernon Mauery         disablePidControlService(false);
194a3702c1fSVernon Mauery     }
195a3702c1fSVernon Mauery 
196d872a4a4SAyushi Smriti     if (mtmTestBeepFd != -1)
197d872a4a4SAyushi Smriti     {
198d872a4a4SAyushi Smriti         ::close(mtmTestBeepFd);
199d872a4a4SAyushi Smriti         mtmTestBeepFd = -1;
200d872a4a4SAyushi Smriti     }
201d872a4a4SAyushi Smriti 
202a3702c1fSVernon Mauery     for (const auto& ledProperty : ledPropertyList)
203a3702c1fSVernon Mauery     {
204a3702c1fSVernon Mauery         const std::string& ledName = ledProperty.getName();
205f365614cSJayaprakash Mutyala         if (ledName == "identify" && mtm.getMfgMode() == SpecialMode::mfg)
206f365614cSJayaprakash Mutyala         {
207f365614cSJayaprakash Mutyala             // Don't revert the behaviour for manufacturing mode
208f365614cSJayaprakash Mutyala             continue;
209f365614cSJayaprakash Mutyala         }
210a3702c1fSVernon Mauery         ledRevert(ledProperty.getSignal());
211a3702c1fSVernon Mauery     }
212a3702c1fSVernon Mauery }
213a3702c1fSVernon Mauery 
214a3702c1fSVernon Mauery Manufacturing::Manufacturing() :
215a3702c1fSVernon Mauery     revertTimer([&](void) { revertTimerHandler(); })
216a3702c1fSVernon Mauery {
217a3702c1fSVernon Mauery     initData();
218a3702c1fSVernon Mauery }
219a3702c1fSVernon Mauery 
22038d2b5a6SJason M. Bills int8_t Manufacturing::getProperty(const std::string& service,
22138d2b5a6SJason M. Bills                                   const std::string& path,
22238d2b5a6SJason M. Bills                                   const std::string& interface,
22338d2b5a6SJason M. Bills                                   const std::string& propertyName,
22438d2b5a6SJason M. Bills                                   ipmi::Value* reply)
225a3702c1fSVernon Mauery {
226a3702c1fSVernon Mauery     try
227a3702c1fSVernon Mauery     {
22838d2b5a6SJason M. Bills         *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface,
22938d2b5a6SJason M. Bills                                        propertyName);
230a3702c1fSVernon Mauery     }
231f944d2e5SPatrick Williams     catch (const sdbusplus::exception_t& e)
232a3702c1fSVernon Mauery     {
233a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
234a3702c1fSVernon Mauery             "ERROR: getProperty");
235a3702c1fSVernon Mauery         return -1;
236a3702c1fSVernon Mauery     }
237a3702c1fSVernon Mauery 
238a3702c1fSVernon Mauery     return 0;
239a3702c1fSVernon Mauery }
240a3702c1fSVernon Mauery 
24138d2b5a6SJason M. Bills int8_t Manufacturing::setProperty(const std::string& service,
24238d2b5a6SJason M. Bills                                   const std::string& path,
24338d2b5a6SJason M. Bills                                   const std::string& interface,
24438d2b5a6SJason M. Bills                                   const std::string& propertyName,
24538d2b5a6SJason M. Bills                                   ipmi::Value value)
246a3702c1fSVernon Mauery {
247a3702c1fSVernon Mauery     try
248a3702c1fSVernon Mauery     {
24938d2b5a6SJason M. Bills         ipmi::setDbusProperty(*getSdBus(), service, path, interface,
250a3702c1fSVernon Mauery                               propertyName, value);
251a3702c1fSVernon Mauery     }
252f944d2e5SPatrick Williams     catch (const sdbusplus::exception_t& e)
253a3702c1fSVernon Mauery     {
254a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
255a3702c1fSVernon Mauery             "ERROR: setProperty");
256a3702c1fSVernon Mauery         return -1;
257a3702c1fSVernon Mauery     }
258a3702c1fSVernon Mauery 
259a3702c1fSVernon Mauery     return 0;
260a3702c1fSVernon Mauery }
261a3702c1fSVernon Mauery 
262a3702c1fSVernon Mauery int8_t Manufacturing::disablePidControlService(const bool disable)
263a3702c1fSVernon Mauery {
264a3702c1fSVernon Mauery     try
265a3702c1fSVernon Mauery     {
266a3702c1fSVernon Mauery         auto dbus = getSdBus();
267a3702c1fSVernon Mauery         auto method = dbus->new_method_call(systemDService, systemDObjPath,
268a3702c1fSVernon Mauery                                             systemDMgrIntf,
269a3702c1fSVernon Mauery                                             disable ? "StopUnit" : "StartUnit");
270a3702c1fSVernon Mauery         method.append(pidControlService, "replace");
271a3702c1fSVernon Mauery         auto reply = dbus->call(method);
272a3702c1fSVernon Mauery     }
273f944d2e5SPatrick Williams     catch (const sdbusplus::exception_t& e)
274a3702c1fSVernon Mauery     {
275a3702c1fSVernon Mauery         phosphor::logging::log<phosphor::logging::level::INFO>(
276a3702c1fSVernon Mauery             "ERROR: phosphor-pid-control service start or stop failed");
277a3702c1fSVernon Mauery         return -1;
278a3702c1fSVernon Mauery     }
279a3702c1fSVernon Mauery     return 0;
280a3702c1fSVernon Mauery }
281a3702c1fSVernon Mauery 
28290eb7876SAlex Schendel static bool findPwmName(ipmi::Context::ptr& ctx, uint8_t instance,
28390eb7876SAlex Schendel                         std::string& pwmName)
28490eb7876SAlex Schendel {
28590eb7876SAlex Schendel     boost::system::error_code ec{};
28690eb7876SAlex Schendel     ObjectValueTree obj;
28790eb7876SAlex Schendel 
28890eb7876SAlex Schendel     // GetAll the objects under service FruDevice
28990eb7876SAlex Schendel     ec = getManagedObjects(ctx, "xyz.openbmc_project.EntityManager",
29090eb7876SAlex Schendel                            "/xyz/openbmc_project/inventory", obj);
29190eb7876SAlex Schendel     if (ec)
29290eb7876SAlex Schendel     {
29390eb7876SAlex Schendel         phosphor::logging::log<phosphor::logging::level::ERR>(
29490eb7876SAlex Schendel             "GetMangagedObjects failed",
29590eb7876SAlex Schendel             phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
29690eb7876SAlex Schendel         return false;
29790eb7876SAlex Schendel     }
29890eb7876SAlex Schendel     for (const auto& [path, objData] : obj)
29990eb7876SAlex Schendel     {
30090eb7876SAlex Schendel         for (const auto& [intf, propMap] : objData)
30190eb7876SAlex Schendel         {
30290eb7876SAlex Schendel             // Currently, these are the three different fan types supported.
30390eb7876SAlex Schendel             if (intf == "xyz.openbmc_project.Configuration.AspeedFan" ||
30490eb7876SAlex Schendel                 intf == "xyz.openbmc_project.Configuration.I2CFan" ||
30590eb7876SAlex Schendel                 intf == "xyz.openbmc_project.Configuration.NuvotonFan")
30690eb7876SAlex Schendel             {
30790eb7876SAlex Schendel                 auto findIndex = propMap.find("Index");
30890eb7876SAlex Schendel                 if (findIndex == propMap.end())
30990eb7876SAlex Schendel                 {
31090eb7876SAlex Schendel                     continue;
31190eb7876SAlex Schendel                 }
31290eb7876SAlex Schendel 
31390eb7876SAlex Schendel                 auto fanIndex = std::get_if<uint64_t>(&findIndex->second);
31490eb7876SAlex Schendel                 if (!fanIndex || *fanIndex != instance)
31590eb7876SAlex Schendel                 {
31690eb7876SAlex Schendel                     continue;
31790eb7876SAlex Schendel                 }
31890eb7876SAlex Schendel                 auto connector = objData.find(intf + std::string(".Connector"));
31990eb7876SAlex Schendel                 if (connector == objData.end())
32090eb7876SAlex Schendel                 {
32190eb7876SAlex Schendel                     return false;
32290eb7876SAlex Schendel                 }
32390eb7876SAlex Schendel                 auto findPwmName = connector->second.find("PwmName");
32490eb7876SAlex Schendel                 if (findPwmName != connector->second.end())
32590eb7876SAlex Schendel                 {
32690eb7876SAlex Schendel                     auto fanPwmName =
32790eb7876SAlex Schendel                         std::get_if<std::string>(&findPwmName->second);
32890eb7876SAlex Schendel                     if (!fanPwmName)
32990eb7876SAlex Schendel                     {
33090eb7876SAlex Schendel                         phosphor::logging::log<phosphor::logging::level::INFO>(
33190eb7876SAlex Schendel                             "PwmName parse ERROR.");
33290eb7876SAlex Schendel                         return false;
33390eb7876SAlex Schendel                     }
33490eb7876SAlex Schendel                     pwmName = *fanPwmName;
33590eb7876SAlex Schendel                     return true;
33690eb7876SAlex Schendel                 }
33790eb7876SAlex Schendel                 auto findPwm = connector->second.find("Pwm");
33890eb7876SAlex Schendel                 if (findPwm == connector->second.end())
33990eb7876SAlex Schendel                 {
34090eb7876SAlex Schendel                     return false;
34190eb7876SAlex Schendel                 }
34290eb7876SAlex Schendel                 auto fanPwm = std::get_if<uint64_t>(&findPwm->second);
34390eb7876SAlex Schendel                 if (!fanPwm)
34490eb7876SAlex Schendel                 {
34590eb7876SAlex Schendel                     return false;
34690eb7876SAlex Schendel                 }
34790eb7876SAlex Schendel                 pwmName = "Pwm_" + std::to_string(*fanPwm + 1);
34890eb7876SAlex Schendel                 return true;
34990eb7876SAlex Schendel             }
35090eb7876SAlex Schendel         }
35190eb7876SAlex Schendel     }
35290eb7876SAlex Schendel     return false;
35390eb7876SAlex Schendel }
35438d2b5a6SJason M. Bills ipmi::RspType<uint8_t,                // Signal value
35538d2b5a6SJason M. Bills               std::optional<uint16_t> // Fan tach value
35638d2b5a6SJason M. Bills               >
357357ddc74SRichard Marian Thomaiyar     appMTMGetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte,
358147daec5SRichard Marian Thomaiyar                     uint8_t instance, uint8_t actionByte)
359a3702c1fSVernon Mauery {
360e0511e5fSAyushi Smriti     // mfg filter logic is used to allow MTM get signal command only in
361e0511e5fSAyushi Smriti     // manfacturing mode.
36238d2b5a6SJason M. Bills 
36338d2b5a6SJason M. Bills     SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte);
36438d2b5a6SJason M. Bills     SmActionGet action = static_cast<SmActionGet>(actionByte);
36538d2b5a6SJason M. Bills 
36638d2b5a6SJason M. Bills     switch (signalType)
36738d2b5a6SJason M. Bills     {
36898705b39Sanil kumar appana         case SmSignalGet::smChassisIntrusion:
36998705b39Sanil kumar appana         {
37098705b39Sanil kumar appana             ipmi::Value reply;
37198705b39Sanil kumar appana             if (mtm.getProperty(intrusionService, intrusionPath, intrusionIntf,
37298705b39Sanil kumar appana                                 "Status", &reply) < 0)
37398705b39Sanil kumar appana             {
37498705b39Sanil kumar appana                 return ipmi::responseInvalidFieldRequest();
37598705b39Sanil kumar appana             }
37698705b39Sanil kumar appana             std::string* intrusionStatus = std::get_if<std::string>(&reply);
37798705b39Sanil kumar appana             if (!intrusionStatus)
37898705b39Sanil kumar appana             {
37998705b39Sanil kumar appana                 return ipmi::responseUnspecifiedError();
38098705b39Sanil kumar appana             }
38198705b39Sanil kumar appana 
38298705b39Sanil kumar appana             uint8_t status = 0;
38398705b39Sanil kumar appana             if (!intrusionStatus->compare("Normal"))
38498705b39Sanil kumar appana             {
38598705b39Sanil kumar appana                 status = static_cast<uint8_t>(IntrusionStatus::normal);
38698705b39Sanil kumar appana             }
38798705b39Sanil kumar appana             else if (!intrusionStatus->compare("HardwareIntrusion"))
38898705b39Sanil kumar appana             {
38998705b39Sanil kumar appana                 status =
39098705b39Sanil kumar appana                     static_cast<uint8_t>(IntrusionStatus::hardwareIntrusion);
39198705b39Sanil kumar appana             }
39298705b39Sanil kumar appana             else if (!intrusionStatus->compare("TamperingDetected"))
39398705b39Sanil kumar appana             {
39498705b39Sanil kumar appana                 status =
39598705b39Sanil kumar appana                     static_cast<uint8_t>(IntrusionStatus::tamperingDetected);
39698705b39Sanil kumar appana             }
39798705b39Sanil kumar appana             else
39898705b39Sanil kumar appana             {
39998705b39Sanil kumar appana                 return ipmi::responseUnspecifiedError();
40098705b39Sanil kumar appana             }
40198705b39Sanil kumar appana             return ipmi::responseSuccess(status, std::nullopt);
40298705b39Sanil kumar appana         }
40338d2b5a6SJason M. Bills         case SmSignalGet::smFanPwmGet:
40438d2b5a6SJason M. Bills         {
405a3702c1fSVernon Mauery             ipmi::Value reply;
40690eb7876SAlex Schendel             std::string pwmName, fullPath;
40790eb7876SAlex Schendel             if (!findPwmName(ctx, instance, pwmName))
40890eb7876SAlex Schendel             {
40990eb7876SAlex Schendel                 // The default PWM name is Pwm_#
41090eb7876SAlex Schendel                 pwmName = "Pwm_" + std::to_string(instance + 1);
41190eb7876SAlex Schendel             }
41290eb7876SAlex Schendel             fullPath = fanPwmPath + pwmName;
41338d2b5a6SJason M. Bills             if (mtm.getProperty(fanService, fullPath, fanIntf, "Value",
41438d2b5a6SJason M. Bills                                 &reply) < 0)
41538d2b5a6SJason M. Bills             {
41638d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
41738d2b5a6SJason M. Bills             }
41838d2b5a6SJason M. Bills             double* doubleVal = std::get_if<double>(&reply);
41938d2b5a6SJason M. Bills             if (doubleVal == nullptr)
42038d2b5a6SJason M. Bills             {
42138d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
42238d2b5a6SJason M. Bills             }
42338d2b5a6SJason M. Bills             uint8_t sensorVal = std::round(*doubleVal);
424357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
42538d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, std::nullopt);
42638d2b5a6SJason M. Bills         }
42738d2b5a6SJason M. Bills         break;
42838d2b5a6SJason M. Bills         case SmSignalGet::smFanTachometerGet:
42938d2b5a6SJason M. Bills         {
430147daec5SRichard Marian Thomaiyar             boost::system::error_code ec;
431147daec5SRichard Marian Thomaiyar             using objFlatMap = boost::container::flat_map<
432147daec5SRichard Marian Thomaiyar                 std::string, boost::container::flat_map<
433147daec5SRichard Marian Thomaiyar                                  std::string, std::vector<std::string>>>;
434147daec5SRichard Marian Thomaiyar 
435357ddc74SRichard Marian Thomaiyar             auto flatMap = ctx->bus->yield_method_call<objFlatMap>(
436357ddc74SRichard Marian Thomaiyar                 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
437147daec5SRichard Marian Thomaiyar                 "/xyz/openbmc_project/object_mapper",
438147daec5SRichard Marian Thomaiyar                 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
439147daec5SRichard Marian Thomaiyar                 fanTachBasePath, 0, std::array<const char*, 1>{fanIntf});
440147daec5SRichard Marian Thomaiyar             if (ec)
441147daec5SRichard Marian Thomaiyar             {
442147daec5SRichard Marian Thomaiyar                 phosphor::logging::log<phosphor::logging::level::ERR>(
443147daec5SRichard Marian Thomaiyar                     "Failed to query fan tach sub tree objects");
444147daec5SRichard Marian Thomaiyar                 return ipmi::responseUnspecifiedError();
445147daec5SRichard Marian Thomaiyar             }
446147daec5SRichard Marian Thomaiyar             if (instance >= flatMap.size())
44738d2b5a6SJason M. Bills             {
44838d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
44938d2b5a6SJason M. Bills             }
450147daec5SRichard Marian Thomaiyar             auto itr = flatMap.nth(instance);
45138d2b5a6SJason M. Bills             ipmi::Value reply;
452147daec5SRichard Marian Thomaiyar             if (mtm.getProperty(fanService, itr->first, fanIntf, "Value",
45338d2b5a6SJason M. Bills                                 &reply) < 0)
45438d2b5a6SJason M. Bills             {
45538d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
45638d2b5a6SJason M. Bills             }
45738d2b5a6SJason M. Bills 
45838d2b5a6SJason M. Bills             double* doubleVal = std::get_if<double>(&reply);
45938d2b5a6SJason M. Bills             if (doubleVal == nullptr)
46038d2b5a6SJason M. Bills             {
46138d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
46238d2b5a6SJason M. Bills             }
46338d2b5a6SJason M. Bills             uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT;
46438d2b5a6SJason M. Bills             std::optional<uint16_t> fanTach = std::round(*doubleVal);
46538d2b5a6SJason M. Bills 
466357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
46738d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, fanTach);
46838d2b5a6SJason M. Bills         }
46938d2b5a6SJason M. Bills         break;
4708e5e2b04SRichard Marian Thomaiyar         case SmSignalGet::smIdentifyButton:
4718e5e2b04SRichard Marian Thomaiyar         {
4728e5e2b04SRichard Marian Thomaiyar             if (action == SmActionGet::revert || action == SmActionGet::ignore)
4738e5e2b04SRichard Marian Thomaiyar             {
4748e5e2b04SRichard Marian Thomaiyar                 // ButtonMasked property is not supported for ID button as it is
4758e5e2b04SRichard Marian Thomaiyar                 // unnecessary. Hence if requested for revert / ignore, override
4768e5e2b04SRichard Marian Thomaiyar                 // it to sample action to make tools happy.
4778e5e2b04SRichard Marian Thomaiyar                 action = SmActionGet::sample;
4788e5e2b04SRichard Marian Thomaiyar             }
4798e5e2b04SRichard Marian Thomaiyar             // fall-through
4808e5e2b04SRichard Marian Thomaiyar         }
48138d2b5a6SJason M. Bills         case SmSignalGet::smResetButton:
48238d2b5a6SJason M. Bills         case SmSignalGet::smPowerButton:
48338d2b5a6SJason M. Bills         case SmSignalGet::smNMIButton:
48438d2b5a6SJason M. Bills         {
48538d2b5a6SJason M. Bills             std::string path;
48638d2b5a6SJason M. Bills             if (getGpioPathForSmSignal(signalType, path) < 0)
48738d2b5a6SJason M. Bills             {
48838d2b5a6SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
48938d2b5a6SJason M. Bills             }
490a3702c1fSVernon Mauery 
491a3702c1fSVernon Mauery             switch (action)
492a3702c1fSVernon Mauery             {
493a3702c1fSVernon Mauery                 case SmActionGet::sample:
494a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
495a3702c1fSVernon Mauery                         "case SmActionGet::sample");
496a3702c1fSVernon Mauery                     break;
497a3702c1fSVernon Mauery                 case SmActionGet::ignore:
498a3702c1fSVernon Mauery                 {
499a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
500a3702c1fSVernon Mauery                         "case SmActionGet::ignore");
50138d2b5a6SJason M. Bills                     if (mtm.setProperty(buttonService, path, buttonIntf,
50238d2b5a6SJason M. Bills                                         "ButtonMasked", true) < 0)
503a3702c1fSVernon Mauery                     {
50438d2b5a6SJason M. Bills                         return ipmi::responseUnspecifiedError();
505a3702c1fSVernon Mauery                     }
506a3702c1fSVernon Mauery                 }
507a3702c1fSVernon Mauery                 break;
508a3702c1fSVernon Mauery                 case SmActionGet::revert:
509a3702c1fSVernon Mauery                 {
510a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
511a3702c1fSVernon Mauery                         "case SmActionGet::revert");
51238d2b5a6SJason M. Bills                     if (mtm.setProperty(buttonService, path, buttonIntf,
51338d2b5a6SJason M. Bills                                         "ButtonMasked", false) < 0)
514a3702c1fSVernon Mauery                     {
51538d2b5a6SJason M. Bills                         return ipmi::responseUnspecifiedError();
516a3702c1fSVernon Mauery                     }
517a3702c1fSVernon Mauery                 }
518a3702c1fSVernon Mauery                 break;
519a3702c1fSVernon Mauery 
520a3702c1fSVernon Mauery                 default:
52138d2b5a6SJason M. Bills                     return ipmi::responseInvalidFieldRequest();
522a3702c1fSVernon Mauery                     break;
523a3702c1fSVernon Mauery             }
524a3702c1fSVernon Mauery 
525a3702c1fSVernon Mauery             ipmi::Value reply;
52638d2b5a6SJason M. Bills             if (mtm.getProperty(buttonService, path, buttonIntf,
52738d2b5a6SJason M. Bills                                 "ButtonPressed", &reply) < 0)
528a3702c1fSVernon Mauery             {
52938d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
530a3702c1fSVernon Mauery             }
53138d2b5a6SJason M. Bills             bool* valPtr = std::get_if<bool>(&reply);
53238d2b5a6SJason M. Bills             if (valPtr == nullptr)
533a3702c1fSVernon Mauery             {
53438d2b5a6SJason M. Bills                 return ipmi::responseUnspecifiedError();
535a3702c1fSVernon Mauery             }
536357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
53738d2b5a6SJason M. Bills             uint8_t sensorVal = *valPtr;
53838d2b5a6SJason M. Bills             return ipmi::responseSuccess(sensorVal, std::nullopt);
539a3702c1fSVernon Mauery         }
540a3702c1fSVernon Mauery         break;
5411b74a210SRichard Marian Thomaiyar         case SmSignalGet::smNcsiDiag:
5421b74a210SRichard Marian Thomaiyar         {
5431b74a210SRichard Marian Thomaiyar             constexpr const char* netBasePath = "/sys/class/net/eth";
5441b74a210SRichard Marian Thomaiyar             constexpr const char* carrierSuffix = "/carrier";
5451b74a210SRichard Marian Thomaiyar             std::ifstream netIfs(netBasePath + std::to_string(instance) +
5461b74a210SRichard Marian Thomaiyar                                  carrierSuffix);
5471b74a210SRichard Marian Thomaiyar             if (!netIfs.good())
5481b74a210SRichard Marian Thomaiyar             {
5491b74a210SRichard Marian Thomaiyar                 return ipmi::responseInvalidFieldRequest();
5501b74a210SRichard Marian Thomaiyar             }
5511b74a210SRichard Marian Thomaiyar             std::string carrier;
5521b74a210SRichard Marian Thomaiyar             netIfs >> carrier;
553357ddc74SRichard Marian Thomaiyar             resetMtmTimer(ctx);
5541b74a210SRichard Marian Thomaiyar             return ipmi::responseSuccess(
5551b74a210SRichard Marian Thomaiyar                 static_cast<uint8_t>(std::stoi(carrier)), std::nullopt);
5561b74a210SRichard Marian Thomaiyar         }
5571b74a210SRichard Marian Thomaiyar         break;
558a3702c1fSVernon Mauery         default:
55938d2b5a6SJason M. Bills             return ipmi::responseInvalidFieldRequest();
560a3702c1fSVernon Mauery             break;
561a3702c1fSVernon Mauery     }
562a3702c1fSVernon Mauery }
563a3702c1fSVernon Mauery 
564357ddc74SRichard Marian Thomaiyar ipmi::RspType<> appMTMSetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte,
565357ddc74SRichard Marian Thomaiyar                                 uint8_t instance, uint8_t actionByte,
5665e3bf557SAyushi Smriti                                 std::optional<uint8_t> pwmSpeed)
567a3702c1fSVernon Mauery {
568e0511e5fSAyushi Smriti     // mfg filter logic is used to allow MTM set signal command only in
569e0511e5fSAyushi Smriti     // manfacturing mode.
5705e3bf557SAyushi Smriti 
5715e3bf557SAyushi Smriti     SmSignalSet signalType = static_cast<SmSignalSet>(signalTypeByte);
5725e3bf557SAyushi Smriti     SmActionSet action = static_cast<SmActionSet>(actionByte);
5735e3bf557SAyushi Smriti     Cc retCode = ccSuccess;
57413b0039dSJames Feist     int8_t ret = 0;
5755e3bf557SAyushi Smriti 
5765e3bf557SAyushi Smriti     switch (signalType)
577a3702c1fSVernon Mauery     {
578a3702c1fSVernon Mauery         case SmSignalSet::smPowerFaultLed:
579a3702c1fSVernon Mauery         case SmSignalSet::smSystemReadyLed:
580a3702c1fSVernon Mauery         case SmSignalSet::smIdentifyLed:
5815e3bf557SAyushi Smriti             switch (action)
582a3702c1fSVernon Mauery             {
583a3702c1fSVernon Mauery                 case SmActionSet::forceDeasserted:
584a3702c1fSVernon Mauery                 {
585a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
586a3702c1fSVernon Mauery                         "case SmActionSet::forceDeasserted");
587a3702c1fSVernon Mauery 
5885e3bf557SAyushi Smriti                     retCode = ledStoreAndSet(signalType, std::string("Off"));
5895e3bf557SAyushi Smriti                     if (retCode != ccSuccess)
590a3702c1fSVernon Mauery                     {
5915e3bf557SAyushi Smriti                         return ipmi::response(retCode);
592a3702c1fSVernon Mauery                     }
593a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
594a3702c1fSVernon Mauery                 }
595a3702c1fSVernon Mauery                 break;
596a3702c1fSVernon Mauery                 case SmActionSet::forceAsserted:
597a3702c1fSVernon Mauery                 {
598a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
599a3702c1fSVernon Mauery                         "case SmActionSet::forceAsserted");
600a3702c1fSVernon Mauery 
6015e3bf557SAyushi Smriti                     retCode = ledStoreAndSet(signalType, std::string("On"));
6025e3bf557SAyushi Smriti                     if (retCode != ccSuccess)
603a3702c1fSVernon Mauery                     {
6045e3bf557SAyushi Smriti                         return ipmi::response(retCode);
605a3702c1fSVernon Mauery                     }
606a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
6075e3bf557SAyushi Smriti                     if (SmSignalSet::smPowerFaultLed == signalType)
608a3702c1fSVernon Mauery                     {
609a3702c1fSVernon Mauery                         // Deassert "system ready"
6105e3bf557SAyushi Smriti                         retCode = ledStoreAndSet(SmSignalSet::smSystemReadyLed,
611a3702c1fSVernon Mauery                                                  std::string("Off"));
612a3702c1fSVernon Mauery                     }
6135e3bf557SAyushi Smriti                     else if (SmSignalSet::smSystemReadyLed == signalType)
614a3702c1fSVernon Mauery                     {
615a3702c1fSVernon Mauery                         // Deassert "fault led"
6165e3bf557SAyushi Smriti                         retCode = ledStoreAndSet(SmSignalSet::smPowerFaultLed,
617a3702c1fSVernon Mauery                                                  std::string("Off"));
618a3702c1fSVernon Mauery                     }
619a3702c1fSVernon Mauery                 }
620a3702c1fSVernon Mauery                 break;
621a3702c1fSVernon Mauery                 case SmActionSet::revert:
622a3702c1fSVernon Mauery                 {
623a3702c1fSVernon Mauery                     phosphor::logging::log<phosphor::logging::level::INFO>(
624a3702c1fSVernon Mauery                         "case SmActionSet::revert");
6255e3bf557SAyushi Smriti                     retCode = ledRevert(signalType);
626a3702c1fSVernon Mauery                 }
627a3702c1fSVernon Mauery                 break;
628a3702c1fSVernon Mauery                 default:
629a3702c1fSVernon Mauery                 {
6305e3bf557SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
631a3702c1fSVernon Mauery                 }
632a3702c1fSVernon Mauery             }
633a3702c1fSVernon Mauery             break;
634a3702c1fSVernon Mauery         case SmSignalSet::smFanPowerSpeed:
635a3702c1fSVernon Mauery         {
6365e3bf557SAyushi Smriti             if ((action == SmActionSet::forceAsserted) && (!pwmSpeed))
637a3702c1fSVernon Mauery             {
6385e3bf557SAyushi Smriti                 return ipmi::responseReqDataLenInvalid();
639a3702c1fSVernon Mauery             }
6405e3bf557SAyushi Smriti 
6415e3bf557SAyushi Smriti             if ((action == SmActionSet::forceAsserted) && (*pwmSpeed > 100))
6425e3bf557SAyushi Smriti             {
6435e3bf557SAyushi Smriti                 return ipmi::responseInvalidFieldRequest();
6445e3bf557SAyushi Smriti             }
6455e3bf557SAyushi Smriti 
646a3702c1fSVernon Mauery             uint8_t pwmValue = 0;
6475e3bf557SAyushi Smriti             switch (action)
648a3702c1fSVernon Mauery             {
649a3702c1fSVernon Mauery                 case SmActionSet::revert:
650a3702c1fSVernon Mauery                 {
651a3702c1fSVernon Mauery                     if (mtm.revertFanPWM)
652a3702c1fSVernon Mauery                     {
653a3702c1fSVernon Mauery                         ret = mtm.disablePidControlService(false);
654a3702c1fSVernon Mauery                         if (ret < 0)
655a3702c1fSVernon Mauery                         {
6565e3bf557SAyushi Smriti                             return ipmi::responseUnspecifiedError();
657a3702c1fSVernon Mauery                         }
658a3702c1fSVernon Mauery                         mtm.revertFanPWM = false;
659a3702c1fSVernon Mauery                     }
660a3702c1fSVernon Mauery                 }
661a3702c1fSVernon Mauery                 break;
662a3702c1fSVernon Mauery                 case SmActionSet::forceAsserted:
663a3702c1fSVernon Mauery                 {
6645e3bf557SAyushi Smriti                     pwmValue = *pwmSpeed;
665a3702c1fSVernon Mauery                 } // fall-through
666a3702c1fSVernon Mauery                 case SmActionSet::forceDeasserted:
667a3702c1fSVernon Mauery                 {
668a3702c1fSVernon Mauery                     if (!mtm.revertFanPWM)
669a3702c1fSVernon Mauery                     {
670a3702c1fSVernon Mauery                         ret = mtm.disablePidControlService(true);
671a3702c1fSVernon Mauery                         if (ret < 0)
672a3702c1fSVernon Mauery                         {
6735e3bf557SAyushi Smriti                             return ipmi::responseUnspecifiedError();
674a3702c1fSVernon Mauery                         }
675a3702c1fSVernon Mauery                         mtm.revertFanPWM = true;
676a3702c1fSVernon Mauery                     }
677a3702c1fSVernon Mauery                     mtm.revertTimer.start(revertTimeOut);
67890eb7876SAlex Schendel                     std::string pwmName, fanPwmInstancePath;
67990eb7876SAlex Schendel                     if (!findPwmName(ctx, instance, pwmName))
68090eb7876SAlex Schendel                     {
68190eb7876SAlex Schendel                         pwmName = "Pwm_" + std::to_string(instance + 1);
68290eb7876SAlex Schendel                     }
68390eb7876SAlex Schendel                     fanPwmInstancePath = fanPwmPath + pwmName;
6845e3bf557SAyushi Smriti                     ret =
6855e3bf557SAyushi Smriti                         mtm.setProperty(fanService, fanPwmInstancePath, fanIntf,
6865e3bf557SAyushi Smriti                                         "Value", static_cast<double>(pwmValue));
687a3702c1fSVernon Mauery                     if (ret < 0)
688a3702c1fSVernon Mauery                     {
6895e3bf557SAyushi Smriti                         return ipmi::responseUnspecifiedError();
690a3702c1fSVernon Mauery                     }
691a3702c1fSVernon Mauery                 }
692a3702c1fSVernon Mauery                 break;
693a3702c1fSVernon Mauery                 default:
694a3702c1fSVernon Mauery                 {
6955e3bf557SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
696a3702c1fSVernon Mauery                 }
697a3702c1fSVernon Mauery             }
698a3702c1fSVernon Mauery         }
699a3702c1fSVernon Mauery         break;
700d872a4a4SAyushi Smriti         case SmSignalSet::smSpeaker:
701d872a4a4SAyushi Smriti         {
702d872a4a4SAyushi Smriti             phosphor::logging::log<phosphor::logging::level::INFO>(
703d872a4a4SAyushi Smriti                 "Performing Speaker SmActionSet",
704d872a4a4SAyushi Smriti                 phosphor::logging::entry("ACTION=%d",
705d872a4a4SAyushi Smriti                                          static_cast<uint8_t>(action)));
706d872a4a4SAyushi Smriti             switch (action)
707d872a4a4SAyushi Smriti             {
708d872a4a4SAyushi Smriti                 case SmActionSet::forceAsserted:
709d872a4a4SAyushi Smriti                 {
710d872a4a4SAyushi Smriti                     char beepDevName[] = "/dev/input/event0";
711d872a4a4SAyushi Smriti                     if (mtm.mtmTestBeepFd != -1)
712d872a4a4SAyushi Smriti                     {
713d872a4a4SAyushi Smriti                         phosphor::logging::log<phosphor::logging::level::INFO>(
714d872a4a4SAyushi Smriti                             "mtm beep device is opened already!");
715d872a4a4SAyushi Smriti                         // returning success as already beep is in progress
716d872a4a4SAyushi Smriti                         return ipmi::response(retCode);
717d872a4a4SAyushi Smriti                     }
718d872a4a4SAyushi Smriti 
719d872a4a4SAyushi Smriti                     if ((mtm.mtmTestBeepFd =
720d872a4a4SAyushi Smriti                              ::open(beepDevName, O_RDWR | O_CLOEXEC)) < 0)
721d872a4a4SAyushi Smriti                     {
722d872a4a4SAyushi Smriti                         phosphor::logging::log<phosphor::logging::level::ERR>(
723d872a4a4SAyushi Smriti                             "Failed to open input device");
724d872a4a4SAyushi Smriti                         return ipmi::responseUnspecifiedError();
725d872a4a4SAyushi Smriti                     }
726d872a4a4SAyushi Smriti 
727d872a4a4SAyushi Smriti                     struct input_event event;
728d872a4a4SAyushi Smriti                     event.type = EV_SND;
729d872a4a4SAyushi Smriti                     event.code = SND_TONE;
730d872a4a4SAyushi Smriti                     event.value = 2000;
731d872a4a4SAyushi Smriti 
732d872a4a4SAyushi Smriti                     if (::write(mtm.mtmTestBeepFd, &event,
733d872a4a4SAyushi Smriti                                 sizeof(struct input_event)) !=
734d872a4a4SAyushi Smriti                         sizeof(struct input_event))
735d872a4a4SAyushi Smriti                     {
736d872a4a4SAyushi Smriti                         phosphor::logging::log<phosphor::logging::level::ERR>(
737d872a4a4SAyushi Smriti                             "Failed to write a tone sound event");
738d872a4a4SAyushi Smriti                         ::close(mtm.mtmTestBeepFd);
739d872a4a4SAyushi Smriti                         mtm.mtmTestBeepFd = -1;
740d872a4a4SAyushi Smriti                         return ipmi::responseUnspecifiedError();
741d872a4a4SAyushi Smriti                     }
742d872a4a4SAyushi Smriti                     mtm.revertTimer.start(revertTimeOut);
743d872a4a4SAyushi Smriti                 }
744d872a4a4SAyushi Smriti                 break;
745d872a4a4SAyushi Smriti                 case SmActionSet::revert:
746d872a4a4SAyushi Smriti                 case SmActionSet::forceDeasserted:
747d872a4a4SAyushi Smriti                 {
748d872a4a4SAyushi Smriti                     if (mtm.mtmTestBeepFd != -1)
749d872a4a4SAyushi Smriti                     {
750d872a4a4SAyushi Smriti                         ::close(mtm.mtmTestBeepFd);
751d872a4a4SAyushi Smriti                         mtm.mtmTestBeepFd = -1;
752d872a4a4SAyushi Smriti                     }
753d872a4a4SAyushi Smriti                 }
754d872a4a4SAyushi Smriti                 break;
755d872a4a4SAyushi Smriti                 default:
756d872a4a4SAyushi Smriti                 {
757d872a4a4SAyushi Smriti                     return ipmi::responseInvalidFieldRequest();
758d872a4a4SAyushi Smriti                 }
759d872a4a4SAyushi Smriti             }
760d872a4a4SAyushi Smriti         }
761d872a4a4SAyushi Smriti         break;
7623594c6d6SRichard Marian Thomaiyar         case SmSignalSet::smDiskFaultLed:
7633594c6d6SRichard Marian Thomaiyar         {
7643594c6d6SRichard Marian Thomaiyar             boost::system::error_code ec;
7653594c6d6SRichard Marian Thomaiyar             using objPaths = std::vector<std::string>;
7663594c6d6SRichard Marian Thomaiyar             std::string driveBasePath =
7673594c6d6SRichard Marian Thomaiyar                 "/xyz/openbmc_project/inventory/item/drive/";
7683594c6d6SRichard Marian Thomaiyar             static constexpr const char* driveLedIntf =
7693594c6d6SRichard Marian Thomaiyar                 "xyz.openbmc_project.Led.Group";
7703594c6d6SRichard Marian Thomaiyar             static constexpr const char* hsbpService =
7713594c6d6SRichard Marian Thomaiyar                 "xyz.openbmc_project.HsbpManager";
7723594c6d6SRichard Marian Thomaiyar 
7733594c6d6SRichard Marian Thomaiyar             auto driveList = ctx->bus->yield_method_call<objPaths>(
7743594c6d6SRichard Marian Thomaiyar                 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
7753594c6d6SRichard Marian Thomaiyar                 "/xyz/openbmc_project/object_mapper",
7763594c6d6SRichard Marian Thomaiyar                 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
7773594c6d6SRichard Marian Thomaiyar                 driveBasePath, 0, std::array<const char*, 1>{driveLedIntf});
7783594c6d6SRichard Marian Thomaiyar             if (ec)
7793594c6d6SRichard Marian Thomaiyar             {
7803594c6d6SRichard Marian Thomaiyar                 phosphor::logging::log<phosphor::logging::level::ERR>(
7813594c6d6SRichard Marian Thomaiyar                     "Failed to query HSBP drive sub tree objects");
7823594c6d6SRichard Marian Thomaiyar                 return ipmi::responseUnspecifiedError();
7833594c6d6SRichard Marian Thomaiyar             }
7843594c6d6SRichard Marian Thomaiyar             std::string driveObjPath =
7853594c6d6SRichard Marian Thomaiyar                 driveBasePath + "Drive_" + std::to_string(instance + 1);
7863594c6d6SRichard Marian Thomaiyar             if (std::find(driveList.begin(), driveList.end(), driveObjPath) ==
7873594c6d6SRichard Marian Thomaiyar                 driveList.end())
7883594c6d6SRichard Marian Thomaiyar             {
7893594c6d6SRichard Marian Thomaiyar                 return ipmi::responseInvalidFieldRequest();
7903594c6d6SRichard Marian Thomaiyar             }
7913594c6d6SRichard Marian Thomaiyar             bool driveLedState = false;
7923594c6d6SRichard Marian Thomaiyar             switch (action)
7933594c6d6SRichard Marian Thomaiyar             {
7943594c6d6SRichard Marian Thomaiyar                 case SmActionSet::forceAsserted:
7953594c6d6SRichard Marian Thomaiyar                 {
7963594c6d6SRichard Marian Thomaiyar                     driveLedState = true;
7973594c6d6SRichard Marian Thomaiyar                 }
7983594c6d6SRichard Marian Thomaiyar                 break;
7993594c6d6SRichard Marian Thomaiyar                 case SmActionSet::revert:
8003594c6d6SRichard Marian Thomaiyar                 {
8013594c6d6SRichard Marian Thomaiyar                     driveLedState = false;
8023594c6d6SRichard Marian Thomaiyar                 }
8033594c6d6SRichard Marian Thomaiyar                 break;
8043594c6d6SRichard Marian Thomaiyar                 case SmActionSet::forceDeasserted:
8053594c6d6SRichard Marian Thomaiyar                 {
8063594c6d6SRichard Marian Thomaiyar                     driveLedState = false;
8073594c6d6SRichard Marian Thomaiyar                 }
8083594c6d6SRichard Marian Thomaiyar                 break;
8093594c6d6SRichard Marian Thomaiyar                 default:
8103594c6d6SRichard Marian Thomaiyar                 {
8113594c6d6SRichard Marian Thomaiyar                     return ipmi::responseInvalidFieldRequest();
8123594c6d6SRichard Marian Thomaiyar                 }
8133594c6d6SRichard Marian Thomaiyar             }
8143594c6d6SRichard Marian Thomaiyar             ret = mtm.setProperty(hsbpService, driveObjPath, driveLedIntf,
8153594c6d6SRichard Marian Thomaiyar                                   "Asserted", driveLedState);
8163594c6d6SRichard Marian Thomaiyar             if (ret < 0)
8173594c6d6SRichard Marian Thomaiyar             {
8183594c6d6SRichard Marian Thomaiyar                 return ipmi::responseUnspecifiedError();
8193594c6d6SRichard Marian Thomaiyar             }
8203594c6d6SRichard Marian Thomaiyar         }
8213594c6d6SRichard Marian Thomaiyar         break;
822a3702c1fSVernon Mauery         default:
823a3702c1fSVernon Mauery         {
8245e3bf557SAyushi Smriti             return ipmi::responseInvalidFieldRequest();
825a3702c1fSVernon Mauery         }
826a3702c1fSVernon Mauery     }
8274cc10159SRichard Marian Thomaiyar     if (retCode == ccSuccess)
8284cc10159SRichard Marian Thomaiyar     {
829357ddc74SRichard Marian Thomaiyar         resetMtmTimer(ctx);
8304cc10159SRichard Marian Thomaiyar     }
8315e3bf557SAyushi Smriti     return ipmi::response(retCode);
832a3702c1fSVernon Mauery }
833a3702c1fSVernon Mauery 
834357ddc74SRichard Marian Thomaiyar ipmi::RspType<> mtmKeepAlive(ipmi::Context::ptr ctx, uint8_t reserved,
835666dd01cSRichard Marian Thomaiyar                              const std::array<char, 5>& intentionalSignature)
836666dd01cSRichard Marian Thomaiyar {
837e0511e5fSAyushi Smriti     // mfg filter logic is used to allow MTM keep alive command only in
838e0511e5fSAyushi Smriti     // manfacturing mode
839e0511e5fSAyushi Smriti 
840666dd01cSRichard Marian Thomaiyar     constexpr std::array<char, 5> signatureOk = {'I', 'N', 'T', 'E', 'L'};
841666dd01cSRichard Marian Thomaiyar     if (intentionalSignature != signatureOk || reserved != 0)
842666dd01cSRichard Marian Thomaiyar     {
843666dd01cSRichard Marian Thomaiyar         return ipmi::responseInvalidFieldRequest();
844666dd01cSRichard Marian Thomaiyar     }
845357ddc74SRichard Marian Thomaiyar     return ipmi::response(resetMtmTimer(ctx));
846666dd01cSRichard Marian Thomaiyar }
847666dd01cSRichard Marian Thomaiyar 
848e0511e5fSAyushi Smriti static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd)
849e0511e5fSAyushi Smriti {
850e0511e5fSAyushi Smriti     return (netFn << 8) | cmd;
851e0511e5fSAyushi Smriti }
852e0511e5fSAyushi Smriti 
85385feb130SYong Li ipmi::Cc mfgFilterMessage(ipmi::message::Request::ptr request)
85485feb130SYong Li {
855e0511e5fSAyushi Smriti     // Restricted commands, must be executed only in Manufacturing mode
856e0511e5fSAyushi Smriti     switch (makeCmdKey(request->ctx->netFn, request->ctx->cmd))
85785feb130SYong Li     {
858e0511e5fSAyushi Smriti         // i2c master write read command needs additional checking
859e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead):
86085feb130SYong Li             if (request->payload.size() > 4)
86185feb130SYong Li             {
862ae13ac62SRichard Marian Thomaiyar                 // Allow write data count > 1 only in Special mode
863ae13ac62SRichard Marian Thomaiyar                 if (mtm.getMfgMode() == SpecialMode::none)
86485feb130SYong Li                 {
86585feb130SYong Li                     return ipmi::ccInsufficientPrivilege;
86685feb130SYong Li                 }
86785feb130SYong Li             }
8682d4a0198Sjayaprakash Mutyala             return ipmi::ccSuccess;
869e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
870e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdGetSmSignal):
871e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
872e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdSetSmSignal):
873e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
874e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdMtmKeepAlive):
875e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
876e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdSetManufacturingData):
877e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnOemOne,
878e0511e5fSAyushi Smriti                         ipmi::intel::general::cmdGetManufacturingData):
87927d2356eSVernon Mauery         case makeCmdKey(ipmi::intel::netFnGeneral,
88027d2356eSVernon Mauery                         ipmi::intel::general::cmdSetFITcLayout):
88106584cd0SArun P. Mohanan         case makeCmdKey(ipmi::netFnOemOne,
88206584cd0SArun P. Mohanan                         ipmi::intel::general::cmdMTMBMCFeatureControl):
883e0511e5fSAyushi Smriti         case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdWriteFruData):
8849a13daaeSAppaRao Puli         case makeCmdKey(ipmi::netFnOemTwo, ipmi::intel::platform::cmdClearCMOS):
88585feb130SYong Li 
886ae13ac62SRichard Marian Thomaiyar             // Check for Special mode
887ae13ac62SRichard Marian Thomaiyar             if (mtm.getMfgMode() == SpecialMode::none)
888e0511e5fSAyushi Smriti             {
889e0511e5fSAyushi Smriti                 return ipmi::ccInvalidCommand;
890e0511e5fSAyushi Smriti             }
8912d4a0198Sjayaprakash Mutyala             return ipmi::ccSuccess;
8922d4a0198Sjayaprakash Mutyala         case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdDeleteSelEntry):
8932d4a0198Sjayaprakash Mutyala         {
8942d4a0198Sjayaprakash Mutyala             return ipmi::ccInvalidCommand;
8952d4a0198Sjayaprakash Mutyala         }
896e0511e5fSAyushi Smriti     }
89785feb130SYong Li     return ipmi::ccSuccess;
89885feb130SYong Li }
89985feb130SYong Li 
9001f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxEthSize = 6;
9011f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxSupportedEth = 3;
9021f0839c2SRichard Marian Thomaiyar static constexpr const char* factoryEthAddrBaseFileName =
9031f0839c2SRichard Marian Thomaiyar     "/var/sofs/factory-settings/network/mac/eth";
9041f0839c2SRichard Marian Thomaiyar 
905*097497fbSAlex Schendel bool findFruDevice(ipmi::Context::ptr& ctx, uint64_t& macOffset,
906ad129c68SZhikui Ren                    uint64_t& busNum, uint64_t& address)
907ad129c68SZhikui Ren {
908*097497fbSAlex Schendel     boost::system::error_code ec{};
909*097497fbSAlex Schendel     ObjectValueTree obj;
910ad129c68SZhikui Ren 
911ad129c68SZhikui Ren     // GetAll the objects under service FruDevice
912*097497fbSAlex Schendel     ec = getManagedObjects(ctx, "xyz.openbmc_project.EntityManager",
913*097497fbSAlex Schendel                            "/xyz/openbmc_project/inventory", obj);
914ad129c68SZhikui Ren     if (ec)
915ad129c68SZhikui Ren     {
916ad129c68SZhikui Ren         phosphor::logging::log<phosphor::logging::level::ERR>(
917ad129c68SZhikui Ren             "GetMangagedObjects failed",
918ad129c68SZhikui Ren             phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
919ad129c68SZhikui Ren         return false;
920ad129c68SZhikui Ren     }
921ad129c68SZhikui Ren 
922ad129c68SZhikui Ren     for (const auto& [path, fru] : obj)
923ad129c68SZhikui Ren     {
924ad129c68SZhikui Ren         for (const auto& [intf, propMap] : fru)
925ad129c68SZhikui Ren         {
926ad129c68SZhikui Ren             if (intf == "xyz.openbmc_project.Inventory.Item.Board.Motherboard")
927ad129c68SZhikui Ren             {
928ad129c68SZhikui Ren                 auto findBus = propMap.find("FruBus");
929ad129c68SZhikui Ren                 auto findAddress = propMap.find("FruAddress");
930ad129c68SZhikui Ren                 auto findMacOffset = propMap.find("MacOffset");
931ad129c68SZhikui Ren                 if (findBus == propMap.end() || findAddress == propMap.end() ||
932ad129c68SZhikui Ren                     findMacOffset == propMap.end())
933ad129c68SZhikui Ren                 {
934ad129c68SZhikui Ren                     continue;
935ad129c68SZhikui Ren                 }
936ad129c68SZhikui Ren 
937ad129c68SZhikui Ren                 auto fruBus = std::get_if<uint64_t>(&findBus->second);
938ad129c68SZhikui Ren                 auto fruAddress = std::get_if<uint64_t>(&findAddress->second);
939ad129c68SZhikui Ren                 auto macFruOffset =
940ad129c68SZhikui Ren                     std::get_if<uint64_t>(&findMacOffset->second);
941ad129c68SZhikui Ren                 if (!fruBus || !fruAddress || !macFruOffset)
942ad129c68SZhikui Ren                 {
943ad129c68SZhikui Ren                     phosphor::logging::log<phosphor::logging::level::INFO>(
944ad129c68SZhikui Ren                         "ERROR: MotherBoard FRU config data type invalid, not "
945ad129c68SZhikui Ren                         "used");
946ad129c68SZhikui Ren                     return false;
947ad129c68SZhikui Ren                 }
948ad129c68SZhikui Ren                 busNum = *fruBus;
949ad129c68SZhikui Ren                 address = *fruAddress;
950ad129c68SZhikui Ren                 macOffset = *macFruOffset;
951ad129c68SZhikui Ren                 return true;
952ad129c68SZhikui Ren             }
953ad129c68SZhikui Ren         }
954ad129c68SZhikui Ren     }
955ad129c68SZhikui Ren     return false;
956ad129c68SZhikui Ren }
957ad129c68SZhikui Ren 
95898fa87e6SZhikui Ren static constexpr uint64_t fruEnd = 0xff;
95998fa87e6SZhikui Ren // write rolls over within current page, need to keep mac within a page
96098fa87e6SZhikui Ren static constexpr uint64_t fruPageSize = 0x8;
96198fa87e6SZhikui Ren // MAC record struct: HEADER, MAC DATA, CheckSum
96298fa87e6SZhikui Ren static constexpr uint64_t macRecordSize = maxEthSize + 2;
96398fa87e6SZhikui Ren static_assert(fruPageSize >= macRecordSize,
96498fa87e6SZhikui Ren               "macRecordSize greater than eeprom page size");
96598fa87e6SZhikui Ren static constexpr uint8_t macHeader = 0x40;
96698fa87e6SZhikui Ren // Calculate new checksum for fru info area
96798fa87e6SZhikui Ren static uint8_t calculateChecksum(std::vector<uint8_t>::const_iterator iter,
96898fa87e6SZhikui Ren                                  std::vector<uint8_t>::const_iterator end)
96998fa87e6SZhikui Ren {
97098fa87e6SZhikui Ren     constexpr int checksumMod = 256;
97198fa87e6SZhikui Ren     uint8_t sum = std::accumulate(iter, end, static_cast<uint8_t>(0));
97298fa87e6SZhikui Ren     return (checksumMod - sum) % checksumMod;
97398fa87e6SZhikui Ren }
97498fa87e6SZhikui Ren 
975ad129c68SZhikui Ren bool readMacFromFru(ipmi::Context::ptr ctx, uint8_t macIndex,
976ad129c68SZhikui Ren                     std::array<uint8_t, maxEthSize>& ethData)
977ad129c68SZhikui Ren {
978ad129c68SZhikui Ren     uint64_t macOffset = fruEnd;
979ad129c68SZhikui Ren     uint64_t fruBus = 0;
980ad129c68SZhikui Ren     uint64_t fruAddress = 0;
981ad129c68SZhikui Ren 
982*097497fbSAlex Schendel     if (findFruDevice(ctx, macOffset, fruBus, fruAddress))
983ad129c68SZhikui Ren     {
984ad129c68SZhikui Ren         phosphor::logging::log<phosphor::logging::level::INFO>(
985ad129c68SZhikui Ren             "Found mac fru",
986ad129c68SZhikui Ren             phosphor::logging::entry("BUS=%d", static_cast<uint8_t>(fruBus)),
987ad129c68SZhikui Ren             phosphor::logging::entry("ADDRESS=%d",
988ad129c68SZhikui Ren                                      static_cast<uint8_t>(fruAddress)));
989ad129c68SZhikui Ren 
99098fa87e6SZhikui Ren         if (macOffset % fruPageSize)
99198fa87e6SZhikui Ren         {
99298fa87e6SZhikui Ren             macOffset = (macOffset / fruPageSize + 1) * fruPageSize;
99398fa87e6SZhikui Ren         }
99498fa87e6SZhikui Ren         macOffset += macIndex * fruPageSize;
99598fa87e6SZhikui Ren         if ((macOffset + macRecordSize) > fruEnd)
996ad129c68SZhikui Ren         {
997ad129c68SZhikui Ren             phosphor::logging::log<phosphor::logging::level::ERR>(
998ad129c68SZhikui Ren                 "ERROR: read fru mac failed, offset invalid");
999ad129c68SZhikui Ren             return false;
1000ad129c68SZhikui Ren         }
1001ad129c68SZhikui Ren         std::vector<uint8_t> writeData;
100298fa87e6SZhikui Ren         writeData.push_back(static_cast<uint8_t>(macOffset));
100398fa87e6SZhikui Ren         std::vector<uint8_t> readBuf(macRecordSize);
1004ad129c68SZhikui Ren         std::string i2cBus = "/dev/i2c-" + std::to_string(fruBus);
1005ad129c68SZhikui Ren         ipmi::Cc retI2C =
1006ad129c68SZhikui Ren             ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, readBuf);
1007ad129c68SZhikui Ren         if (retI2C == ipmi::ccSuccess)
1008ad129c68SZhikui Ren         {
100998fa87e6SZhikui Ren             uint8_t cs = calculateChecksum(readBuf.cbegin(), readBuf.cend());
101098fa87e6SZhikui Ren             if (cs == 0)
101198fa87e6SZhikui Ren             {
101298fa87e6SZhikui Ren                 std::copy(++readBuf.begin(), --readBuf.end(), ethData.data());
1013ad129c68SZhikui Ren                 return true;
1014ad129c68SZhikui Ren             }
1015ad129c68SZhikui Ren         }
101698fa87e6SZhikui Ren     }
1017ad129c68SZhikui Ren     return false;
1018ad129c68SZhikui Ren }
1019ad129c68SZhikui Ren 
1020ad129c68SZhikui Ren ipmi::Cc writeMacToFru(ipmi::Context::ptr ctx, uint8_t macIndex,
1021ad129c68SZhikui Ren                        std::array<uint8_t, maxEthSize>& ethData)
1022ad129c68SZhikui Ren {
1023ad129c68SZhikui Ren     uint64_t macOffset = fruEnd;
1024ad129c68SZhikui Ren     uint64_t fruBus = 0;
1025ad129c68SZhikui Ren     uint64_t fruAddress = 0;
1026ad129c68SZhikui Ren 
1027*097497fbSAlex Schendel     if (findFruDevice(ctx, macOffset, fruBus, fruAddress))
1028ad129c68SZhikui Ren     {
1029ad129c68SZhikui Ren         phosphor::logging::log<phosphor::logging::level::INFO>(
1030ad129c68SZhikui Ren             "Found mac fru",
1031ad129c68SZhikui Ren             phosphor::logging::entry("BUS=%d", static_cast<uint8_t>(fruBus)),
1032ad129c68SZhikui Ren             phosphor::logging::entry("ADDRESS=%d",
1033ad129c68SZhikui Ren                                      static_cast<uint8_t>(fruAddress)));
1034ad129c68SZhikui Ren 
103598fa87e6SZhikui Ren         if (macOffset % fruPageSize)
103698fa87e6SZhikui Ren         {
103798fa87e6SZhikui Ren             macOffset = (macOffset / fruPageSize + 1) * fruPageSize;
103898fa87e6SZhikui Ren         }
103998fa87e6SZhikui Ren         macOffset += macIndex * fruPageSize;
104098fa87e6SZhikui Ren         if ((macOffset + macRecordSize) > fruEnd)
1041ad129c68SZhikui Ren         {
1042ad129c68SZhikui Ren             phosphor::logging::log<phosphor::logging::level::ERR>(
1043ad129c68SZhikui Ren                 "ERROR: write mac fru failed, offset invalid.");
1044ad129c68SZhikui Ren             return ipmi::ccParmOutOfRange;
1045ad129c68SZhikui Ren         }
1046ad129c68SZhikui Ren         std::vector<uint8_t> writeData;
104798fa87e6SZhikui Ren         writeData.reserve(macRecordSize + 1); // include start location
104898fa87e6SZhikui Ren         writeData.push_back(static_cast<uint8_t>(macOffset));
104998fa87e6SZhikui Ren         writeData.push_back(macHeader);
1050ad129c68SZhikui Ren         std::for_each(ethData.cbegin(), ethData.cend(),
1051ad129c68SZhikui Ren                       [&](uint8_t i) { writeData.push_back(i); });
105298fa87e6SZhikui Ren         uint8_t macCheckSum =
105398fa87e6SZhikui Ren             calculateChecksum(++writeData.cbegin(), writeData.cend());
105498fa87e6SZhikui Ren         writeData.push_back(macCheckSum);
1055ad129c68SZhikui Ren 
1056ad129c68SZhikui Ren         std::string i2cBus = "/dev/i2c-" + std::to_string(fruBus);
1057ad129c68SZhikui Ren         std::vector<uint8_t> readBuf;
1058ad129c68SZhikui Ren         ipmi::Cc ret =
1059ad129c68SZhikui Ren             ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, readBuf);
106098fa87e6SZhikui Ren 
10610408e79eSZhikui Ren         // prepare for read to detect chip is write protected
10620408e79eSZhikui Ren         writeData.resize(1);
10630408e79eSZhikui Ren         readBuf.resize(maxEthSize + 1); // include macHeader
10640408e79eSZhikui Ren 
1065ad129c68SZhikui Ren         switch (ret)
1066ad129c68SZhikui Ren         {
1067ad129c68SZhikui Ren             case ipmi::ccSuccess:
106898fa87e6SZhikui Ren                 // Wait for internal write cycle to complete
106998fa87e6SZhikui Ren                 // example: ATMEL 24c0x chip has Twr spec as 5ms
107098fa87e6SZhikui Ren 
107198fa87e6SZhikui Ren                 // Ideally we want yield wait, but currently following code
107298fa87e6SZhikui Ren                 // crash with "thread not supported"
107398fa87e6SZhikui Ren                 // boost::asio::deadline_timer timer(
107498fa87e6SZhikui Ren                 //    boost::asio::get_associated_executor(ctx->yield),
107598fa87e6SZhikui Ren                 //    boost::posix_time::seconds(1));
107698fa87e6SZhikui Ren                 // timer.async_wait(ctx->yield);
107798fa87e6SZhikui Ren                 // use usleep as temp WA
107898fa87e6SZhikui Ren                 usleep(5000);
107998fa87e6SZhikui Ren                 if (ipmi::i2cWriteRead(i2cBus, fruAddress, writeData,
108098fa87e6SZhikui Ren                                        readBuf) == ipmi::ccSuccess)
1081ad129c68SZhikui Ren                 {
1082ad129c68SZhikui Ren                     if (std::equal(ethData.begin(), ethData.end(),
108398fa87e6SZhikui Ren                                    ++readBuf.begin())) // skip macHeader
1084ad129c68SZhikui Ren                     {
1085ad129c68SZhikui Ren                         return ipmi::ccSuccess;
1086ad129c68SZhikui Ren                     }
1087ad129c68SZhikui Ren                     phosphor::logging::log<phosphor::logging::level::INFO>(
1088ad129c68SZhikui Ren                         "INFO: write mac fru verify failed, fru may be write "
1089ad129c68SZhikui Ren                         "protected.");
1090ad129c68SZhikui Ren                 }
1091ad129c68SZhikui Ren                 return ipmi::ccCommandNotAvailable;
10920408e79eSZhikui Ren             default:
10930408e79eSZhikui Ren                 if (ipmi::i2cWriteRead(i2cBus, fruAddress, writeData,
10940408e79eSZhikui Ren                                        readBuf) == ipmi::ccSuccess)
10950408e79eSZhikui Ren                 {
10960408e79eSZhikui Ren                     phosphor::logging::log<phosphor::logging::level::INFO>(
10970408e79eSZhikui Ren                         "INFO: write mac fru failed, but successfully read "
10980408e79eSZhikui Ren                         "from fru, fru may be write protected.");
10990408e79eSZhikui Ren                     return ipmi::ccCommandNotAvailable;
11000408e79eSZhikui Ren                 }
11010408e79eSZhikui Ren                 else // assume failure is due to no eeprom on board
11020408e79eSZhikui Ren                 {
1103ad129c68SZhikui Ren                     phosphor::logging::log<phosphor::logging::level::ERR>(
1104ad129c68SZhikui Ren                         "ERROR: write mac fru failed, assume no eeprom is "
1105ad129c68SZhikui Ren                         "available.");
11060408e79eSZhikui Ren                 }
1107ad129c68SZhikui Ren                 break;
1108ad129c68SZhikui Ren         }
1109ad129c68SZhikui Ren     }
1110ad129c68SZhikui Ren     // no FRU eeprom found
1111ad129c68SZhikui Ren     return ipmi::ccDestinationUnavailable;
1112ad129c68SZhikui Ren }
1113ad129c68SZhikui Ren 
1114357ddc74SRichard Marian Thomaiyar ipmi::RspType<> setManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType,
11151f0839c2SRichard Marian Thomaiyar                                      std::array<uint8_t, maxEthSize> ethData)
11161f0839c2SRichard Marian Thomaiyar {
1117ad129c68SZhikui Ren     // mfg filter logic will restrict this command executing only in mfg
1118ad129c68SZhikui Ren     // mode.
11191f0839c2SRichard Marian Thomaiyar     if (dataType >= maxSupportedEth)
11201f0839c2SRichard Marian Thomaiyar     {
11211f0839c2SRichard Marian Thomaiyar         return ipmi::responseParmOutOfRange();
11221f0839c2SRichard Marian Thomaiyar     }
11231f0839c2SRichard Marian Thomaiyar 
11241f0839c2SRichard Marian Thomaiyar     constexpr uint8_t invalidData = 0;
11251f0839c2SRichard Marian Thomaiyar     constexpr uint8_t validData = 1;
1126ad129c68SZhikui Ren 
1127ad129c68SZhikui Ren     ipmi::Cc ret = writeMacToFru(ctx, dataType, ethData);
1128ad129c68SZhikui Ren     if (ret != ipmi::ccDestinationUnavailable)
1129ad129c68SZhikui Ren     {
1130ad129c68SZhikui Ren         resetMtmTimer(ctx);
1131ad129c68SZhikui Ren         return response(ret);
1132ad129c68SZhikui Ren     }
1133ad129c68SZhikui Ren 
11341f0839c2SRichard Marian Thomaiyar     constexpr uint8_t ethAddrStrSize =
11351f0839c2SRichard Marian Thomaiyar         19; // XX:XX:XX:XX:XX:XX + \n + null termination;
11361f0839c2SRichard Marian Thomaiyar     std::vector<uint8_t> buff(ethAddrStrSize);
11371f0839c2SRichard Marian Thomaiyar     std::snprintf(reinterpret_cast<char*>(buff.data()), ethAddrStrSize,
11381f0839c2SRichard Marian Thomaiyar                   "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", ethData.at(0),
11391f0839c2SRichard Marian Thomaiyar                   ethData.at(1), ethData.at(2), ethData.at(3), ethData.at(4),
11401f0839c2SRichard Marian Thomaiyar                   ethData.at(5));
11411f0839c2SRichard Marian Thomaiyar     std::ofstream oEthFile(factoryEthAddrBaseFileName +
11421f0839c2SRichard Marian Thomaiyar                                std::to_string(dataType),
11431f0839c2SRichard Marian Thomaiyar                            std::ofstream::out);
11441f0839c2SRichard Marian Thomaiyar     if (!oEthFile.good())
11451f0839c2SRichard Marian Thomaiyar     {
11461f0839c2SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
11471f0839c2SRichard Marian Thomaiyar     }
11481f0839c2SRichard Marian Thomaiyar 
11491f0839c2SRichard Marian Thomaiyar     oEthFile << reinterpret_cast<char*>(buff.data());
11506d83e4eeSJohnathan Mantey     oEthFile.flush();
11511f0839c2SRichard Marian Thomaiyar     oEthFile.close();
11521f0839c2SRichard Marian Thomaiyar 
1153357ddc74SRichard Marian Thomaiyar     resetMtmTimer(ctx);
11541f0839c2SRichard Marian Thomaiyar     return ipmi::responseSuccess();
11551f0839c2SRichard Marian Thomaiyar }
11561f0839c2SRichard Marian Thomaiyar 
11571f0839c2SRichard Marian Thomaiyar ipmi::RspType<uint8_t, std::array<uint8_t, maxEthSize>>
1158357ddc74SRichard Marian Thomaiyar     getManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType)
11591f0839c2SRichard Marian Thomaiyar {
1160ad129c68SZhikui Ren     // mfg filter logic will restrict this command executing only in mfg
1161ad129c68SZhikui Ren     // mode.
11621f0839c2SRichard Marian Thomaiyar     if (dataType >= maxSupportedEth)
11631f0839c2SRichard Marian Thomaiyar     {
11641f0839c2SRichard Marian Thomaiyar         return ipmi::responseParmOutOfRange();
11651f0839c2SRichard Marian Thomaiyar     }
11661f0839c2SRichard Marian Thomaiyar     std::array<uint8_t, maxEthSize> ethData{0};
11671f0839c2SRichard Marian Thomaiyar     constexpr uint8_t invalidData = 0;
11681f0839c2SRichard Marian Thomaiyar     constexpr uint8_t validData = 1;
11691f0839c2SRichard Marian Thomaiyar 
11701f0839c2SRichard Marian Thomaiyar     std::ifstream iEthFile(factoryEthAddrBaseFileName +
11711f0839c2SRichard Marian Thomaiyar                                std::to_string(dataType),
11721f0839c2SRichard Marian Thomaiyar                            std::ifstream::in);
11731f0839c2SRichard Marian Thomaiyar     if (!iEthFile.good())
11741f0839c2SRichard Marian Thomaiyar     {
1175ad129c68SZhikui Ren         if (readMacFromFru(ctx, dataType, ethData))
1176ad129c68SZhikui Ren         {
1177ad129c68SZhikui Ren             resetMtmTimer(ctx);
1178ad129c68SZhikui Ren             return ipmi::responseSuccess(validData, ethData);
1179ad129c68SZhikui Ren         }
11801f0839c2SRichard Marian Thomaiyar         return ipmi::responseSuccess(invalidData, ethData);
11811f0839c2SRichard Marian Thomaiyar     }
11821f0839c2SRichard Marian Thomaiyar     std::string ethStr;
11831f0839c2SRichard Marian Thomaiyar     iEthFile >> ethStr;
11841f0839c2SRichard Marian Thomaiyar     uint8_t* data = ethData.data();
11851f0839c2SRichard Marian Thomaiyar     std::sscanf(ethStr.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
11861f0839c2SRichard Marian Thomaiyar                 data, (data + 1), (data + 2), (data + 3), (data + 4),
11871f0839c2SRichard Marian Thomaiyar                 (data + 5));
11881f0839c2SRichard Marian Thomaiyar 
1189357ddc74SRichard Marian Thomaiyar     resetMtmTimer(ctx);
11901f0839c2SRichard Marian Thomaiyar     return ipmi::responseSuccess(validData, ethData);
11911f0839c2SRichard Marian Thomaiyar }
11921f0839c2SRichard Marian Thomaiyar 
1193ad129c68SZhikui Ren /** @brief implements slot master write read IPMI command which can be used
1194ad129c68SZhikui Ren  * for low-level I2C/SMBus write, read or write-read access for PCIE slots
1195f267a67dSYong Li  * @param reserved - skip 6 bit
1196f267a67dSYong Li  * @param addressType - address type
1197f267a67dSYong Li  * @param bbSlotNum - baseboard slot number
1198f267a67dSYong Li  * @param riserSlotNum - riser slot number
1199f267a67dSYong Li  * @param reserved2 - skip 2 bit
1200f267a67dSYong Li  * @param slaveAddr - slave address
1201f267a67dSYong Li  * @param readCount - number of bytes to be read
1202f267a67dSYong Li  * @param writeData - data to be written
1203f267a67dSYong Li  *
1204f267a67dSYong Li  * @returns IPMI completion code plus response data
1205f267a67dSYong Li  */
1206f267a67dSYong Li ipmi::RspType<std::vector<uint8_t>>
1207f267a67dSYong Li     appSlotI2CMasterWriteRead(uint6_t reserved, uint2_t addressType,
1208f267a67dSYong Li                               uint3_t bbSlotNum, uint3_t riserSlotNum,
1209fc3bc381SVernon Mauery                               uint2_t reserved2, uint8_t slaveAddr,
1210f267a67dSYong Li                               uint8_t readCount, std::vector<uint8_t> writeData)
1211f267a67dSYong Li {
1212fc3bc381SVernon Mauery     if (reserved || reserved2)
1213fc3bc381SVernon Mauery     {
1214fc3bc381SVernon Mauery         return ipmi::responseInvalidFieldRequest();
1215fc3bc381SVernon Mauery     }
1216f267a67dSYong Li     const size_t writeCount = writeData.size();
1217f267a67dSYong Li     std::string i2cBus;
1218f267a67dSYong Li     if (addressType == slotAddressTypeBus)
1219f267a67dSYong Li     {
1220f267a67dSYong Li         std::string path = "/dev/i2c-mux/Riser_" +
1221f267a67dSYong Li                            std::to_string(static_cast<uint8_t>(bbSlotNum)) +
1222f267a67dSYong Li                            "_Mux/Pcie_Slot_" +
1223f267a67dSYong Li                            std::to_string(static_cast<uint8_t>(riserSlotNum));
1224f267a67dSYong Li 
1225f267a67dSYong Li         if (std::filesystem::exists(path) && std::filesystem::is_symlink(path))
1226f267a67dSYong Li         {
1227f267a67dSYong Li             i2cBus = std::filesystem::read_symlink(path);
1228f267a67dSYong Li         }
1229f267a67dSYong Li         else
1230f267a67dSYong Li         {
1231f267a67dSYong Li             phosphor::logging::log<phosphor::logging::level::ERR>(
1232f267a67dSYong Li                 "Master write read command: Cannot get BusID");
1233f267a67dSYong Li             return ipmi::responseInvalidFieldRequest();
1234f267a67dSYong Li         }
1235f267a67dSYong Li     }
1236f267a67dSYong Li     else if (addressType == slotAddressTypeUniqueid)
1237f267a67dSYong Li     {
1238f267a67dSYong Li         i2cBus = "/dev/i2c-" +
1239f267a67dSYong Li                  std::to_string(static_cast<uint8_t>(bbSlotNum) |
1240f267a67dSYong Li                                 (static_cast<uint8_t>(riserSlotNum) << 3));
1241f267a67dSYong Li     }
1242f267a67dSYong Li     else
1243f267a67dSYong Li     {
1244f267a67dSYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
1245f267a67dSYong Li             "Master write read command: invalid request");
1246f267a67dSYong Li         return ipmi::responseInvalidFieldRequest();
1247f267a67dSYong Li     }
1248f267a67dSYong Li 
1249ad129c68SZhikui Ren     // Allow single byte write as it is offset byte to read the data, rest
1250ad129c68SZhikui Ren     // allow only in Special mode.
1251f267a67dSYong Li     if (writeCount > 1)
1252f267a67dSYong Li     {
1253ae13ac62SRichard Marian Thomaiyar         if (mtm.getMfgMode() == SpecialMode::none)
1254f267a67dSYong Li         {
1255f267a67dSYong Li             return ipmi::responseInsufficientPrivilege();
1256f267a67dSYong Li         }
1257f267a67dSYong Li     }
1258f267a67dSYong Li 
1259f267a67dSYong Li     if (readCount > slotI2CMaxReadSize)
1260f267a67dSYong Li     {
1261f267a67dSYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
1262f267a67dSYong Li             "Master write read command: Read count exceeds limit");
1263f267a67dSYong Li         return ipmi::responseParmOutOfRange();
1264f267a67dSYong Li     }
1265f267a67dSYong Li 
1266f267a67dSYong Li     if (!readCount && !writeCount)
1267f267a67dSYong Li     {
1268f267a67dSYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
1269f267a67dSYong Li             "Master write read command: Read & write count are 0");
1270f267a67dSYong Li         return ipmi::responseInvalidFieldRequest();
1271f267a67dSYong Li     }
1272f267a67dSYong Li 
1273f267a67dSYong Li     std::vector<uint8_t> readBuf(readCount);
1274f267a67dSYong Li 
1275f267a67dSYong Li     ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf);
1276f267a67dSYong Li     if (retI2C != ipmi::ccSuccess)
1277f267a67dSYong Li     {
1278f267a67dSYong Li         return ipmi::response(retI2C);
1279f267a67dSYong Li     }
1280f267a67dSYong Li 
1281f267a67dSYong Li     return ipmi::responseSuccess(readBuf);
1282f267a67dSYong Li }
1283068b4f2cSYong Li 
1284068b4f2cSYong Li ipmi::RspType<> clearCMOS()
1285068b4f2cSYong Li {
1286ad129c68SZhikui Ren     // There is an i2c device on bus 4, the slave address is 0x38. Based on
1287ad129c68SZhikui Ren     // the spec, writing 0x1 to address 0x61 on this device, will trigger
1288ad129c68SZhikui Ren     // the clear CMOS action.
1289d0d010b7SYong Li     constexpr uint8_t slaveAddr = 0x38;
1290068b4f2cSYong Li     std::string i2cBus = "/dev/i2c-4";
1291eaeb6cb0SYong Li     std::vector<uint8_t> writeData = {0x61, 0x1};
1292068b4f2cSYong Li     std::vector<uint8_t> readBuf(0);
1293068b4f2cSYong Li 
1294068b4f2cSYong Li     ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf);
1295068b4f2cSYong Li     return ipmi::response(retI2C);
1296068b4f2cSYong Li }
129727d2356eSVernon Mauery 
129827d2356eSVernon Mauery ipmi::RspType<> setFITcLayout(uint32_t layout)
129927d2356eSVernon Mauery {
130027d2356eSVernon Mauery     static constexpr const char* factoryFITcLayout =
130127d2356eSVernon Mauery         "/var/sofs/factory-settings/layout/fitc";
130227d2356eSVernon Mauery     std::filesystem::path fitcDir =
130327d2356eSVernon Mauery         std::filesystem::path(factoryFITcLayout).parent_path();
130427d2356eSVernon Mauery     std::error_code ec;
130527d2356eSVernon Mauery     std::filesystem::create_directories(fitcDir, ec);
130627d2356eSVernon Mauery     if (ec)
130727d2356eSVernon Mauery     {
130827d2356eSVernon Mauery         return ipmi::responseUnspecifiedError();
130927d2356eSVernon Mauery     }
131027d2356eSVernon Mauery     try
131127d2356eSVernon Mauery     {
131227d2356eSVernon Mauery         std::ofstream file(factoryFITcLayout);
131327d2356eSVernon Mauery         file << layout;
131427d2356eSVernon Mauery         file.flush();
131527d2356eSVernon Mauery         file.close();
131627d2356eSVernon Mauery     }
131727d2356eSVernon Mauery     catch (const std::exception& e)
131827d2356eSVernon Mauery     {
131927d2356eSVernon Mauery         return ipmi::responseUnspecifiedError();
132027d2356eSVernon Mauery     }
132127d2356eSVernon Mauery 
132227d2356eSVernon Mauery     return ipmi::responseSuccess();
132327d2356eSVernon Mauery }
132427d2356eSVernon Mauery 
132506584cd0SArun P. Mohanan static std::vector<std::string>
132606584cd0SArun P. Mohanan     getMCTPServiceConfigPaths(ipmi::Context::ptr& ctx)
132706584cd0SArun P. Mohanan {
132806584cd0SArun P. Mohanan     boost::system::error_code ec;
132906584cd0SArun P. Mohanan     auto configPaths = ctx->bus->yield_method_call<std::vector<std::string>>(
133006584cd0SArun P. Mohanan         ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
133106584cd0SArun P. Mohanan         "/xyz/openbmc_project/object_mapper",
133206584cd0SArun P. Mohanan         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
133306584cd0SArun P. Mohanan         "/xyz/openbmc_project/inventory/system/board", 2,
133406584cd0SArun P. Mohanan         std::array<const char*, 1>{
133506584cd0SArun P. Mohanan             "xyz.openbmc_project.Configuration.MctpConfiguration"});
133606584cd0SArun P. Mohanan     if (ec)
133706584cd0SArun P. Mohanan     {
133806584cd0SArun P. Mohanan         throw std::runtime_error(
133906584cd0SArun P. Mohanan             "Failed to query configuration sub tree objects");
134006584cd0SArun P. Mohanan     }
134106584cd0SArun P. Mohanan     return configPaths;
134206584cd0SArun P. Mohanan }
134306584cd0SArun P. Mohanan 
134406584cd0SArun P. Mohanan static ipmi::RspType<> startOrStopService(ipmi::Context::ptr& ctx,
134506584cd0SArun P. Mohanan                                           const uint8_t enable,
13461fe485cdSANJALI RAY                                           const std::string& serviceName,
13471fe485cdSANJALI RAY                                           bool disableOrEnableUnitFiles = true)
134806584cd0SArun P. Mohanan {
134906584cd0SArun P. Mohanan     constexpr bool runtimeOnly = false;
135006584cd0SArun P. Mohanan     constexpr bool force = false;
135106584cd0SArun P. Mohanan 
135206584cd0SArun P. Mohanan     boost::system::error_code ec;
135306584cd0SArun P. Mohanan     switch (enable)
135406584cd0SArun P. Mohanan     {
135506584cd0SArun P. Mohanan         case ipmi::SupportedFeatureActions::stop:
135606584cd0SArun P. Mohanan             ctx->bus->yield_method_call(ctx->yield, ec, systemDService,
135706584cd0SArun P. Mohanan                                         systemDObjPath, systemDMgrIntf,
135806584cd0SArun P. Mohanan                                         "StopUnit", serviceName, "replace");
135906584cd0SArun P. Mohanan             break;
136006584cd0SArun P. Mohanan         case ipmi::SupportedFeatureActions::start:
136106584cd0SArun P. Mohanan             ctx->bus->yield_method_call(ctx->yield, ec, systemDService,
136206584cd0SArun P. Mohanan                                         systemDObjPath, systemDMgrIntf,
136306584cd0SArun P. Mohanan                                         "StartUnit", serviceName, "replace");
136406584cd0SArun P. Mohanan             break;
136506584cd0SArun P. Mohanan         case ipmi::SupportedFeatureActions::disable:
13661fe485cdSANJALI RAY             if (disableOrEnableUnitFiles == true)
13671fe485cdSANJALI RAY             {
13681fe485cdSANJALI RAY                 ctx->bus->yield_method_call(
13691fe485cdSANJALI RAY                     ctx->yield, ec, systemDService, systemDObjPath,
13701fe485cdSANJALI RAY                     systemDMgrIntf, "DisableUnitFiles",
13711fe485cdSANJALI RAY                     std::array<const char*, 1>{serviceName.c_str()},
13721fe485cdSANJALI RAY                     runtimeOnly);
13731fe485cdSANJALI RAY             }
137406584cd0SArun P. Mohanan             ctx->bus->yield_method_call(
137506584cd0SArun P. Mohanan                 ctx->yield, ec, systemDService, systemDObjPath, systemDMgrIntf,
137606584cd0SArun P. Mohanan                 "MaskUnitFiles",
137706584cd0SArun P. Mohanan                 std::array<const char*, 1>{serviceName.c_str()}, runtimeOnly,
137806584cd0SArun P. Mohanan                 force);
137906584cd0SArun P. Mohanan             break;
138006584cd0SArun P. Mohanan         case ipmi::SupportedFeatureActions::enable:
138106584cd0SArun P. Mohanan             ctx->bus->yield_method_call(
138206584cd0SArun P. Mohanan                 ctx->yield, ec, systemDService, systemDObjPath, systemDMgrIntf,
138306584cd0SArun P. Mohanan                 "UnmaskUnitFiles",
138406584cd0SArun P. Mohanan                 std::array<const char*, 1>{serviceName.c_str()}, runtimeOnly);
13851fe485cdSANJALI RAY             if (disableOrEnableUnitFiles == true)
13861fe485cdSANJALI RAY             {
138706584cd0SArun P. Mohanan                 ctx->bus->yield_method_call(
13881fe485cdSANJALI RAY                     ctx->yield, ec, systemDService, systemDObjPath,
13891fe485cdSANJALI RAY                     systemDMgrIntf, "EnableUnitFiles",
13901fe485cdSANJALI RAY                     std::array<const char*, 1>{serviceName.c_str()},
13911fe485cdSANJALI RAY                     runtimeOnly, force);
13921fe485cdSANJALI RAY             }
139306584cd0SArun P. Mohanan             break;
139406584cd0SArun P. Mohanan         default:
139506584cd0SArun P. Mohanan             phosphor::logging::log<phosphor::logging::level::WARNING>(
139606584cd0SArun P. Mohanan                 "ERROR: Invalid feature action selected",
139706584cd0SArun P. Mohanan                 phosphor::logging::entry("ACTION=%d", enable));
139806584cd0SArun P. Mohanan             return ipmi::responseInvalidFieldRequest();
139906584cd0SArun P. Mohanan     }
140006584cd0SArun P. Mohanan     if (ec)
140106584cd0SArun P. Mohanan     {
140206584cd0SArun P. Mohanan         phosphor::logging::log<phosphor::logging::level::WARNING>(
140306584cd0SArun P. Mohanan             "ERROR: Service start or stop failed",
140406584cd0SArun P. Mohanan             phosphor::logging::entry("SERVICE=%s", serviceName.c_str()));
140506584cd0SArun P. Mohanan         return ipmi::responseUnspecifiedError();
140606584cd0SArun P. Mohanan     }
140706584cd0SArun P. Mohanan     return ipmi::responseSuccess();
140806584cd0SArun P. Mohanan }
140906584cd0SArun P. Mohanan 
141006584cd0SArun P. Mohanan static std::string getMCTPServiceName(const std::string& objectPath)
141106584cd0SArun P. Mohanan {
141206584cd0SArun P. Mohanan     const auto serviceArgument = boost::algorithm::replace_all_copy(
141306584cd0SArun P. Mohanan         boost::algorithm::replace_first_copy(
141406584cd0SArun P. Mohanan             objectPath, "/xyz/openbmc_project/inventory/system/board/", ""),
141506584cd0SArun P. Mohanan         "/", "_2f");
141606584cd0SArun P. Mohanan     std::string unitName =
141706584cd0SArun P. Mohanan         "xyz.openbmc_project.mctpd@" + serviceArgument + ".service";
141806584cd0SArun P. Mohanan     return unitName;
141906584cd0SArun P. Mohanan }
142006584cd0SArun P. Mohanan 
142106584cd0SArun P. Mohanan static ipmi::RspType<> handleMCTPFeature(ipmi::Context::ptr& ctx,
142206584cd0SArun P. Mohanan                                          const uint8_t enable,
142306584cd0SArun P. Mohanan                                          const std::string& binding)
142406584cd0SArun P. Mohanan {
142506584cd0SArun P. Mohanan     std::vector<std::string> configPaths;
142606584cd0SArun P. Mohanan     try
142706584cd0SArun P. Mohanan     {
142806584cd0SArun P. Mohanan         configPaths = getMCTPServiceConfigPaths(ctx);
142906584cd0SArun P. Mohanan     }
143006584cd0SArun P. Mohanan     catch (const std::exception& e)
143106584cd0SArun P. Mohanan     {
143206584cd0SArun P. Mohanan         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
143306584cd0SArun P. Mohanan         return ipmi::responseUnspecifiedError();
143406584cd0SArun P. Mohanan     }
143506584cd0SArun P. Mohanan 
143606584cd0SArun P. Mohanan     for (const auto& objectPath : configPaths)
143706584cd0SArun P. Mohanan     {
143806584cd0SArun P. Mohanan         auto const pos = objectPath.find_last_of('/');
143906584cd0SArun P. Mohanan         if (binding == objectPath.substr(pos + 1))
144006584cd0SArun P. Mohanan         {
144106584cd0SArun P. Mohanan             return startOrStopService(ctx, enable,
14421fe485cdSANJALI RAY                                       getMCTPServiceName(objectPath), false);
144306584cd0SArun P. Mohanan         }
144406584cd0SArun P. Mohanan     }
144506584cd0SArun P. Mohanan     return ipmi::responseSuccess();
144606584cd0SArun P. Mohanan }
144706584cd0SArun P. Mohanan 
144806584cd0SArun P. Mohanan /** @brief implements MTM BMC Feature Control IPMI command which can be
144906584cd0SArun P. Mohanan  * used to enable or disable the supported BMC features.
145006584cd0SArun P. Mohanan  * @param yield - context object that represents the currently executing
145106584cd0SArun P. Mohanan  * coroutine
145206584cd0SArun P. Mohanan  * @param feature - feature enum to enable or disable
145306584cd0SArun P. Mohanan  * @param enable - enable or disable the feature
145406584cd0SArun P. Mohanan  * @param featureArg - custom arguments for that feature
145506584cd0SArun P. Mohanan  * @param reserved - reserved for future use
145606584cd0SArun P. Mohanan  *
145706584cd0SArun P. Mohanan  * @returns IPMI completion code
145806584cd0SArun P. Mohanan  */
145906584cd0SArun P. Mohanan ipmi::RspType<> mtmBMCFeatureControl(ipmi::Context::ptr ctx,
146006584cd0SArun P. Mohanan                                      const uint8_t feature,
146106584cd0SArun P. Mohanan                                      const uint8_t enable,
146206584cd0SArun P. Mohanan                                      const uint8_t featureArg,
146306584cd0SArun P. Mohanan                                      const uint16_t reserved)
146406584cd0SArun P. Mohanan {
146506584cd0SArun P. Mohanan     if (reserved != 0)
146606584cd0SArun P. Mohanan     {
146706584cd0SArun P. Mohanan         return ipmi::responseInvalidFieldRequest();
146806584cd0SArun P. Mohanan     }
146906584cd0SArun P. Mohanan 
147006584cd0SArun P. Mohanan     switch (feature)
147106584cd0SArun P. Mohanan     {
147206584cd0SArun P. Mohanan         case ipmi::SupportedFeatureControls::mctp:
147306584cd0SArun P. Mohanan             switch (featureArg)
147406584cd0SArun P. Mohanan             {
147506584cd0SArun P. Mohanan                 case ipmi::SupportedMCTPBindings::mctpPCIe:
147606584cd0SArun P. Mohanan                     return handleMCTPFeature(ctx, enable, "MCTP_PCIe");
147706584cd0SArun P. Mohanan                 case ipmi::SupportedMCTPBindings::mctpSMBusHSBP:
147806584cd0SArun P. Mohanan                     return handleMCTPFeature(ctx, enable, "MCTP_SMBus_HSBP");
147906584cd0SArun P. Mohanan                 case ipmi::SupportedMCTPBindings::mctpSMBusPCIeSlot:
148006584cd0SArun P. Mohanan                     return handleMCTPFeature(ctx, enable,
148106584cd0SArun P. Mohanan                                              "MCTP_SMBus_PCIe_slot");
148206584cd0SArun P. Mohanan                 default:
148306584cd0SArun P. Mohanan                     return ipmi::responseInvalidFieldRequest();
148406584cd0SArun P. Mohanan             }
148506584cd0SArun P. Mohanan             break;
14865cb2c045SJason M. Bills         case ipmi::SupportedFeatureControls::pcieScan:
14875cb2c045SJason M. Bills             if (featureArg != 0)
14885cb2c045SJason M. Bills             {
14895cb2c045SJason M. Bills                 return ipmi::responseInvalidFieldRequest();
14905cb2c045SJason M. Bills             }
14915cb2c045SJason M. Bills             startOrStopService(ctx, enable, "xyz.openbmc_project.PCIe.service");
14925cb2c045SJason M. Bills             break;
149306584cd0SArun P. Mohanan         default:
149406584cd0SArun P. Mohanan             return ipmi::responseInvalidFieldRequest();
149506584cd0SArun P. Mohanan     }
149606584cd0SArun P. Mohanan     return ipmi::responseSuccess();
149706584cd0SArun P. Mohanan }
1498a3702c1fSVernon Mauery } // namespace ipmi
1499a3702c1fSVernon Mauery 
1500a3702c1fSVernon Mauery void register_mtm_commands() __attribute__((constructor));
1501a3702c1fSVernon Mauery void register_mtm_commands()
1502a3702c1fSVernon Mauery {
150338d2b5a6SJason M. Bills     // <Get SM Signal>
150498bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
150598bbf69aSVernon Mauery                           ipmi::intel::general::cmdGetSmSignal,
15065e3bf557SAyushi Smriti                           ipmi::Privilege::Admin, ipmi::appMTMGetSignal);
1507a3702c1fSVernon Mauery 
150898bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
150998bbf69aSVernon Mauery                           ipmi::intel::general::cmdSetSmSignal,
15105e3bf557SAyushi Smriti                           ipmi::Privilege::Admin, ipmi::appMTMSetSignal);
1511a3702c1fSVernon Mauery 
151298bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
151398bbf69aSVernon Mauery                           ipmi::intel::general::cmdMtmKeepAlive,
1514666dd01cSRichard Marian Thomaiyar                           ipmi::Privilege::Admin, ipmi::mtmKeepAlive);
1515666dd01cSRichard Marian Thomaiyar 
151698bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
151798bbf69aSVernon Mauery                           ipmi::intel::general::cmdSetManufacturingData,
15181f0839c2SRichard Marian Thomaiyar                           ipmi::Privilege::Admin, ipmi::setManufacturingData);
15191f0839c2SRichard Marian Thomaiyar 
152098bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
152198bbf69aSVernon Mauery                           ipmi::intel::general::cmdGetManufacturingData,
15221f0839c2SRichard Marian Thomaiyar                           ipmi::Privilege::Admin, ipmi::getManufacturingData);
15231f0839c2SRichard Marian Thomaiyar 
152427d2356eSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
152527d2356eSVernon Mauery                           ipmi::intel::general::cmdSetFITcLayout,
152627d2356eSVernon Mauery                           ipmi::Privilege::Admin, ipmi::setFITcLayout);
152727d2356eSVernon Mauery 
152806584cd0SArun P. Mohanan     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
152906584cd0SArun P. Mohanan                           ipmi::intel::general::cmdMTMBMCFeatureControl,
153006584cd0SArun P. Mohanan                           ipmi::Privilege::Admin, ipmi::mtmBMCFeatureControl);
153106584cd0SArun P. Mohanan 
153298bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
153398bbf69aSVernon Mauery                           ipmi::intel::general::cmdSlotI2CMasterWriteRead,
153498bbf69aSVernon Mauery                           ipmi::Privilege::Admin,
153598bbf69aSVernon Mauery                           ipmi::appSlotI2CMasterWriteRead);
1536f267a67dSYong Li 
1537068b4f2cSYong Li     ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnPlatform,
1538068b4f2cSYong Li                           ipmi::intel::platform::cmdClearCMOS,
1539068b4f2cSYong Li                           ipmi::Privilege::Admin, ipmi::clearCMOS);
1540068b4f2cSYong Li 
154198bbf69aSVernon Mauery     ipmi::registerFilter(ipmi::prioOemBase,
154285feb130SYong Li                          [](ipmi::message::Request::ptr request) {
154385feb130SYong Li                              return ipmi::mfgFilterMessage(request);
154485feb130SYong Li                          });
1545a3702c1fSVernon Mauery }
1546