blob: 456366271b148707eab82e3c45615fb3480b6112 [file] [log] [blame]
Vernon Mauerya3702c12019-05-22 13:20:59 -07001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Ayushi Smritid872a4a2019-10-15 10:20:11 +053017#include <linux/input.h>
18
Arun P. Mohanan06584cd2021-08-13 20:56:01 +053019#include <boost/algorithm/string.hpp>
Richard Marian Thomaiyar147daec2019-06-15 07:43:48 +053020#include <boost/container/flat_map.hpp>
Vernon Mauerya3702c12019-05-22 13:20:59 -070021#include <ipmid/api.hpp>
22#include <manufacturingcommands.hpp>
23#include <oemcommands.hpp>
Jason M. Bills0748c692022-09-08 15:34:08 -070024#include <types.hpp>
Vernon Mauerya3702c12019-05-22 13:20:59 -070025
James Feistfcd2d3a2020-05-28 10:38:15 -070026#include <filesystem>
27#include <fstream>
28
Vernon Mauerya3702c12019-05-22 13:20:59 -070029namespace ipmi
30{
31
32Manufacturing mtm;
33
34static auto revertTimeOut =
35 std::chrono::duration_cast<std::chrono::microseconds>(
36 std::chrono::seconds(60)); // 1 minute timeout
37
V-Sanjana7acb2d22022-11-15 11:13:54 +053038static constexpr uint8_t bbRiserMux = 0;
39static constexpr uint8_t leftRiserMux = 1;
40static constexpr uint8_t rightRiserMux = 2;
41static constexpr uint8_t pcieMux = 3;
42static constexpr uint8_t hsbpMux = 4;
43
Yong Lif267a672019-08-29 11:16:07 +080044static constexpr uint8_t slotAddressTypeBus = 0;
45static constexpr uint8_t slotAddressTypeUniqueid = 1;
46static constexpr uint8_t slotI2CMaxReadSize = 35;
47
Vernon Mauerya3702c12019-05-22 13:20:59 -070048static constexpr const char* callbackMgrService =
49 "xyz.openbmc_project.CallbackManager";
50static constexpr const char* callbackMgrIntf =
51 "xyz.openbmc_project.CallbackManager";
52static constexpr const char* callbackMgrObjPath =
53 "/xyz/openbmc_project/CallbackManager";
54static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate";
55
56const static constexpr char* systemDService = "org.freedesktop.systemd1";
57const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1";
58const static constexpr char* systemDMgrIntf =
59 "org.freedesktop.systemd1.Manager";
60const static constexpr char* pidControlService = "phosphor-pid-control.service";
61
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +053062static inline Cc resetMtmTimer(ipmi::Context::ptr ctx)
Richard Marian Thomaiyar666dd012019-08-02 20:55:37 +053063{
Richard Marian Thomaiyar666dd012019-08-02 20:55:37 +053064 boost::system::error_code ec;
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +053065 ctx->bus->yield_method_call<>(ctx->yield, ec, specialModeService,
66 specialModeObjPath, specialModeIntf,
67 "ResetTimer");
Richard Marian Thomaiyar666dd012019-08-02 20:55:37 +053068 if (ec)
69 {
70 phosphor::logging::log<phosphor::logging::level::ERR>(
71 "Failed to reset the manufacturing mode timer");
72 return ccUnspecifiedError;
73 }
74 return ccSuccess;
75}
76
Jason M. Bills38d2b5a2019-06-03 16:26:11 -070077int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path)
Vernon Mauerya3702c12019-05-22 13:20:59 -070078{
Jason M. Bills38d2b5a2019-06-03 16:26:11 -070079 switch (signal)
80 {
81 case SmSignalGet::smPowerButton:
82 path = "/xyz/openbmc_project/chassis/buttons/power";
83 break;
84 case SmSignalGet::smResetButton:
85 path = "/xyz/openbmc_project/chassis/buttons/reset";
86 break;
87 case SmSignalGet::smNMIButton:
88 path = "/xyz/openbmc_project/chassis/buttons/nmi";
89 break;
Richard Marian Thomaiyar8e5e2b02019-08-01 07:50:55 +053090 case SmSignalGet::smIdentifyButton:
91 path = "/xyz/openbmc_project/chassis/buttons/id";
92 break;
Jason M. Bills38d2b5a2019-06-03 16:26:11 -070093 default:
94 return -1;
95 break;
96 }
97 return 0;
Vernon Mauerya3702c12019-05-22 13:20:59 -070098}
99
Patrick Venture37890392019-09-25 17:05:03 -0700100ipmi_ret_t ledStoreAndSet(SmSignalSet signal, const std::string& setState)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700101{
102 LedProperty* ledProp = mtm.findLedProperty(signal);
103 if (ledProp == nullptr)
104 {
105 return IPMI_CC_INVALID_FIELD_REQUEST;
106 }
107
108 std::string ledName = ledProp->getName();
109 std::string ledService = ledServicePrefix + ledName;
110 std::string ledPath = ledPathPrefix + ledName;
111 ipmi::Value presentState;
112
113 if (false == ledProp->getLock())
114 {
115 if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf,
116 "State", &presentState) != 0)
117 {
118 return IPMI_CC_UNSPECIFIED_ERROR;
119 }
120 ledProp->setPrevState(std::get<std::string>(presentState));
121 ledProp->setLock(true);
122 if (signal == SmSignalSet::smPowerFaultLed ||
123 signal == SmSignalSet::smSystemReadyLed)
124 {
125 mtm.revertLedCallback = true;
126 }
127 }
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700128 if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
Vernon Mauerya3702c12019-05-22 13:20:59 -0700129 ledStateStr + setState) != 0)
130 {
131 return IPMI_CC_UNSPECIFIED_ERROR;
132 }
133 return IPMI_CC_OK;
134}
135
136ipmi_ret_t ledRevert(SmSignalSet signal)
137{
138 LedProperty* ledProp = mtm.findLedProperty(signal);
139 if (ledProp == nullptr)
140 {
141 return IPMI_CC_INVALID_FIELD_REQUEST;
142 }
143 if (true == ledProp->getLock())
144 {
145 ledProp->setLock(false);
146 if (signal == SmSignalSet::smPowerFaultLed ||
147 signal == SmSignalSet::smSystemReadyLed)
148 {
149 try
150 {
151 ipmi::method_no_args::callDbusMethod(
152 *getSdBus(), callbackMgrService, callbackMgrObjPath,
153 callbackMgrIntf, retriggerLedUpdate);
154 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500155 catch (const sdbusplus::exception_t& e)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700156 {
157 return IPMI_CC_UNSPECIFIED_ERROR;
158 }
159 mtm.revertLedCallback = false;
160 }
161 else
162 {
163 std::string ledName = ledProp->getName();
164 std::string ledService = ledServicePrefix + ledName;
165 std::string ledPath = ledPathPrefix + ledName;
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700166 if (mtm.setProperty(ledService, ledPath, ledIntf, "State",
167 ledProp->getPrevState()) != 0)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700168 {
169 return IPMI_CC_UNSPECIFIED_ERROR;
170 }
171 }
172 }
173 return IPMI_CC_OK;
174}
175
176void Manufacturing::initData()
177{
Vernon Mauerya3702c12019-05-22 13:20:59 -0700178 ledPropertyList.push_back(
179 LedProperty(SmSignalSet::smPowerFaultLed, "status_amber"));
180 ledPropertyList.push_back(
181 LedProperty(SmSignalSet::smSystemReadyLed, "status_green"));
182 ledPropertyList.push_back(
183 LedProperty(SmSignalSet::smIdentifyLed, "identify"));
184}
185
186void Manufacturing::revertTimerHandler()
187{
Richard Marian Thomaiyarae13ac62019-12-17 15:45:12 +0530188
189#ifdef BMC_VALIDATION_UNSECURE_FEATURE
190 if (mtm.getMfgMode() == SpecialMode::valUnsecure)
191 {
192 // Don't revert the behaviour for validation unsecure mode.
193 return;
194 }
195#endif
Vernon Mauerya3702c12019-05-22 13:20:59 -0700196 if (revertFanPWM)
197 {
198 revertFanPWM = false;
199 disablePidControlService(false);
200 }
201
Ayushi Smritid872a4a2019-10-15 10:20:11 +0530202 if (mtmTestBeepFd != -1)
203 {
204 ::close(mtmTestBeepFd);
205 mtmTestBeepFd = -1;
206 }
207
Vernon Mauerya3702c12019-05-22 13:20:59 -0700208 for (const auto& ledProperty : ledPropertyList)
209 {
210 const std::string& ledName = ledProperty.getName();
Jayaprakash Mutyalaf3656142021-01-24 01:04:19 +0000211 if (ledName == "identify" && mtm.getMfgMode() == SpecialMode::mfg)
212 {
213 // Don't revert the behaviour for manufacturing mode
214 continue;
215 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700216 ledRevert(ledProperty.getSignal());
217 }
218}
219
220Manufacturing::Manufacturing() :
221 revertTimer([&](void) { revertTimerHandler(); })
222{
223 initData();
224}
225
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700226int8_t Manufacturing::getProperty(const std::string& service,
227 const std::string& path,
228 const std::string& interface,
229 const std::string& propertyName,
230 ipmi::Value* reply)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700231{
232 try
233 {
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700234 *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface,
235 propertyName);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700236 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500237 catch (const sdbusplus::exception_t& e)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700238 {
239 phosphor::logging::log<phosphor::logging::level::INFO>(
240 "ERROR: getProperty");
241 return -1;
242 }
243
244 return 0;
245}
246
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700247int8_t Manufacturing::setProperty(const std::string& service,
248 const std::string& path,
249 const std::string& interface,
250 const std::string& propertyName,
251 ipmi::Value value)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700252{
253 try
254 {
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700255 ipmi::setDbusProperty(*getSdBus(), service, path, interface,
Vernon Mauerya3702c12019-05-22 13:20:59 -0700256 propertyName, value);
257 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500258 catch (const sdbusplus::exception_t& e)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700259 {
260 phosphor::logging::log<phosphor::logging::level::INFO>(
261 "ERROR: setProperty");
262 return -1;
263 }
264
265 return 0;
266}
267
268int8_t Manufacturing::disablePidControlService(const bool disable)
269{
270 try
271 {
272 auto dbus = getSdBus();
273 auto method = dbus->new_method_call(systemDService, systemDObjPath,
274 systemDMgrIntf,
275 disable ? "StopUnit" : "StartUnit");
276 method.append(pidControlService, "replace");
277 auto reply = dbus->call(method);
278 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500279 catch (const sdbusplus::exception_t& e)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700280 {
281 phosphor::logging::log<phosphor::logging::level::INFO>(
282 "ERROR: phosphor-pid-control service start or stop failed");
283 return -1;
284 }
285 return 0;
286}
287
Alex Schendel90eb7872022-09-01 11:56:52 -0700288static bool findPwmName(ipmi::Context::ptr& ctx, uint8_t instance,
289 std::string& pwmName)
290{
291 boost::system::error_code ec{};
292 ObjectValueTree obj;
293
294 // GetAll the objects under service FruDevice
295 ec = getManagedObjects(ctx, "xyz.openbmc_project.EntityManager",
296 "/xyz/openbmc_project/inventory", obj);
297 if (ec)
298 {
299 phosphor::logging::log<phosphor::logging::level::ERR>(
300 "GetMangagedObjects failed",
301 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
302 return false;
303 }
304 for (const auto& [path, objData] : obj)
305 {
306 for (const auto& [intf, propMap] : objData)
307 {
308 // Currently, these are the three different fan types supported.
309 if (intf == "xyz.openbmc_project.Configuration.AspeedFan" ||
310 intf == "xyz.openbmc_project.Configuration.I2CFan" ||
311 intf == "xyz.openbmc_project.Configuration.NuvotonFan")
312 {
313 auto findIndex = propMap.find("Index");
314 if (findIndex == propMap.end())
315 {
316 continue;
317 }
318
319 auto fanIndex = std::get_if<uint64_t>(&findIndex->second);
320 if (!fanIndex || *fanIndex != instance)
321 {
322 continue;
323 }
324 auto connector = objData.find(intf + std::string(".Connector"));
325 if (connector == objData.end())
326 {
327 return false;
328 }
329 auto findPwmName = connector->second.find("PwmName");
330 if (findPwmName != connector->second.end())
331 {
332 auto fanPwmName =
333 std::get_if<std::string>(&findPwmName->second);
334 if (!fanPwmName)
335 {
336 phosphor::logging::log<phosphor::logging::level::INFO>(
337 "PwmName parse ERROR.");
338 return false;
339 }
340 pwmName = *fanPwmName;
341 return true;
342 }
343 auto findPwm = connector->second.find("Pwm");
344 if (findPwm == connector->second.end())
345 {
346 return false;
347 }
348 auto fanPwm = std::get_if<uint64_t>(&findPwm->second);
349 if (!fanPwm)
350 {
351 return false;
352 }
353 pwmName = "Pwm_" + std::to_string(*fanPwm + 1);
354 return true;
355 }
356 }
357 }
358 return false;
359}
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700360ipmi::RspType<uint8_t, // Signal value
361 std::optional<uint16_t> // Fan tach value
362 >
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +0530363 appMTMGetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte,
Richard Marian Thomaiyar147daec2019-06-15 07:43:48 +0530364 uint8_t instance, uint8_t actionByte)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700365{
Ayushi Smritie0511e52019-08-27 17:30:34 +0000366 // mfg filter logic is used to allow MTM get signal command only in
367 // manfacturing mode.
Vernon Mauerya3702c12019-05-22 13:20:59 -0700368
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700369 SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte);
370 SmActionGet action = static_cast<SmActionGet>(actionByte);
371
372 switch (signalType)
373 {
anil kumar appana98705b32019-09-11 14:15:50 +0000374 case SmSignalGet::smChassisIntrusion:
375 {
376 ipmi::Value reply;
377 if (mtm.getProperty(intrusionService, intrusionPath, intrusionIntf,
378 "Status", &reply) < 0)
379 {
380 return ipmi::responseInvalidFieldRequest();
381 }
382 std::string* intrusionStatus = std::get_if<std::string>(&reply);
383 if (!intrusionStatus)
384 {
385 return ipmi::responseUnspecifiedError();
386 }
387
388 uint8_t status = 0;
389 if (!intrusionStatus->compare("Normal"))
390 {
391 status = static_cast<uint8_t>(IntrusionStatus::normal);
392 }
393 else if (!intrusionStatus->compare("HardwareIntrusion"))
394 {
395 status =
396 static_cast<uint8_t>(IntrusionStatus::hardwareIntrusion);
397 }
398 else if (!intrusionStatus->compare("TamperingDetected"))
399 {
400 status =
401 static_cast<uint8_t>(IntrusionStatus::tamperingDetected);
402 }
403 else
404 {
405 return ipmi::responseUnspecifiedError();
406 }
407 return ipmi::responseSuccess(status, std::nullopt);
408 }
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700409 case SmSignalGet::smFanPwmGet:
410 {
411 ipmi::Value reply;
Alex Schendel90eb7872022-09-01 11:56:52 -0700412 std::string pwmName, fullPath;
413 if (!findPwmName(ctx, instance, pwmName))
414 {
415 // The default PWM name is Pwm_#
416 pwmName = "Pwm_" + std::to_string(instance + 1);
417 }
418 fullPath = fanPwmPath + pwmName;
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700419 if (mtm.getProperty(fanService, fullPath, fanIntf, "Value",
420 &reply) < 0)
421 {
422 return ipmi::responseInvalidFieldRequest();
423 }
424 double* doubleVal = std::get_if<double>(&reply);
425 if (doubleVal == nullptr)
426 {
427 return ipmi::responseUnspecifiedError();
428 }
429 uint8_t sensorVal = std::round(*doubleVal);
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +0530430 resetMtmTimer(ctx);
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700431 return ipmi::responseSuccess(sensorVal, std::nullopt);
432 }
433 break;
434 case SmSignalGet::smFanTachometerGet:
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700435 {
Richard Marian Thomaiyar147daec2019-06-15 07:43:48 +0530436 boost::system::error_code ec;
437 using objFlatMap = boost::container::flat_map<
438 std::string, boost::container::flat_map<
439 std::string, std::vector<std::string>>>;
440
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +0530441 auto flatMap = ctx->bus->yield_method_call<objFlatMap>(
442 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
Richard Marian Thomaiyar147daec2019-06-15 07:43:48 +0530443 "/xyz/openbmc_project/object_mapper",
444 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
445 fanTachBasePath, 0, std::array<const char*, 1>{fanIntf});
446 if (ec)
447 {
448 phosphor::logging::log<phosphor::logging::level::ERR>(
449 "Failed to query fan tach sub tree objects");
450 return ipmi::responseUnspecifiedError();
451 }
452 if (instance >= flatMap.size())
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700453 {
454 return ipmi::responseInvalidFieldRequest();
455 }
Richard Marian Thomaiyar147daec2019-06-15 07:43:48 +0530456 auto itr = flatMap.nth(instance);
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700457 ipmi::Value reply;
Richard Marian Thomaiyar147daec2019-06-15 07:43:48 +0530458 if (mtm.getProperty(fanService, itr->first, fanIntf, "Value",
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700459 &reply) < 0)
460 {
461 return ipmi::responseInvalidFieldRequest();
462 }
463
464 double* doubleVal = std::get_if<double>(&reply);
465 if (doubleVal == nullptr)
466 {
467 return ipmi::responseUnspecifiedError();
468 }
469 uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT;
470 std::optional<uint16_t> fanTach = std::round(*doubleVal);
471
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +0530472 resetMtmTimer(ctx);
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700473 return ipmi::responseSuccess(sensorVal, fanTach);
474 }
475 break;
Richard Marian Thomaiyar8e5e2b02019-08-01 07:50:55 +0530476 case SmSignalGet::smIdentifyButton:
477 {
478 if (action == SmActionGet::revert || action == SmActionGet::ignore)
479 {
480 // ButtonMasked property is not supported for ID button as it is
481 // unnecessary. Hence if requested for revert / ignore, override
482 // it to sample action to make tools happy.
483 action = SmActionGet::sample;
484 }
485 // fall-through
486 }
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700487 case SmSignalGet::smResetButton:
488 case SmSignalGet::smPowerButton:
489 case SmSignalGet::smNMIButton:
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700490 {
491 std::string path;
492 if (getGpioPathForSmSignal(signalType, path) < 0)
493 {
494 return ipmi::responseInvalidFieldRequest();
495 }
496
497 switch (action)
498 {
499 case SmActionGet::sample:
500 phosphor::logging::log<phosphor::logging::level::INFO>(
501 "case SmActionGet::sample");
502 break;
503 case SmActionGet::ignore:
504 {
505 phosphor::logging::log<phosphor::logging::level::INFO>(
506 "case SmActionGet::ignore");
507 if (mtm.setProperty(buttonService, path, buttonIntf,
508 "ButtonMasked", true) < 0)
509 {
510 return ipmi::responseUnspecifiedError();
511 }
512 }
513 break;
514 case SmActionGet::revert:
515 {
516 phosphor::logging::log<phosphor::logging::level::INFO>(
517 "case SmActionGet::revert");
518 if (mtm.setProperty(buttonService, path, buttonIntf,
519 "ButtonMasked", false) < 0)
520 {
521 return ipmi::responseUnspecifiedError();
522 }
523 }
524 break;
525
526 default:
527 return ipmi::responseInvalidFieldRequest();
528 break;
529 }
530
531 ipmi::Value reply;
532 if (mtm.getProperty(buttonService, path, buttonIntf,
533 "ButtonPressed", &reply) < 0)
534 {
535 return ipmi::responseUnspecifiedError();
536 }
537 bool* valPtr = std::get_if<bool>(&reply);
538 if (valPtr == nullptr)
539 {
540 return ipmi::responseUnspecifiedError();
541 }
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +0530542 resetMtmTimer(ctx);
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700543 uint8_t sensorVal = *valPtr;
544 return ipmi::responseSuccess(sensorVal, std::nullopt);
545 }
546 break;
Richard Marian Thomaiyar1b74a212019-08-03 13:26:17 +0530547 case SmSignalGet::smNcsiDiag:
548 {
549 constexpr const char* netBasePath = "/sys/class/net/eth";
550 constexpr const char* carrierSuffix = "/carrier";
551 std::ifstream netIfs(netBasePath + std::to_string(instance) +
552 carrierSuffix);
553 if (!netIfs.good())
554 {
555 return ipmi::responseInvalidFieldRequest();
556 }
557 std::string carrier;
558 netIfs >> carrier;
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +0530559 resetMtmTimer(ctx);
Richard Marian Thomaiyar1b74a212019-08-03 13:26:17 +0530560 return ipmi::responseSuccess(
561 static_cast<uint8_t>(std::stoi(carrier)), std::nullopt);
562 }
563 break;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700564 default:
Jason M. Bills38d2b5a2019-06-03 16:26:11 -0700565 return ipmi::responseInvalidFieldRequest();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700566 break;
567 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700568}
569
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +0530570ipmi::RspType<> appMTMSetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte,
571 uint8_t instance, uint8_t actionByte,
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000572 std::optional<uint8_t> pwmSpeed)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700573{
Ayushi Smritie0511e52019-08-27 17:30:34 +0000574 // mfg filter logic is used to allow MTM set signal command only in
575 // manfacturing mode.
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000576
577 SmSignalSet signalType = static_cast<SmSignalSet>(signalTypeByte);
578 SmActionSet action = static_cast<SmActionSet>(actionByte);
579 Cc retCode = ccSuccess;
580 int8_t ret = 0;
581
582 switch (signalType)
583 {
584 case SmSignalSet::smPowerFaultLed:
585 case SmSignalSet::smSystemReadyLed:
586 case SmSignalSet::smIdentifyLed:
587 switch (action)
588 {
589 case SmActionSet::forceDeasserted:
Vernon Mauerya3702c12019-05-22 13:20:59 -0700590 {
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000591 phosphor::logging::log<phosphor::logging::level::INFO>(
592 "case SmActionSet::forceDeasserted");
Vernon Mauerya3702c12019-05-22 13:20:59 -0700593
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000594 retCode = ledStoreAndSet(signalType, std::string("Off"));
595 if (retCode != ccSuccess)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700596 {
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000597 return ipmi::response(retCode);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700598 }
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000599 mtm.revertTimer.start(revertTimeOut);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700600 }
601 break;
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000602 case SmActionSet::forceAsserted:
Vernon Mauerya3702c12019-05-22 13:20:59 -0700603 {
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000604 phosphor::logging::log<phosphor::logging::level::INFO>(
605 "case SmActionSet::forceAsserted");
Vernon Mauerya3702c12019-05-22 13:20:59 -0700606
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000607 retCode = ledStoreAndSet(signalType, std::string("On"));
608 if (retCode != ccSuccess)
609 {
610 return ipmi::response(retCode);
611 }
612 mtm.revertTimer.start(revertTimeOut);
613 if (SmSignalSet::smPowerFaultLed == signalType)
614 {
615 // Deassert "system ready"
616 retCode = ledStoreAndSet(SmSignalSet::smSystemReadyLed,
617 std::string("Off"));
618 }
619 else if (SmSignalSet::smSystemReadyLed == signalType)
620 {
621 // Deassert "fault led"
622 retCode = ledStoreAndSet(SmSignalSet::smPowerFaultLed,
623 std::string("Off"));
624 }
625 }
626 break;
627 case SmActionSet::revert:
628 {
629 phosphor::logging::log<phosphor::logging::level::INFO>(
630 "case SmActionSet::revert");
631 retCode = ledRevert(signalType);
632 }
633 break;
634 default:
635 {
636 return ipmi::responseInvalidFieldRequest();
637 }
638 }
639 break;
640 case SmSignalSet::smFanPowerSpeed:
641 {
642 if ((action == SmActionSet::forceAsserted) && (!pwmSpeed))
643 {
644 return ipmi::responseReqDataLenInvalid();
645 }
646
647 if ((action == SmActionSet::forceAsserted) && (*pwmSpeed > 100))
648 {
649 return ipmi::responseInvalidFieldRequest();
650 }
651
652 uint8_t pwmValue = 0;
653 switch (action)
654 {
655 case SmActionSet::revert:
656 {
657 if (mtm.revertFanPWM)
658 {
659 ret = mtm.disablePidControlService(false);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700660 if (ret < 0)
661 {
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000662 return ipmi::responseUnspecifiedError();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700663 }
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000664 mtm.revertFanPWM = false;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700665 }
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000666 }
667 break;
668 case SmActionSet::forceAsserted:
669 {
670 pwmValue = *pwmSpeed;
671 } // fall-through
672 case SmActionSet::forceDeasserted:
673 {
674 if (!mtm.revertFanPWM)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700675 {
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000676 ret = mtm.disablePidControlService(true);
677 if (ret < 0)
678 {
679 return ipmi::responseUnspecifiedError();
680 }
681 mtm.revertFanPWM = true;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700682 }
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000683 mtm.revertTimer.start(revertTimeOut);
Alex Schendel90eb7872022-09-01 11:56:52 -0700684 std::string pwmName, fanPwmInstancePath;
685 if (!findPwmName(ctx, instance, pwmName))
686 {
687 pwmName = "Pwm_" + std::to_string(instance + 1);
688 }
689 fanPwmInstancePath = fanPwmPath + pwmName;
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000690 ret =
691 mtm.setProperty(fanService, fanPwmInstancePath, fanIntf,
692 "Value", static_cast<double>(pwmValue));
693 if (ret < 0)
694 {
695 return ipmi::responseUnspecifiedError();
696 }
697 }
698 break;
699 default:
700 {
701 return ipmi::responseInvalidFieldRequest();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700702 }
703 }
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000704 }
705 break;
Ayushi Smritid872a4a2019-10-15 10:20:11 +0530706 case SmSignalSet::smSpeaker:
707 {
708 phosphor::logging::log<phosphor::logging::level::INFO>(
709 "Performing Speaker SmActionSet",
710 phosphor::logging::entry("ACTION=%d",
711 static_cast<uint8_t>(action)));
712 switch (action)
713 {
714 case SmActionSet::forceAsserted:
715 {
716 char beepDevName[] = "/dev/input/event0";
717 if (mtm.mtmTestBeepFd != -1)
718 {
719 phosphor::logging::log<phosphor::logging::level::INFO>(
720 "mtm beep device is opened already!");
721 // returning success as already beep is in progress
722 return ipmi::response(retCode);
723 }
724
725 if ((mtm.mtmTestBeepFd =
726 ::open(beepDevName, O_RDWR | O_CLOEXEC)) < 0)
727 {
728 phosphor::logging::log<phosphor::logging::level::ERR>(
729 "Failed to open input device");
730 return ipmi::responseUnspecifiedError();
731 }
732
733 struct input_event event;
734 event.type = EV_SND;
735 event.code = SND_TONE;
736 event.value = 2000;
737
738 if (::write(mtm.mtmTestBeepFd, &event,
739 sizeof(struct input_event)) !=
740 sizeof(struct input_event))
741 {
742 phosphor::logging::log<phosphor::logging::level::ERR>(
743 "Failed to write a tone sound event");
744 ::close(mtm.mtmTestBeepFd);
745 mtm.mtmTestBeepFd = -1;
746 return ipmi::responseUnspecifiedError();
747 }
748 mtm.revertTimer.start(revertTimeOut);
749 }
750 break;
751 case SmActionSet::revert:
752 case SmActionSet::forceDeasserted:
753 {
754 if (mtm.mtmTestBeepFd != -1)
755 {
756 ::close(mtm.mtmTestBeepFd);
757 mtm.mtmTestBeepFd = -1;
758 }
759 }
760 break;
761 default:
762 {
763 return ipmi::responseInvalidFieldRequest();
764 }
765 }
766 }
767 break;
Richard Marian Thomaiyar3594c6d2019-11-19 21:29:04 +0530768 case SmSignalSet::smDiskFaultLed:
769 {
770 boost::system::error_code ec;
771 using objPaths = std::vector<std::string>;
772 std::string driveBasePath =
773 "/xyz/openbmc_project/inventory/item/drive/";
774 static constexpr const char* driveLedIntf =
775 "xyz.openbmc_project.Led.Group";
776 static constexpr const char* hsbpService =
777 "xyz.openbmc_project.HsbpManager";
778
779 auto driveList = ctx->bus->yield_method_call<objPaths>(
780 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
781 "/xyz/openbmc_project/object_mapper",
782 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
783 driveBasePath, 0, std::array<const char*, 1>{driveLedIntf});
784 if (ec)
785 {
786 phosphor::logging::log<phosphor::logging::level::ERR>(
787 "Failed to query HSBP drive sub tree objects");
788 return ipmi::responseUnspecifiedError();
789 }
790 std::string driveObjPath =
791 driveBasePath + "Drive_" + std::to_string(instance + 1);
792 if (std::find(driveList.begin(), driveList.end(), driveObjPath) ==
793 driveList.end())
794 {
795 return ipmi::responseInvalidFieldRequest();
796 }
797 bool driveLedState = false;
798 switch (action)
799 {
800 case SmActionSet::forceAsserted:
801 {
802 driveLedState = true;
803 }
804 break;
805 case SmActionSet::revert:
806 {
807 driveLedState = false;
808 }
809 break;
810 case SmActionSet::forceDeasserted:
811 {
812 driveLedState = false;
813 }
814 break;
815 default:
816 {
817 return ipmi::responseInvalidFieldRequest();
818 }
819 }
820 ret = mtm.setProperty(hsbpService, driveObjPath, driveLedIntf,
821 "Asserted", driveLedState);
822 if (ret < 0)
823 {
824 return ipmi::responseUnspecifiedError();
825 }
826 }
827 break;
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000828 default:
829 {
830 return ipmi::responseInvalidFieldRequest();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700831 }
832 }
Richard Marian Thomaiyar4cc10152019-08-02 23:21:45 +0530833 if (retCode == ccSuccess)
834 {
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +0530835 resetMtmTimer(ctx);
Richard Marian Thomaiyar4cc10152019-08-02 23:21:45 +0530836 }
Ayushi Smriti5e3bf552019-07-30 15:32:06 +0000837 return ipmi::response(retCode);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700838}
839
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +0530840ipmi::RspType<> mtmKeepAlive(ipmi::Context::ptr ctx, uint8_t reserved,
Richard Marian Thomaiyar666dd012019-08-02 20:55:37 +0530841 const std::array<char, 5>& intentionalSignature)
842{
Ayushi Smritie0511e52019-08-27 17:30:34 +0000843 // mfg filter logic is used to allow MTM keep alive command only in
844 // manfacturing mode
845
Richard Marian Thomaiyar666dd012019-08-02 20:55:37 +0530846 constexpr std::array<char, 5> signatureOk = {'I', 'N', 'T', 'E', 'L'};
847 if (intentionalSignature != signatureOk || reserved != 0)
848 {
849 return ipmi::responseInvalidFieldRequest();
850 }
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +0530851 return ipmi::response(resetMtmTimer(ctx));
Richard Marian Thomaiyar666dd012019-08-02 20:55:37 +0530852}
853
Ayushi Smritie0511e52019-08-27 17:30:34 +0000854static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd)
855{
856 return (netFn << 8) | cmd;
857}
858
Yong Li85feb132019-08-09 16:06:03 +0800859ipmi::Cc mfgFilterMessage(ipmi::message::Request::ptr request)
860{
Ayushi Smritie0511e52019-08-27 17:30:34 +0000861 // Restricted commands, must be executed only in Manufacturing mode
862 switch (makeCmdKey(request->ctx->netFn, request->ctx->cmd))
Yong Li85feb132019-08-09 16:06:03 +0800863 {
Ayushi Smritie0511e52019-08-27 17:30:34 +0000864 // i2c master write read command needs additional checking
865 case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead):
866 if (request->payload.size() > 4)
867 {
Richard Marian Thomaiyarae13ac62019-12-17 15:45:12 +0530868 // Allow write data count > 1 only in Special mode
869 if (mtm.getMfgMode() == SpecialMode::none)
Ayushi Smritie0511e52019-08-27 17:30:34 +0000870 {
871 return ipmi::ccInsufficientPrivilege;
872 }
873 }
jayaprakash Mutyala2d4a0192019-11-11 22:12:45 +0000874 return ipmi::ccSuccess;
Ayushi Smritie0511e52019-08-27 17:30:34 +0000875 case makeCmdKey(ipmi::netFnOemOne,
876 ipmi::intel::general::cmdGetSmSignal):
877 case makeCmdKey(ipmi::netFnOemOne,
878 ipmi::intel::general::cmdSetSmSignal):
879 case makeCmdKey(ipmi::netFnOemOne,
880 ipmi::intel::general::cmdMtmKeepAlive):
881 case makeCmdKey(ipmi::netFnOemOne,
882 ipmi::intel::general::cmdSetManufacturingData):
883 case makeCmdKey(ipmi::netFnOemOne,
884 ipmi::intel::general::cmdGetManufacturingData):
Vernon Mauery27d23562021-08-12 10:43:39 -0700885 case makeCmdKey(ipmi::intel::netFnGeneral,
886 ipmi::intel::general::cmdSetFITcLayout):
Arun P. Mohanan06584cd2021-08-13 20:56:01 +0530887 case makeCmdKey(ipmi::netFnOemOne,
888 ipmi::intel::general::cmdMTMBMCFeatureControl):
Ayushi Smritie0511e52019-08-27 17:30:34 +0000889 case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdWriteFruData):
AppaRao Puli9a13daa2020-07-13 17:53:00 +0530890 case makeCmdKey(ipmi::netFnOemTwo, ipmi::intel::platform::cmdClearCMOS):
Ayushi Smritie0511e52019-08-27 17:30:34 +0000891
Richard Marian Thomaiyarae13ac62019-12-17 15:45:12 +0530892 // Check for Special mode
893 if (mtm.getMfgMode() == SpecialMode::none)
Yong Li85feb132019-08-09 16:06:03 +0800894 {
Ayushi Smritie0511e52019-08-27 17:30:34 +0000895 return ipmi::ccInvalidCommand;
Yong Li85feb132019-08-09 16:06:03 +0800896 }
jayaprakash Mutyala2d4a0192019-11-11 22:12:45 +0000897 return ipmi::ccSuccess;
898 case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdDeleteSelEntry):
899 {
900 return ipmi::ccInvalidCommand;
901 }
Yong Li85feb132019-08-09 16:06:03 +0800902 }
Yong Li85feb132019-08-09 16:06:03 +0800903 return ipmi::ccSuccess;
904}
905
Richard Marian Thomaiyar1f0839c2019-08-25 20:10:52 +0530906static constexpr uint8_t maxEthSize = 6;
907static constexpr uint8_t maxSupportedEth = 3;
908static constexpr const char* factoryEthAddrBaseFileName =
909 "/var/sofs/factory-settings/network/mac/eth";
910
Alex Schendel097497f2022-10-07 14:37:15 -0700911bool findFruDevice(ipmi::Context::ptr& ctx, uint64_t& macOffset,
Zhikui Renad129c62022-04-05 20:11:24 -0700912 uint64_t& busNum, uint64_t& address)
913{
Alex Schendel097497f2022-10-07 14:37:15 -0700914 boost::system::error_code ec{};
915 ObjectValueTree obj;
Zhikui Renad129c62022-04-05 20:11:24 -0700916
917 // GetAll the objects under service FruDevice
Alex Schendel097497f2022-10-07 14:37:15 -0700918 ec = getManagedObjects(ctx, "xyz.openbmc_project.EntityManager",
919 "/xyz/openbmc_project/inventory", obj);
Zhikui Renad129c62022-04-05 20:11:24 -0700920 if (ec)
921 {
922 phosphor::logging::log<phosphor::logging::level::ERR>(
923 "GetMangagedObjects failed",
924 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
925 return false;
926 }
927
928 for (const auto& [path, fru] : obj)
929 {
930 for (const auto& [intf, propMap] : fru)
931 {
932 if (intf == "xyz.openbmc_project.Inventory.Item.Board.Motherboard")
933 {
934 auto findBus = propMap.find("FruBus");
935 auto findAddress = propMap.find("FruAddress");
936 auto findMacOffset = propMap.find("MacOffset");
937 if (findBus == propMap.end() || findAddress == propMap.end() ||
938 findMacOffset == propMap.end())
939 {
940 continue;
941 }
942
943 auto fruBus = std::get_if<uint64_t>(&findBus->second);
944 auto fruAddress = std::get_if<uint64_t>(&findAddress->second);
945 auto macFruOffset =
946 std::get_if<uint64_t>(&findMacOffset->second);
947 if (!fruBus || !fruAddress || !macFruOffset)
948 {
949 phosphor::logging::log<phosphor::logging::level::INFO>(
950 "ERROR: MotherBoard FRU config data type invalid, not "
951 "used");
952 return false;
953 }
954 busNum = *fruBus;
955 address = *fruAddress;
956 macOffset = *macFruOffset;
957 return true;
958 }
959 }
960 }
961 return false;
962}
963
Zhikui Ren98fa87e2022-05-04 08:10:29 -0700964static constexpr uint64_t fruEnd = 0xff;
965// write rolls over within current page, need to keep mac within a page
966static constexpr uint64_t fruPageSize = 0x8;
967// MAC record struct: HEADER, MAC DATA, CheckSum
968static constexpr uint64_t macRecordSize = maxEthSize + 2;
969static_assert(fruPageSize >= macRecordSize,
970 "macRecordSize greater than eeprom page size");
971static constexpr uint8_t macHeader = 0x40;
972// Calculate new checksum for fru info area
973static uint8_t calculateChecksum(std::vector<uint8_t>::const_iterator iter,
974 std::vector<uint8_t>::const_iterator end)
975{
976 constexpr int checksumMod = 256;
977 uint8_t sum = std::accumulate(iter, end, static_cast<uint8_t>(0));
978 return (checksumMod - sum) % checksumMod;
979}
980
Zhikui Renad129c62022-04-05 20:11:24 -0700981bool readMacFromFru(ipmi::Context::ptr ctx, uint8_t macIndex,
982 std::array<uint8_t, maxEthSize>& ethData)
983{
Zhikui Renad129c62022-04-05 20:11:24 -0700984 uint64_t macOffset = fruEnd;
985 uint64_t fruBus = 0;
986 uint64_t fruAddress = 0;
987
Alex Schendel097497f2022-10-07 14:37:15 -0700988 if (findFruDevice(ctx, macOffset, fruBus, fruAddress))
Zhikui Renad129c62022-04-05 20:11:24 -0700989 {
990 phosphor::logging::log<phosphor::logging::level::INFO>(
991 "Found mac fru",
992 phosphor::logging::entry("BUS=%d", static_cast<uint8_t>(fruBus)),
993 phosphor::logging::entry("ADDRESS=%d",
994 static_cast<uint8_t>(fruAddress)));
995
Zhikui Ren98fa87e2022-05-04 08:10:29 -0700996 if (macOffset % fruPageSize)
997 {
998 macOffset = (macOffset / fruPageSize + 1) * fruPageSize;
999 }
1000 macOffset += macIndex * fruPageSize;
1001 if ((macOffset + macRecordSize) > fruEnd)
Zhikui Renad129c62022-04-05 20:11:24 -07001002 {
1003 phosphor::logging::log<phosphor::logging::level::ERR>(
1004 "ERROR: read fru mac failed, offset invalid");
1005 return false;
1006 }
1007 std::vector<uint8_t> writeData;
Zhikui Ren98fa87e2022-05-04 08:10:29 -07001008 writeData.push_back(static_cast<uint8_t>(macOffset));
1009 std::vector<uint8_t> readBuf(macRecordSize);
Zhikui Renad129c62022-04-05 20:11:24 -07001010 std::string i2cBus = "/dev/i2c-" + std::to_string(fruBus);
1011 ipmi::Cc retI2C =
1012 ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, readBuf);
1013 if (retI2C == ipmi::ccSuccess)
1014 {
Zhikui Ren98fa87e2022-05-04 08:10:29 -07001015 uint8_t cs = calculateChecksum(readBuf.cbegin(), readBuf.cend());
1016 if (cs == 0)
1017 {
1018 std::copy(++readBuf.begin(), --readBuf.end(), ethData.data());
1019 return true;
1020 }
Zhikui Renad129c62022-04-05 20:11:24 -07001021 }
1022 }
1023 return false;
1024}
1025
1026ipmi::Cc writeMacToFru(ipmi::Context::ptr ctx, uint8_t macIndex,
1027 std::array<uint8_t, maxEthSize>& ethData)
1028{
Zhikui Renad129c62022-04-05 20:11:24 -07001029 uint64_t macOffset = fruEnd;
1030 uint64_t fruBus = 0;
1031 uint64_t fruAddress = 0;
1032
Alex Schendel097497f2022-10-07 14:37:15 -07001033 if (findFruDevice(ctx, macOffset, fruBus, fruAddress))
Zhikui Renad129c62022-04-05 20:11:24 -07001034 {
1035 phosphor::logging::log<phosphor::logging::level::INFO>(
1036 "Found mac fru",
1037 phosphor::logging::entry("BUS=%d", static_cast<uint8_t>(fruBus)),
1038 phosphor::logging::entry("ADDRESS=%d",
1039 static_cast<uint8_t>(fruAddress)));
1040
Zhikui Ren98fa87e2022-05-04 08:10:29 -07001041 if (macOffset % fruPageSize)
1042 {
1043 macOffset = (macOffset / fruPageSize + 1) * fruPageSize;
1044 }
1045 macOffset += macIndex * fruPageSize;
1046 if ((macOffset + macRecordSize) > fruEnd)
Zhikui Renad129c62022-04-05 20:11:24 -07001047 {
1048 phosphor::logging::log<phosphor::logging::level::ERR>(
1049 "ERROR: write mac fru failed, offset invalid.");
1050 return ipmi::ccParmOutOfRange;
1051 }
1052 std::vector<uint8_t> writeData;
Zhikui Ren98fa87e2022-05-04 08:10:29 -07001053 writeData.reserve(macRecordSize + 1); // include start location
1054 writeData.push_back(static_cast<uint8_t>(macOffset));
1055 writeData.push_back(macHeader);
Zhikui Renad129c62022-04-05 20:11:24 -07001056 std::for_each(ethData.cbegin(), ethData.cend(),
1057 [&](uint8_t i) { writeData.push_back(i); });
Zhikui Ren98fa87e2022-05-04 08:10:29 -07001058 uint8_t macCheckSum =
1059 calculateChecksum(++writeData.cbegin(), writeData.cend());
1060 writeData.push_back(macCheckSum);
Zhikui Renad129c62022-04-05 20:11:24 -07001061
1062 std::string i2cBus = "/dev/i2c-" + std::to_string(fruBus);
1063 std::vector<uint8_t> readBuf;
1064 ipmi::Cc ret =
1065 ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, readBuf);
Zhikui Ren98fa87e2022-05-04 08:10:29 -07001066
Zhikui Ren0408e792022-06-07 21:03:33 -07001067 // prepare for read to detect chip is write protected
1068 writeData.resize(1);
1069 readBuf.resize(maxEthSize + 1); // include macHeader
1070
Zhikui Renad129c62022-04-05 20:11:24 -07001071 switch (ret)
1072 {
1073 case ipmi::ccSuccess:
Zhikui Ren98fa87e2022-05-04 08:10:29 -07001074 // Wait for internal write cycle to complete
1075 // example: ATMEL 24c0x chip has Twr spec as 5ms
1076
1077 // Ideally we want yield wait, but currently following code
1078 // crash with "thread not supported"
1079 // boost::asio::deadline_timer timer(
1080 // boost::asio::get_associated_executor(ctx->yield),
1081 // boost::posix_time::seconds(1));
1082 // timer.async_wait(ctx->yield);
1083 // use usleep as temp WA
1084 usleep(5000);
1085 if (ipmi::i2cWriteRead(i2cBus, fruAddress, writeData,
1086 readBuf) == ipmi::ccSuccess)
Zhikui Renad129c62022-04-05 20:11:24 -07001087 {
1088 if (std::equal(ethData.begin(), ethData.end(),
Zhikui Ren98fa87e2022-05-04 08:10:29 -07001089 ++readBuf.begin())) // skip macHeader
Zhikui Renad129c62022-04-05 20:11:24 -07001090 {
1091 return ipmi::ccSuccess;
1092 }
1093 phosphor::logging::log<phosphor::logging::level::INFO>(
1094 "INFO: write mac fru verify failed, fru may be write "
1095 "protected.");
1096 }
1097 return ipmi::ccCommandNotAvailable;
Zhikui Ren0408e792022-06-07 21:03:33 -07001098 default:
1099 if (ipmi::i2cWriteRead(i2cBus, fruAddress, writeData,
1100 readBuf) == ipmi::ccSuccess)
1101 {
1102 phosphor::logging::log<phosphor::logging::level::INFO>(
1103 "INFO: write mac fru failed, but successfully read "
1104 "from fru, fru may be write protected.");
1105 return ipmi::ccCommandNotAvailable;
1106 }
1107 else // assume failure is due to no eeprom on board
1108 {
1109 phosphor::logging::log<phosphor::logging::level::ERR>(
1110 "ERROR: write mac fru failed, assume no eeprom is "
1111 "available.");
1112 }
Zhikui Renad129c62022-04-05 20:11:24 -07001113 break;
1114 }
1115 }
1116 // no FRU eeprom found
1117 return ipmi::ccDestinationUnavailable;
1118}
1119
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +05301120ipmi::RspType<> setManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType,
Richard Marian Thomaiyar1f0839c2019-08-25 20:10:52 +05301121 std::array<uint8_t, maxEthSize> ethData)
1122{
Zhikui Renad129c62022-04-05 20:11:24 -07001123 // mfg filter logic will restrict this command executing only in mfg
1124 // mode.
Richard Marian Thomaiyar1f0839c2019-08-25 20:10:52 +05301125 if (dataType >= maxSupportedEth)
1126 {
1127 return ipmi::responseParmOutOfRange();
1128 }
1129
1130 constexpr uint8_t invalidData = 0;
1131 constexpr uint8_t validData = 1;
Zhikui Renad129c62022-04-05 20:11:24 -07001132
1133 ipmi::Cc ret = writeMacToFru(ctx, dataType, ethData);
1134 if (ret != ipmi::ccDestinationUnavailable)
1135 {
1136 resetMtmTimer(ctx);
1137 return response(ret);
1138 }
1139
Richard Marian Thomaiyar1f0839c2019-08-25 20:10:52 +05301140 constexpr uint8_t ethAddrStrSize =
1141 19; // XX:XX:XX:XX:XX:XX + \n + null termination;
1142 std::vector<uint8_t> buff(ethAddrStrSize);
1143 std::snprintf(reinterpret_cast<char*>(buff.data()), ethAddrStrSize,
1144 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", ethData.at(0),
1145 ethData.at(1), ethData.at(2), ethData.at(3), ethData.at(4),
1146 ethData.at(5));
1147 std::ofstream oEthFile(factoryEthAddrBaseFileName +
1148 std::to_string(dataType),
1149 std::ofstream::out);
1150 if (!oEthFile.good())
1151 {
1152 return ipmi::responseUnspecifiedError();
1153 }
1154
1155 oEthFile << reinterpret_cast<char*>(buff.data());
Johnathan Mantey6d83e4e2020-05-08 11:01:01 -07001156 oEthFile.flush();
Richard Marian Thomaiyar1f0839c2019-08-25 20:10:52 +05301157 oEthFile.close();
1158
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +05301159 resetMtmTimer(ctx);
Richard Marian Thomaiyar1f0839c2019-08-25 20:10:52 +05301160 return ipmi::responseSuccess();
1161}
1162
1163ipmi::RspType<uint8_t, std::array<uint8_t, maxEthSize>>
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +05301164 getManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType)
Richard Marian Thomaiyar1f0839c2019-08-25 20:10:52 +05301165{
Zhikui Renad129c62022-04-05 20:11:24 -07001166 // mfg filter logic will restrict this command executing only in mfg
1167 // mode.
Richard Marian Thomaiyar1f0839c2019-08-25 20:10:52 +05301168 if (dataType >= maxSupportedEth)
1169 {
1170 return ipmi::responseParmOutOfRange();
1171 }
1172 std::array<uint8_t, maxEthSize> ethData{0};
1173 constexpr uint8_t invalidData = 0;
1174 constexpr uint8_t validData = 1;
1175
1176 std::ifstream iEthFile(factoryEthAddrBaseFileName +
1177 std::to_string(dataType),
1178 std::ifstream::in);
1179 if (!iEthFile.good())
1180 {
Zhikui Renad129c62022-04-05 20:11:24 -07001181 if (readMacFromFru(ctx, dataType, ethData))
1182 {
1183 resetMtmTimer(ctx);
1184 return ipmi::responseSuccess(validData, ethData);
1185 }
Richard Marian Thomaiyar1f0839c2019-08-25 20:10:52 +05301186 return ipmi::responseSuccess(invalidData, ethData);
1187 }
1188 std::string ethStr;
1189 iEthFile >> ethStr;
1190 uint8_t* data = ethData.data();
1191 std::sscanf(ethStr.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
1192 data, (data + 1), (data + 2), (data + 3), (data + 4),
1193 (data + 5));
1194
Richard Marian Thomaiyar357ddc72019-09-01 22:40:07 +05301195 resetMtmTimer(ctx);
Richard Marian Thomaiyar1f0839c2019-08-25 20:10:52 +05301196 return ipmi::responseSuccess(validData, ethData);
1197}
1198
Zhikui Renad129c62022-04-05 20:11:24 -07001199/** @brief implements slot master write read IPMI command which can be used
1200 * for low-level I2C/SMBus write, read or write-read access for PCIE slots
V-Sanjana7acb2d22022-11-15 11:13:54 +05301201 * @param reserved - skip 3 bit
1202 * @param muxType - mux type
Yong Lif267a672019-08-29 11:16:07 +08001203 * @param addressType - address type
1204 * @param bbSlotNum - baseboard slot number
1205 * @param riserSlotNum - riser slot number
1206 * @param reserved2 - skip 2 bit
1207 * @param slaveAddr - slave address
1208 * @param readCount - number of bytes to be read
1209 * @param writeData - data to be written
1210 *
1211 * @returns IPMI completion code plus response data
1212 */
V-Sanjana7acb2d22022-11-15 11:13:54 +05301213
1214ipmi::RspType<std::vector<uint8_t>> appSlotI2CMasterWriteRead(
1215 uint3_t reserved, uint3_t muxType, uint2_t addressType, uint3_t bbSlotNum,
1216 uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr,
1217 uint8_t readCount, std::vector<uint8_t> writeData)
Yong Lif267a672019-08-29 11:16:07 +08001218{
Vernon Maueryfc3bc382022-06-02 13:52:04 -07001219 if (reserved || reserved2)
1220 {
1221 return ipmi::responseInvalidFieldRequest();
1222 }
Yong Lif267a672019-08-29 11:16:07 +08001223 const size_t writeCount = writeData.size();
1224 std::string i2cBus;
1225 if (addressType == slotAddressTypeBus)
1226 {
V-Sanjana7acb2d22022-11-15 11:13:54 +05301227 std::string path = "/dev/i2c-mux/";
1228 if (muxType == bbRiserMux)
1229 {
1230 path += "Riser_" + std::to_string(static_cast<uint8_t>(bbSlotNum)) +
1231 "_Mux/Pcie_Slot_" +
1232 std::to_string(static_cast<uint8_t>(riserSlotNum));
1233 }
1234 else if (muxType == leftRiserMux)
1235 {
1236 path += "Left_Riser_Mux/Slot_" +
1237 std::to_string(static_cast<uint8_t>(riserSlotNum));
1238 }
1239 else if (muxType == rightRiserMux)
1240 {
1241 path += "Right_Riser_Mux/Slot_" +
1242 std::to_string(static_cast<uint8_t>(riserSlotNum));
1243 }
1244 else if (muxType == pcieMux)
1245 {
1246 path += "PCIe_Mux/Slot_" +
1247 std::to_string(static_cast<uint8_t>(riserSlotNum));
1248 }
1249 else if (muxType == hsbpMux)
1250 {
1251 path += "HSBP_Mux/Slot" +
1252 std::to_string(static_cast<uint8_t>(riserSlotNum));
1253 }
1254 phosphor::logging::log<phosphor::logging::level::DEBUG>(
1255 ("Path is: " + path).c_str());
Yong Lif267a672019-08-29 11:16:07 +08001256 if (std::filesystem::exists(path) && std::filesystem::is_symlink(path))
1257 {
1258 i2cBus = std::filesystem::read_symlink(path);
1259 }
1260 else
1261 {
1262 phosphor::logging::log<phosphor::logging::level::ERR>(
1263 "Master write read command: Cannot get BusID");
1264 return ipmi::responseInvalidFieldRequest();
1265 }
1266 }
1267 else if (addressType == slotAddressTypeUniqueid)
1268 {
1269 i2cBus = "/dev/i2c-" +
1270 std::to_string(static_cast<uint8_t>(bbSlotNum) |
1271 (static_cast<uint8_t>(riserSlotNum) << 3));
1272 }
1273 else
1274 {
1275 phosphor::logging::log<phosphor::logging::level::ERR>(
1276 "Master write read command: invalid request");
1277 return ipmi::responseInvalidFieldRequest();
1278 }
1279
Zhikui Renad129c62022-04-05 20:11:24 -07001280 // Allow single byte write as it is offset byte to read the data, rest
1281 // allow only in Special mode.
Yong Lif267a672019-08-29 11:16:07 +08001282 if (writeCount > 1)
1283 {
Richard Marian Thomaiyarae13ac62019-12-17 15:45:12 +05301284 if (mtm.getMfgMode() == SpecialMode::none)
Yong Lif267a672019-08-29 11:16:07 +08001285 {
1286 return ipmi::responseInsufficientPrivilege();
1287 }
1288 }
1289
1290 if (readCount > slotI2CMaxReadSize)
1291 {
1292 phosphor::logging::log<phosphor::logging::level::ERR>(
1293 "Master write read command: Read count exceeds limit");
1294 return ipmi::responseParmOutOfRange();
1295 }
1296
1297 if (!readCount && !writeCount)
1298 {
1299 phosphor::logging::log<phosphor::logging::level::ERR>(
1300 "Master write read command: Read & write count are 0");
1301 return ipmi::responseInvalidFieldRequest();
1302 }
1303
1304 std::vector<uint8_t> readBuf(readCount);
1305
1306 ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf);
1307 if (retI2C != ipmi::ccSuccess)
1308 {
1309 return ipmi::response(retI2C);
1310 }
1311
1312 return ipmi::responseSuccess(readBuf);
1313}
Yong Li068b4f22019-09-17 16:32:18 +08001314
1315ipmi::RspType<> clearCMOS()
1316{
Zhikui Renad129c62022-04-05 20:11:24 -07001317 // There is an i2c device on bus 4, the slave address is 0x38. Based on
1318 // the spec, writing 0x1 to address 0x61 on this device, will trigger
1319 // the clear CMOS action.
Yong Lid0d010b2019-11-18 12:15:21 +08001320 constexpr uint8_t slaveAddr = 0x38;
Yong Li068b4f22019-09-17 16:32:18 +08001321 std::string i2cBus = "/dev/i2c-4";
Yong Lieaeb6cb2020-03-09 20:21:50 +08001322 std::vector<uint8_t> writeData = {0x61, 0x1};
Yong Li068b4f22019-09-17 16:32:18 +08001323 std::vector<uint8_t> readBuf(0);
1324
Yong Li068b4f22019-09-17 16:32:18 +08001325 ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf);
1326 return ipmi::response(retI2C);
1327}
Vernon Mauery27d23562021-08-12 10:43:39 -07001328
1329ipmi::RspType<> setFITcLayout(uint32_t layout)
1330{
1331 static constexpr const char* factoryFITcLayout =
1332 "/var/sofs/factory-settings/layout/fitc";
1333 std::filesystem::path fitcDir =
1334 std::filesystem::path(factoryFITcLayout).parent_path();
1335 std::error_code ec;
1336 std::filesystem::create_directories(fitcDir, ec);
1337 if (ec)
1338 {
1339 return ipmi::responseUnspecifiedError();
1340 }
1341 try
1342 {
1343 std::ofstream file(factoryFITcLayout);
1344 file << layout;
1345 file.flush();
1346 file.close();
1347 }
1348 catch (const std::exception& e)
1349 {
1350 return ipmi::responseUnspecifiedError();
1351 }
1352
1353 return ipmi::responseSuccess();
1354}
1355
Arun P. Mohanan06584cd2021-08-13 20:56:01 +05301356static std::vector<std::string>
1357 getMCTPServiceConfigPaths(ipmi::Context::ptr& ctx)
1358{
1359 boost::system::error_code ec;
1360 auto configPaths = ctx->bus->yield_method_call<std::vector<std::string>>(
1361 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
1362 "/xyz/openbmc_project/object_mapper",
1363 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
1364 "/xyz/openbmc_project/inventory/system/board", 2,
1365 std::array<const char*, 1>{
1366 "xyz.openbmc_project.Configuration.MctpConfiguration"});
1367 if (ec)
1368 {
1369 throw std::runtime_error(
1370 "Failed to query configuration sub tree objects");
1371 }
1372 return configPaths;
1373}
1374
1375static ipmi::RspType<> startOrStopService(ipmi::Context::ptr& ctx,
1376 const uint8_t enable,
ANJALI RAY1fe485c2021-12-17 16:41:30 +00001377 const std::string& serviceName,
1378 bool disableOrEnableUnitFiles = true)
Arun P. Mohanan06584cd2021-08-13 20:56:01 +05301379{
1380 constexpr bool runtimeOnly = false;
1381 constexpr bool force = false;
1382
1383 boost::system::error_code ec;
1384 switch (enable)
1385 {
1386 case ipmi::SupportedFeatureActions::stop:
1387 ctx->bus->yield_method_call(ctx->yield, ec, systemDService,
1388 systemDObjPath, systemDMgrIntf,
1389 "StopUnit", serviceName, "replace");
1390 break;
1391 case ipmi::SupportedFeatureActions::start:
1392 ctx->bus->yield_method_call(ctx->yield, ec, systemDService,
1393 systemDObjPath, systemDMgrIntf,
1394 "StartUnit", serviceName, "replace");
1395 break;
1396 case ipmi::SupportedFeatureActions::disable:
ANJALI RAY1fe485c2021-12-17 16:41:30 +00001397 if (disableOrEnableUnitFiles == true)
1398 {
1399 ctx->bus->yield_method_call(
1400 ctx->yield, ec, systemDService, systemDObjPath,
1401 systemDMgrIntf, "DisableUnitFiles",
1402 std::array<const char*, 1>{serviceName.c_str()},
1403 runtimeOnly);
1404 }
Arun P. Mohanan06584cd2021-08-13 20:56:01 +05301405 ctx->bus->yield_method_call(
1406 ctx->yield, ec, systemDService, systemDObjPath, systemDMgrIntf,
1407 "MaskUnitFiles",
1408 std::array<const char*, 1>{serviceName.c_str()}, runtimeOnly,
1409 force);
Arun P. Mohanan06584cd2021-08-13 20:56:01 +05301410 break;
1411 case ipmi::SupportedFeatureActions::enable:
1412 ctx->bus->yield_method_call(
1413 ctx->yield, ec, systemDService, systemDObjPath, systemDMgrIntf,
1414 "UnmaskUnitFiles",
1415 std::array<const char*, 1>{serviceName.c_str()}, runtimeOnly);
ANJALI RAY1fe485c2021-12-17 16:41:30 +00001416 if (disableOrEnableUnitFiles == true)
1417 {
1418 ctx->bus->yield_method_call(
1419 ctx->yield, ec, systemDService, systemDObjPath,
1420 systemDMgrIntf, "EnableUnitFiles",
1421 std::array<const char*, 1>{serviceName.c_str()},
1422 runtimeOnly, force);
1423 }
Arun P. Mohanan06584cd2021-08-13 20:56:01 +05301424 break;
1425 default:
1426 phosphor::logging::log<phosphor::logging::level::WARNING>(
1427 "ERROR: Invalid feature action selected",
1428 phosphor::logging::entry("ACTION=%d", enable));
1429 return ipmi::responseInvalidFieldRequest();
1430 }
1431 if (ec)
1432 {
1433 phosphor::logging::log<phosphor::logging::level::WARNING>(
1434 "ERROR: Service start or stop failed",
1435 phosphor::logging::entry("SERVICE=%s", serviceName.c_str()));
1436 return ipmi::responseUnspecifiedError();
1437 }
1438 return ipmi::responseSuccess();
1439}
1440
1441static std::string getMCTPServiceName(const std::string& objectPath)
1442{
1443 const auto serviceArgument = boost::algorithm::replace_all_copy(
1444 boost::algorithm::replace_first_copy(
1445 objectPath, "/xyz/openbmc_project/inventory/system/board/", ""),
1446 "/", "_2f");
1447 std::string unitName =
1448 "xyz.openbmc_project.mctpd@" + serviceArgument + ".service";
1449 return unitName;
1450}
1451
1452static ipmi::RspType<> handleMCTPFeature(ipmi::Context::ptr& ctx,
1453 const uint8_t enable,
1454 const std::string& binding)
1455{
1456 std::vector<std::string> configPaths;
1457 try
1458 {
1459 configPaths = getMCTPServiceConfigPaths(ctx);
1460 }
1461 catch (const std::exception& e)
1462 {
1463 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1464 return ipmi::responseUnspecifiedError();
1465 }
1466
1467 for (const auto& objectPath : configPaths)
1468 {
1469 auto const pos = objectPath.find_last_of('/');
1470 if (binding == objectPath.substr(pos + 1))
1471 {
1472 return startOrStopService(ctx, enable,
ANJALI RAY1fe485c2021-12-17 16:41:30 +00001473 getMCTPServiceName(objectPath), false);
Arun P. Mohanan06584cd2021-08-13 20:56:01 +05301474 }
1475 }
1476 return ipmi::responseSuccess();
1477}
1478
1479/** @brief implements MTM BMC Feature Control IPMI command which can be
1480 * used to enable or disable the supported BMC features.
1481 * @param yield - context object that represents the currently executing
1482 * coroutine
1483 * @param feature - feature enum to enable or disable
1484 * @param enable - enable or disable the feature
1485 * @param featureArg - custom arguments for that feature
1486 * @param reserved - reserved for future use
1487 *
1488 * @returns IPMI completion code
1489 */
1490ipmi::RspType<> mtmBMCFeatureControl(ipmi::Context::ptr ctx,
1491 const uint8_t feature,
1492 const uint8_t enable,
1493 const uint8_t featureArg,
1494 const uint16_t reserved)
1495{
1496 if (reserved != 0)
1497 {
1498 return ipmi::responseInvalidFieldRequest();
1499 }
1500
1501 switch (feature)
1502 {
1503 case ipmi::SupportedFeatureControls::mctp:
1504 switch (featureArg)
1505 {
1506 case ipmi::SupportedMCTPBindings::mctpPCIe:
1507 return handleMCTPFeature(ctx, enable, "MCTP_PCIe");
1508 case ipmi::SupportedMCTPBindings::mctpSMBusHSBP:
1509 return handleMCTPFeature(ctx, enable, "MCTP_SMBus_HSBP");
1510 case ipmi::SupportedMCTPBindings::mctpSMBusPCIeSlot:
1511 return handleMCTPFeature(ctx, enable,
1512 "MCTP_SMBus_PCIe_slot");
1513 default:
1514 return ipmi::responseInvalidFieldRequest();
1515 }
1516 break;
Jason M. Bills5cb2c042021-08-17 12:03:39 -07001517 case ipmi::SupportedFeatureControls::pcieScan:
1518 if (featureArg != 0)
1519 {
1520 return ipmi::responseInvalidFieldRequest();
1521 }
1522 startOrStopService(ctx, enable, "xyz.openbmc_project.PCIe.service");
1523 break;
Arun P. Mohanan06584cd2021-08-13 20:56:01 +05301524 default:
1525 return ipmi::responseInvalidFieldRequest();
1526 }
1527 return ipmi::responseSuccess();
1528}
Vernon Mauerya3702c12019-05-22 13:20:59 -07001529} // namespace ipmi
1530
1531void register_mtm_commands() __attribute__((constructor));
1532void register_mtm_commands()
1533{
Jason M. Bills38d2b5a2019-06-03 16:26:11 -07001534 // <Get SM Signal>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001535 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
1536 ipmi::intel::general::cmdGetSmSignal,
1537 ipmi::Privilege::Admin, ipmi::appMTMGetSignal);
Vernon Mauerya3702c12019-05-22 13:20:59 -07001538
Vernon Mauery98bbf692019-09-16 11:14:59 -07001539 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
1540 ipmi::intel::general::cmdSetSmSignal,
1541 ipmi::Privilege::Admin, ipmi::appMTMSetSignal);
Vernon Mauerya3702c12019-05-22 13:20:59 -07001542
Vernon Mauery98bbf692019-09-16 11:14:59 -07001543 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
1544 ipmi::intel::general::cmdMtmKeepAlive,
1545 ipmi::Privilege::Admin, ipmi::mtmKeepAlive);
Richard Marian Thomaiyar666dd012019-08-02 20:55:37 +05301546
Vernon Mauery98bbf692019-09-16 11:14:59 -07001547 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
1548 ipmi::intel::general::cmdSetManufacturingData,
1549 ipmi::Privilege::Admin, ipmi::setManufacturingData);
Richard Marian Thomaiyar1f0839c2019-08-25 20:10:52 +05301550
Vernon Mauery98bbf692019-09-16 11:14:59 -07001551 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
1552 ipmi::intel::general::cmdGetManufacturingData,
1553 ipmi::Privilege::Admin, ipmi::getManufacturingData);
Richard Marian Thomaiyar1f0839c2019-08-25 20:10:52 +05301554
Vernon Mauery27d23562021-08-12 10:43:39 -07001555 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
1556 ipmi::intel::general::cmdSetFITcLayout,
1557 ipmi::Privilege::Admin, ipmi::setFITcLayout);
1558
Arun P. Mohanan06584cd2021-08-13 20:56:01 +05301559 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral,
1560 ipmi::intel::general::cmdMTMBMCFeatureControl,
1561 ipmi::Privilege::Admin, ipmi::mtmBMCFeatureControl);
1562
Vernon Mauery98bbf692019-09-16 11:14:59 -07001563 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp,
1564 ipmi::intel::general::cmdSlotI2CMasterWriteRead,
1565 ipmi::Privilege::Admin,
1566 ipmi::appSlotI2CMasterWriteRead);
Yong Lif267a672019-08-29 11:16:07 +08001567
Yong Li068b4f22019-09-17 16:32:18 +08001568 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnPlatform,
1569 ipmi::intel::platform::cmdClearCMOS,
1570 ipmi::Privilege::Admin, ipmi::clearCMOS);
1571
Vernon Mauery98bbf692019-09-16 11:14:59 -07001572 ipmi::registerFilter(ipmi::prioOemBase,
Yong Li85feb132019-08-09 16:06:03 +08001573 [](ipmi::message::Request::ptr request) {
1574 return ipmi::mfgFilterMessage(request);
1575 });
Vernon Mauerya3702c12019-05-22 13:20:59 -07001576}