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 "types.hpp" 18 #include "xyz/openbmc_project/Common/error.hpp" 19 #include "xyz/openbmc_project/Led/Physical/server.hpp" 20 21 #include <openssl/crypto.h> 22 #include <systemd/sd-journal.h> 23 24 #include <appcommands.hpp> 25 #include <boost/container/flat_map.hpp> 26 #include <boost/process/child.hpp> 27 #include <boost/process/io.hpp> 28 #include <com/intel/Control/OCOTShutdownPolicy/server.hpp> 29 #include <commandutils.hpp> 30 #include <gpiod.hpp> 31 #include <ipmid/api.hpp> 32 #include <ipmid/utils.hpp> 33 #include <nlohmann/json.hpp> 34 #include <oemcommands.hpp> 35 #include <phosphor-logging/log.hpp> 36 #include <sdbusplus/bus.hpp> 37 #include <sdbusplus/message/types.hpp> 38 #include <xyz/openbmc_project/Chassis/Control/NMISource/server.hpp> 39 #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp> 40 #include <xyz/openbmc_project/Control/Boot/Source/server.hpp> 41 #include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp> 42 #include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp> 43 #include <xyz/openbmc_project/Control/Security/SpecialMode/server.hpp> 44 45 #include <array> 46 #include <filesystem> 47 #include <iostream> 48 #include <regex> 49 #include <string> 50 #include <variant> 51 #include <vector> 52 53 namespace ipmi 54 { 55 static void registerOEMFunctions() __attribute__((constructor)); 56 57 static constexpr size_t maxFRUStringLength = 0x3F; 58 59 static constexpr auto ethernetIntf = 60 "xyz.openbmc_project.Network.EthernetInterface"; 61 static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP"; 62 static constexpr auto networkService = "xyz.openbmc_project.Network"; 63 static constexpr auto networkRoot = "/xyz/openbmc_project/network"; 64 65 static constexpr const char* oemNmiSourceIntf = 66 "xyz.openbmc_project.Chassis.Control.NMISource"; 67 static constexpr const char* oemNmiSourceObjPath = 68 "/xyz/openbmc_project/Chassis/Control/NMISource"; 69 static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource"; 70 static constexpr const char* oemNmiEnabledObjPathProp = "Enabled"; 71 72 static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json"; 73 static constexpr const char* multiNodeObjPath = 74 "/xyz/openbmc_project/MultiNode/Status"; 75 static constexpr const char* multiNodeIntf = 76 "xyz.openbmc_project.Chassis.MultiNode"; 77 78 enum class NmiSource : uint8_t 79 { 80 none = 0, 81 frontPanelButton = 1, 82 watchdog = 2, 83 chassisCmd = 3, 84 memoryError = 4, 85 pciBusError = 5, 86 pch = 6, 87 chipset = 7, 88 }; 89 90 enum class SpecialUserIndex : uint8_t 91 { 92 rootUser = 0, 93 atScaleDebugUser = 1 94 }; 95 96 static constexpr const char* restricionModeService = 97 "xyz.openbmc_project.RestrictionMode.Manager"; 98 static constexpr const char* restricionModeBasePath = 99 "/xyz/openbmc_project/control/security/restriction_mode"; 100 static constexpr const char* restricionModeIntf = 101 "xyz.openbmc_project.Control.Security.RestrictionMode"; 102 static constexpr const char* restricionModeProperty = "RestrictionMode"; 103 104 static constexpr const char* specialModeService = 105 "xyz.openbmc_project.SpecialMode"; 106 static constexpr const char* specialModeBasePath = 107 "/xyz/openbmc_project/security/special_mode"; 108 static constexpr const char* specialModeIntf = 109 "xyz.openbmc_project.Security.SpecialMode"; 110 static constexpr const char* specialModeProperty = "SpecialMode"; 111 112 static constexpr const char* dBusPropertyIntf = 113 "org.freedesktop.DBus.Properties"; 114 static constexpr const char* dBusPropertyGetMethod = "Get"; 115 static constexpr const char* dBusPropertySetMethod = "Set"; 116 117 // return code: 0 successful 118 int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial) 119 { 120 std::string objpath = "/xyz/openbmc_project/FruDevice"; 121 std::string intf = "xyz.openbmc_project.FruDeviceManager"; 122 std::string service = getService(bus, intf, objpath); 123 ObjectValueTree valueTree = getManagedObjects(bus, service, "/"); 124 if (valueTree.empty()) 125 { 126 phosphor::logging::log<phosphor::logging::level::ERR>( 127 "No object implements interface", 128 phosphor::logging::entry("INTF=%s", intf.c_str())); 129 return -1; 130 } 131 132 for (const auto& item : valueTree) 133 { 134 auto interface = item.second.find("xyz.openbmc_project.FruDevice"); 135 if (interface == item.second.end()) 136 { 137 continue; 138 } 139 140 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER"); 141 if (property == interface->second.end()) 142 { 143 continue; 144 } 145 146 try 147 { 148 Value variant = property->second; 149 std::string& result = std::get<std::string>(variant); 150 if (result.size() > maxFRUStringLength) 151 { 152 phosphor::logging::log<phosphor::logging::level::ERR>( 153 "FRU serial number exceed maximum length"); 154 return -1; 155 } 156 serial = result; 157 return 0; 158 } 159 catch (std::bad_variant_access& e) 160 { 161 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 162 return -1; 163 } 164 } 165 return -1; 166 } 167 168 // Returns the Chassis Identifier (serial #) 169 ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 170 ipmi_request_t request, 171 ipmi_response_t response, 172 ipmi_data_len_t dataLen, 173 ipmi_context_t context) 174 { 175 std::string serial; 176 if (*dataLen != 0) // invalid request if there are extra parameters 177 { 178 *dataLen = 0; 179 return IPMI_CC_REQ_DATA_LEN_INVALID; 180 } 181 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 182 if (getChassisSerialNumber(*dbus, serial) == 0) 183 { 184 *dataLen = serial.size(); // length will never exceed response length 185 // as it is checked in getChassisSerialNumber 186 char* resp = static_cast<char*>(response); 187 serial.copy(resp, *dataLen); 188 return IPMI_CC_OK; 189 } 190 *dataLen = 0; 191 return IPMI_CC_RESPONSE_ERROR; 192 } 193 194 ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 195 ipmi_request_t request, 196 ipmi_response_t response, 197 ipmi_data_len_t dataLen, ipmi_context_t context) 198 { 199 static constexpr size_t safeBufferLength = 50; 200 char buf[safeBufferLength] = {0}; 201 GUIDData* Data = reinterpret_cast<GUIDData*>(request); 202 203 if (*dataLen != sizeof(GUIDData)) // 16bytes 204 { 205 *dataLen = 0; 206 return IPMI_CC_REQ_DATA_LEN_INVALID; 207 } 208 209 *dataLen = 0; 210 211 snprintf( 212 buf, safeBufferLength, 213 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", 214 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1, 215 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1, 216 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4, 217 Data->node3, Data->node2, Data->node1); 218 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 219 std::string guid = buf; 220 221 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID"; 222 std::string intf = "xyz.openbmc_project.Common.UUID"; 223 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 224 std::string service = getService(*dbus, intf, objpath); 225 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid); 226 return IPMI_CC_OK; 227 } 228 229 ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI, 230 uint7_t reserved1) 231 { 232 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 233 234 try 235 { 236 auto service = 237 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath); 238 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath, 239 bmcResetDisablesIntf, "ResetOnSMI", 240 !disableResetOnSMI); 241 } 242 catch (std::exception& e) 243 { 244 phosphor::logging::log<phosphor::logging::level::ERR>( 245 "Failed to set BMC reset disables", 246 phosphor::logging::entry("EXCEPTION=%s", e.what())); 247 return ipmi::responseUnspecifiedError(); 248 } 249 250 return ipmi::responseSuccess(); 251 } 252 253 ipmi::RspType<bool, // disableResetOnSMI 254 uint7_t // reserved 255 > 256 ipmiOEMGetBMCResetDisables() 257 { 258 bool disableResetOnSMI = true; 259 260 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 261 try 262 { 263 auto service = 264 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath); 265 Value variant = 266 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath, 267 bmcResetDisablesIntf, "ResetOnSMI"); 268 disableResetOnSMI = !std::get<bool>(variant); 269 } 270 catch (std::exception& e) 271 { 272 phosphor::logging::log<phosphor::logging::level::ERR>( 273 "Failed to get BMC reset disables", 274 phosphor::logging::entry("EXCEPTION=%s", e.what())); 275 return ipmi::responseUnspecifiedError(); 276 } 277 278 return ipmi::responseSuccess(disableResetOnSMI, 0); 279 } 280 281 ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 282 ipmi_request_t request, ipmi_response_t response, 283 ipmi_data_len_t dataLen, ipmi_context_t context) 284 { 285 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request); 286 287 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength))) 288 { 289 *dataLen = 0; 290 return IPMI_CC_REQ_DATA_LEN_INVALID; 291 } 292 std::string idString((char*)data->biosId, data->biosIDLength); 293 for (auto idChar : idString) 294 { 295 if (!std::isprint(static_cast<unsigned char>(idChar))) 296 { 297 phosphor::logging::log<phosphor::logging::level::ERR>( 298 "BIOS ID contains non printable character"); 299 return IPMI_CC_INVALID_FIELD_REQUEST; 300 } 301 } 302 303 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 304 std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath); 305 setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf, 306 biosVersionProp, idString); 307 uint8_t* bytesWritten = static_cast<uint8_t*>(response); 308 *bytesWritten = 309 data->biosIDLength; // how many bytes are written into storage 310 *dataLen = 1; 311 return IPMI_CC_OK; 312 } 313 314 bool getSwVerInfo(ipmi::Context::ptr ctx, uint8_t& bmcMajor, uint8_t& bmcMinor, 315 uint8_t& meMajor, uint8_t& meMinor) 316 { 317 // step 1 : get BMC Major and Minor numbers from its DBUS property 318 std::string bmcVersion; 319 if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion)) 320 { 321 return false; 322 } 323 324 std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion); 325 if (rev.has_value()) 326 { 327 MetaRevision revision = rev.value(); 328 bmcMajor = revision.major; 329 330 revision.minor = (revision.minor > 99 ? 99 : revision.minor); 331 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16; 332 } 333 334 // step 2 : get ME Major and Minor numbers from its DBUS property 335 std::string meVersion; 336 if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion)) 337 { 338 return false; 339 } 340 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)"); 341 constexpr size_t matchedPhosphor = 6; 342 std::smatch results; 343 if (std::regex_match(meVersion, results, pattern1)) 344 { 345 if (results.size() == matchedPhosphor) 346 { 347 meMajor = static_cast<uint8_t>(std::stoi(results[1])); 348 meMinor = static_cast<uint8_t>(std::stoi(results[2])); 349 } 350 } 351 return true; 352 } 353 354 ipmi::RspType< 355 std::variant<std::string, 356 std::tuple<uint8_t, std::array<uint8_t, 2>, 357 std::array<uint8_t, 2>, std::array<uint8_t, 2>, 358 std::array<uint8_t, 2>, std::array<uint8_t, 2>>, 359 std::tuple<uint8_t, std::array<uint8_t, 2>>>> 360 ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType, 361 std::optional<uint8_t> countToRead, 362 std::optional<uint8_t> offset) 363 { 364 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer)) 365 { 366 return ipmi::responseInvalidFieldRequest(); 367 } 368 369 // handle OEM command items 370 switch (OEMDevEntityType(entityType)) 371 { 372 case OEMDevEntityType::biosId: 373 { 374 // Byte 2&3, Only used with selecting BIOS 375 if (!countToRead || !offset) 376 { 377 return ipmi::responseReqDataLenInvalid(); 378 } 379 380 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 381 std::string service = 382 getService(*dbus, biosVersionIntf, biosActiveObjPath); 383 try 384 { 385 Value variant = 386 getDbusProperty(*dbus, service, biosActiveObjPath, 387 biosVersionIntf, biosVersionProp); 388 std::string& idString = std::get<std::string>(variant); 389 if (*offset >= idString.size()) 390 { 391 return ipmi::responseParmOutOfRange(); 392 } 393 size_t length = 0; 394 if (*countToRead > (idString.size() - *offset)) 395 { 396 length = idString.size() - *offset; 397 } 398 else 399 { 400 length = *countToRead; 401 } 402 403 std::string readBuf = {0}; 404 readBuf.resize(length); 405 std::copy_n(idString.begin() + *offset, length, 406 (readBuf.begin())); 407 return ipmi::responseSuccess(readBuf); 408 } 409 catch (std::bad_variant_access& e) 410 { 411 return ipmi::responseUnspecifiedError(); 412 } 413 } 414 break; 415 416 case OEMDevEntityType::devVer: 417 { 418 // Byte 2&3, Only used with selecting BIOS 419 if (countToRead || offset) 420 { 421 return ipmi::responseReqDataLenInvalid(); 422 } 423 424 constexpr const size_t verLen = 2; 425 constexpr const size_t verTotalLen = 10; 426 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff}; 427 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff}; 428 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff}; 429 std::array<uint8_t, verLen> meBuf = {0xff, 0xff}; 430 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff}; 431 // data0/1: BMC version number; data6/7: ME version number 432 // the others: HSC0/1/2 version number, not avaible. 433 if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1])) 434 { 435 return ipmi::responseUnspecifiedError(); 436 } 437 return ipmi::responseSuccess( 438 std::tuple< 439 uint8_t, std::array<uint8_t, verLen>, 440 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>, 441 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{ 442 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf}); 443 } 444 break; 445 446 case OEMDevEntityType::sdrVer: 447 { 448 // Byte 2&3, Only used with selecting BIOS 449 if (countToRead || offset) 450 { 451 return ipmi::responseReqDataLenInvalid(); 452 } 453 454 constexpr const size_t sdrLen = 2; 455 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0}; 456 return ipmi::responseSuccess( 457 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen, 458 readBuf}); 459 } 460 break; 461 462 default: 463 return ipmi::responseInvalidFieldRequest(); 464 } 465 } 466 467 ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 468 ipmi_request_t request, ipmi_response_t response, 469 ipmi_data_len_t dataLen, ipmi_context_t context) 470 { 471 if (*dataLen != 0) 472 { 473 *dataLen = 0; 474 return IPMI_CC_REQ_DATA_LEN_INVALID; 475 } 476 477 *dataLen = 1; 478 uint8_t* res = reinterpret_cast<uint8_t*>(response); 479 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no 480 // AIC is available so that BIOS will not timeout repeatly which leads to 481 // slow booting. 482 *res = 0; // Byte1=Count of SlotPosition/FruID records. 483 return IPMI_CC_OK; 484 } 485 486 ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 487 ipmi_request_t request, 488 ipmi_response_t response, 489 ipmi_data_len_t dataLen, 490 ipmi_context_t context) 491 { 492 GetPowerRestoreDelayRes* resp = 493 reinterpret_cast<GetPowerRestoreDelayRes*>(response); 494 495 if (*dataLen != 0) 496 { 497 *dataLen = 0; 498 return IPMI_CC_REQ_DATA_LEN_INVALID; 499 } 500 501 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 502 std::string service = 503 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath); 504 Value variant = 505 getDbusProperty(*dbus, service, powerRestoreDelayObjPath, 506 powerRestoreDelayIntf, powerRestoreDelayProp); 507 508 uint16_t delay = std::get<uint16_t>(variant); 509 resp->byteLSB = delay; 510 resp->byteMSB = delay >> 8; 511 512 *dataLen = sizeof(GetPowerRestoreDelayRes); 513 514 return IPMI_CC_OK; 515 } 516 517 static uint8_t bcdToDec(uint8_t val) 518 { 519 return ((val / 16 * 10) + (val % 16)); 520 } 521 522 // Allows an update utility or system BIOS to send the status of an embedded 523 // firmware update attempt to the BMC. After received, BMC will create a logging 524 // record. 525 ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target, 526 uint8_t majorRevision, 527 uint8_t minorRevision, 528 uint32_t auxInfo) 529 { 530 std::string firmware; 531 int instance = (target & targetInstanceMask) >> targetInstanceShift; 532 target = (target & selEvtTargetMask) >> selEvtTargetShift; 533 534 /* make sure the status is 0, 1, or 2 as per the spec */ 535 if (status > 2) 536 { 537 return ipmi::response(ipmi::ccInvalidFieldRequest); 538 } 539 /* make sure the target is 0, 1, 2, or 4 as per the spec */ 540 if (target > 4 || target == 3) 541 { 542 return ipmi::response(ipmi::ccInvalidFieldRequest); 543 } 544 /*orignal OEM command is to record OEM SEL. 545 But openbmc does not support OEM SEL, so we redirect it to redfish event 546 logging. */ 547 std::string buildInfo; 548 std::string action; 549 switch (FWUpdateTarget(target)) 550 { 551 case FWUpdateTarget::targetBMC: 552 firmware = "BMC"; 553 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " + 554 std::to_string(bcdToDec(minorRevision)) + // BCD encoded 555 " BuildID: " + std::to_string(auxInfo); 556 buildInfo += std::to_string(auxInfo); 557 break; 558 case FWUpdateTarget::targetBIOS: 559 firmware = "BIOS"; 560 buildInfo = 561 "major: " + 562 std::to_string(bcdToDec(majorRevision)) + // BCD encoded 563 " minor: " + 564 std::to_string(bcdToDec(minorRevision)) + // BCD encoded 565 " ReleaseNumber: " + // ASCII encoded 566 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') + 567 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') + 568 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') + 569 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0'); 570 break; 571 case FWUpdateTarget::targetME: 572 firmware = "ME"; 573 buildInfo = 574 "major: " + std::to_string(majorRevision) + " minor1: " + 575 std::to_string(bcdToDec(minorRevision)) + // BCD encoded 576 " minor2: " + 577 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) + 578 " build1: " + 579 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) + 580 " build2: " + 581 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16))); 582 break; 583 case FWUpdateTarget::targetOEMEWS: 584 firmware = "EWS"; 585 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " + 586 std::to_string(bcdToDec(minorRevision)) + // BCD encoded 587 " BuildID: " + std::to_string(auxInfo); 588 break; 589 } 590 591 static const std::string openBMCMessageRegistryVersion("0.1"); 592 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion; 593 594 switch (status) 595 { 596 case 0x0: 597 action = "update started"; 598 redfishMsgID += ".FirmwareUpdateStarted"; 599 break; 600 case 0x1: 601 action = "update completed successfully"; 602 redfishMsgID += ".FirmwareUpdateCompleted"; 603 break; 604 case 0x2: 605 action = "update failure"; 606 redfishMsgID += ".FirmwareUpdateFailed"; 607 break; 608 default: 609 action = "unknown"; 610 break; 611 } 612 613 std::string firmwareInstanceStr = 614 firmware + " instance: " + std::to_string(instance); 615 std::string message("[firmware update] " + firmwareInstanceStr + 616 " status: <" + action + "> " + buildInfo); 617 618 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO, 619 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(), 620 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(), 621 buildInfo.c_str(), NULL); 622 return ipmi::responseSuccess(); 623 } 624 625 ipmi::RspType<uint8_t, std::vector<uint8_t>> 626 ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1, 627 uint2_t slotNumber, uint3_t baseBoardSlotNum, 628 uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr, 629 uint8_t netFn, uint8_t cmd, 630 std::optional<std::vector<uint8_t>> writeData) 631 { 632 if (reserved1 || reserved2) 633 { 634 return ipmi::responseInvalidFieldRequest(); 635 } 636 637 boost::system::error_code ec; 638 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, 639 std::vector<uint8_t>>; 640 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>( 641 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb", 642 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb", 643 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber), 644 static_cast<uint8_t>(baseBoardSlotNum), slaveAddr, netFn, cmd, 645 *writeData); 646 if (ec) 647 { 648 phosphor::logging::log<phosphor::logging::level::ERR>( 649 "Failed to call dbus method SlotIpmbRequest"); 650 return ipmi::responseUnspecifiedError(); 651 } 652 653 std::vector<uint8_t> dataReceived(0); 654 int status = -1; 655 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0; 656 657 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res; 658 659 if (status) 660 { 661 phosphor::logging::log<phosphor::logging::level::ERR>( 662 "Failed to get response from SlotIpmbRequest"); 663 return ipmi::responseResponseError(); 664 } 665 return ipmi::responseSuccess(cc, dataReceived); 666 } 667 668 ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 669 ipmi_request_t request, 670 ipmi_response_t response, 671 ipmi_data_len_t dataLen, 672 ipmi_context_t context) 673 { 674 SetPowerRestoreDelayReq* data = 675 reinterpret_cast<SetPowerRestoreDelayReq*>(request); 676 uint16_t delay = 0; 677 678 if (*dataLen != sizeof(SetPowerRestoreDelayReq)) 679 { 680 *dataLen = 0; 681 return IPMI_CC_REQ_DATA_LEN_INVALID; 682 } 683 delay = data->byteMSB; 684 delay = (delay << 8) | data->byteLSB; 685 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 686 std::string service = 687 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath); 688 setDbusProperty(*dbus, service, powerRestoreDelayObjPath, 689 powerRestoreDelayIntf, powerRestoreDelayProp, delay); 690 *dataLen = 0; 691 692 return IPMI_CC_OK; 693 } 694 695 static bool cpuPresent(const std::string& cpuName) 696 { 697 static constexpr const char* cpuPresencePathPrefix = 698 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"; 699 static constexpr const char* cpuPresenceIntf = 700 "xyz.openbmc_project.Inventory.Item"; 701 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName; 702 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 703 try 704 { 705 auto service = 706 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath); 707 708 ipmi::Value result = ipmi::getDbusProperty( 709 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present"); 710 return std::get<bool>(result); 711 } 712 catch (const std::exception& e) 713 { 714 phosphor::logging::log<phosphor::logging::level::INFO>( 715 "Cannot find processor presence", 716 phosphor::logging::entry("NAME=%s", cpuName.c_str())); 717 return false; 718 } 719 } 720 721 ipmi::RspType<bool, // CATERR Reset Enabled 722 bool, // ERR2 Reset Enabled 723 uint6_t, // reserved 724 uint8_t, // reserved, returns 0x3F 725 uint6_t, // CPU1 CATERR Count 726 uint2_t, // CPU1 Status 727 uint6_t, // CPU2 CATERR Count 728 uint2_t, // CPU2 Status 729 uint6_t, // CPU3 CATERR Count 730 uint2_t, // CPU3 Status 731 uint6_t, // CPU4 CATERR Count 732 uint2_t, // CPU4 Status 733 uint8_t // Crashdump Count 734 > 735 ipmiOEMGetProcessorErrConfig() 736 { 737 bool resetOnCATERR = false; 738 bool resetOnERR2 = false; 739 uint6_t cpu1CATERRCount = 0; 740 uint6_t cpu2CATERRCount = 0; 741 uint6_t cpu3CATERRCount = 0; 742 uint6_t cpu4CATERRCount = 0; 743 uint8_t crashdumpCount = 0; 744 uint2_t cpu1Status = cpuPresent("CPU_1") 745 ? types::enum_cast<uint8_t>(CPUStatus::enabled) 746 : types::enum_cast<uint8_t>(CPUStatus::notPresent); 747 uint2_t cpu2Status = cpuPresent("CPU_2") 748 ? types::enum_cast<uint8_t>(CPUStatus::enabled) 749 : types::enum_cast<uint8_t>(CPUStatus::notPresent); 750 uint2_t cpu3Status = cpuPresent("CPU_3") 751 ? types::enum_cast<uint8_t>(CPUStatus::enabled) 752 : types::enum_cast<uint8_t>(CPUStatus::notPresent); 753 uint2_t cpu4Status = cpuPresent("CPU_4") 754 ? types::enum_cast<uint8_t>(CPUStatus::enabled) 755 : types::enum_cast<uint8_t>(CPUStatus::notPresent); 756 757 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 758 try 759 { 760 auto service = ipmi::getService(*busp, processorErrConfigIntf, 761 processorErrConfigObjPath); 762 763 ipmi::PropertyMap result = ipmi::getAllDbusProperties( 764 *busp, service, processorErrConfigObjPath, processorErrConfigIntf); 765 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR")); 766 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2")); 767 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1")); 768 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2")); 769 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3")); 770 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4")); 771 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount")); 772 } 773 catch (const std::exception& e) 774 { 775 phosphor::logging::log<phosphor::logging::level::ERR>( 776 "Failed to fetch processor error config", 777 phosphor::logging::entry("ERROR=%s", e.what())); 778 return ipmi::responseUnspecifiedError(); 779 } 780 781 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F, 782 cpu1CATERRCount, cpu1Status, cpu2CATERRCount, 783 cpu2Status, cpu3CATERRCount, cpu3Status, 784 cpu4CATERRCount, cpu4Status, crashdumpCount); 785 } 786 787 ipmi::RspType<> ipmiOEMSetProcessorErrConfig( 788 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2, 789 std::optional<bool> clearCPUErrorCount, 790 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3) 791 { 792 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 793 794 try 795 { 796 auto service = ipmi::getService(*busp, processorErrConfigIntf, 797 processorErrConfigObjPath); 798 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 799 processorErrConfigIntf, "ResetOnCATERR", 800 resetOnCATERR); 801 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 802 processorErrConfigIntf, "ResetOnERR2", 803 resetOnERR2); 804 if (clearCPUErrorCount.value_or(false)) 805 { 806 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 807 processorErrConfigIntf, "ErrorCountCPU1", 808 static_cast<uint8_t>(0)); 809 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 810 processorErrConfigIntf, "ErrorCountCPU2", 811 static_cast<uint8_t>(0)); 812 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 813 processorErrConfigIntf, "ErrorCountCPU3", 814 static_cast<uint8_t>(0)); 815 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 816 processorErrConfigIntf, "ErrorCountCPU4", 817 static_cast<uint8_t>(0)); 818 } 819 if (clearCrashdumpCount.value_or(false)) 820 { 821 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 822 processorErrConfigIntf, "CrashdumpCount", 823 static_cast<uint8_t>(0)); 824 } 825 } 826 catch (std::exception& e) 827 { 828 phosphor::logging::log<phosphor::logging::level::ERR>( 829 "Failed to set processor error config", 830 phosphor::logging::entry("EXCEPTION=%s", e.what())); 831 return ipmi::responseUnspecifiedError(); 832 } 833 834 return ipmi::responseSuccess(); 835 } 836 837 ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 838 ipmi_request_t request, 839 ipmi_response_t response, 840 ipmi_data_len_t dataLen, 841 ipmi_context_t context) 842 { 843 GetOEMShutdownPolicyRes* resp = 844 reinterpret_cast<GetOEMShutdownPolicyRes*>(response); 845 846 if (*dataLen != 0) 847 { 848 phosphor::logging::log<phosphor::logging::level::ERR>( 849 "oem_get_shutdown_policy: invalid input len!"); 850 *dataLen = 0; 851 return IPMI_CC_REQ_DATA_LEN_INVALID; 852 } 853 854 *dataLen = 0; 855 856 try 857 { 858 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 859 std::string service = 860 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath); 861 Value variant = getDbusProperty( 862 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf, 863 oemShutdownPolicyObjPathProp); 864 865 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 866 convertPolicyFromString(std::get<std::string>(variant)) == 867 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy:: 868 NoShutdownOnOCOT) 869 { 870 resp->policy = 0; 871 } 872 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 873 convertPolicyFromString(std::get<std::string>(variant)) == 874 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 875 Policy::ShutdownOnOCOT) 876 { 877 resp->policy = 1; 878 } 879 else 880 { 881 phosphor::logging::log<phosphor::logging::level::ERR>( 882 "oem_set_shutdown_policy: invalid property!", 883 phosphor::logging::entry( 884 "PROP=%s", std::get<std::string>(variant).c_str())); 885 return IPMI_CC_UNSPECIFIED_ERROR; 886 } 887 // TODO needs to check if it is multi-node products, 888 // policy is only supported on node 3/4 889 resp->policySupport = shutdownPolicySupported; 890 } 891 catch (sdbusplus::exception_t& e) 892 { 893 phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 894 return IPMI_CC_UNSPECIFIED_ERROR; 895 } 896 897 *dataLen = sizeof(GetOEMShutdownPolicyRes); 898 return IPMI_CC_OK; 899 } 900 901 ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 902 ipmi_request_t request, 903 ipmi_response_t response, 904 ipmi_data_len_t dataLen, 905 ipmi_context_t context) 906 { 907 uint8_t* req = reinterpret_cast<uint8_t*>(request); 908 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy = 909 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy:: 910 NoShutdownOnOCOT; 911 912 // TODO needs to check if it is multi-node products, 913 // policy is only supported on node 3/4 914 if (*dataLen != 1) 915 { 916 phosphor::logging::log<phosphor::logging::level::ERR>( 917 "oem_set_shutdown_policy: invalid input len!"); 918 *dataLen = 0; 919 return IPMI_CC_REQ_DATA_LEN_INVALID; 920 } 921 922 *dataLen = 0; 923 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT)) 924 { 925 phosphor::logging::log<phosphor::logging::level::ERR>( 926 "oem_set_shutdown_policy: invalid input!"); 927 return IPMI_CC_INVALID_FIELD_REQUEST; 928 } 929 930 if (*req == noShutdownOnOCOT) 931 { 932 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 933 Policy::NoShutdownOnOCOT; 934 } 935 else 936 { 937 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 938 Policy::ShutdownOnOCOT; 939 } 940 941 try 942 { 943 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 944 std::string service = 945 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath); 946 setDbusProperty( 947 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf, 948 oemShutdownPolicyObjPathProp, 949 sdbusplus::com::intel::Control::server::convertForMessage(policy)); 950 } 951 catch (sdbusplus::exception_t& e) 952 { 953 phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 954 return IPMI_CC_UNSPECIFIED_ERROR; 955 } 956 957 return IPMI_CC_OK; 958 } 959 960 /** @brief implementation for check the DHCP or not in IPv4 961 * @param[in] Channel - Channel number 962 * @returns true or false. 963 */ 964 static bool isDHCPEnabled(uint8_t Channel) 965 { 966 try 967 { 968 auto ethdevice = getChannelName(Channel); 969 if (ethdevice.empty()) 970 { 971 return false; 972 } 973 auto ethIP = ethdevice + "/ipv4"; 974 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 975 auto ethernetObj = 976 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP); 977 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first, 978 networkIPIntf, "Origin"); 979 if (std::get<std::string>(value) == 980 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") 981 { 982 return true; 983 } 984 else 985 { 986 return false; 987 } 988 } 989 catch (sdbusplus::exception_t& e) 990 { 991 phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 992 return true; 993 } 994 } 995 996 /** @brief implementes for check the DHCP or not in IPv6 997 * @param[in] Channel - Channel number 998 * @returns true or false. 999 */ 1000 static bool isDHCPIPv6Enabled(uint8_t Channel) 1001 { 1002 1003 try 1004 { 1005 auto ethdevice = getChannelName(Channel); 1006 if (ethdevice.empty()) 1007 { 1008 return false; 1009 } 1010 auto ethIP = ethdevice + "/ipv6"; 1011 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1012 auto objectInfo = 1013 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP); 1014 auto properties = getAllDbusProperties(*dbus, objectInfo.second, 1015 objectInfo.first, networkIPIntf); 1016 if (std::get<std::string>(properties["Origin"]) == 1017 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") 1018 { 1019 return true; 1020 } 1021 else 1022 { 1023 return false; 1024 } 1025 } 1026 catch (sdbusplus::exception_t& e) 1027 { 1028 phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 1029 return true; 1030 } 1031 } 1032 1033 /** @brief implementes the creating of default new user 1034 * @param[in] userName - new username in 16 bytes. 1035 * @param[in] userPassword - new password in 20 bytes 1036 * @returns ipmi completion code. 1037 */ 1038 ipmi::RspType<> ipmiOEMSetUser2Activation( 1039 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName, 1040 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword) 1041 { 1042 bool userState = false; 1043 // Check for System Interface not exist and LAN should be static 1044 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++) 1045 { 1046 ChannelInfo chInfo; 1047 try 1048 { 1049 getChannelInfo(channel, chInfo); 1050 } 1051 catch (sdbusplus::exception_t& e) 1052 { 1053 phosphor::logging::log<phosphor::logging::level::ERR>( 1054 "ipmiOEMSetUser2Activation: Failed to get Channel Info", 1055 phosphor::logging::entry("MSG: %s", e.description())); 1056 return ipmi::response(ipmi::ccUnspecifiedError); 1057 } 1058 if (chInfo.mediumType == 1059 static_cast<uint8_t>(EChannelMediumType::systemInterface)) 1060 { 1061 phosphor::logging::log<phosphor::logging::level::ERR>( 1062 "ipmiOEMSetUser2Activation: system interface exist ."); 1063 return ipmi::response(ipmi::ccCommandNotAvailable); 1064 } 1065 else 1066 { 1067 1068 if (chInfo.mediumType == 1069 static_cast<uint8_t>(EChannelMediumType::lan8032)) 1070 { 1071 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel)) 1072 { 1073 phosphor::logging::log<phosphor::logging::level::ERR>( 1074 "ipmiOEMSetUser2Activation: DHCP enabled ."); 1075 return ipmi::response(ipmi::ccCommandNotAvailable); 1076 } 1077 } 1078 } 1079 } 1080 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0; 1081 if (ipmi::ccSuccess == 1082 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers)) 1083 { 1084 if (enabledUsers > 1) 1085 { 1086 phosphor::logging::log<phosphor::logging::level::ERR>( 1087 "ipmiOEMSetUser2Activation: more than one user is enabled."); 1088 return ipmi::response(ipmi::ccCommandNotAvailable); 1089 } 1090 // Check the user 2 is enabled or not 1091 ipmiUserCheckEnabled(ipmiDefaultUserId, userState); 1092 if (userState == true) 1093 { 1094 phosphor::logging::log<phosphor::logging::level::ERR>( 1095 "ipmiOEMSetUser2Activation: user 2 already enabled ."); 1096 return ipmi::response(ipmi::ccCommandNotAvailable); 1097 } 1098 } 1099 else 1100 { 1101 return ipmi::response(ipmi::ccUnspecifiedError); 1102 } 1103 1104 #if BYTE_ORDER == LITTLE_ENDIAN 1105 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0}; 1106 #endif 1107 #if BYTE_ORDER == BIG_ENDIAN 1108 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN}; 1109 #endif 1110 1111 // ipmiUserSetUserName correctly handles char*, possibly non-null 1112 // terminated strings using ipmiMaxUserName size 1113 size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()), 1114 sizeof(userName)); 1115 const std::string userNameRaw( 1116 reinterpret_cast<const char*>(userName.data()), nameLen); 1117 1118 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw)) 1119 { 1120 if (ipmi::ccSuccess == 1121 ipmiUserSetUserPassword( 1122 ipmiDefaultUserId, 1123 reinterpret_cast<const char*>(userPassword.data()))) 1124 { 1125 if (ipmi::ccSuccess == 1126 ipmiUserSetPrivilegeAccess( 1127 ipmiDefaultUserId, 1128 static_cast<uint8_t>(ipmi::EChannelID::chanLan1), 1129 privAccess, true)) 1130 { 1131 phosphor::logging::log<phosphor::logging::level::INFO>( 1132 "ipmiOEMSetUser2Activation: user created successfully "); 1133 OPENSSL_cleanse(userPassword.data(), userPassword.size()); 1134 1135 return ipmi::responseSuccess(); 1136 } 1137 } 1138 // we need to delete the default user id which added in this command as 1139 // password / priv setting is failed. 1140 ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>("")); 1141 phosphor::logging::log<phosphor::logging::level::ERR>( 1142 "ipmiOEMSetUser2Activation: password / priv setting is failed."); 1143 OPENSSL_cleanse(userPassword.data(), userPassword.size()); 1144 } 1145 else 1146 { 1147 phosphor::logging::log<phosphor::logging::level::ERR>( 1148 "ipmiOEMSetUser2Activation: Setting username failed."); 1149 } 1150 1151 return ipmi::response(ipmi::ccCommandNotAvailable); 1152 } 1153 1154 /** @brief implementes executing the linux command 1155 * @param[in] linux command 1156 * @returns status 1157 */ 1158 1159 static uint8_t executeCmd(const char* path) 1160 { 1161 boost::process::child execProg(path); 1162 execProg.wait(); 1163 1164 int retCode = execProg.exit_code(); 1165 if (retCode) 1166 { 1167 return ipmi::ccUnspecifiedError; 1168 } 1169 return ipmi::ccSuccess; 1170 } 1171 1172 /** @brief implementes ASD Security event logging 1173 * @param[in] Event message string 1174 * @param[in] Event Severity 1175 * @returns status 1176 */ 1177 1178 static void atScaleDebugEventlog(std::string msg, int severity) 1179 { 1180 std::string eventStr = "OpenBMC.0.1." + msg; 1181 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(), 1182 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s", 1183 eventStr.c_str(), NULL); 1184 } 1185 1186 /** @brief implementes setting password for special user 1187 * @param[in] specialUserIndex 1188 * @param[in] userPassword - new password in 20 bytes 1189 * @returns ipmi completion code. 1190 */ 1191 ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx, 1192 uint8_t specialUserIndex, 1193 std::vector<uint8_t> userPassword) 1194 { 1195 ChannelInfo chInfo; 1196 ipmi_ret_t status = ipmi::ccSuccess; 1197 1198 try 1199 { 1200 getChannelInfo(ctx->channel, chInfo); 1201 } 1202 catch (sdbusplus::exception_t& e) 1203 { 1204 phosphor::logging::log<phosphor::logging::level::ERR>( 1205 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info", 1206 phosphor::logging::entry("MSG: %s", e.description())); 1207 return ipmi::responseUnspecifiedError(); 1208 } 1209 if (chInfo.mediumType != 1210 static_cast<uint8_t>(EChannelMediumType::systemInterface)) 1211 { 1212 phosphor::logging::log<phosphor::logging::level::ERR>( 1213 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS " 1214 "interface"); 1215 return ipmi::responseCommandNotAvailable(); 1216 } 1217 1218 // 0 for root user and 1 for AtScaleDebug is allowed 1219 if (specialUserIndex > 1220 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser)) 1221 { 1222 phosphor::logging::log<phosphor::logging::level::ERR>( 1223 "ipmiOEMSetSpecialUserPassword: Invalid user account"); 1224 return ipmi::responseParmOutOfRange(); 1225 } 1226 if (userPassword.size() != 0) 1227 { 1228 constexpr uint8_t minPasswordSizeRequired = 6; 1229 std::string passwd; 1230 if (userPassword.size() < minPasswordSizeRequired || 1231 userPassword.size() > ipmi::maxIpmi20PasswordSize) 1232 { 1233 OPENSSL_cleanse(userPassword.data(), userPassword.size()); 1234 return ipmi::responseReqDataLenInvalid(); 1235 } 1236 passwd.assign(reinterpret_cast<const char*>(userPassword.data()), 1237 userPassword.size()); 1238 // Clear sensitive data 1239 OPENSSL_cleanse(userPassword.data(), userPassword.size()); 1240 if (specialUserIndex == 1241 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser)) 1242 { 1243 status = ipmiSetSpecialUserPassword("asdbg", passwd); 1244 1245 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT); 1246 } 1247 else 1248 { 1249 status = ipmiSetSpecialUserPassword("root", passwd); 1250 } 1251 // Clear sensitive data 1252 OPENSSL_cleanse(&passwd, passwd.length()); 1253 1254 return ipmi::response(status); 1255 } 1256 else 1257 { 1258 if (specialUserIndex == 1259 static_cast<uint8_t>(SpecialUserIndex::rootUser)) 1260 { 1261 status = executeCmd("passwd -d root"); 1262 } 1263 else 1264 { 1265 1266 status = executeCmd("passwd -d asdbg"); 1267 1268 if (status == 0) 1269 { 1270 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled", 1271 LOG_INFO); 1272 } 1273 } 1274 return ipmi::response(status); 1275 } 1276 } 1277 1278 namespace ledAction 1279 { 1280 using namespace sdbusplus::xyz::openbmc_project::Led::server; 1281 std::map<Physical::Action, uint8_t> actionDbusToIpmi = { 1282 {Physical::Action::Off, 0}, 1283 {Physical::Action::On, 2}, 1284 {Physical::Action::Blink, 1}}; 1285 1286 std::map<uint8_t, std::string> offsetObjPath = { 1287 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}}; 1288 1289 } // namespace ledAction 1290 1291 int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf, 1292 const std::string& objPath, uint8_t& state) 1293 { 1294 try 1295 { 1296 std::string service = getService(bus, intf, objPath); 1297 Value stateValue = 1298 getDbusProperty(bus, service, objPath, intf, "State"); 1299 std::string strState = std::get<std::string>(stateValue); 1300 state = ledAction::actionDbusToIpmi.at( 1301 sdbusplus::xyz::openbmc_project::Led::server::Physical:: 1302 convertActionFromString(strState)); 1303 } 1304 catch (sdbusplus::exception::SdBusError& e) 1305 { 1306 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 1307 return -1; 1308 } 1309 return 0; 1310 } 1311 1312 ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus() 1313 { 1314 uint8_t ledstate = 0; 1315 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status"); 1316 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1317 for (auto it = ledAction::offsetObjPath.begin(); 1318 it != ledAction::offsetObjPath.end(); ++it) 1319 { 1320 uint8_t state = 0; 1321 if (getLEDState(*dbus, ledIntf, it->second, state) == -1) 1322 { 1323 phosphor::logging::log<phosphor::logging::level::ERR>( 1324 "oem_get_led_status: fail to get ID LED status!"); 1325 return ipmi::responseUnspecifiedError(); 1326 } 1327 ledstate |= state << it->first; 1328 } 1329 return ipmi::responseSuccess(ledstate); 1330 } 1331 1332 ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 1333 ipmi_request_t request, 1334 ipmi_response_t response, 1335 ipmi_data_len_t dataLen, 1336 ipmi_context_t context) 1337 { 1338 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request); 1339 uint8_t* resp = reinterpret_cast<uint8_t*>(response); 1340 1341 if (*dataLen == 0) 1342 { 1343 phosphor::logging::log<phosphor::logging::level::ERR>( 1344 "CfgHostSerial: invalid input len!", 1345 phosphor::logging::entry("LEN=%d", *dataLen)); 1346 return IPMI_CC_REQ_DATA_LEN_INVALID; 1347 } 1348 1349 switch (req->command) 1350 { 1351 case getHostSerialCfgCmd: 1352 { 1353 if (*dataLen != 1) 1354 { 1355 phosphor::logging::log<phosphor::logging::level::ERR>( 1356 "CfgHostSerial: invalid input len!"); 1357 *dataLen = 0; 1358 return IPMI_CC_REQ_DATA_LEN_INVALID; 1359 } 1360 1361 *dataLen = 0; 1362 1363 boost::process::ipstream is; 1364 std::vector<std::string> data; 1365 std::string line; 1366 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName, 1367 boost::process::std_out > is); 1368 1369 while (c1.running() && std::getline(is, line) && !line.empty()) 1370 { 1371 data.push_back(line); 1372 } 1373 1374 c1.wait(); 1375 if (c1.exit_code()) 1376 { 1377 phosphor::logging::log<phosphor::logging::level::ERR>( 1378 "CfgHostSerial:: error on execute", 1379 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd)); 1380 // Using the default value 1381 *resp = 0; 1382 } 1383 else 1384 { 1385 if (data.size() != 1) 1386 { 1387 phosphor::logging::log<phosphor::logging::level::ERR>( 1388 "CfgHostSerial:: error on read env"); 1389 return IPMI_CC_UNSPECIFIED_ERROR; 1390 } 1391 try 1392 { 1393 unsigned long tmp = std::stoul(data[0]); 1394 if (tmp > std::numeric_limits<uint8_t>::max()) 1395 { 1396 throw std::out_of_range("Out of range"); 1397 } 1398 *resp = static_cast<uint8_t>(tmp); 1399 } 1400 catch (const std::invalid_argument& e) 1401 { 1402 phosphor::logging::log<phosphor::logging::level::ERR>( 1403 "invalid config ", 1404 phosphor::logging::entry("ERR=%s", e.what())); 1405 return IPMI_CC_UNSPECIFIED_ERROR; 1406 } 1407 catch (const std::out_of_range& e) 1408 { 1409 phosphor::logging::log<phosphor::logging::level::ERR>( 1410 "out_of_range config ", 1411 phosphor::logging::entry("ERR=%s", e.what())); 1412 return IPMI_CC_UNSPECIFIED_ERROR; 1413 } 1414 } 1415 1416 *dataLen = 1; 1417 break; 1418 } 1419 case setHostSerialCfgCmd: 1420 { 1421 if (*dataLen != sizeof(CfgHostSerialReq)) 1422 { 1423 phosphor::logging::log<phosphor::logging::level::ERR>( 1424 "CfgHostSerial: invalid input len!"); 1425 *dataLen = 0; 1426 return IPMI_CC_REQ_DATA_LEN_INVALID; 1427 } 1428 1429 *dataLen = 0; 1430 1431 if (req->parameter > HostSerialCfgParamMax) 1432 { 1433 phosphor::logging::log<phosphor::logging::level::ERR>( 1434 "CfgHostSerial: invalid input!"); 1435 return IPMI_CC_INVALID_FIELD_REQUEST; 1436 } 1437 1438 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName, 1439 std::to_string(req->parameter)); 1440 1441 c1.wait(); 1442 if (c1.exit_code()) 1443 { 1444 phosphor::logging::log<phosphor::logging::level::ERR>( 1445 "CfgHostSerial:: error on execute", 1446 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd)); 1447 return IPMI_CC_UNSPECIFIED_ERROR; 1448 } 1449 break; 1450 } 1451 default: 1452 phosphor::logging::log<phosphor::logging::level::ERR>( 1453 "CfgHostSerial: invalid input!"); 1454 *dataLen = 0; 1455 return IPMI_CC_INVALID_FIELD_REQUEST; 1456 } 1457 1458 return IPMI_CC_OK; 1459 } 1460 1461 constexpr const char* thermalModeInterface = 1462 "xyz.openbmc_project.Control.ThermalMode"; 1463 constexpr const char* thermalModePath = 1464 "/xyz/openbmc_project/control/thermal_mode"; 1465 1466 bool getFanProfileInterface( 1467 sdbusplus::bus::bus& bus, 1468 boost::container::flat_map< 1469 std::string, std::variant<std::vector<std::string>, std::string>>& resp) 1470 { 1471 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF, 1472 "GetAll"); 1473 call.append(thermalModeInterface); 1474 try 1475 { 1476 auto data = bus.call(call); 1477 data.read(resp); 1478 } 1479 catch (sdbusplus::exception_t& e) 1480 { 1481 phosphor::logging::log<phosphor::logging::level::ERR>( 1482 "getFanProfileInterface: can't get thermal mode!", 1483 phosphor::logging::entry("ERR=%s", e.what())); 1484 return false; 1485 } 1486 return true; 1487 } 1488 1489 /**@brief implements the OEM set fan config. 1490 * @param selectedFanProfile - fan profile to enable 1491 * @param reserved1 1492 * @param performanceMode - Performance/Acoustic mode 1493 * @param reserved2 1494 * @param setPerformanceMode - set Performance/Acoustic mode 1495 * @param setFanProfile - set fan profile 1496 * 1497 * @return IPMI completion code. 1498 **/ 1499 ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile, 1500 1501 uint2_t reserved1, bool performanceMode, 1502 uint3_t reserved2, bool setPerformanceMode, 1503 bool setFanProfile, 1504 std::optional<uint8_t> dimmGroupId, 1505 std::optional<uint32_t> dimmPresenceBitmap) 1506 { 1507 if (reserved1 || reserved2) 1508 { 1509 return ipmi::responseInvalidFieldRequest(); 1510 } 1511 1512 if (dimmGroupId) 1513 { 1514 if (*dimmGroupId >= maxCPUNum) 1515 { 1516 return ipmi::responseInvalidFieldRequest(); 1517 } 1518 if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1))) 1519 { 1520 return ipmi::responseInvalidFieldRequest(); 1521 } 1522 } 1523 1524 // todo: tell bios to only send first 2 bytes 1525 boost::container::flat_map< 1526 std::string, std::variant<std::vector<std::string>, std::string>> 1527 profileData; 1528 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1529 if (!getFanProfileInterface(*dbus, profileData)) 1530 { 1531 return ipmi::responseUnspecifiedError(); 1532 } 1533 1534 std::vector<std::string>* supported = 1535 std::get_if<std::vector<std::string>>(&profileData["Supported"]); 1536 if (supported == nullptr) 1537 { 1538 return ipmi::responseInvalidFieldRequest(); 1539 } 1540 std::string mode; 1541 if (setPerformanceMode) 1542 { 1543 if (performanceMode) 1544 { 1545 1546 if (std::find(supported->begin(), supported->end(), 1547 "Performance") != supported->end()) 1548 { 1549 mode = "Performance"; 1550 } 1551 } 1552 else 1553 { 1554 if (std::find(supported->begin(), supported->end(), "Acoustic") != 1555 supported->end()) 1556 { 1557 mode = "Acoustic"; 1558 } 1559 } 1560 if (mode.empty()) 1561 { 1562 return ipmi::responseInvalidFieldRequest(); 1563 } 1564 1565 try 1566 { 1567 setDbusProperty(*dbus, settingsBusName, thermalModePath, 1568 thermalModeInterface, "Current", mode); 1569 } 1570 catch (sdbusplus::exception_t& e) 1571 { 1572 phosphor::logging::log<phosphor::logging::level::ERR>( 1573 "ipmiOEMSetFanConfig: can't set thermal mode!", 1574 phosphor::logging::entry("EXCEPTION=%s", e.what())); 1575 return ipmi::responseResponseError(); 1576 } 1577 } 1578 1579 return ipmi::responseSuccess(); 1580 } 1581 1582 ipmi::RspType<uint8_t, // profile support map 1583 uint8_t, // fan control profile enable 1584 uint8_t, // flags 1585 uint32_t // dimm presence bit map 1586 > 1587 ipmiOEMGetFanConfig(uint8_t dimmGroupId) 1588 { 1589 if (dimmGroupId >= maxCPUNum) 1590 { 1591 return ipmi::responseInvalidFieldRequest(); 1592 } 1593 1594 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1)); 1595 1596 if (!cpuStatus) 1597 { 1598 return ipmi::responseInvalidFieldRequest(); 1599 } 1600 1601 boost::container::flat_map< 1602 std::string, std::variant<std::vector<std::string>, std::string>> 1603 profileData; 1604 1605 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1606 if (!getFanProfileInterface(*dbus, profileData)) 1607 { 1608 return ipmi::responseResponseError(); 1609 } 1610 1611 std::string* current = std::get_if<std::string>(&profileData["Current"]); 1612 1613 if (current == nullptr) 1614 { 1615 phosphor::logging::log<phosphor::logging::level::ERR>( 1616 "ipmiOEMGetFanConfig: can't get current mode!"); 1617 return ipmi::responseResponseError(); 1618 } 1619 bool performance = (*current == "Performance"); 1620 1621 uint8_t flags = 0; 1622 if (performance) 1623 { 1624 flags |= 1 << 2; 1625 } 1626 1627 constexpr uint8_t fanControlDefaultProfile = 0x80; 1628 constexpr uint8_t fanControlProfileState = 0x00; 1629 constexpr uint32_t dimmPresenceBitmap = 0x00; 1630 1631 return ipmi::responseSuccess(fanControlDefaultProfile, 1632 fanControlProfileState, flags, 1633 dimmPresenceBitmap); 1634 } 1635 constexpr const char* cfmLimitSettingPath = 1636 "/xyz/openbmc_project/control/cfm_limit"; 1637 constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit"; 1638 constexpr const size_t legacyExitAirSensorNumber = 0x2e; 1639 constexpr const size_t legacyPCHSensorNumber = 0x22; 1640 constexpr const char* exitAirPathName = "Exit_Air"; 1641 constexpr const char* pchPathName = "SSB_Temp"; 1642 constexpr const char* pidConfigurationIface = 1643 "xyz.openbmc_project.Configuration.Pid"; 1644 1645 static std::string getConfigPath(const std::string& name) 1646 { 1647 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1648 auto method = 1649 dbus->new_method_call("xyz.openbmc_project.ObjectMapper", 1650 "/xyz/openbmc_project/object_mapper", 1651 "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 1652 1653 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface}); 1654 std::string path; 1655 GetSubTreeType resp; 1656 try 1657 { 1658 auto reply = dbus->call(method); 1659 reply.read(resp); 1660 } 1661 catch (sdbusplus::exception_t&) 1662 { 1663 phosphor::logging::log<phosphor::logging::level::ERR>( 1664 "ipmiOEMGetFscParameter: mapper error"); 1665 }; 1666 auto config = 1667 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) { 1668 return pair.first.find(name) != std::string::npos; 1669 }); 1670 if (config != resp.end()) 1671 { 1672 path = std::move(config->first); 1673 } 1674 return path; 1675 } 1676 1677 // flat map to make alphabetical 1678 static boost::container::flat_map<std::string, PropertyMap> getPidConfigs() 1679 { 1680 boost::container::flat_map<std::string, PropertyMap> ret; 1681 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1682 auto method = 1683 dbus->new_method_call("xyz.openbmc_project.ObjectMapper", 1684 "/xyz/openbmc_project/object_mapper", 1685 "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 1686 1687 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface}); 1688 GetSubTreeType resp; 1689 1690 try 1691 { 1692 auto reply = dbus->call(method); 1693 reply.read(resp); 1694 } 1695 catch (sdbusplus::exception_t&) 1696 { 1697 phosphor::logging::log<phosphor::logging::level::ERR>( 1698 "getFanConfigPaths: mapper error"); 1699 }; 1700 for (const auto& [path, objects] : resp) 1701 { 1702 if (objects.empty()) 1703 { 1704 continue; // should be impossible 1705 } 1706 1707 try 1708 { 1709 ret.emplace(path, 1710 getAllDbusProperties(*dbus, objects[0].first, path, 1711 pidConfigurationIface)); 1712 } 1713 catch (sdbusplus::exception_t& e) 1714 { 1715 phosphor::logging::log<phosphor::logging::level::ERR>( 1716 "getPidConfigs: can't get DbusProperties!", 1717 phosphor::logging::entry("ERR=%s", e.what())); 1718 } 1719 } 1720 return ret; 1721 } 1722 1723 ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void) 1724 { 1725 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs(); 1726 if (data.empty()) 1727 { 1728 return ipmi::responseResponseError(); 1729 } 1730 uint8_t minOffset = std::numeric_limits<uint8_t>::max(); 1731 for (const auto& [_, pid] : data) 1732 { 1733 auto findClass = pid.find("Class"); 1734 if (findClass == pid.end()) 1735 { 1736 phosphor::logging::log<phosphor::logging::level::ERR>( 1737 "ipmiOEMGetFscParameter: found illegal pid " 1738 "configurations"); 1739 return ipmi::responseResponseError(); 1740 } 1741 std::string type = std::get<std::string>(findClass->second); 1742 if (type == "fan") 1743 { 1744 auto findOutLimit = pid.find("OutLimitMin"); 1745 if (findOutLimit == pid.end()) 1746 { 1747 phosphor::logging::log<phosphor::logging::level::ERR>( 1748 "ipmiOEMGetFscParameter: found illegal pid " 1749 "configurations"); 1750 return ipmi::responseResponseError(); 1751 } 1752 // get the min out of all the offsets 1753 minOffset = std::min( 1754 minOffset, 1755 static_cast<uint8_t>(std::get<double>(findOutLimit->second))); 1756 } 1757 } 1758 if (minOffset == std::numeric_limits<uint8_t>::max()) 1759 { 1760 phosphor::logging::log<phosphor::logging::level::ERR>( 1761 "ipmiOEMGetFscParameter: found no fan configurations!"); 1762 return ipmi::responseResponseError(); 1763 } 1764 1765 return ipmi::responseSuccess(minOffset); 1766 } 1767 1768 ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset) 1769 { 1770 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs(); 1771 if (data.empty()) 1772 { 1773 1774 phosphor::logging::log<phosphor::logging::level::ERR>( 1775 "ipmiOEMSetFanSpeedOffset: found no pid configurations!"); 1776 return ipmi::responseResponseError(); 1777 } 1778 1779 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1780 bool found = false; 1781 for (const auto& [path, pid] : data) 1782 { 1783 auto findClass = pid.find("Class"); 1784 if (findClass == pid.end()) 1785 { 1786 1787 phosphor::logging::log<phosphor::logging::level::ERR>( 1788 "ipmiOEMSetFanSpeedOffset: found illegal pid " 1789 "configurations"); 1790 return ipmi::responseResponseError(); 1791 } 1792 std::string type = std::get<std::string>(findClass->second); 1793 if (type == "fan") 1794 { 1795 auto findOutLimit = pid.find("OutLimitMin"); 1796 if (findOutLimit == pid.end()) 1797 { 1798 1799 phosphor::logging::log<phosphor::logging::level::ERR>( 1800 "ipmiOEMSetFanSpeedOffset: found illegal pid " 1801 "configurations"); 1802 return ipmi::responseResponseError(); 1803 } 1804 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", 1805 path, pidConfigurationIface, "OutLimitMin", 1806 static_cast<double>(offset)); 1807 found = true; 1808 } 1809 } 1810 if (!found) 1811 { 1812 phosphor::logging::log<phosphor::logging::level::ERR>( 1813 "ipmiOEMSetFanSpeedOffset: set no fan offsets"); 1814 return ipmi::responseResponseError(); 1815 } 1816 1817 return ipmi::responseSuccess(); 1818 } 1819 1820 ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1, 1821 uint8_t param2) 1822 { 1823 constexpr const size_t disableLimiting = 0x0; 1824 1825 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1826 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol)) 1827 { 1828 std::string pathName; 1829 if (param1 == legacyExitAirSensorNumber) 1830 { 1831 pathName = exitAirPathName; 1832 } 1833 else if (param1 == legacyPCHSensorNumber) 1834 { 1835 pathName = pchPathName; 1836 } 1837 else 1838 { 1839 return ipmi::responseParmOutOfRange(); 1840 } 1841 std::string path = getConfigPath(pathName); 1842 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path, 1843 pidConfigurationIface, "SetPoint", 1844 static_cast<double>(param2)); 1845 return ipmi::responseSuccess(); 1846 } 1847 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm)) 1848 { 1849 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8); 1850 1851 // must be greater than 50 based on eps 1852 if (cfm < 50 && cfm != disableLimiting) 1853 { 1854 return ipmi::responseParmOutOfRange(); 1855 } 1856 1857 try 1858 { 1859 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath, 1860 cfmLimitIface, "Limit", 1861 static_cast<double>(cfm)); 1862 } 1863 catch (sdbusplus::exception_t& e) 1864 { 1865 phosphor::logging::log<phosphor::logging::level::ERR>( 1866 "ipmiOEMSetFscParameter: can't set cfm setting!", 1867 phosphor::logging::entry("ERR=%s", e.what())); 1868 return ipmi::responseResponseError(); 1869 } 1870 return ipmi::responseSuccess(); 1871 } 1872 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm)) 1873 { 1874 constexpr const size_t maxDomainCount = 8; 1875 uint8_t requestedDomainMask = param1; 1876 boost::container::flat_map data = getPidConfigs(); 1877 if (data.empty()) 1878 { 1879 1880 phosphor::logging::log<phosphor::logging::level::ERR>( 1881 "ipmiOEMSetFscParameter: found no pid configurations!"); 1882 return ipmi::responseResponseError(); 1883 } 1884 size_t count = 0; 1885 for (const auto& [path, pid] : data) 1886 { 1887 auto findClass = pid.find("Class"); 1888 if (findClass == pid.end()) 1889 { 1890 1891 phosphor::logging::log<phosphor::logging::level::ERR>( 1892 "ipmiOEMSetFscParameter: found illegal pid " 1893 "configurations"); 1894 return ipmi::responseResponseError(); 1895 } 1896 std::string type = std::get<std::string>(findClass->second); 1897 if (type == "fan") 1898 { 1899 if (requestedDomainMask & (1 << count)) 1900 { 1901 ipmi::setDbusProperty( 1902 *dbus, "xyz.openbmc_project.EntityManager", path, 1903 pidConfigurationIface, "OutLimitMax", 1904 static_cast<double>(param2)); 1905 } 1906 count++; 1907 } 1908 } 1909 return ipmi::responseSuccess(); 1910 } 1911 else 1912 { 1913 // todo other command parts possibly 1914 // tcontrol is handled in peci now 1915 // fan speed offset not implemented yet 1916 // domain pwm limit not implemented 1917 return ipmi::responseParmOutOfRange(); 1918 } 1919 } 1920 1921 ipmi::RspType< 1922 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>> 1923 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param) 1924 { 1925 constexpr uint8_t legacyDefaultSetpoint = -128; 1926 1927 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1928 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol)) 1929 { 1930 if (!param) 1931 { 1932 return ipmi::responseReqDataLenInvalid(); 1933 } 1934 1935 std::string pathName; 1936 1937 if (*param == legacyExitAirSensorNumber) 1938 { 1939 pathName = exitAirPathName; 1940 } 1941 else if (*param == legacyPCHSensorNumber) 1942 { 1943 pathName = pchPathName; 1944 } 1945 else 1946 { 1947 return ipmi::responseParmOutOfRange(); 1948 } 1949 1950 uint8_t setpoint = legacyDefaultSetpoint; 1951 std::string path = getConfigPath(pathName); 1952 if (path.size()) 1953 { 1954 Value val = ipmi::getDbusProperty( 1955 *dbus, "xyz.openbmc_project.EntityManager", path, 1956 pidConfigurationIface, "SetPoint"); 1957 setpoint = std::floor(std::get<double>(val) + 0.5); 1958 } 1959 1960 // old implementation used to return the "default" and current, we 1961 // don't make the default readily available so just make both the 1962 // same 1963 1964 return ipmi::responseSuccess( 1965 std::array<uint8_t, 2>{setpoint, setpoint}); 1966 } 1967 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm)) 1968 { 1969 constexpr const size_t maxDomainCount = 8; 1970 1971 if (!param) 1972 { 1973 return ipmi::responseReqDataLenInvalid(); 1974 } 1975 uint8_t requestedDomain = *param; 1976 if (requestedDomain >= maxDomainCount) 1977 { 1978 return ipmi::responseInvalidFieldRequest(); 1979 } 1980 1981 boost::container::flat_map data = getPidConfigs(); 1982 if (data.empty()) 1983 { 1984 phosphor::logging::log<phosphor::logging::level::ERR>( 1985 "ipmiOEMGetFscParameter: found no pid configurations!"); 1986 return ipmi::responseResponseError(); 1987 } 1988 size_t count = 0; 1989 for (const auto& [_, pid] : data) 1990 { 1991 auto findClass = pid.find("Class"); 1992 if (findClass == pid.end()) 1993 { 1994 phosphor::logging::log<phosphor::logging::level::ERR>( 1995 "ipmiOEMGetFscParameter: found illegal pid " 1996 "configurations"); 1997 return ipmi::responseResponseError(); 1998 } 1999 std::string type = std::get<std::string>(findClass->second); 2000 if (type == "fan") 2001 { 2002 if (requestedDomain == count) 2003 { 2004 auto findOutLimit = pid.find("OutLimitMax"); 2005 if (findOutLimit == pid.end()) 2006 { 2007 phosphor::logging::log<phosphor::logging::level::ERR>( 2008 "ipmiOEMGetFscParameter: found illegal pid " 2009 "configurations"); 2010 return ipmi::responseResponseError(); 2011 } 2012 2013 return ipmi::responseSuccess( 2014 static_cast<uint8_t>(std::floor( 2015 std::get<double>(findOutLimit->second) + 0.5))); 2016 } 2017 else 2018 { 2019 count++; 2020 } 2021 } 2022 } 2023 2024 return ipmi::responseInvalidFieldRequest(); 2025 } 2026 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm)) 2027 { 2028 2029 /* 2030 DataLen should be 1, but host is sending us an extra bit. As the 2031 previous behavior didn't seem to prevent this, ignore the check for 2032 now. 2033 2034 if (param) 2035 { 2036 phosphor::logging::log<phosphor::logging::level::ERR>( 2037 "ipmiOEMGetFscParameter: invalid input len!"); 2038 return IPMI_CC_REQ_DATA_LEN_INVALID; 2039 } 2040 */ 2041 Value cfmLimit; 2042 Value cfmMaximum; 2043 try 2044 { 2045 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName, 2046 cfmLimitSettingPath, cfmLimitIface, 2047 "Limit"); 2048 cfmMaximum = ipmi::getDbusProperty( 2049 *dbus, "xyz.openbmc_project.ExitAirTempSensor", 2050 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit"); 2051 } 2052 catch (sdbusplus::exception_t& e) 2053 { 2054 phosphor::logging::log<phosphor::logging::level::ERR>( 2055 "ipmiOEMGetFscParameter: can't get cfm setting!", 2056 phosphor::logging::entry("ERR=%s", e.what())); 2057 return ipmi::responseResponseError(); 2058 } 2059 2060 double cfmMax = std::get<double>(cfmMaximum); 2061 double cfmLim = std::get<double>(cfmLimit); 2062 2063 cfmLim = std::floor(cfmLim + 0.5); 2064 cfmMax = std::floor(cfmMax + 0.5); 2065 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim); 2066 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax); 2067 2068 return ipmi::responseSuccess( 2069 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp}); 2070 } 2071 2072 else 2073 { 2074 // todo other command parts possibly 2075 // domain pwm limit not implemented 2076 return ipmi::responseParmOutOfRange(); 2077 } 2078 } 2079 2080 using crConfigVariant = 2081 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>; 2082 2083 int setCRConfig(ipmi::Context::ptr ctx, const std::string& property, 2084 const crConfigVariant& value, 2085 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT) 2086 { 2087 boost::system::error_code ec; 2088 ctx->bus->yield_method_call<void>( 2089 ctx->yield, ec, "xyz.openbmc_project.PSURedundancy", 2090 "/xyz/openbmc_project/control/power_supply_redundancy", 2091 "org.freedesktop.DBus.Properties", "Set", 2092 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value); 2093 if (ec) 2094 { 2095 phosphor::logging::log<phosphor::logging::level::ERR>( 2096 "Failed to set dbus property to cold redundancy"); 2097 return -1; 2098 } 2099 2100 return 0; 2101 } 2102 2103 int getCRConfig( 2104 ipmi::Context::ptr ctx, const std::string& property, crConfigVariant& value, 2105 const std::string& service = "xyz.openbmc_project.PSURedundancy", 2106 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT) 2107 { 2108 boost::system::error_code ec; 2109 value = ctx->bus->yield_method_call<crConfigVariant>( 2110 ctx->yield, ec, service, 2111 "/xyz/openbmc_project/control/power_supply_redundancy", 2112 "org.freedesktop.DBus.Properties", "Get", 2113 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property); 2114 if (ec) 2115 { 2116 phosphor::logging::log<phosphor::logging::level::ERR>( 2117 "Failed to get dbus property to cold redundancy"); 2118 return -1; 2119 } 2120 return 0; 2121 } 2122 2123 uint8_t getPSUCount(void) 2124 { 2125 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 2126 ipmi::Value num; 2127 try 2128 { 2129 num = ipmi::getDbusProperty( 2130 *dbus, "xyz.openbmc_project.PSURedundancy", 2131 "/xyz/openbmc_project/control/power_supply_redundancy", 2132 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber"); 2133 } 2134 catch (sdbusplus::exception_t& e) 2135 { 2136 phosphor::logging::log<phosphor::logging::level::ERR>( 2137 "Failed to get PSUNumber property from dbus interface"); 2138 return 0; 2139 } 2140 uint8_t* pNum = std::get_if<uint8_t>(&num); 2141 if (!pNum) 2142 { 2143 phosphor::logging::log<phosphor::logging::level::ERR>( 2144 "Error to get PSU Number"); 2145 return 0; 2146 } 2147 return *pNum; 2148 } 2149 2150 bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num) 2151 { 2152 if (conf.size() < num) 2153 { 2154 phosphor::logging::log<phosphor::logging::level::ERR>( 2155 "Invalid PSU Ranking"); 2156 return false; 2157 } 2158 std::set<uint8_t> confSet; 2159 for (uint8_t i = 0; i < num; i++) 2160 { 2161 if (conf[i] > num) 2162 { 2163 phosphor::logging::log<phosphor::logging::level::ERR>( 2164 "PSU Ranking is larger than current PSU number"); 2165 return false; 2166 } 2167 confSet.emplace(conf[i]); 2168 } 2169 2170 if (confSet.size() != num) 2171 { 2172 phosphor::logging::log<phosphor::logging::level::ERR>( 2173 "duplicate PSU Ranking"); 2174 return false; 2175 } 2176 return true; 2177 } 2178 2179 enum class crParameter 2180 { 2181 crStatus = 0, 2182 crFeature = 1, 2183 rotationFeature = 2, 2184 rotationAlgo = 3, 2185 rotationPeriod = 4, 2186 numOfPSU = 5, 2187 rotationRankOrderEffective = 6 2188 }; 2189 2190 constexpr ipmi::Cc ccParameterNotSupported = 0x80; 2191 static const constexpr uint32_t oneDay = 0x15180; 2192 static const constexpr uint32_t oneMonth = 0xf53700; 2193 static const constexpr uint8_t userSpecific = 0x01; 2194 static const constexpr uint8_t crSetCompleted = 0; 2195 ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx, 2196 uint8_t parameter, 2197 ipmi::message::Payload& payload) 2198 { 2199 switch (static_cast<crParameter>(parameter)) 2200 { 2201 case crParameter::rotationFeature: 2202 { 2203 uint8_t param1; 2204 if (payload.unpack(param1) || !payload.fullyUnpacked()) 2205 { 2206 return ipmi::responseReqDataLenInvalid(); 2207 } 2208 // Rotation Enable can only be true or false 2209 if (param1 > 1) 2210 { 2211 return ipmi::responseInvalidFieldRequest(); 2212 } 2213 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1))) 2214 { 2215 return ipmi::responseResponseError(); 2216 } 2217 break; 2218 } 2219 case crParameter::rotationAlgo: 2220 { 2221 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific 2222 std::string algoName; 2223 uint8_t param1; 2224 if (payload.unpack(param1)) 2225 { 2226 return ipmi::responseReqDataLenInvalid(); 2227 } 2228 switch (param1) 2229 { 2230 case 0: 2231 algoName = "xyz.openbmc_project.Control." 2232 "PowerSupplyRedundancy.Algo.bmcSpecific"; 2233 break; 2234 case 1: 2235 algoName = "xyz.openbmc_project.Control." 2236 "PowerSupplyRedundancy.Algo.userSpecific"; 2237 break; 2238 default: 2239 return ipmi::responseInvalidFieldRequest(); 2240 } 2241 if (setCRConfig(ctx, "RotationAlgorithm", algoName)) 2242 { 2243 return ipmi::responseResponseError(); 2244 } 2245 2246 uint8_t numberOfPSU = getPSUCount(); 2247 if (!numberOfPSU) 2248 { 2249 return ipmi::responseResponseError(); 2250 } 2251 std::vector<uint8_t> rankOrder; 2252 2253 if (param1 == userSpecific) 2254 { 2255 if (payload.unpack(rankOrder) || !payload.fullyUnpacked()) 2256 { 2257 ipmi::responseReqDataLenInvalid(); 2258 } 2259 if (rankOrder.size() != numberOfPSU) 2260 { 2261 return ipmi::responseReqDataLenInvalid(); 2262 } 2263 2264 if (!validateCRAlgo(rankOrder, numberOfPSU)) 2265 { 2266 return ipmi::responseInvalidFieldRequest(); 2267 } 2268 } 2269 else 2270 { 2271 if (rankOrder.size() > 0) 2272 { 2273 return ipmi::responseReqDataLenInvalid(); 2274 } 2275 for (uint8_t i = 1; i <= numberOfPSU; i++) 2276 { 2277 rankOrder.emplace_back(i); 2278 } 2279 } 2280 if (setCRConfig(ctx, "RotationRankOrder", rankOrder)) 2281 { 2282 return ipmi::responseResponseError(); 2283 } 2284 break; 2285 } 2286 case crParameter::rotationPeriod: 2287 { 2288 // Minimum Rotation period is One day (86400 seconds) and Max 2289 // Rotation Period is 6 month (0xf53700 seconds) 2290 uint32_t period; 2291 if (payload.unpack(period) || !payload.fullyUnpacked()) 2292 { 2293 return ipmi::responseReqDataLenInvalid(); 2294 } 2295 if ((period < oneDay) || (period > oneMonth)) 2296 { 2297 return ipmi::responseInvalidFieldRequest(); 2298 } 2299 if (setCRConfig(ctx, "PeriodOfRotation", period)) 2300 { 2301 return ipmi::responseResponseError(); 2302 } 2303 break; 2304 } 2305 default: 2306 { 2307 return ipmi::response(ccParameterNotSupported); 2308 } 2309 } 2310 2311 return ipmi::responseSuccess(crSetCompleted); 2312 } 2313 2314 ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>> 2315 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter) 2316 { 2317 crConfigVariant value; 2318 switch (static_cast<crParameter>(parameter)) 2319 { 2320 case crParameter::crStatus: 2321 { 2322 if (getCRConfig(ctx, "ColdRedundancyStatus", value)) 2323 { 2324 return ipmi::responseResponseError(); 2325 } 2326 std::string* pStatus = std::get_if<std::string>(&value); 2327 if (!pStatus) 2328 { 2329 phosphor::logging::log<phosphor::logging::level::ERR>( 2330 "Error to get ColdRedundancyStatus property"); 2331 return ipmi::responseResponseError(); 2332 } 2333 namespace server = sdbusplus::xyz::openbmc_project::Control::server; 2334 auto status = 2335 server::PowerSupplyRedundancy::convertStatusFromString( 2336 *pStatus); 2337 switch (status) 2338 { 2339 case server::PowerSupplyRedundancy::Status::inProgress: 2340 return ipmi::responseSuccess(parameter, 2341 static_cast<uint8_t>(1)); 2342 2343 case server::PowerSupplyRedundancy::Status::completed: 2344 return ipmi::responseSuccess(parameter, 2345 static_cast<uint8_t>(0)); 2346 default: 2347 phosphor::logging::log<phosphor::logging::level::ERR>( 2348 "Error to get valid status"); 2349 return ipmi::responseResponseError(); 2350 } 2351 } 2352 case crParameter::crFeature: 2353 { 2354 if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value)) 2355 { 2356 return ipmi::responseResponseError(); 2357 } 2358 bool* pResponse = std::get_if<bool>(&value); 2359 if (!pResponse) 2360 { 2361 phosphor::logging::log<phosphor::logging::level::ERR>( 2362 "Error to get PowerSupplyRedundancyEnabled property"); 2363 return ipmi::responseResponseError(); 2364 } 2365 2366 return ipmi::responseSuccess(parameter, 2367 static_cast<uint8_t>(*pResponse)); 2368 } 2369 case crParameter::rotationFeature: 2370 { 2371 if (getCRConfig(ctx, "RotationEnabled", value)) 2372 { 2373 return ipmi::responseResponseError(); 2374 } 2375 bool* pResponse = std::get_if<bool>(&value); 2376 if (!pResponse) 2377 { 2378 phosphor::logging::log<phosphor::logging::level::ERR>( 2379 "Error to get RotationEnabled property"); 2380 return ipmi::responseResponseError(); 2381 } 2382 return ipmi::responseSuccess(parameter, 2383 static_cast<uint8_t>(*pResponse)); 2384 } 2385 case crParameter::rotationAlgo: 2386 { 2387 if (getCRConfig(ctx, "RotationAlgorithm", value)) 2388 { 2389 return ipmi::responseResponseError(); 2390 } 2391 2392 std::string* pAlgo = std::get_if<std::string>(&value); 2393 if (!pAlgo) 2394 { 2395 phosphor::logging::log<phosphor::logging::level::ERR>( 2396 "Error to get RotationAlgorithm property"); 2397 return ipmi::responseResponseError(); 2398 } 2399 std::vector<uint8_t> response; 2400 namespace server = sdbusplus::xyz::openbmc_project::Control::server; 2401 auto algo = 2402 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo); 2403 2404 switch (algo) 2405 { 2406 case server::PowerSupplyRedundancy::Algo::bmcSpecific: 2407 response.push_back(0); 2408 break; 2409 case server::PowerSupplyRedundancy::Algo::userSpecific: 2410 response.push_back(1); 2411 break; 2412 default: 2413 phosphor::logging::log<phosphor::logging::level::ERR>( 2414 "Error to get valid algo"); 2415 return ipmi::responseResponseError(); 2416 } 2417 2418 if (getCRConfig(ctx, "RotationRankOrder", value)) 2419 { 2420 return ipmi::responseResponseError(); 2421 } 2422 std::vector<uint8_t>* pResponse = 2423 std::get_if<std::vector<uint8_t>>(&value); 2424 if (!pResponse) 2425 { 2426 phosphor::logging::log<phosphor::logging::level::ERR>( 2427 "Error to get RotationRankOrder property"); 2428 return ipmi::responseResponseError(); 2429 } 2430 2431 std::copy(pResponse->begin(), pResponse->end(), 2432 std::back_inserter(response)); 2433 2434 return ipmi::responseSuccess(parameter, response); 2435 } 2436 case crParameter::rotationPeriod: 2437 { 2438 if (getCRConfig(ctx, "PeriodOfRotation", value)) 2439 { 2440 return ipmi::responseResponseError(); 2441 } 2442 uint32_t* pResponse = std::get_if<uint32_t>(&value); 2443 if (!pResponse) 2444 { 2445 phosphor::logging::log<phosphor::logging::level::ERR>( 2446 "Error to get RotationAlgorithm property"); 2447 return ipmi::responseResponseError(); 2448 } 2449 return ipmi::responseSuccess(parameter, *pResponse); 2450 } 2451 case crParameter::numOfPSU: 2452 { 2453 uint8_t numberOfPSU = getPSUCount(); 2454 if (!numberOfPSU) 2455 { 2456 return ipmi::responseResponseError(); 2457 } 2458 return ipmi::responseSuccess(parameter, numberOfPSU); 2459 } 2460 case crParameter::rotationRankOrderEffective: 2461 { 2462 if (getCRConfig(ctx, "RotationRankOrder", value, 2463 "xyz.openbmc_project.PSURedundancy")) 2464 { 2465 return ipmi::responseResponseError(); 2466 } 2467 std::vector<uint8_t>* pResponse = 2468 std::get_if<std::vector<uint8_t>>(&value); 2469 if (!pResponse) 2470 { 2471 phosphor::logging::log<phosphor::logging::level::ERR>( 2472 "Error to get effective RotationRankOrder property"); 2473 return ipmi::responseResponseError(); 2474 } 2475 return ipmi::responseSuccess(parameter, *pResponse); 2476 } 2477 default: 2478 { 2479 return ipmi::response(ccParameterNotSupported); 2480 } 2481 } 2482 } 2483 2484 ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType, 2485 uint8_t faultState, 2486 uint8_t faultGroup, 2487 std::array<uint8_t, 8>& ledStateData) 2488 { 2489 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max); 2490 static const std::array<std::string, maxFaultType> faultNames = { 2491 "faultFan", "faultTemp", "faultPower", 2492 "faultDriveSlot", "faultSoftware", "faultMemory"}; 2493 2494 constexpr uint8_t maxFaultSource = 0x4; 2495 constexpr uint8_t skipLEDs = 0xFF; 2496 constexpr uint8_t pinSize = 64; 2497 constexpr uint8_t groupSize = 16; 2498 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan 2499 2500 // same pin names need to be defined in dts file 2501 static const std::array<std::array<std::string, groupSize>, groupNum> 2502 faultLedPinNames = {{ 2503 "LED_CPU1_CH1_DIMM1_FAULT", 2504 "LED_CPU1_CH1_DIMM2_FAULT", 2505 "LED_CPU1_CH2_DIMM1_FAULT", 2506 "LED_CPU1_CH2_DIMM2_FAULT", 2507 "LED_CPU1_CH3_DIMM1_FAULT", 2508 "LED_CPU1_CH3_DIMM2_FAULT", 2509 "LED_CPU1_CH4_DIMM1_FAULT", 2510 "LED_CPU1_CH4_DIMM2_FAULT", 2511 "LED_CPU1_CH5_DIMM1_FAULT", 2512 "LED_CPU1_CH5_DIMM2_FAULT", 2513 "LED_CPU1_CH6_DIMM1_FAULT", 2514 "LED_CPU1_CH6_DIMM2_FAULT", 2515 "", 2516 "", 2517 "", 2518 "", // end of group1 2519 "LED_CPU2_CH1_DIMM1_FAULT", 2520 "LED_CPU2_CH1_DIMM2_FAULT", 2521 "LED_CPU2_CH2_DIMM1_FAULT", 2522 "LED_CPU2_CH2_DIMM2_FAULT", 2523 "LED_CPU2_CH3_DIMM1_FAULT", 2524 "LED_CPU2_CH3_DIMM2_FAULT", 2525 "LED_CPU2_CH4_DIMM1_FAULT", 2526 "LED_CPU2_CH4_DIMM2_FAULT", 2527 "LED_CPU2_CH5_DIMM1_FAULT", 2528 "LED_CPU2_CH5_DIMM2_FAULT", 2529 "LED_CPU2_CH6_DIMM1_FAULT", 2530 "LED_CPU2_CH6_DIMM2_FAULT", 2531 "", 2532 "", 2533 "", 2534 "", // endof group2 2535 "LED_CPU3_CH1_DIMM1_FAULT", 2536 "LED_CPU3_CH1_DIMM2_FAULT", 2537 "LED_CPU3_CH2_DIMM1_FAULT", 2538 "LED_CPU3_CH2_DIMM2_FAULT", 2539 "LED_CPU3_CH3_DIMM1_FAULT", 2540 "LED_CPU3_CH3_DIMM2_FAULT", 2541 "LED_CPU3_CH4_DIMM1_FAULT", 2542 "LED_CPU3_CH4_DIMM2_FAULT", 2543 "LED_CPU3_CH5_DIMM1_FAULT", 2544 "LED_CPU3_CH5_DIMM2_FAULT", 2545 "LED_CPU3_CH6_DIMM1_FAULT", 2546 "LED_CPU3_CH6_DIMM2_FAULT", 2547 "", 2548 "", 2549 "", 2550 "", // end of group3 2551 "LED_CPU4_CH1_DIMM1_FAULT", 2552 "LED_CPU4_CH1_DIMM2_FAULT", 2553 "LED_CPU4_CH2_DIMM1_FAULT", 2554 "LED_CPU4_CH2_DIMM2_FAULT", 2555 "LED_CPU4_CH3_DIMM1_FAULT", 2556 "LED_CPU4_CH3_DIMM2_FAULT", 2557 "LED_CPU4_CH4_DIMM1_FAULT", 2558 "LED_CPU4_CH4_DIMM2_FAULT", 2559 "LED_CPU4_CH5_DIMM1_FAULT", 2560 "LED_CPU4_CH5_DIMM2_FAULT", 2561 "LED_CPU4_CH6_DIMM1_FAULT", 2562 "LED_CPU4_CH6_DIMM2_FAULT", 2563 "", 2564 "", 2565 "", 2566 "", // end of group4 2567 "LED_FAN1_FAULT", 2568 "LED_FAN2_FAULT", 2569 "LED_FAN3_FAULT", 2570 "LED_FAN4_FAULT", 2571 "LED_FAN5_FAULT", 2572 "LED_FAN6_FAULT", 2573 "LED_FAN7_FAULT", 2574 "LED_FAN8_FAULT", 2575 "", 2576 "", 2577 "", 2578 "", 2579 "", 2580 "", 2581 "", 2582 "" // end of group5 2583 }}; 2584 2585 // Validate the source, fault type -- 2586 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap 2587 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power, 2588 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded, 2589 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup, 2590 // definition differs based on fault type (Byte 2) 2591 // Type Fan=> Group: 0=FanGroupID, FF-not used 2592 // Byte 5-11 00h, not used 2593 // Byte12 FanLedState [7:0]-Fans 7:0 2594 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used 2595 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first) 2596 // [63:48] = CPU4 channels 7:0, 2 bits per channel 2597 // [47:32] = CPU3 channels 7:0, 2 bits per channel 2598 // [31:16] = CPU2 channels 7:0, 2 bits per channel 2599 // [15:0] = CPU1 channels 7:0, 2 bits per channel 2600 // Type Other=> Component Fault LED Group ID, not used set to 0xFF 2601 // Byte[5:12]: reserved 0x00h 2602 if ((sourceId >= maxFaultSource) || 2603 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) || 2604 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) || 2605 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup))) 2606 { 2607 return ipmi::responseParmOutOfRange(); 2608 } 2609 2610 size_t pinGroupOffset = 0; 2611 size_t pinGroupMax = pinSize / groupSize; 2612 if (RemoteFaultType::fan == RemoteFaultType(faultType)) 2613 { 2614 pinGroupOffset = 4; 2615 pinGroupMax = groupNum - pinSize / groupSize; 2616 } 2617 2618 switch (RemoteFaultType(faultType)) 2619 { 2620 case (RemoteFaultType::fan): 2621 case (RemoteFaultType::memory): 2622 { 2623 if (faultGroup == skipLEDs) 2624 { 2625 return ipmi::responseSuccess(); 2626 } 2627 // calculate led state bit filed count, each byte has 8bits 2628 // the maximum bits will be 8 * 8 bits 2629 constexpr uint8_t size = sizeof(ledStateData) * 8; 2630 2631 // assemble ledState 2632 uint64_t ledState = 0; 2633 bool hasError = false; 2634 for (int i = 0; i < sizeof(ledStateData); i++) 2635 { 2636 ledState = (uint64_t)(ledState << 8); 2637 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]); 2638 } 2639 std::bitset<size> ledStateBits(ledState); 2640 2641 for (int group = 0; group < pinGroupMax; group++) 2642 { 2643 for (int i = 0; i < groupSize; i++) 2644 { // skip non-existing pins 2645 if (0 == faultLedPinNames[group + pinGroupOffset][i].size()) 2646 { 2647 continue; 2648 } 2649 2650 gpiod::line line = gpiod::find_line( 2651 faultLedPinNames[group + pinGroupOffset][i]); 2652 if (!line) 2653 { 2654 phosphor::logging::log<phosphor::logging::level::ERR>( 2655 "Not Find Led Gpio Device!", 2656 phosphor::logging::entry( 2657 "DEVICE=%s", 2658 faultLedPinNames[group + pinGroupOffset][i] 2659 .c_str())); 2660 hasError = true; 2661 continue; 2662 } 2663 2664 bool activeHigh = 2665 (line.active_state() == gpiod::line::ACTIVE_HIGH); 2666 try 2667 { 2668 line.request( 2669 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT, 2670 activeHigh 2671 ? 0 2672 : gpiod::line_request::FLAG_ACTIVE_LOW}); 2673 line.set_value(ledStateBits[i + group * groupSize]); 2674 } 2675 catch (std::system_error&) 2676 { 2677 phosphor::logging::log<phosphor::logging::level::ERR>( 2678 "Error write Led Gpio Device!", 2679 phosphor::logging::entry( 2680 "DEVICE=%s", 2681 faultLedPinNames[group + pinGroupOffset][i] 2682 .c_str())); 2683 hasError = true; 2684 continue; 2685 } 2686 } // for int i 2687 } 2688 if (hasError) 2689 { 2690 return ipmi::responseResponseError(); 2691 } 2692 break; 2693 } 2694 default: 2695 { 2696 // now only support two fault types 2697 return ipmi::responseParmOutOfRange(); 2698 } 2699 } // switch 2700 return ipmi::responseSuccess(); 2701 } 2702 2703 ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId() 2704 { 2705 uint8_t prodId = 0; 2706 try 2707 { 2708 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 2709 const DbusObjectInfo& object = getDbusObject( 2710 *dbus, "xyz.openbmc_project.Inventory.Item.Board", 2711 "/xyz/openbmc_project/inventory/system/board/", "Baseboard"); 2712 const Value& propValue = getDbusProperty( 2713 *dbus, object.second, object.first, 2714 "xyz.openbmc_project.Inventory.Item.Board.Motherboard", 2715 "ProductId"); 2716 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue)); 2717 } 2718 catch (std::exception& e) 2719 { 2720 phosphor::logging::log<phosphor::logging::level::ERR>( 2721 "ipmiOEMReadBoardProductId: Product ID read failed!", 2722 phosphor::logging::entry("ERR=%s", e.what())); 2723 } 2724 return ipmi::responseSuccess(prodId); 2725 } 2726 2727 /** @brief implements the get security mode command 2728 * @param ctx - ctx pointer 2729 * 2730 * @returns IPMI completion code with following data 2731 * - restriction mode value - As specified in 2732 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml 2733 * - special mode value - As specified in 2734 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml 2735 */ 2736 ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx) 2737 { 2738 namespace securityNameSpace = 2739 sdbusplus::xyz::openbmc_project::Control::Security::server; 2740 uint8_t restrictionModeValue = 0; 2741 uint8_t specialModeValue = 0; 2742 2743 boost::system::error_code ec; 2744 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>( 2745 ctx->yield, ec, restricionModeService, restricionModeBasePath, 2746 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf, 2747 restricionModeProperty); 2748 if (ec) 2749 { 2750 phosphor::logging::log<phosphor::logging::level::ERR>( 2751 "ipmiGetSecurityMode: failed to get RestrictionMode property", 2752 phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 2753 return ipmi::responseUnspecifiedError(); 2754 } 2755 restrictionModeValue = static_cast<uint8_t>( 2756 securityNameSpace::RestrictionMode::convertModesFromString( 2757 std::get<std::string>(varRestrMode))); 2758 auto varSpecialMode = 2759 ctx->bus->yield_method_call<std::variant<std::string>>( 2760 ctx->yield, ec, specialModeService, specialModeBasePath, 2761 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf, 2762 specialModeProperty); 2763 if (ec) 2764 { 2765 phosphor::logging::log<phosphor::logging::level::ERR>( 2766 "ipmiGetSecurityMode: failed to get SpecialMode property", 2767 phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 2768 // fall through, let us not worry about SpecialMode property, which is 2769 // not required in user scenario 2770 } 2771 else 2772 { 2773 specialModeValue = static_cast<uint8_t>( 2774 securityNameSpace::SpecialMode::convertModesFromString( 2775 std::get<std::string>(varSpecialMode))); 2776 } 2777 return ipmi::responseSuccess(restrictionModeValue, specialModeValue); 2778 } 2779 2780 /** @brief implements the set security mode command 2781 * Command allows to upgrade the restriction mode and won't allow 2782 * to downgrade from system interface 2783 * @param ctx - ctx pointer 2784 * @param restrictionMode - restriction mode value to be set. 2785 * 2786 * @returns IPMI completion code 2787 */ 2788 ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx, 2789 uint8_t restrictionMode, 2790 std::optional<uint8_t> specialMode) 2791 { 2792 #ifndef BMC_VALIDATION_UNSECURE_FEATURE 2793 if (specialMode) 2794 { 2795 return ipmi::responseReqDataLenInvalid(); 2796 } 2797 #endif 2798 namespace securityNameSpace = 2799 sdbusplus::xyz::openbmc_project::Control::Security::server; 2800 2801 ChannelInfo chInfo; 2802 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess) 2803 { 2804 phosphor::logging::log<phosphor::logging::level::ERR>( 2805 "ipmiSetSecurityMode: Failed to get Channel Info", 2806 phosphor::logging::entry("CHANNEL=%d", ctx->channel)); 2807 return ipmi::responseUnspecifiedError(); 2808 } 2809 auto reqMode = 2810 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode); 2811 2812 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) || 2813 (reqMode > 2814 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled)) 2815 { 2816 return ipmi::responseInvalidFieldRequest(); 2817 } 2818 2819 boost::system::error_code ec; 2820 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>( 2821 ctx->yield, ec, restricionModeService, restricionModeBasePath, 2822 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf, 2823 restricionModeProperty); 2824 if (ec) 2825 { 2826 phosphor::logging::log<phosphor::logging::level::ERR>( 2827 "ipmiSetSecurityMode: failed to get RestrictionMode property", 2828 phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 2829 return ipmi::responseUnspecifiedError(); 2830 } 2831 auto currentRestrictionMode = 2832 securityNameSpace::RestrictionMode::convertModesFromString( 2833 std::get<std::string>(varRestrMode)); 2834 2835 if (chInfo.mediumType != 2836 static_cast<uint8_t>(EChannelMediumType::lan8032) && 2837 currentRestrictionMode > reqMode) 2838 { 2839 phosphor::logging::log<phosphor::logging::level::ERR>( 2840 "ipmiSetSecurityMode - Downgrading security mode not supported " 2841 "through system interface", 2842 phosphor::logging::entry( 2843 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)), 2844 phosphor::logging::entry("REQ_MODE=%d", restrictionMode)); 2845 return ipmi::responseCommandNotAvailable(); 2846 } 2847 2848 ec.clear(); 2849 ctx->bus->yield_method_call<>( 2850 ctx->yield, ec, restricionModeService, restricionModeBasePath, 2851 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf, 2852 restricionModeProperty, 2853 static_cast<std::variant<std::string>>( 2854 securityNameSpace::convertForMessage(reqMode))); 2855 2856 if (ec) 2857 { 2858 phosphor::logging::log<phosphor::logging::level::ERR>( 2859 "ipmiSetSecurityMode: failed to set RestrictionMode property", 2860 phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 2861 return ipmi::responseUnspecifiedError(); 2862 } 2863 2864 #ifdef BMC_VALIDATION_UNSECURE_FEATURE 2865 if (specialMode) 2866 { 2867 constexpr uint8_t mfgMode = 0x01; 2868 // Manufacturing mode is reserved. So can't enable this mode. 2869 if (specialMode.value() == mfgMode) 2870 { 2871 phosphor::logging::log<phosphor::logging::level::INFO>( 2872 "ipmiSetSecurityMode: Can't enable Manufacturing mode"); 2873 return ipmi::responseInvalidFieldRequest(); 2874 } 2875 2876 ec.clear(); 2877 ctx->bus->yield_method_call<>( 2878 ctx->yield, ec, specialModeService, specialModeBasePath, 2879 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf, 2880 specialModeProperty, 2881 static_cast<std::variant<std::string>>( 2882 securityNameSpace::convertForMessage( 2883 static_cast<securityNameSpace::SpecialMode::Modes>( 2884 specialMode.value())))); 2885 2886 if (ec) 2887 { 2888 phosphor::logging::log<phosphor::logging::level::ERR>( 2889 "ipmiSetSecurityMode: failed to set SpecialMode property", 2890 phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 2891 return ipmi::responseUnspecifiedError(); 2892 } 2893 } 2894 #endif 2895 return ipmi::responseSuccess(); 2896 } 2897 2898 ipmi::RspType<uint8_t /* restore status */> 2899 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd) 2900 { 2901 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'}; 2902 2903 if (clr != expClr) 2904 { 2905 return ipmi::responseInvalidFieldRequest(); 2906 } 2907 constexpr uint8_t cmdStatus = 0; 2908 constexpr uint8_t cmdDefaultRestore = 0xaa; 2909 constexpr uint8_t cmdFullRestore = 0xbb; 2910 constexpr uint8_t cmdFormat = 0xcc; 2911 2912 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op"; 2913 2914 switch (cmd) 2915 { 2916 case cmdStatus: 2917 break; 2918 case cmdDefaultRestore: 2919 case cmdFullRestore: 2920 case cmdFormat: 2921 { 2922 // write file to rwfs root 2923 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3 2924 std::ofstream restoreFile(restoreOpFname); 2925 if (!restoreFile) 2926 { 2927 return ipmi::responseUnspecifiedError(); 2928 } 2929 restoreFile << value << "\n"; 2930 2931 phosphor::logging::log<phosphor::logging::level::WARNING>( 2932 "Restore to default will be performed on next BMC boot", 2933 phosphor::logging::entry("ACTION=0x%0X", cmd)); 2934 2935 break; 2936 } 2937 default: 2938 return ipmi::responseInvalidFieldRequest(); 2939 } 2940 2941 constexpr uint8_t restorePending = 0; 2942 constexpr uint8_t restoreComplete = 1; 2943 2944 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname) 2945 ? restorePending 2946 : restoreComplete; 2947 return ipmi::responseSuccess(restoreStatus); 2948 } 2949 2950 ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void) 2951 { 2952 uint8_t bmcSource; 2953 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server; 2954 2955 try 2956 { 2957 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 2958 std::string service = 2959 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath); 2960 Value variant = 2961 getDbusProperty(*dbus, service, oemNmiSourceObjPath, 2962 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp); 2963 2964 switch (nmi::NMISource::convertBMCSourceSignalFromString( 2965 std::get<std::string>(variant))) 2966 { 2967 case nmi::NMISource::BMCSourceSignal::None: 2968 bmcSource = static_cast<uint8_t>(NmiSource::none); 2969 break; 2970 case nmi::NMISource::BMCSourceSignal::FrontPanelButton: 2971 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton); 2972 break; 2973 case nmi::NMISource::BMCSourceSignal::Watchdog: 2974 bmcSource = static_cast<uint8_t>(NmiSource::watchdog); 2975 break; 2976 case nmi::NMISource::BMCSourceSignal::ChassisCmd: 2977 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd); 2978 break; 2979 case nmi::NMISource::BMCSourceSignal::MemoryError: 2980 bmcSource = static_cast<uint8_t>(NmiSource::memoryError); 2981 break; 2982 case nmi::NMISource::BMCSourceSignal::PciBusError: 2983 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError); 2984 break; 2985 case nmi::NMISource::BMCSourceSignal::PCH: 2986 bmcSource = static_cast<uint8_t>(NmiSource::pch); 2987 break; 2988 case nmi::NMISource::BMCSourceSignal::Chipset: 2989 bmcSource = static_cast<uint8_t>(NmiSource::chipset); 2990 break; 2991 default: 2992 phosphor::logging::log<phosphor::logging::level::ERR>( 2993 "NMI source: invalid property!", 2994 phosphor::logging::entry( 2995 "PROP=%s", std::get<std::string>(variant).c_str())); 2996 return ipmi::responseResponseError(); 2997 } 2998 } 2999 catch (sdbusplus::exception::SdBusError& e) 3000 { 3001 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 3002 return ipmi::responseResponseError(); 3003 } 3004 3005 return ipmi::responseSuccess(bmcSource); 3006 } 3007 3008 ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId) 3009 { 3010 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server; 3011 3012 nmi::NMISource::BMCSourceSignal bmcSourceSignal = 3013 nmi::NMISource::BMCSourceSignal::None; 3014 3015 switch (NmiSource(sourceId)) 3016 { 3017 case NmiSource::none: 3018 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None; 3019 break; 3020 case NmiSource::frontPanelButton: 3021 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton; 3022 break; 3023 case NmiSource::watchdog: 3024 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog; 3025 break; 3026 case NmiSource::chassisCmd: 3027 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd; 3028 break; 3029 case NmiSource::memoryError: 3030 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError; 3031 break; 3032 case NmiSource::pciBusError: 3033 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError; 3034 break; 3035 case NmiSource::pch: 3036 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH; 3037 break; 3038 case NmiSource::chipset: 3039 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset; 3040 break; 3041 default: 3042 phosphor::logging::log<phosphor::logging::level::ERR>( 3043 "NMI source: invalid property!"); 3044 return ipmi::responseResponseError(); 3045 } 3046 3047 try 3048 { 3049 // keep NMI signal source 3050 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 3051 std::string service = 3052 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath); 3053 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf, 3054 oemNmiBmcSourceObjPathProp, 3055 nmi::convertForMessage(bmcSourceSignal)); 3056 // set Enabled property to inform NMI source handling 3057 // to trigger a NMI_OUT BSOD. 3058 // if it's triggered by NMI source property changed, 3059 // NMI_OUT BSOD could be missed if the same source occurs twice in a row 3060 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None) 3061 { 3062 setDbusProperty(*dbus, service, oemNmiSourceObjPath, 3063 oemNmiSourceIntf, oemNmiEnabledObjPathProp, 3064 static_cast<bool>(true)); 3065 } 3066 } 3067 catch (sdbusplus::exception_t& e) 3068 { 3069 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 3070 return ipmi::responseResponseError(); 3071 } 3072 3073 return ipmi::responseSuccess(); 3074 } 3075 3076 namespace dimmOffset 3077 { 3078 constexpr const char* dimmPower = "DimmPower"; 3079 constexpr const char* staticCltt = "StaticCltt"; 3080 constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm"; 3081 constexpr const char* offsetInterface = 3082 "xyz.openbmc_project.Inventory.Item.Dimm.Offset"; 3083 constexpr const char* property = "DimmOffset"; 3084 3085 }; // namespace dimmOffset 3086 3087 ipmi::RspType<> 3088 ipmiOEMSetDimmOffset(uint8_t type, 3089 const std::vector<std::tuple<uint8_t, uint8_t>>& data) 3090 { 3091 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) && 3092 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt)) 3093 { 3094 return ipmi::responseInvalidFieldRequest(); 3095 } 3096 3097 if (data.empty()) 3098 { 3099 return ipmi::responseInvalidFieldRequest(); 3100 } 3101 nlohmann::json json; 3102 3103 std::ifstream jsonStream(dimmOffsetFile); 3104 if (jsonStream.good()) 3105 { 3106 json = nlohmann::json::parse(jsonStream, nullptr, false); 3107 if (json.is_discarded()) 3108 { 3109 json = nlohmann::json(); 3110 } 3111 jsonStream.close(); 3112 } 3113 3114 std::string typeName; 3115 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower)) 3116 { 3117 typeName = dimmOffset::dimmPower; 3118 } 3119 else 3120 { 3121 typeName = dimmOffset::staticCltt; 3122 } 3123 3124 nlohmann::json& field = json[typeName]; 3125 3126 for (const auto& [index, value] : data) 3127 { 3128 field[index] = value; 3129 } 3130 3131 for (nlohmann::json& val : field) 3132 { 3133 if (val == nullptr) 3134 { 3135 val = static_cast<uint8_t>(0); 3136 } 3137 } 3138 3139 std::ofstream output(dimmOffsetFile); 3140 if (!output.good()) 3141 { 3142 std::cerr << "Error writing json file\n"; 3143 return ipmi::responseResponseError(); 3144 } 3145 3146 output << json.dump(4); 3147 3148 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt)) 3149 { 3150 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 3151 3152 std::variant<std::vector<uint8_t>> offsets = 3153 field.get<std::vector<uint8_t>>(); 3154 auto call = bus->new_method_call( 3155 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set"); 3156 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets); 3157 try 3158 { 3159 bus->call(call); 3160 } 3161 catch (sdbusplus::exception_t& e) 3162 { 3163 phosphor::logging::log<phosphor::logging::level::ERR>( 3164 "ipmiOEMSetDimmOffset: can't set dimm offsets!", 3165 phosphor::logging::entry("ERR=%s", e.what())); 3166 return ipmi::responseResponseError(); 3167 } 3168 } 3169 3170 return ipmi::responseSuccess(); 3171 } 3172 3173 ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index) 3174 { 3175 3176 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) && 3177 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt)) 3178 { 3179 return ipmi::responseInvalidFieldRequest(); 3180 } 3181 3182 std::ifstream jsonStream(dimmOffsetFile); 3183 3184 auto json = nlohmann::json::parse(jsonStream, nullptr, false); 3185 if (json.is_discarded()) 3186 { 3187 std::cerr << "File error in " << dimmOffsetFile << "\n"; 3188 return ipmi::responseResponseError(); 3189 } 3190 3191 std::string typeName; 3192 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower)) 3193 { 3194 typeName = dimmOffset::dimmPower; 3195 } 3196 else 3197 { 3198 typeName = dimmOffset::staticCltt; 3199 } 3200 3201 auto it = json.find(typeName); 3202 if (it == json.end()) 3203 { 3204 return ipmi::responseInvalidFieldRequest(); 3205 } 3206 3207 if (it->size() <= index) 3208 { 3209 return ipmi::responseInvalidFieldRequest(); 3210 } 3211 3212 uint8_t resp = it->at(index).get<uint8_t>(); 3213 return ipmi::responseSuccess(resp); 3214 } 3215 3216 namespace boot_options 3217 { 3218 3219 using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server; 3220 using IpmiValue = uint8_t; 3221 constexpr auto ipmiDefault = 0; 3222 3223 std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = { 3224 {0x01, Source::Sources::Network}, 3225 {0x02, Source::Sources::Disk}, 3226 {0x05, Source::Sources::ExternalMedia}, 3227 {0x0f, Source::Sources::RemovableMedia}, 3228 {ipmiDefault, Source::Sources::Default}}; 3229 3230 std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = { 3231 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}}; 3232 3233 std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = { 3234 {Source::Sources::Network, 0x01}, 3235 {Source::Sources::Disk, 0x02}, 3236 {Source::Sources::ExternalMedia, 0x05}, 3237 {Source::Sources::RemovableMedia, 0x0f}, 3238 {Source::Sources::Default, ipmiDefault}}; 3239 3240 std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = { 3241 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}}; 3242 3243 static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode"; 3244 static constexpr auto bootSourceIntf = 3245 "xyz.openbmc_project.Control.Boot.Source"; 3246 static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable"; 3247 static constexpr auto persistentObjPath = 3248 "/xyz/openbmc_project/control/host0/boot"; 3249 static constexpr auto oneTimePath = 3250 "/xyz/openbmc_project/control/host0/boot/one_time"; 3251 static constexpr auto bootSourceProp = "BootSource"; 3252 static constexpr auto bootModeProp = "BootMode"; 3253 static constexpr auto oneTimeBootEnableProp = "Enabled"; 3254 static constexpr auto httpBootMode = 3255 "xyz.openbmc_project.Control.Boot.Source.Sources.Http"; 3256 3257 enum class BootOptionParameter : size_t 3258 { 3259 setInProgress = 0x0, 3260 bootFlags = 0x5, 3261 }; 3262 static constexpr uint8_t setComplete = 0x0; 3263 static constexpr uint8_t setInProgress = 0x1; 3264 static uint8_t transferStatus = setComplete; 3265 static constexpr uint8_t setParmVersion = 0x01; 3266 static constexpr uint8_t setParmBootFlagsPermanent = 0x40; 3267 static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80; 3268 static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0; 3269 static constexpr uint8_t httpBoot = 0xd; 3270 static constexpr uint8_t bootSourceMask = 0x3c; 3271 3272 } // namespace boot_options 3273 3274 ipmi::RspType<uint8_t, // version 3275 uint8_t, // param 3276 uint8_t, // data0, dependent on parameter 3277 std::optional<uint8_t> // data1, dependent on parameter 3278 > 3279 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block) 3280 { 3281 using namespace boot_options; 3282 uint8_t bootOption = 0; 3283 3284 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress)) 3285 { 3286 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus, 3287 std::nullopt); 3288 } 3289 3290 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags)) 3291 { 3292 phosphor::logging::log<phosphor::logging::level::ERR>( 3293 "Unsupported parameter"); 3294 return ipmi::responseResponseError(); 3295 } 3296 3297 try 3298 { 3299 auto oneTimeEnabled = false; 3300 // read one time Enabled property 3301 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 3302 std::string service = getService(*dbus, enabledIntf, oneTimePath); 3303 Value variant = getDbusProperty(*dbus, service, oneTimePath, 3304 enabledIntf, oneTimeBootEnableProp); 3305 oneTimeEnabled = std::get<bool>(variant); 3306 3307 // get BootSource and BootMode properties 3308 // according to oneTimeEnable 3309 auto bootObjPath = oneTimePath; 3310 if (oneTimeEnabled == false) 3311 { 3312 bootObjPath = persistentObjPath; 3313 } 3314 3315 service = getService(*dbus, bootModeIntf, bootObjPath); 3316 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf, 3317 bootModeProp); 3318 3319 auto bootMode = 3320 Mode::convertModesFromString(std::get<std::string>(variant)); 3321 3322 service = getService(*dbus, bootSourceIntf, bootObjPath); 3323 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf, 3324 bootSourceProp); 3325 3326 if (std::get<std::string>(variant) == httpBootMode) 3327 { 3328 bootOption = httpBoot; 3329 } 3330 else 3331 { 3332 auto bootSource = Source::convertSourcesFromString( 3333 std::get<std::string>(variant)); 3334 bootOption = sourceDbusToIpmi.at(bootSource); 3335 if (Source::Sources::Default == bootSource) 3336 { 3337 bootOption = modeDbusToIpmi.at(bootMode); 3338 } 3339 } 3340 3341 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime 3342 : setParmBootFlagsValidPermanent; 3343 bootOption <<= 2; // shift for responseconstexpr 3344 return ipmi::responseSuccess(setParmVersion, parameter, oneTime, 3345 bootOption); 3346 } 3347 catch (sdbusplus::exception_t& e) 3348 { 3349 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 3350 return ipmi::responseResponseError(); 3351 } 3352 } 3353 3354 ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam, 3355 std::optional<uint8_t> bootOption) 3356 { 3357 using namespace boot_options; 3358 auto oneTimeEnabled = false; 3359 3360 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress)) 3361 { 3362 if (bootOption) 3363 { 3364 return ipmi::responseReqDataLenInvalid(); 3365 } 3366 3367 if (transferStatus == setInProgress) 3368 { 3369 phosphor::logging::log<phosphor::logging::level::ERR>( 3370 "boot option set in progress!"); 3371 return ipmi::responseResponseError(); 3372 } 3373 3374 transferStatus = bootParam; 3375 return ipmi::responseSuccess(); 3376 } 3377 3378 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags) 3379 { 3380 phosphor::logging::log<phosphor::logging::level::ERR>( 3381 "Unsupported parameter"); 3382 return ipmi::responseResponseError(); 3383 } 3384 3385 if (!bootOption) 3386 { 3387 return ipmi::responseReqDataLenInvalid(); 3388 } 3389 3390 if (((bootOption.value() & bootSourceMask) >> 2) != 3391 httpBoot) // not http boot, exit 3392 { 3393 phosphor::logging::log<phosphor::logging::level::ERR>( 3394 "wrong boot option parameter!"); 3395 return ipmi::responseParmOutOfRange(); 3396 } 3397 3398 try 3399 { 3400 bool permanent = (bootParam & setParmBootFlagsPermanent) == 3401 setParmBootFlagsPermanent; 3402 3403 // read one time Enabled property 3404 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 3405 std::string service = getService(*dbus, enabledIntf, oneTimePath); 3406 Value variant = getDbusProperty(*dbus, service, oneTimePath, 3407 enabledIntf, oneTimeBootEnableProp); 3408 oneTimeEnabled = std::get<bool>(variant); 3409 3410 /* 3411 * Check if the current boot setting is onetime or permanent, if the 3412 * request in the command is otherwise, then set the "Enabled" 3413 * property in one_time object path to 'True' to indicate onetime 3414 * and 'False' to indicate permanent. 3415 * 3416 * Once the onetime/permanent setting is applied, then the bootMode 3417 * and bootSource is updated for the corresponding object. 3418 */ 3419 if (permanent == oneTimeEnabled) 3420 { 3421 setDbusProperty(*dbus, service, oneTimePath, enabledIntf, 3422 oneTimeBootEnableProp, !permanent); 3423 } 3424 3425 // set BootSource and BootMode properties 3426 // according to oneTimeEnable or persistent 3427 auto bootObjPath = oneTimePath; 3428 if (oneTimeEnabled == false) 3429 { 3430 bootObjPath = persistentObjPath; 3431 } 3432 std::string bootMode = 3433 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 3434 std::string bootSource = httpBootMode; 3435 3436 service = getService(*dbus, bootModeIntf, bootObjPath); 3437 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp, 3438 bootMode); 3439 3440 service = getService(*dbus, bootSourceIntf, bootObjPath); 3441 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf, 3442 bootSourceProp, bootSource); 3443 } 3444 catch (sdbusplus::exception_t& e) 3445 { 3446 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 3447 return ipmi::responseResponseError(); 3448 } 3449 3450 return ipmi::responseSuccess(); 3451 } 3452 3453 using BasicVariantType = 3454 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string, 3455 int64_t, uint64_t, double, int32_t, uint32_t, int16_t, 3456 uint16_t, uint8_t, bool>; 3457 using PropertyMapType = 3458 boost::container::flat_map<std::string, BasicVariantType>; 3459 static constexpr const std::array<const char*, 1> psuPresenceTypes = { 3460 "xyz.openbmc_project.Configuration.PSUPresence"}; 3461 int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus, 3462 std::vector<uint64_t>& addrTable) 3463 { 3464 boost::system::error_code ec; 3465 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>( 3466 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper", 3467 "/xyz/openbmc_project/object_mapper", 3468 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 3469 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes); 3470 if (ec) 3471 { 3472 phosphor::logging::log<phosphor::logging::level::ERR>( 3473 "Failed to set dbus property to cold redundancy"); 3474 return -1; 3475 } 3476 for (const auto& object : subtree) 3477 { 3478 std::string pathName = object.first; 3479 for (const auto& serviceIface : object.second) 3480 { 3481 std::string serviceName = serviceIface.first; 3482 3483 ec.clear(); 3484 PropertyMapType propMap = 3485 ctx->bus->yield_method_call<PropertyMapType>( 3486 ctx->yield, ec, serviceName, pathName, 3487 "org.freedesktop.DBus.Properties", "GetAll", 3488 "xyz.openbmc_project.Configuration.PSUPresence"); 3489 if (ec) 3490 { 3491 phosphor::logging::log<phosphor::logging::level::ERR>( 3492 "Failed to set dbus property to cold redundancy"); 3493 return -1; 3494 } 3495 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]); 3496 auto psuAddress = 3497 std::get_if<std::vector<uint64_t>>(&propMap["Address"]); 3498 3499 if (psuBus == nullptr || psuAddress == nullptr) 3500 { 3501 std::cerr << "error finding necessary " 3502 "entry in configuration\n"; 3503 return -1; 3504 } 3505 bus = static_cast<uint8_t>(*psuBus); 3506 addrTable = *psuAddress; 3507 return 0; 3508 } 3509 } 3510 return -1; 3511 } 3512 3513 static const constexpr uint8_t addrOffset = 8; 3514 static const constexpr uint8_t psuRevision = 0xd9; 3515 static const constexpr uint8_t defaultPSUBus = 7; 3516 // Second Minor, Primary Minor, Major 3517 static const constexpr size_t verLen = 3; 3518 ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx) 3519 { 3520 uint8_t bus = defaultPSUBus; 3521 std::vector<uint64_t> addrTable; 3522 std::vector<uint8_t> result; 3523 if (getPSUAddress(ctx, bus, addrTable)) 3524 { 3525 std::cerr << "Failed to get PSU bus and address\n"; 3526 return ipmi::responseResponseError(); 3527 } 3528 3529 for (const auto& slaveAddr : addrTable) 3530 { 3531 std::vector<uint8_t> writeData = {psuRevision}; 3532 std::vector<uint8_t> readBuf(verLen); 3533 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset; 3534 std::string i2cBus = "/dev/i2c-" + std::to_string(bus); 3535 3536 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf); 3537 if (retI2C != ipmi::ccSuccess) 3538 { 3539 for (size_t idx = 0; idx < verLen; idx++) 3540 { 3541 result.emplace_back(0x00); 3542 } 3543 } 3544 else 3545 { 3546 for (const uint8_t& data : readBuf) 3547 { 3548 result.emplace_back(data); 3549 } 3550 } 3551 } 3552 3553 return ipmi::responseSuccess(result); 3554 } 3555 3556 std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr ctx, 3557 const std::string& name) 3558 { 3559 Value dbusValue = 0; 3560 std::string serviceName; 3561 3562 boost::system::error_code ec = 3563 ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName); 3564 3565 if (ec) 3566 { 3567 phosphor::logging::log<phosphor::logging::level::ERR>( 3568 "Failed to perform Multinode getService."); 3569 return std::nullopt; 3570 } 3571 3572 ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath, 3573 multiNodeIntf, name, dbusValue); 3574 if (ec) 3575 { 3576 phosphor::logging::log<phosphor::logging::level::ERR>( 3577 "Failed to perform Multinode get property"); 3578 return std::nullopt; 3579 } 3580 3581 auto multiNodeVal = std::get_if<uint8_t>(&dbusValue); 3582 if (!multiNodeVal) 3583 { 3584 phosphor::logging::log<phosphor::logging::level::ERR>( 3585 "getMultiNodeInfoPresence: error to get multinode"); 3586 return std::nullopt; 3587 } 3588 return *multiNodeVal; 3589 } 3590 3591 /** @brief implements OEM get reading command 3592 * @param domain ID 3593 * @param reading Type 3594 * - 00h = platform Power Consumption 3595 * - 01h = inlet Air Temp 3596 * - 02h = icc_TDC from PECI 3597 * @param reserved, write as 0000h 3598 * 3599 * @returns IPMI completion code plus response data 3600 * - response 3601 * - domain ID 3602 * - reading Type 3603 * - 00h = platform Power Consumption 3604 * - 01h = inlet Air Temp 3605 * - 02h = icc_TDC from PECI 3606 * - reading 3607 */ 3608 ipmi::RspType<uint4_t, // domain ID 3609 uint4_t, // reading Type 3610 uint16_t // reading Value 3611 > 3612 ipmiOEMGetReading(ipmi::Context::ptr ctx, uint4_t domainId, 3613 uint4_t readingType, uint16_t reserved) 3614 { 3615 constexpr uint8_t platformPower = 0; 3616 constexpr uint8_t inletAirTemp = 1; 3617 constexpr uint8_t iccTdc = 2; 3618 3619 if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved) 3620 { 3621 return ipmi::responseInvalidFieldRequest(); 3622 } 3623 3624 // This command should run only from multi-node product. 3625 // For all other platforms this command will return invalid. 3626 3627 std::optional<uint8_t> nodeInfo = 3628 getMultiNodeInfoPresence(ctx, "NodePresence"); 3629 if (!nodeInfo || !*nodeInfo) 3630 { 3631 return ipmi::responseInvalidCommand(); 3632 } 3633 3634 uint16_t oemReadingValue = 0; 3635 if (static_cast<uint8_t>(readingType) == inletAirTemp) 3636 { 3637 double value = 0; 3638 boost::system::error_code ec = ipmi::getDbusProperty( 3639 ctx, "xyz.openbmc_project.HwmonTempSensor", 3640 "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp", 3641 "xyz.openbmc_project.Sensor.Value", "Value", value); 3642 if (ec) 3643 { 3644 phosphor::logging::log<phosphor::logging::level::ERR>( 3645 "Failed to get BMC Get OEM temperature", 3646 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str())); 3647 return ipmi::responseUnspecifiedError(); 3648 } 3649 // Take the Inlet temperature 3650 oemReadingValue = static_cast<uint16_t>(value); 3651 } 3652 else 3653 { 3654 phosphor::logging::log<phosphor::logging::level::ERR>( 3655 "Currently Get OEM Reading support only for Inlet Air Temp"); 3656 return ipmi::responseParmOutOfRange(); 3657 } 3658 return ipmi::responseSuccess(domainId, readingType, oemReadingValue); 3659 } 3660 3661 /** @brief implements the maximum size of 3662 * bridgeable messages used between KCS and 3663 * IPMB interfacesget security mode command. 3664 * 3665 * @returns IPMI completion code with following data 3666 * - KCS Buffer Size (In multiples of four bytes) 3667 * - IPMB Buffer Size (In multiples of four bytes) 3668 **/ 3669 ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize() 3670 { 3671 // for now this is hard coded; really this number is dependent on 3672 // the BMC kcs driver as well as the host kcs driver.... 3673 // we can't know the latter. 3674 uint8_t kcsMaxBufferSize = 63 / 4; 3675 uint8_t ipmbMaxBufferSize = 128 / 4; 3676 3677 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize); 3678 } 3679 3680 static void registerOEMFunctions(void) 3681 { 3682 phosphor::logging::log<phosphor::logging::level::INFO>( 3683 "Registering OEM commands"); 3684 ipmiPrintAndRegister(intel::netFnGeneral, 3685 intel::general::cmdGetChassisIdentifier, NULL, 3686 ipmiOEMGetChassisIdentifier, 3687 PRIVILEGE_USER); // get chassis identifier 3688 3689 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID, 3690 NULL, ipmiOEMSetSystemGUID, 3691 PRIVILEGE_ADMIN); // set system guid 3692 3693 // <Disable BMC System Reset Action> 3694 registerHandler(prioOemBase, intel::netFnGeneral, 3695 intel::general::cmdDisableBMCSystemReset, Privilege::Admin, 3696 ipmiOEMDisableBMCSystemReset); 3697 3698 // <Get BMC Reset Disables> 3699 registerHandler(prioOemBase, intel::netFnGeneral, 3700 intel::general::cmdGetBMCResetDisables, Privilege::Admin, 3701 ipmiOEMGetBMCResetDisables); 3702 3703 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID, 3704 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN); 3705 3706 registerHandler(prioOemBase, intel::netFnGeneral, 3707 intel::general::cmdGetOEMDeviceInfo, Privilege::User, 3708 ipmiOEMGetDeviceInfo); 3709 3710 ipmiPrintAndRegister(intel::netFnGeneral, 3711 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL, 3712 ipmiOEMGetAICFRU, PRIVILEGE_USER); 3713 3714 registerHandler(prioOpenBmcBase, intel::netFnGeneral, 3715 intel::general::cmdSendEmbeddedFWUpdStatus, 3716 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus); 3717 3718 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb, 3719 Privilege::Admin, ipmiOEMSlotIpmb); 3720 3721 ipmiPrintAndRegister(intel::netFnGeneral, 3722 intel::general::cmdSetPowerRestoreDelay, NULL, 3723 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR); 3724 3725 ipmiPrintAndRegister(intel::netFnGeneral, 3726 intel::general::cmdGetPowerRestoreDelay, NULL, 3727 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER); 3728 3729 registerHandler(prioOpenBmcBase, intel::netFnGeneral, 3730 intel::general::cmdSetOEMUser2Activation, 3731 Privilege::Callback, ipmiOEMSetUser2Activation); 3732 3733 registerHandler(prioOpenBmcBase, intel::netFnGeneral, 3734 intel::general::cmdSetSpecialUserPassword, 3735 Privilege::Callback, ipmiOEMSetSpecialUserPassword); 3736 3737 // <Get Processor Error Config> 3738 registerHandler(prioOemBase, intel::netFnGeneral, 3739 intel::general::cmdGetProcessorErrConfig, Privilege::User, 3740 ipmiOEMGetProcessorErrConfig); 3741 3742 // <Set Processor Error Config> 3743 registerHandler(prioOemBase, intel::netFnGeneral, 3744 intel::general::cmdSetProcessorErrConfig, Privilege::Admin, 3745 ipmiOEMSetProcessorErrConfig); 3746 3747 ipmiPrintAndRegister(intel::netFnGeneral, 3748 intel::general::cmdSetShutdownPolicy, NULL, 3749 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN); 3750 3751 ipmiPrintAndRegister(intel::netFnGeneral, 3752 intel::general::cmdGetShutdownPolicy, NULL, 3753 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN); 3754 3755 registerHandler(prioOemBase, intel::netFnGeneral, 3756 intel::general::cmdSetFanConfig, Privilege::User, 3757 ipmiOEMSetFanConfig); 3758 3759 registerHandler(prioOemBase, intel::netFnGeneral, 3760 intel::general::cmdGetFanConfig, Privilege::User, 3761 ipmiOEMGetFanConfig); 3762 3763 registerHandler(prioOemBase, intel::netFnGeneral, 3764 intel::general::cmdGetFanSpeedOffset, Privilege::User, 3765 ipmiOEMGetFanSpeedOffset); 3766 3767 registerHandler(prioOemBase, intel::netFnGeneral, 3768 intel::general::cmdSetFanSpeedOffset, Privilege::User, 3769 ipmiOEMSetFanSpeedOffset); 3770 3771 registerHandler(prioOemBase, intel::netFnGeneral, 3772 intel::general::cmdSetFscParameter, Privilege::User, 3773 ipmiOEMSetFscParameter); 3774 3775 registerHandler(prioOemBase, intel::netFnGeneral, 3776 intel::general::cmdGetFscParameter, Privilege::User, 3777 ipmiOEMGetFscParameter); 3778 3779 registerHandler(prioOpenBmcBase, intel::netFnGeneral, 3780 intel::general::cmdReadBaseBoardProductId, Privilege::Admin, 3781 ipmiOEMReadBoardProductId); 3782 3783 registerHandler(prioOemBase, intel::netFnGeneral, 3784 intel::general::cmdGetNmiStatus, Privilege::User, 3785 ipmiOEMGetNmiSource); 3786 3787 registerHandler(prioOemBase, intel::netFnGeneral, 3788 intel::general::cmdSetNmiStatus, Privilege::Operator, 3789 ipmiOEMSetNmiSource); 3790 3791 registerHandler(prioOemBase, intel::netFnGeneral, 3792 intel::general::cmdGetEfiBootOptions, Privilege::User, 3793 ipmiOemGetEfiBootOptions); 3794 3795 registerHandler(prioOemBase, intel::netFnGeneral, 3796 intel::general::cmdSetEfiBootOptions, Privilege::Operator, 3797 ipmiOemSetEfiBootOptions); 3798 3799 registerHandler(prioOemBase, intel::netFnGeneral, 3800 intel::general::cmdGetSecurityMode, Privilege::User, 3801 ipmiGetSecurityMode); 3802 3803 registerHandler(prioOemBase, intel::netFnGeneral, 3804 intel::general::cmdSetSecurityMode, Privilege::Admin, 3805 ipmiSetSecurityMode); 3806 3807 registerHandler(prioOemBase, intel::netFnGeneral, 3808 intel::general::cmdGetLEDStatus, Privilege::Admin, 3809 ipmiOEMGetLEDStatus); 3810 3811 ipmiPrintAndRegister(ipmi::intel::netFnPlatform, 3812 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL, 3813 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN); 3814 3815 registerHandler(prioOemBase, intel::netFnGeneral, 3816 intel::general::cmdSetFaultIndication, Privilege::Operator, 3817 ipmiOEMSetFaultIndication); 3818 3819 registerHandler(prioOemBase, intel::netFnGeneral, 3820 intel::general::cmdSetColdRedundancyConfig, Privilege::User, 3821 ipmiOEMSetCRConfig); 3822 3823 registerHandler(prioOemBase, intel::netFnGeneral, 3824 intel::general::cmdGetColdRedundancyConfig, Privilege::User, 3825 ipmiOEMGetCRConfig); 3826 3827 registerHandler(prioOemBase, intel::netFnGeneral, 3828 intel::general::cmdRestoreConfiguration, Privilege::Admin, 3829 ipmiRestoreConfiguration); 3830 3831 registerHandler(prioOemBase, intel::netFnGeneral, 3832 intel::general::cmdSetDimmOffset, Privilege::Operator, 3833 ipmiOEMSetDimmOffset); 3834 3835 registerHandler(prioOemBase, intel::netFnGeneral, 3836 intel::general::cmdGetDimmOffset, Privilege::Operator, 3837 ipmiOEMGetDimmOffset); 3838 3839 registerHandler(prioOemBase, intel::netFnGeneral, 3840 intel::general::cmdGetPSUVersion, Privilege::User, 3841 ipmiOEMGetPSUVersion); 3842 3843 registerHandler(prioOemBase, intel::netFnGeneral, 3844 intel::general::cmdGetBufferSize, Privilege::User, 3845 ipmiOEMGetBufferSize); 3846 3847 registerHandler(prioOemBase, intel::netFnGeneral, 3848 intel::general::cmdOEMGetReading, Privilege::User, 3849 ipmiOEMGetReading); 3850 } 3851 3852 } // namespace ipmi 3853