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