1 /* 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 17 #include <boost/container/flat_map.hpp> 18 #include <filesystem> 19 #include <fstream> 20 #include <ipmid/api.hpp> 21 #include <manufacturingcommands.hpp> 22 #include <oemcommands.hpp> 23 24 namespace ipmi 25 { 26 27 Manufacturing mtm; 28 29 static auto revertTimeOut = 30 std::chrono::duration_cast<std::chrono::microseconds>( 31 std::chrono::seconds(60)); // 1 minute timeout 32 33 static constexpr uint8_t slotAddressTypeBus = 0; 34 static constexpr uint8_t slotAddressTypeUniqueid = 1; 35 static constexpr uint8_t slotI2CMaxReadSize = 35; 36 37 static constexpr const char* callbackMgrService = 38 "xyz.openbmc_project.CallbackManager"; 39 static constexpr const char* callbackMgrIntf = 40 "xyz.openbmc_project.CallbackManager"; 41 static constexpr const char* callbackMgrObjPath = 42 "/xyz/openbmc_project/CallbackManager"; 43 static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate"; 44 45 const static constexpr char* systemDService = "org.freedesktop.systemd1"; 46 const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1"; 47 const static constexpr char* systemDMgrIntf = 48 "org.freedesktop.systemd1.Manager"; 49 const static constexpr char* pidControlService = "phosphor-pid-control.service"; 50 51 static inline Cc resetMtmTimer(boost::asio::yield_context yield) 52 { 53 auto sdbusp = getSdBus(); 54 boost::system::error_code ec; 55 sdbusp->yield_method_call<>(yield, ec, specialModeService, 56 specialModeObjPath, specialModeIntf, 57 "ResetTimer"); 58 if (ec) 59 { 60 phosphor::logging::log<phosphor::logging::level::ERR>( 61 "Failed to reset the manufacturing mode timer"); 62 return ccUnspecifiedError; 63 } 64 return ccSuccess; 65 } 66 67 int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path) 68 { 69 switch (signal) 70 { 71 case SmSignalGet::smPowerButton: 72 path = "/xyz/openbmc_project/chassis/buttons/power"; 73 break; 74 case SmSignalGet::smResetButton: 75 path = "/xyz/openbmc_project/chassis/buttons/reset"; 76 break; 77 case SmSignalGet::smNMIButton: 78 path = "/xyz/openbmc_project/chassis/buttons/nmi"; 79 break; 80 case SmSignalGet::smIdentifyButton: 81 path = "/xyz/openbmc_project/chassis/buttons/id"; 82 break; 83 default: 84 return -1; 85 break; 86 } 87 return 0; 88 } 89 90 ipmi_ret_t ledStoreAndSet(SmSignalSet signal, std::string setState) 91 { 92 LedProperty* ledProp = mtm.findLedProperty(signal); 93 if (ledProp == nullptr) 94 { 95 return IPMI_CC_INVALID_FIELD_REQUEST; 96 } 97 98 std::string ledName = ledProp->getName(); 99 std::string ledService = ledServicePrefix + ledName; 100 std::string ledPath = ledPathPrefix + ledName; 101 ipmi::Value presentState; 102 103 if (false == ledProp->getLock()) 104 { 105 if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf, 106 "State", &presentState) != 0) 107 { 108 return IPMI_CC_UNSPECIFIED_ERROR; 109 } 110 ledProp->setPrevState(std::get<std::string>(presentState)); 111 ledProp->setLock(true); 112 if (signal == SmSignalSet::smPowerFaultLed || 113 signal == SmSignalSet::smSystemReadyLed) 114 { 115 mtm.revertLedCallback = true; 116 } 117 } 118 if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 119 ledStateStr + setState) != 0) 120 { 121 return IPMI_CC_UNSPECIFIED_ERROR; 122 } 123 return IPMI_CC_OK; 124 } 125 126 ipmi_ret_t ledRevert(SmSignalSet signal) 127 { 128 LedProperty* ledProp = mtm.findLedProperty(signal); 129 if (ledProp == nullptr) 130 { 131 return IPMI_CC_INVALID_FIELD_REQUEST; 132 } 133 if (true == ledProp->getLock()) 134 { 135 ledProp->setLock(false); 136 if (signal == SmSignalSet::smPowerFaultLed || 137 signal == SmSignalSet::smSystemReadyLed) 138 { 139 try 140 { 141 ipmi::method_no_args::callDbusMethod( 142 *getSdBus(), callbackMgrService, callbackMgrObjPath, 143 callbackMgrIntf, retriggerLedUpdate); 144 } 145 catch (sdbusplus::exception_t& e) 146 { 147 return IPMI_CC_UNSPECIFIED_ERROR; 148 } 149 mtm.revertLedCallback = false; 150 } 151 else 152 { 153 std::string ledName = ledProp->getName(); 154 std::string ledService = ledServicePrefix + ledName; 155 std::string ledPath = ledPathPrefix + ledName; 156 if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 157 ledProp->getPrevState()) != 0) 158 { 159 return IPMI_CC_UNSPECIFIED_ERROR; 160 } 161 } 162 } 163 return IPMI_CC_OK; 164 } 165 166 void Manufacturing::initData() 167 { 168 ledPropertyList.push_back( 169 LedProperty(SmSignalSet::smPowerFaultLed, "status_amber")); 170 ledPropertyList.push_back( 171 LedProperty(SmSignalSet::smSystemReadyLed, "status_green")); 172 ledPropertyList.push_back( 173 LedProperty(SmSignalSet::smIdentifyLed, "identify")); 174 } 175 176 void Manufacturing::revertTimerHandler() 177 { 178 if (revertFanPWM) 179 { 180 revertFanPWM = false; 181 disablePidControlService(false); 182 } 183 184 for (const auto& ledProperty : ledPropertyList) 185 { 186 const std::string& ledName = ledProperty.getName(); 187 ledRevert(ledProperty.getSignal()); 188 } 189 } 190 191 Manufacturing::Manufacturing() : 192 revertTimer([&](void) { revertTimerHandler(); }) 193 { 194 initData(); 195 } 196 197 int8_t Manufacturing::getProperty(const std::string& service, 198 const std::string& path, 199 const std::string& interface, 200 const std::string& propertyName, 201 ipmi::Value* reply) 202 { 203 try 204 { 205 *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface, 206 propertyName); 207 } 208 catch (const sdbusplus::exception::SdBusError& e) 209 { 210 phosphor::logging::log<phosphor::logging::level::INFO>( 211 "ERROR: getProperty"); 212 return -1; 213 } 214 215 return 0; 216 } 217 218 int8_t Manufacturing::setProperty(const std::string& service, 219 const std::string& path, 220 const std::string& interface, 221 const std::string& propertyName, 222 ipmi::Value value) 223 { 224 try 225 { 226 ipmi::setDbusProperty(*getSdBus(), service, path, interface, 227 propertyName, value); 228 } 229 catch (const sdbusplus::exception::SdBusError& e) 230 { 231 phosphor::logging::log<phosphor::logging::level::INFO>( 232 "ERROR: setProperty"); 233 return -1; 234 } 235 236 return 0; 237 } 238 239 int8_t Manufacturing::disablePidControlService(const bool disable) 240 { 241 try 242 { 243 auto dbus = getSdBus(); 244 auto method = dbus->new_method_call(systemDService, systemDObjPath, 245 systemDMgrIntf, 246 disable ? "StopUnit" : "StartUnit"); 247 method.append(pidControlService, "replace"); 248 auto reply = dbus->call(method); 249 } 250 catch (const sdbusplus::exception::SdBusError& e) 251 { 252 phosphor::logging::log<phosphor::logging::level::INFO>( 253 "ERROR: phosphor-pid-control service start or stop failed"); 254 return -1; 255 } 256 return 0; 257 } 258 259 ipmi::RspType<uint8_t, // Signal value 260 std::optional<uint16_t> // Fan tach value 261 > 262 appMTMGetSignal(boost::asio::yield_context yield, uint8_t signalTypeByte, 263 uint8_t instance, uint8_t actionByte) 264 { 265 if (mtm.getAccessLvl() < MtmLvl::mtmAvailable) 266 { 267 return ipmi::responseInvalidCommand(); 268 } 269 270 SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte); 271 SmActionGet action = static_cast<SmActionGet>(actionByte); 272 273 switch (signalType) 274 { 275 case SmSignalGet::smFanPwmGet: 276 { 277 ipmi::Value reply; 278 std::string fullPath = fanPwmPath + std::to_string(instance + 1); 279 if (mtm.getProperty(fanService, fullPath, fanIntf, "Value", 280 &reply) < 0) 281 { 282 return ipmi::responseInvalidFieldRequest(); 283 } 284 double* doubleVal = std::get_if<double>(&reply); 285 if (doubleVal == nullptr) 286 { 287 return ipmi::responseUnspecifiedError(); 288 } 289 uint8_t sensorVal = std::round(*doubleVal); 290 resetMtmTimer(yield); 291 return ipmi::responseSuccess(sensorVal, std::nullopt); 292 } 293 break; 294 case SmSignalGet::smFanTachometerGet: 295 { 296 auto sdbusp = getSdBus(); 297 boost::system::error_code ec; 298 using objFlatMap = boost::container::flat_map< 299 std::string, boost::container::flat_map< 300 std::string, std::vector<std::string>>>; 301 302 auto flatMap = sdbusp->yield_method_call<objFlatMap>( 303 yield, ec, "xyz.openbmc_project.ObjectMapper", 304 "/xyz/openbmc_project/object_mapper", 305 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 306 fanTachBasePath, 0, std::array<const char*, 1>{fanIntf}); 307 if (ec) 308 { 309 phosphor::logging::log<phosphor::logging::level::ERR>( 310 "Failed to query fan tach sub tree objects"); 311 return ipmi::responseUnspecifiedError(); 312 } 313 if (instance >= flatMap.size()) 314 { 315 return ipmi::responseInvalidFieldRequest(); 316 } 317 auto itr = flatMap.nth(instance); 318 ipmi::Value reply; 319 if (mtm.getProperty(fanService, itr->first, fanIntf, "Value", 320 &reply) < 0) 321 { 322 return ipmi::responseInvalidFieldRequest(); 323 } 324 325 double* doubleVal = std::get_if<double>(&reply); 326 if (doubleVal == nullptr) 327 { 328 return ipmi::responseUnspecifiedError(); 329 } 330 uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT; 331 std::optional<uint16_t> fanTach = std::round(*doubleVal); 332 333 resetMtmTimer(yield); 334 return ipmi::responseSuccess(sensorVal, fanTach); 335 } 336 break; 337 case SmSignalGet::smIdentifyButton: 338 { 339 if (action == SmActionGet::revert || action == SmActionGet::ignore) 340 { 341 // ButtonMasked property is not supported for ID button as it is 342 // unnecessary. Hence if requested for revert / ignore, override 343 // it to sample action to make tools happy. 344 action = SmActionGet::sample; 345 } 346 // fall-through 347 } 348 case SmSignalGet::smResetButton: 349 case SmSignalGet::smPowerButton: 350 case SmSignalGet::smNMIButton: 351 { 352 std::string path; 353 if (getGpioPathForSmSignal(signalType, path) < 0) 354 { 355 return ipmi::responseInvalidFieldRequest(); 356 } 357 358 switch (action) 359 { 360 case SmActionGet::sample: 361 phosphor::logging::log<phosphor::logging::level::INFO>( 362 "case SmActionGet::sample"); 363 break; 364 case SmActionGet::ignore: 365 { 366 phosphor::logging::log<phosphor::logging::level::INFO>( 367 "case SmActionGet::ignore"); 368 if (mtm.setProperty(buttonService, path, buttonIntf, 369 "ButtonMasked", true) < 0) 370 { 371 return ipmi::responseUnspecifiedError(); 372 } 373 } 374 break; 375 case SmActionGet::revert: 376 { 377 phosphor::logging::log<phosphor::logging::level::INFO>( 378 "case SmActionGet::revert"); 379 if (mtm.setProperty(buttonService, path, buttonIntf, 380 "ButtonMasked", false) < 0) 381 { 382 return ipmi::responseUnspecifiedError(); 383 } 384 } 385 break; 386 387 default: 388 return ipmi::responseInvalidFieldRequest(); 389 break; 390 } 391 392 ipmi::Value reply; 393 if (mtm.getProperty(buttonService, path, buttonIntf, 394 "ButtonPressed", &reply) < 0) 395 { 396 return ipmi::responseUnspecifiedError(); 397 } 398 bool* valPtr = std::get_if<bool>(&reply); 399 if (valPtr == nullptr) 400 { 401 return ipmi::responseUnspecifiedError(); 402 } 403 resetMtmTimer(yield); 404 uint8_t sensorVal = *valPtr; 405 return ipmi::responseSuccess(sensorVal, std::nullopt); 406 } 407 break; 408 case SmSignalGet::smNcsiDiag: 409 { 410 constexpr const char* netBasePath = "/sys/class/net/eth"; 411 constexpr const char* carrierSuffix = "/carrier"; 412 std::ifstream netIfs(netBasePath + std::to_string(instance) + 413 carrierSuffix); 414 if (!netIfs.good()) 415 { 416 return ipmi::responseInvalidFieldRequest(); 417 } 418 std::string carrier; 419 netIfs >> carrier; 420 resetMtmTimer(yield); 421 return ipmi::responseSuccess( 422 static_cast<uint8_t>(std::stoi(carrier)), std::nullopt); 423 } 424 break; 425 default: 426 return ipmi::responseInvalidFieldRequest(); 427 break; 428 } 429 } 430 431 ipmi::RspType<> appMTMSetSignal(boost::asio::yield_context yield, 432 uint8_t signalTypeByte, uint8_t instance, 433 uint8_t actionByte, 434 std::optional<uint8_t> pwmSpeed) 435 { 436 if (mtm.getAccessLvl() < MtmLvl::mtmAvailable) 437 { 438 return ipmi::responseInvalidCommand(); 439 } 440 441 SmSignalSet signalType = static_cast<SmSignalSet>(signalTypeByte); 442 SmActionSet action = static_cast<SmActionSet>(actionByte); 443 Cc retCode = ccSuccess; 444 int8_t ret = 0; 445 446 switch (signalType) 447 { 448 case SmSignalSet::smPowerFaultLed: 449 case SmSignalSet::smSystemReadyLed: 450 case SmSignalSet::smIdentifyLed: 451 switch (action) 452 { 453 case SmActionSet::forceDeasserted: 454 { 455 phosphor::logging::log<phosphor::logging::level::INFO>( 456 "case SmActionSet::forceDeasserted"); 457 458 retCode = ledStoreAndSet(signalType, std::string("Off")); 459 if (retCode != ccSuccess) 460 { 461 return ipmi::response(retCode); 462 } 463 mtm.revertTimer.start(revertTimeOut); 464 } 465 break; 466 case SmActionSet::forceAsserted: 467 { 468 phosphor::logging::log<phosphor::logging::level::INFO>( 469 "case SmActionSet::forceAsserted"); 470 471 retCode = ledStoreAndSet(signalType, std::string("On")); 472 if (retCode != ccSuccess) 473 { 474 return ipmi::response(retCode); 475 } 476 mtm.revertTimer.start(revertTimeOut); 477 if (SmSignalSet::smPowerFaultLed == signalType) 478 { 479 // Deassert "system ready" 480 retCode = ledStoreAndSet(SmSignalSet::smSystemReadyLed, 481 std::string("Off")); 482 } 483 else if (SmSignalSet::smSystemReadyLed == signalType) 484 { 485 // Deassert "fault led" 486 retCode = ledStoreAndSet(SmSignalSet::smPowerFaultLed, 487 std::string("Off")); 488 } 489 } 490 break; 491 case SmActionSet::revert: 492 { 493 phosphor::logging::log<phosphor::logging::level::INFO>( 494 "case SmActionSet::revert"); 495 retCode = ledRevert(signalType); 496 } 497 break; 498 default: 499 { 500 return ipmi::responseInvalidFieldRequest(); 501 } 502 } 503 break; 504 case SmSignalSet::smFanPowerSpeed: 505 { 506 if ((action == SmActionSet::forceAsserted) && (!pwmSpeed)) 507 { 508 return ipmi::responseReqDataLenInvalid(); 509 } 510 511 if ((action == SmActionSet::forceAsserted) && (*pwmSpeed > 100)) 512 { 513 return ipmi::responseInvalidFieldRequest(); 514 } 515 516 uint8_t pwmValue = 0; 517 switch (action) 518 { 519 case SmActionSet::revert: 520 { 521 if (mtm.revertFanPWM) 522 { 523 ret = mtm.disablePidControlService(false); 524 if (ret < 0) 525 { 526 return ipmi::responseUnspecifiedError(); 527 } 528 mtm.revertFanPWM = false; 529 } 530 } 531 break; 532 case SmActionSet::forceAsserted: 533 { 534 pwmValue = *pwmSpeed; 535 } // fall-through 536 case SmActionSet::forceDeasserted: 537 { 538 if (!mtm.revertFanPWM) 539 { 540 ret = mtm.disablePidControlService(true); 541 if (ret < 0) 542 { 543 return ipmi::responseUnspecifiedError(); 544 } 545 mtm.revertFanPWM = true; 546 } 547 mtm.revertTimer.start(revertTimeOut); 548 std::string fanPwmInstancePath = 549 fanPwmPath + std::to_string(instance + 1); 550 551 ret = 552 mtm.setProperty(fanService, fanPwmInstancePath, fanIntf, 553 "Value", static_cast<double>(pwmValue)); 554 if (ret < 0) 555 { 556 return ipmi::responseUnspecifiedError(); 557 } 558 } 559 break; 560 default: 561 { 562 return ipmi::responseInvalidFieldRequest(); 563 } 564 } 565 } 566 break; 567 default: 568 { 569 return ipmi::responseInvalidFieldRequest(); 570 } 571 } 572 if (retCode == ccSuccess) 573 { 574 resetMtmTimer(yield); 575 } 576 return ipmi::response(retCode); 577 } 578 579 ipmi::RspType<> mtmKeepAlive(boost::asio::yield_context yield, uint8_t reserved, 580 const std::array<char, 5>& intentionalSignature) 581 { 582 // Allow MTM keep alive command only in manfacturing mode. 583 if (mtm.getAccessLvl() != MtmLvl::mtmAvailable) 584 { 585 return ipmi::responseInvalidCommand(); 586 } 587 constexpr std::array<char, 5> signatureOk = {'I', 'N', 'T', 'E', 'L'}; 588 if (intentionalSignature != signatureOk || reserved != 0) 589 { 590 return ipmi::responseInvalidFieldRequest(); 591 } 592 return ipmi::response(resetMtmTimer(yield)); 593 } 594 595 ipmi::Cc mfgFilterMessage(ipmi::message::Request::ptr request) 596 { 597 // i2c master write read command needs additional checking 598 if ((request->ctx->netFn == ipmi::netFnApp) && 599 (request->ctx->cmd == ipmi::app::cmdMasterWriteRead)) 600 { 601 if (request->payload.size() > 4) 602 { 603 // Allow write data count > 1, only if it is in MFG mode 604 if (mtm.getAccessLvl() != MtmLvl::mtmAvailable) 605 { 606 return ipmi::ccInsufficientPrivilege; 607 } 608 } 609 } 610 611 return ipmi::ccSuccess; 612 } 613 614 static constexpr uint8_t maxEthSize = 6; 615 static constexpr uint8_t maxSupportedEth = 3; 616 static constexpr const char* factoryEthAddrBaseFileName = 617 "/var/sofs/factory-settings/network/mac/eth"; 618 619 ipmi::RspType<> setManufacturingData(boost::asio::yield_context yield, 620 uint8_t dataType, 621 std::array<uint8_t, maxEthSize> ethData) 622 { 623 // mfg filter logic will restrict this command executing only in mfg mode. 624 if (dataType >= maxSupportedEth) 625 { 626 return ipmi::responseParmOutOfRange(); 627 } 628 629 constexpr uint8_t invalidData = 0; 630 constexpr uint8_t validData = 1; 631 constexpr uint8_t ethAddrStrSize = 632 19; // XX:XX:XX:XX:XX:XX + \n + null termination; 633 std::vector<uint8_t> buff(ethAddrStrSize); 634 std::snprintf(reinterpret_cast<char*>(buff.data()), ethAddrStrSize, 635 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", ethData.at(0), 636 ethData.at(1), ethData.at(2), ethData.at(3), ethData.at(4), 637 ethData.at(5)); 638 std::ofstream oEthFile(factoryEthAddrBaseFileName + 639 std::to_string(dataType), 640 std::ofstream::out); 641 if (!oEthFile.good()) 642 { 643 return ipmi::responseUnspecifiedError(); 644 } 645 646 oEthFile << reinterpret_cast<char*>(buff.data()); 647 oEthFile << fflush; 648 oEthFile.close(); 649 650 resetMtmTimer(yield); 651 return ipmi::responseSuccess(); 652 } 653 654 ipmi::RspType<uint8_t, std::array<uint8_t, maxEthSize>> 655 getManufacturingData(boost::asio::yield_context yield, uint8_t dataType) 656 { 657 // mfg filter logic will restrict this command executing only in mfg mode. 658 if (dataType >= maxSupportedEth) 659 { 660 return ipmi::responseParmOutOfRange(); 661 } 662 std::array<uint8_t, maxEthSize> ethData{0}; 663 constexpr uint8_t invalidData = 0; 664 constexpr uint8_t validData = 1; 665 666 std::ifstream iEthFile(factoryEthAddrBaseFileName + 667 std::to_string(dataType), 668 std::ifstream::in); 669 if (!iEthFile.good()) 670 { 671 return ipmi::responseSuccess(invalidData, ethData); 672 } 673 std::string ethStr; 674 iEthFile >> ethStr; 675 uint8_t* data = ethData.data(); 676 std::sscanf(ethStr.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 677 data, (data + 1), (data + 2), (data + 3), (data + 4), 678 (data + 5)); 679 680 resetMtmTimer(yield); 681 return ipmi::responseSuccess(validData, ethData); 682 } 683 684 /** @brief implements slot master write read IPMI command which can be used for 685 * low-level I2C/SMBus write, read or write-read access for PCIE slots 686 * @param reserved - skip 6 bit 687 * @param addressType - address type 688 * @param bbSlotNum - baseboard slot number 689 * @param riserSlotNum - riser slot number 690 * @param reserved2 - skip 2 bit 691 * @param slaveAddr - slave address 692 * @param readCount - number of bytes to be read 693 * @param writeData - data to be written 694 * 695 * @returns IPMI completion code plus response data 696 */ 697 ipmi::RspType<std::vector<uint8_t>> 698 appSlotI2CMasterWriteRead(uint6_t reserved, uint2_t addressType, 699 uint3_t bbSlotNum, uint3_t riserSlotNum, 700 uint2_t resvered2, uint8_t slaveAddr, 701 uint8_t readCount, std::vector<uint8_t> writeData) 702 { 703 const size_t writeCount = writeData.size(); 704 std::string i2cBus; 705 if (addressType == slotAddressTypeBus) 706 { 707 std::string path = "/dev/i2c-mux/Riser_" + 708 std::to_string(static_cast<uint8_t>(bbSlotNum)) + 709 "_Mux/Pcie_Slot_" + 710 std::to_string(static_cast<uint8_t>(riserSlotNum)); 711 712 if (std::filesystem::exists(path) && std::filesystem::is_symlink(path)) 713 { 714 i2cBus = std::filesystem::read_symlink(path); 715 } 716 else 717 { 718 phosphor::logging::log<phosphor::logging::level::ERR>( 719 "Master write read command: Cannot get BusID"); 720 return ipmi::responseInvalidFieldRequest(); 721 } 722 } 723 else if (addressType == slotAddressTypeUniqueid) 724 { 725 i2cBus = "/dev/i2c-" + 726 std::to_string(static_cast<uint8_t>(bbSlotNum) | 727 (static_cast<uint8_t>(riserSlotNum) << 3)); 728 } 729 else 730 { 731 phosphor::logging::log<phosphor::logging::level::ERR>( 732 "Master write read command: invalid request"); 733 return ipmi::responseInvalidFieldRequest(); 734 } 735 736 // Allow single byte write as it is offset byte to read the data, rest allow 737 // only in MFG mode. 738 if (writeCount > 1) 739 { 740 if (mtm.getAccessLvl() < MtmLvl::mtmAvailable) 741 { 742 return ipmi::responseInsufficientPrivilege(); 743 } 744 } 745 746 if (readCount > slotI2CMaxReadSize) 747 { 748 phosphor::logging::log<phosphor::logging::level::ERR>( 749 "Master write read command: Read count exceeds limit"); 750 return ipmi::responseParmOutOfRange(); 751 } 752 753 if (!readCount && !writeCount) 754 { 755 phosphor::logging::log<phosphor::logging::level::ERR>( 756 "Master write read command: Read & write count are 0"); 757 return ipmi::responseInvalidFieldRequest(); 758 } 759 760 std::vector<uint8_t> readBuf(readCount); 761 762 ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf); 763 if (retI2C != ipmi::ccSuccess) 764 { 765 return ipmi::response(retI2C); 766 } 767 768 return ipmi::responseSuccess(readBuf); 769 } 770 } // namespace ipmi 771 772 void register_mtm_commands() __attribute__((constructor)); 773 void register_mtm_commands() 774 { 775 // <Get SM Signal> 776 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 777 ipmi::intel::general::cmdGetSmSignal, 778 ipmi::Privilege::Admin, ipmi::appMTMGetSignal); 779 780 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 781 ipmi::intel::general::cmdSetSmSignal, 782 ipmi::Privilege::Admin, ipmi::appMTMSetSignal); 783 784 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 785 ipmi::intel::general::cmdMtmKeepAlive, 786 ipmi::Privilege::Admin, ipmi::mtmKeepAlive); 787 788 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 789 ipmi::intel::general::cmdSetManufacturingData, 790 ipmi::Privilege::Admin, ipmi::setManufacturingData); 791 792 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 793 ipmi::intel::general::cmdGetManufacturingData, 794 ipmi::Privilege::Admin, ipmi::getManufacturingData); 795 796 ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 797 ipmi::intel::general::cmdSlotI2CMasterWriteRead, 798 ipmi::Privilege::Admin, 799 ipmi::appSlotI2CMasterWriteRead); 800 801 ipmi::registerFilter(ipmi::prioOemBase, 802 [](ipmi::message::Request::ptr request) { 803 return ipmi::mfgFilterMessage(request); 804 }); 805 } 806