1 #include "config.h" 2 3 #include "chassishandler.hpp" 4 5 #include <arpa/inet.h> 6 #include <endian.h> 7 #include <limits.h> 8 #include <mapper.h> 9 #include <netinet/in.h> 10 11 #include <array> 12 #include <chrono> 13 #include <cstring> 14 #include <filesystem> 15 #include <fstream> 16 #include <future> 17 #include <ipmid/api.hpp> 18 #include <ipmid/types.hpp> 19 #include <ipmid/utils.hpp> 20 #include <map> 21 #include <phosphor-logging/elog-errors.hpp> 22 #include <phosphor-logging/log.hpp> 23 #include <sdbusplus/bus.hpp> 24 #include <sdbusplus/message/types.hpp> 25 #include <sdbusplus/server/object.hpp> 26 #include <sdbusplus/timer.hpp> 27 #include <settings.hpp> 28 #include <sstream> 29 #include <string> 30 #include <xyz/openbmc_project/Common/error.hpp> 31 #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp> 32 #include <xyz/openbmc_project/Control/Boot/Source/server.hpp> 33 #include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp> 34 #include <xyz/openbmc_project/State/Host/server.hpp> 35 #include <xyz/openbmc_project/State/PowerOnHours/server.hpp> 36 37 // Defines 38 #define SET_PARM_VERSION 0x01 39 #define SET_PARM_BOOT_FLAGS_PERMANENT 0x40 40 #define SET_PARM_BOOT_FLAGS_VALID_ONE_TIME 0x80 41 #define SET_PARM_BOOT_FLAGS_VALID_PERMANENT 0xC0 42 43 std::unique_ptr<phosphor::Timer> identifyTimer 44 __attribute__((init_priority(101))); 45 46 static ChassisIDState chassisIDState = ChassisIDState::reserved; 47 48 constexpr size_t SIZE_MAC = 18; 49 constexpr size_t SIZE_BOOT_OPTION = (uint8_t) 50 BootOptionResponseSize::OPAL_NETWORK_SETTINGS; // Maximum size of the boot 51 // option parametrs 52 constexpr size_t SIZE_PREFIX = 7; 53 constexpr size_t MAX_PREFIX_VALUE = 32; 54 constexpr size_t SIZE_COOKIE = 4; 55 constexpr size_t SIZE_VERSION = 2; 56 constexpr size_t DEFAULT_IDENTIFY_TIME_OUT = 15; 57 58 // PetiBoot-Specific 59 static constexpr uint8_t net_conf_initial_bytes[] = {0x80, 0x21, 0x70, 0x62, 60 0x21, 0x00, 0x01, 0x06}; 61 62 static constexpr size_t COOKIE_OFFSET = 1; 63 static constexpr size_t VERSION_OFFSET = 5; 64 static constexpr size_t ADDR_SIZE_OFFSET = 8; 65 static constexpr size_t MAC_OFFSET = 9; 66 static constexpr size_t ADDRTYPE_OFFSET = 16; 67 static constexpr size_t IPADDR_OFFSET = 17; 68 69 static constexpr uint4_t RESERVED = 0; 70 static constexpr uint8_t CHANNEL_NOT_SUPPORTED = 0; 71 72 static constexpr size_t encIdentifyObjectsSize = 1; 73 static constexpr size_t chassisIdentifyReqLength = 2; 74 static constexpr size_t identifyIntervalPos = 0; 75 static constexpr size_t forceIdentifyPos = 1; 76 77 void register_netfn_chassis_functions() __attribute__((constructor)); 78 79 // Host settings in dbus 80 // Service name should be referenced by connection name got via object mapper 81 const char* settings_object_name = "/org/openbmc/settings/host0"; 82 const char* settings_intf_name = "org.freedesktop.DBus.Properties"; 83 const char* identify_led_object_name = 84 "/xyz/openbmc_project/led/groups/enclosure_identify"; 85 86 constexpr auto SETTINGS_ROOT = "/"; 87 constexpr auto SETTINGS_MATCH = "host0"; 88 89 constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP"; 90 constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress"; 91 92 static constexpr auto chassisStateRoot = "/xyz/openbmc_project/state"; 93 static constexpr auto chassisPOHStateIntf = 94 "xyz.openbmc_project.State.PowerOnHours"; 95 static constexpr auto pOHCounterProperty = "POHCounter"; 96 static constexpr auto match = "chassis0"; 97 const static constexpr char chassisCapIntf[] = 98 "xyz.openbmc_project.Control.ChassisCapabilities"; 99 const static constexpr char chassisIntrusionProp[] = "ChassisIntrusionEnabled"; 100 const static constexpr char chassisFrontPanelLockoutProp[] = 101 "ChassisFrontPanelLockoutEnabled"; 102 const static constexpr char chassisNMIProp[] = "ChassisNMIEnabled"; 103 const static constexpr char chassisPowerInterlockProp[] = 104 "ChassisPowerInterlockEnabled"; 105 const static constexpr char chassisFRUDevAddrProp[] = "FRUDeviceAddress"; 106 const static constexpr char chassisSDRDevAddrProp[] = "SDRDeviceAddress"; 107 const static constexpr char chassisSELDevAddrProp[] = "SELDeviceAddress"; 108 const static constexpr char chassisSMDevAddrProp[] = "SMDeviceAddress"; 109 const static constexpr char chassisBridgeDevAddrProp[] = "BridgeDeviceAddress"; 110 static constexpr uint8_t chassisCapFlagMask = 0x0f; 111 static constexpr uint8_t chassisCapAddrMask = 0xfe; 112 static constexpr const char* powerButtonIntf = 113 "xyz.openbmc_project.Chassis.Buttons.Power"; 114 static constexpr const char* powerButtonPath = 115 "/xyz/openbmc_project/Chassis/Buttons/Power0"; 116 static constexpr const char* resetButtonIntf = 117 "xyz.openbmc_project.Chassis.Buttons.Reset"; 118 static constexpr const char* resetButtonPath = 119 "/xyz/openbmc_project/Chassis/Buttons/Reset0"; 120 121 // Phosphor Host State manager 122 namespace State = sdbusplus::xyz::openbmc_project::State::server; 123 124 namespace fs = std::filesystem; 125 126 using namespace phosphor::logging; 127 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 128 using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server; 129 130 namespace chassis 131 { 132 namespace internal 133 { 134 135 constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode"; 136 constexpr auto bootSourceIntf = "xyz.openbmc_project.Control.Boot.Source"; 137 constexpr auto powerRestoreIntf = 138 "xyz.openbmc_project.Control.Power.RestorePolicy"; 139 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); 140 141 namespace cache 142 { 143 144 std::unique_ptr<settings::Objects> objectsPtr = nullptr; 145 146 settings::Objects& getObjects() 147 { 148 if (objectsPtr == nullptr) 149 { 150 objectsPtr = std::make_unique<settings::Objects>( 151 dbus, std::vector<std::string>{bootModeIntf, bootSourceIntf, 152 powerRestoreIntf}); 153 } 154 return *objectsPtr; 155 } 156 157 } // namespace cache 158 } // namespace internal 159 } // namespace chassis 160 161 namespace poh 162 { 163 164 constexpr auto minutesPerCount = 60; 165 166 } // namespace poh 167 168 struct get_sys_boot_options_t 169 { 170 uint8_t parameter; 171 uint8_t set; 172 uint8_t block; 173 } __attribute__((packed)); 174 175 struct get_sys_boot_options_response_t 176 { 177 uint8_t version; 178 uint8_t parm; 179 uint8_t data[SIZE_BOOT_OPTION]; 180 } __attribute__((packed)); 181 182 struct set_sys_boot_options_t 183 { 184 uint8_t parameter; 185 uint8_t data[SIZE_BOOT_OPTION]; 186 } __attribute__((packed)); 187 188 int getHostNetworkData(get_sys_boot_options_response_t* respptr) 189 { 190 ipmi::PropertyMap properties; 191 int rc = 0; 192 uint8_t addrSize = ipmi::network::IPV4_ADDRESS_SIZE_BYTE; 193 194 try 195 { 196 // TODO There may be cases where an interface is implemented by multiple 197 // objects,to handle such cases we are interested on that object 198 // which are on interested busname. 199 // Currenlty mapper doesn't give the readable busname(gives busid) 200 // so we can't match with bus name so giving some object specific info 201 // as SETTINGS_MATCH. 202 // Later SETTINGS_MATCH will be replaced with busname. 203 204 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 205 206 auto ipObjectInfo = ipmi::getDbusObject(bus, IP_INTERFACE, 207 SETTINGS_ROOT, SETTINGS_MATCH); 208 209 auto macObjectInfo = ipmi::getDbusObject(bus, MAC_INTERFACE, 210 SETTINGS_ROOT, SETTINGS_MATCH); 211 212 properties = ipmi::getAllDbusProperties( 213 bus, ipObjectInfo.second, ipObjectInfo.first, IP_INTERFACE); 214 auto variant = ipmi::getDbusProperty(bus, macObjectInfo.second, 215 macObjectInfo.first, MAC_INTERFACE, 216 "MACAddress"); 217 218 auto ipAddress = std::get<std::string>(properties["Address"]); 219 220 auto gateway = std::get<std::string>(properties["Gateway"]); 221 222 auto prefix = std::get<uint8_t>(properties["PrefixLength"]); 223 224 uint8_t isStatic = 225 (std::get<std::string>(properties["Origin"]) == 226 "xyz.openbmc_project.Network.IP.AddressOrigin.Static") 227 ? 1 228 : 0; 229 230 auto MACAddress = std::get<std::string>(variant); 231 232 // it is expected here that we should get the valid data 233 // but we may also get the default values. 234 // Validation of the data is done by settings. 235 // 236 // if mac address is default mac address then 237 // don't send blank override. 238 if ((MACAddress == ipmi::network::DEFAULT_MAC_ADDRESS)) 239 { 240 std::memset(respptr->data, 0, SIZE_BOOT_OPTION); 241 rc = -1; 242 return rc; 243 } 244 // if addr is static then ipaddress,gateway,prefix 245 // should not be default one,don't send blank override. 246 if (isStatic) 247 { 248 if ((ipAddress == ipmi::network::DEFAULT_ADDRESS) || 249 (gateway == ipmi::network::DEFAULT_ADDRESS) || (!prefix)) 250 { 251 std::memset(respptr->data, 0, SIZE_BOOT_OPTION); 252 rc = -1; 253 return rc; 254 } 255 } 256 257 sscanf( 258 MACAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, 259 (respptr->data + MAC_OFFSET), (respptr->data + MAC_OFFSET + 1), 260 (respptr->data + MAC_OFFSET + 2), (respptr->data + MAC_OFFSET + 3), 261 (respptr->data + MAC_OFFSET + 4), (respptr->data + MAC_OFFSET + 5)); 262 263 respptr->data[MAC_OFFSET + 6] = 0x00; 264 265 std::memcpy(respptr->data + ADDRTYPE_OFFSET, &isStatic, 266 sizeof(isStatic)); 267 268 uint8_t addressFamily = (std::get<std::string>(properties["Type"]) == 269 "xyz.openbmc_project.Network.IP.Protocol.IPv4") 270 ? AF_INET 271 : AF_INET6; 272 273 addrSize = (addressFamily == AF_INET) 274 ? ipmi::network::IPV4_ADDRESS_SIZE_BYTE 275 : ipmi::network::IPV6_ADDRESS_SIZE_BYTE; 276 277 // ipaddress and gateway would be in IPv4 format 278 inet_pton(addressFamily, ipAddress.c_str(), 279 (respptr->data + IPADDR_OFFSET)); 280 281 uint8_t prefixOffset = IPADDR_OFFSET + addrSize; 282 283 std::memcpy(respptr->data + prefixOffset, &prefix, sizeof(prefix)); 284 285 uint8_t gatewayOffset = prefixOffset + sizeof(decltype(prefix)); 286 287 inet_pton(addressFamily, gateway.c_str(), 288 (respptr->data + gatewayOffset)); 289 } 290 catch (InternalFailure& e) 291 { 292 commit<InternalFailure>(); 293 std::memset(respptr->data, 0, SIZE_BOOT_OPTION); 294 rc = -1; 295 return rc; 296 } 297 298 // PetiBoot-Specific 299 // If success then copy the first 9 bytes to the data 300 std::memcpy(respptr->data, net_conf_initial_bytes, 301 sizeof(net_conf_initial_bytes)); 302 303 std::memcpy(respptr->data + ADDR_SIZE_OFFSET, &addrSize, sizeof(addrSize)); 304 305 #ifdef _IPMI_DEBUG_ 306 std::printf("\n===Printing the IPMI Formatted Data========\n"); 307 308 for (uint8_t pos = 0; pos < index; pos++) 309 { 310 std::printf("%02x ", respptr->data[pos]); 311 } 312 #endif 313 314 return rc; 315 } 316 317 /** @brief convert IPv4 and IPv6 addresses from binary to text form. 318 * @param[in] family - IPv4/Ipv6 319 * @param[in] data - req data pointer. 320 * @param[in] offset - offset in the data. 321 * @param[in] addrSize - size of the data which needs to be read from offset. 322 * @returns address in text form. 323 */ 324 325 std::string getAddrStr(uint8_t family, uint8_t* data, uint8_t offset, 326 uint8_t addrSize) 327 { 328 char ipAddr[INET6_ADDRSTRLEN] = {}; 329 330 switch (family) 331 { 332 case AF_INET: 333 { 334 struct sockaddr_in addr4 335 { 336 }; 337 std::memcpy(&addr4.sin_addr.s_addr, &data[offset], addrSize); 338 339 inet_ntop(AF_INET, &addr4.sin_addr, ipAddr, INET_ADDRSTRLEN); 340 341 break; 342 } 343 case AF_INET6: 344 { 345 struct sockaddr_in6 addr6 346 { 347 }; 348 std::memcpy(&addr6.sin6_addr.s6_addr, &data[offset], addrSize); 349 350 inet_ntop(AF_INET6, &addr6.sin6_addr, ipAddr, INET6_ADDRSTRLEN); 351 352 break; 353 } 354 default: 355 { 356 return {}; 357 } 358 } 359 360 return ipAddr; 361 } 362 363 int setHostNetworkData(set_sys_boot_options_t* reqptr) 364 { 365 using namespace std::string_literals; 366 std::string host_network_config; 367 char mac[]{"00:00:00:00:00:00"}; 368 std::string ipAddress, gateway; 369 char addrOrigin{0}; 370 uint8_t addrSize{0}; 371 std::string addressOrigin = 372 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP"; 373 std::string addressType = "xyz.openbmc_project.Network.IP.Protocol.IPv4"; 374 uint8_t prefix{0}; 375 uint32_t zeroCookie = 0; 376 uint8_t family = AF_INET; 377 378 // cookie starts from second byte 379 // version starts from sixth byte 380 381 try 382 { 383 do 384 { 385 // cookie == 0x21 0x70 0x62 0x21 386 if (memcmp(&(reqptr->data[COOKIE_OFFSET]), 387 (net_conf_initial_bytes + COOKIE_OFFSET), 388 SIZE_COOKIE) != 0) 389 { 390 // cookie == 0 391 if (memcmp(&(reqptr->data[COOKIE_OFFSET]), &zeroCookie, 392 SIZE_COOKIE) == 0) 393 { 394 // need to zero out the network settings. 395 break; 396 } 397 398 log<level::ERR>("Invalid Cookie"); 399 elog<InternalFailure>(); 400 } 401 402 // vesion == 0x00 0x01 403 if (memcmp(&(reqptr->data[VERSION_OFFSET]), 404 (net_conf_initial_bytes + VERSION_OFFSET), 405 SIZE_VERSION) != 0) 406 { 407 408 log<level::ERR>("Invalid Version"); 409 elog<InternalFailure>(); 410 } 411 412 std::snprintf( 413 mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT, 414 reqptr->data[MAC_OFFSET], reqptr->data[MAC_OFFSET + 1], 415 reqptr->data[MAC_OFFSET + 2], reqptr->data[MAC_OFFSET + 3], 416 reqptr->data[MAC_OFFSET + 4], reqptr->data[MAC_OFFSET + 5]); 417 418 std::memcpy(&addrOrigin, &(reqptr->data[ADDRTYPE_OFFSET]), 419 sizeof(decltype(addrOrigin))); 420 421 if (addrOrigin) 422 { 423 addressOrigin = 424 "xyz.openbmc_project.Network.IP.AddressOrigin.Static"; 425 } 426 427 // Get the address size 428 std::memcpy(&addrSize, &reqptr->data[ADDR_SIZE_OFFSET], 429 sizeof(addrSize)); 430 431 uint8_t prefixOffset = IPADDR_OFFSET + addrSize; 432 433 std::memcpy(&prefix, &(reqptr->data[prefixOffset]), 434 sizeof(decltype(prefix))); 435 436 uint8_t gatewayOffset = prefixOffset + sizeof(decltype(prefix)); 437 438 if (addrSize != ipmi::network::IPV4_ADDRESS_SIZE_BYTE) 439 { 440 addressType = "xyz.openbmc_project.Network.IP.Protocol.IPv6"; 441 family = AF_INET6; 442 } 443 444 ipAddress = 445 getAddrStr(family, reqptr->data, IPADDR_OFFSET, addrSize); 446 447 gateway = getAddrStr(family, reqptr->data, gatewayOffset, addrSize); 448 449 } while (0); 450 451 // Cookie == 0 or it is a valid cookie 452 host_network_config += "ipaddress="s + ipAddress + ",prefix="s + 453 std::to_string(prefix) + ",gateway="s + gateway + 454 ",mac="s + mac + ",addressOrigin="s + 455 addressOrigin; 456 457 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 458 459 auto ipObjectInfo = ipmi::getDbusObject(bus, IP_INTERFACE, 460 SETTINGS_ROOT, SETTINGS_MATCH); 461 auto macObjectInfo = ipmi::getDbusObject(bus, MAC_INTERFACE, 462 SETTINGS_ROOT, SETTINGS_MATCH); 463 // set the dbus property 464 ipmi::setDbusProperty(bus, ipObjectInfo.second, ipObjectInfo.first, 465 IP_INTERFACE, "Address", std::string(ipAddress)); 466 ipmi::setDbusProperty(bus, ipObjectInfo.second, ipObjectInfo.first, 467 IP_INTERFACE, "PrefixLength", prefix); 468 ipmi::setDbusProperty(bus, ipObjectInfo.second, ipObjectInfo.first, 469 IP_INTERFACE, "Origin", addressOrigin); 470 ipmi::setDbusProperty(bus, ipObjectInfo.second, ipObjectInfo.first, 471 IP_INTERFACE, "Gateway", std::string(gateway)); 472 ipmi::setDbusProperty( 473 bus, ipObjectInfo.second, ipObjectInfo.first, IP_INTERFACE, "Type", 474 std::string("xyz.openbmc_project.Network.IP.Protocol.IPv4")); 475 ipmi::setDbusProperty(bus, macObjectInfo.second, macObjectInfo.first, 476 MAC_INTERFACE, "MACAddress", std::string(mac)); 477 478 log<level::DEBUG>( 479 "Network configuration changed", 480 entry("NETWORKCONFIG=%s", host_network_config.c_str())); 481 } 482 catch (InternalFailure& e) 483 { 484 commit<InternalFailure>(); 485 return -1; 486 } 487 488 return 0; 489 } 490 491 uint32_t getPOHCounter() 492 { 493 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 494 495 auto chassisStateObj = 496 ipmi::getDbusObject(bus, chassisPOHStateIntf, chassisStateRoot, match); 497 498 auto service = 499 ipmi::getService(bus, chassisPOHStateIntf, chassisStateObj.first); 500 501 auto propValue = 502 ipmi::getDbusProperty(bus, service, chassisStateObj.first, 503 chassisPOHStateIntf, pOHCounterProperty); 504 505 return std::get<uint32_t>(propValue); 506 } 507 508 /** @brief Implements the get chassis capabilities command 509 * 510 * @returns IPMI completion code plus response data 511 * chassisCapFlags - chassis capability flag 512 * chassisFRUInfoDevAddr - chassis FRU info Device Address 513 * chassisSDRDevAddr - chassis SDR device address 514 * chassisSELDevAddr - chassis SEL device address 515 * chassisSMDevAddr - chassis system management device address 516 * chassisBridgeDevAddr - chassis bridge device address 517 */ 518 ipmi::RspType<bool, // chassis intrusion sensor 519 bool, // chassis Front panel lockout 520 bool, // chassis NMI 521 bool, // chassis power interlock 522 uint4_t, // reserved 523 uint8_t, // chassis FRU info Device Address 524 uint8_t, // chassis SDR device address 525 uint8_t, // chassis SEL device address 526 uint8_t, // chassis system management device address 527 uint8_t // chassis bridge device address 528 > 529 ipmiGetChassisCap() 530 { 531 ipmi::PropertyMap properties; 532 try 533 { 534 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 535 536 ipmi::DbusObjectInfo chassisCapObject = 537 ipmi::getDbusObject(bus, chassisCapIntf); 538 539 // capabilities flags 540 // [7..4] - reserved 541 // [3] – 1b = provides power interlock (IPM 1.5) 542 // [2] – 1b = provides Diagnostic Interrupt (FP NMI) 543 // [1] – 1b = provides “Front Panel Lockout” (indicates that the chassis 544 // has capabilities 545 // to lock out external power control and reset button or 546 // front panel interfaces and/or detect tampering with those 547 // interfaces). 548 // [0] -1b = Chassis provides intrusion (physical security) sensor. 549 // set to default value 0x0. 550 551 properties = 552 ipmi::getAllDbusProperties(bus, chassisCapObject.second, 553 chassisCapObject.first, chassisCapIntf); 554 } 555 catch (std::exception& e) 556 { 557 log<level::ERR>("Failed to fetch Chassis Capability properties", 558 entry("ERROR=%s", e.what())); 559 return ipmi::responseUnspecifiedError(); 560 } 561 562 bool* chassisIntrusionFlag = 563 std::get_if<bool>(&properties[chassisIntrusionProp]); 564 if (chassisIntrusionFlag == nullptr) 565 { 566 log<level::ERR>("Error to get chassis Intrusion flags"); 567 return ipmi::responseUnspecifiedError(); 568 } 569 bool* chassisFrontPanelFlag = 570 std::get_if<bool>(&properties[chassisFrontPanelLockoutProp]); 571 if (chassisFrontPanelFlag == nullptr) 572 { 573 log<level::ERR>("Error to get chassis intrusion flags"); 574 return ipmi::responseUnspecifiedError(); 575 } 576 bool* chassisNMIFlag = std::get_if<bool>(&properties[chassisNMIProp]); 577 if (chassisNMIFlag == nullptr) 578 { 579 log<level::ERR>("Error to get chassis NMI flags"); 580 return ipmi::responseUnspecifiedError(); 581 } 582 bool* chassisPowerInterlockFlag = 583 std::get_if<bool>(&properties[chassisPowerInterlockProp]); 584 if (chassisPowerInterlockFlag == nullptr) 585 { 586 log<level::ERR>("Error to get chassis power interlock flags"); 587 return ipmi::responseUnspecifiedError(); 588 } 589 uint8_t* chassisFRUInfoDevAddr = 590 std::get_if<uint8_t>(&properties[chassisFRUDevAddrProp]); 591 if (chassisFRUInfoDevAddr == nullptr) 592 { 593 log<level::ERR>("Error to get chassis FRU info device address"); 594 return ipmi::responseUnspecifiedError(); 595 } 596 uint8_t* chassisSDRDevAddr = 597 std::get_if<uint8_t>(&properties[chassisSDRDevAddrProp]); 598 if (chassisSDRDevAddr == nullptr) 599 { 600 log<level::ERR>("Error to get chassis SDR device address"); 601 return ipmi::responseUnspecifiedError(); 602 } 603 uint8_t* chassisSELDevAddr = 604 std::get_if<uint8_t>(&properties[chassisSELDevAddrProp]); 605 if (chassisSELDevAddr == nullptr) 606 { 607 log<level::ERR>("Error to get chassis SEL device address"); 608 return ipmi::responseUnspecifiedError(); 609 } 610 uint8_t* chassisSMDevAddr = 611 std::get_if<uint8_t>(&properties[chassisSMDevAddrProp]); 612 if (chassisSMDevAddr == nullptr) 613 { 614 log<level::ERR>("Error to get chassis SM device address"); 615 return ipmi::responseUnspecifiedError(); 616 } 617 uint8_t* chassisBridgeDevAddr = 618 std::get_if<uint8_t>(&properties[chassisBridgeDevAddrProp]); 619 if (chassisBridgeDevAddr == nullptr) 620 { 621 log<level::ERR>("Error to get chassis bridge device address"); 622 return ipmi::responseUnspecifiedError(); 623 } 624 625 return ipmi::responseSuccess(*chassisIntrusionFlag, *chassisFrontPanelFlag, 626 *chassisNMIFlag, *chassisPowerInterlockFlag, 0, 627 *chassisFRUInfoDevAddr, *chassisSDRDevAddr, 628 *chassisSELDevAddr, *chassisSMDevAddr, 629 *chassisBridgeDevAddr); 630 } 631 632 /** @brief implements set chassis capalibities command 633 * @param intrusion - chassis intrusion 634 * @param fpLockout - frontpannel lockout 635 * @param reserved1 - skip one bit 636 * @param fruDeviceAddr - chassis FRU info Device Address 637 * @param sdrDeviceAddr - chassis SDR device address 638 * @param selDeviceAddr - chassis SEL device address 639 * @param smDeviceAddr - chassis system management device address 640 * @param bridgeDeviceAddr - chassis bridge device address 641 * 642 * @returns IPMI completion code 643 */ 644 ipmi::RspType<> ipmiSetChassisCap(bool intrusion, bool fpLockout, 645 uint6_t reserved1, 646 647 uint8_t fruDeviceAddr, 648 649 uint8_t sdrDeviceAddr, 650 651 uint8_t selDeviceAddr, 652 653 uint8_t smDeviceAddr, 654 655 uint8_t bridgeDeviceAddr) 656 { 657 658 // check input data 659 if (reserved1 != 0) 660 { 661 log<level::ERR>("Unsupported request parameter"); 662 return ipmi::responseInvalidFieldRequest(); 663 } 664 665 if ((fruDeviceAddr & ~chassisCapAddrMask) != 0) 666 { 667 log<level::ERR>("Unsupported request parameter(FRU Addr)", 668 entry("REQ=0x%x", fruDeviceAddr)); 669 return ipmi::responseInvalidFieldRequest(); 670 } 671 if ((sdrDeviceAddr & ~chassisCapAddrMask) != 0) 672 { 673 log<level::ERR>("Unsupported request parameter(SDR Addr)", 674 entry("REQ=0x%x", sdrDeviceAddr)); 675 return ipmi::responseInvalidFieldRequest(); 676 } 677 678 if ((selDeviceAddr & ~chassisCapAddrMask) != 0) 679 { 680 log<level::ERR>("Unsupported request parameter(SEL Addr)", 681 entry("REQ=0x%x", selDeviceAddr)); 682 return ipmi::responseInvalidFieldRequest(); 683 } 684 685 if ((smDeviceAddr & ~chassisCapAddrMask) != 0) 686 { 687 log<level::ERR>("Unsupported request parameter(SM Addr)", 688 entry("REQ=0x%x", smDeviceAddr)); 689 return ipmi::responseInvalidFieldRequest(); 690 } 691 692 if ((bridgeDeviceAddr & ~chassisCapAddrMask) != 0) 693 { 694 log<level::ERR>("Unsupported request parameter(Bridge Addr)", 695 entry("REQ=0x%x", bridgeDeviceAddr)); 696 return ipmi::responseInvalidFieldRequest(); 697 } 698 699 try 700 { 701 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 702 ipmi::DbusObjectInfo chassisCapObject = 703 ipmi::getDbusObject(bus, chassisCapIntf); 704 705 ipmi::setDbusProperty(bus, chassisCapObject.second, 706 chassisCapObject.first, chassisCapIntf, 707 chassisIntrusionProp, intrusion); 708 709 ipmi::setDbusProperty(bus, chassisCapObject.second, 710 chassisCapObject.first, chassisCapIntf, 711 chassisFrontPanelLockoutProp, fpLockout); 712 713 ipmi::setDbusProperty(bus, chassisCapObject.second, 714 chassisCapObject.first, chassisCapIntf, 715 chassisFRUDevAddrProp, fruDeviceAddr); 716 717 ipmi::setDbusProperty(bus, chassisCapObject.second, 718 chassisCapObject.first, chassisCapIntf, 719 chassisSDRDevAddrProp, sdrDeviceAddr); 720 721 ipmi::setDbusProperty(bus, chassisCapObject.second, 722 chassisCapObject.first, chassisCapIntf, 723 chassisSELDevAddrProp, selDeviceAddr); 724 725 ipmi::setDbusProperty(bus, chassisCapObject.second, 726 chassisCapObject.first, chassisCapIntf, 727 chassisSMDevAddrProp, smDeviceAddr); 728 729 ipmi::setDbusProperty(bus, chassisCapObject.second, 730 chassisCapObject.first, chassisCapIntf, 731 chassisBridgeDevAddrProp, bridgeDeviceAddr); 732 } 733 catch (std::exception& e) 734 { 735 log<level::ERR>(e.what()); 736 return ipmi::responseUnspecifiedError(); 737 } 738 return ipmi::responseSuccess(); 739 } 740 741 //------------------------------------------ 742 // Calls into Host State Manager Dbus object 743 //------------------------------------------ 744 int initiate_state_transition(State::Host::Transition transition) 745 { 746 // OpenBMC Host State Manager dbus framework 747 constexpr auto HOST_STATE_MANAGER_ROOT = "/xyz/openbmc_project/state/host0"; 748 constexpr auto HOST_STATE_MANAGER_IFACE = "xyz.openbmc_project.State.Host"; 749 constexpr auto DBUS_PROPERTY_IFACE = "org.freedesktop.DBus.Properties"; 750 constexpr auto PROPERTY = "RequestedHostTransition"; 751 752 // sd_bus error 753 int rc = 0; 754 char* busname = NULL; 755 756 // SD Bus error report mechanism. 757 sd_bus_error bus_error = SD_BUS_ERROR_NULL; 758 759 // Gets a hook onto either a SYSTEM or SESSION bus 760 sd_bus* bus_type = ipmid_get_sd_bus_connection(); 761 rc = mapper_get_service(bus_type, HOST_STATE_MANAGER_ROOT, &busname); 762 if (rc < 0) 763 { 764 log<level::ERR>( 765 "Failed to get bus name", 766 entry("ERRNO=0x%X, OBJPATH=%s", -rc, HOST_STATE_MANAGER_ROOT)); 767 return rc; 768 } 769 770 // Convert to string equivalent of the passed in transition enum. 771 auto request = State::convertForMessage(transition); 772 773 rc = sd_bus_call_method(bus_type, // On the system bus 774 busname, // Service to contact 775 HOST_STATE_MANAGER_ROOT, // Object path 776 DBUS_PROPERTY_IFACE, // Interface name 777 "Set", // Method to be called 778 &bus_error, // object to return error 779 nullptr, // Response buffer if any 780 "ssv", // Takes 3 arguments 781 HOST_STATE_MANAGER_IFACE, PROPERTY, "s", 782 request.c_str()); 783 if (rc < 0) 784 { 785 log<level::ERR>("Failed to initiate transition", 786 entry("ERRNO=0x%X, REQUEST=%s", -rc, request.c_str())); 787 } 788 else 789 { 790 log<level::INFO>("Transition request initiated successfully"); 791 } 792 793 sd_bus_error_free(&bus_error); 794 free(busname); 795 796 return rc; 797 } 798 799 //------------------------------------------ 800 // Set Enabled property to inform NMI source 801 // handling to trigger a NMI_OUT BSOD. 802 //------------------------------------------ 803 int setNmiProperty(const bool value) 804 { 805 constexpr const char* nmiSourceObjPath = 806 "/xyz/openbmc_project/Chassis/Control/NMISource"; 807 constexpr const char* nmiSourceIntf = 808 "xyz.openbmc_project.Chassis.Control.NMISource"; 809 std::string bmcSourceSignal = "xyz.openbmc_project.Chassis.Control." 810 "NMISource.BMCSourceSignal.ChassisCmd"; 811 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 812 813 try 814 { 815 auto service = ipmi::getService(*busp, nmiSourceIntf, nmiSourceObjPath); 816 ipmi::setDbusProperty(*busp, service, nmiSourceObjPath, nmiSourceIntf, 817 "BMCSource", bmcSourceSignal); 818 ipmi::setDbusProperty(*busp, service, nmiSourceObjPath, nmiSourceIntf, 819 "Enabled", value); 820 } 821 catch (std::exception& e) 822 { 823 log<level::ERR>("Failed to trigger NMI_OUT", 824 entry("EXCEPTION=%s", e.what())); 825 return -1; 826 } 827 828 return 0; 829 } 830 831 namespace power_policy 832 { 833 834 using namespace sdbusplus::xyz::openbmc_project::Control::Power::server; 835 using IpmiValue = uint8_t; 836 using DbusValue = RestorePolicy::Policy; 837 838 const std::map<DbusValue, IpmiValue> dbusToIpmi = { 839 {RestorePolicy::Policy::AlwaysOff, 0x00}, 840 {RestorePolicy::Policy::Restore, 0x01}, 841 {RestorePolicy::Policy::AlwaysOn, 0x02}}; 842 843 static constexpr uint8_t noChange = 0x03; 844 static constexpr uint8_t allSupport = 0x01 | 0x02 | 0x04; 845 846 /* helper function for Get Chassis Status Command 847 */ 848 std::optional<uint2_t> getPowerRestorePolicy() 849 { 850 uint2_t restorePolicy = 0; 851 using namespace chassis::internal; 852 853 settings::Objects& objects = cache::getObjects(); 854 855 try 856 { 857 const auto& powerRestoreSetting = 858 objects.map.at(powerRestoreIntf).front(); 859 ipmi::Value result = ipmi::getDbusProperty( 860 *getSdBus(), 861 objects.service(powerRestoreSetting, powerRestoreIntf).c_str(), 862 powerRestoreSetting.c_str(), powerRestoreIntf, 863 "PowerRestorePolicy"); 864 auto powerRestore = RestorePolicy::convertPolicyFromString( 865 std::get<std::string>(result)); 866 restorePolicy = dbusToIpmi.at(powerRestore); 867 } 868 catch (const std::exception& e) 869 { 870 log<level::ERR>( 871 "Failed to fetch pgood property", entry("ERROR=%s", e.what()), 872 entry("PATH=%s", objects.map.at(powerRestoreIntf).front().c_str()), 873 entry("INTERFACE=%s", powerRestoreIntf)); 874 cache::objectsPtr.reset(); 875 return std::nullopt; 876 } 877 return std::make_optional(restorePolicy); 878 } 879 880 /* 881 * getPowerStatus 882 * helper function for Get Chassis Status Command 883 * return - optional value for pgood (no value on error) 884 */ 885 std::optional<bool> getPowerStatus() 886 { 887 bool powerGood = false; 888 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 889 try 890 { 891 constexpr const char* chassisStatePath = 892 "/xyz/openbmc_project/state/chassis0"; 893 constexpr const char* chassisStateIntf = 894 "xyz.openbmc_project.State.Chassis"; 895 auto service = 896 ipmi::getService(*busp, chassisStateIntf, chassisStatePath); 897 898 ipmi::Value powerState = 899 ipmi::getDbusProperty(*busp, service, chassisStatePath, 900 chassisStateIntf, "CurrentPowerState"); 901 powerGood = std::get<std::string>(powerState) == 902 "xyz.openbmc_project.State.Chassis.PowerState.On"; 903 } 904 catch (const std::exception& e) 905 { 906 try 907 { 908 // FIXME: some legacy modules use the older path; try that next 909 constexpr const char* legacyPwrCtrlObj = 910 "/org/openbmc/control/power0"; 911 constexpr const char* legacyPwrCtrlIntf = 912 "org.openbmc.control.Power"; 913 auto service = 914 ipmi::getService(*busp, legacyPwrCtrlIntf, legacyPwrCtrlObj); 915 916 ipmi::Value variant = ipmi::getDbusProperty( 917 *busp, service, legacyPwrCtrlObj, legacyPwrCtrlIntf, "pgood"); 918 powerGood = static_cast<bool>(std::get<int>(variant)); 919 } 920 catch (const std::exception& e) 921 { 922 log<level::ERR>("Failed to fetch pgood property", 923 entry("ERROR=%s", e.what())); 924 return std::nullopt; 925 } 926 } 927 return std::make_optional(powerGood); 928 } 929 930 /* 931 * getACFailStatus 932 * helper function for Get Chassis Status Command 933 * return - bool value for ACFail (false on error) 934 */ 935 bool getACFailStatus() 936 { 937 constexpr const char* powerControlObj = 938 "/xyz/openbmc_project/Chassis/Control/Power0"; 939 constexpr const char* powerControlIntf = 940 "xyz.openbmc_project.Chassis.Control.Power"; 941 bool acFail = false; 942 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 943 try 944 { 945 auto service = 946 ipmi::getService(*bus, powerControlIntf, powerControlObj); 947 948 ipmi::Value variant = ipmi::getDbusProperty( 949 *bus, service, powerControlObj, powerControlIntf, "PFail"); 950 acFail = std::get<bool>(variant); 951 } 952 catch (const std::exception& e) 953 { 954 log<level::ERR>("Failed to fetch PFail property", 955 entry("ERROR=%s", e.what()), 956 entry("PATH=%s", powerControlObj), 957 entry("INTERFACE=%s", powerControlIntf)); 958 } 959 return acFail; 960 } 961 } // namespace power_policy 962 963 static std::optional<bool> getButtonEnabled(const std::string& buttonPath, 964 const std::string& buttonIntf) 965 { 966 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 967 bool buttonDisabled = false; 968 try 969 { 970 auto service = ipmi::getService(*busp, buttonIntf, buttonPath); 971 ipmi::Value enabled = ipmi::getDbusProperty(*busp, service, buttonPath, 972 buttonIntf, "Enabled"); 973 buttonDisabled = !std::get<bool>(enabled); 974 } 975 catch (sdbusplus::exception::SdBusError& e) 976 { 977 log<level::ERR>("Fail to get button Enabled property", 978 entry("PATH=%s", buttonPath.c_str()), 979 entry("ERROR=%s", e.what())); 980 return std::nullopt; 981 } 982 return std::make_optional(buttonDisabled); 983 } 984 985 static bool setButtonEnabled(ipmi::Context::ptr& ctx, 986 const std::string& buttonPath, 987 const std::string& buttonIntf, bool enable) 988 { 989 std::string service; 990 boost::system::error_code ec; 991 ec = ipmi::getService(ctx, buttonIntf, buttonPath, service); 992 if (!ec) 993 { 994 ec = ipmi::setDbusProperty(ctx, service, buttonPath, buttonIntf, 995 "Enabled", enable); 996 } 997 if (ec) 998 { 999 log<level::ERR>("Fail to set button Enabled property", 1000 entry("SERVICE=%s", service.c_str()), 1001 entry("PATH=%s", buttonPath.c_str()), 1002 entry("ERROR=%s", ec.message().c_str())); 1003 return false; 1004 } 1005 return true; 1006 } 1007 1008 //---------------------------------------------------------------------- 1009 // Get Chassis Status commands 1010 //---------------------------------------------------------------------- 1011 ipmi::RspType<bool, // Power is on 1012 bool, // Power overload 1013 bool, // Interlock 1014 bool, // power fault 1015 bool, // power control fault 1016 uint2_t, // power restore policy 1017 bool, // reserved 1018 1019 bool, // AC failed 1020 bool, // last power down caused by a Power overload 1021 bool, // last power down caused by a power interlock 1022 bool, // last power down caused by power fault 1023 bool, // last ‘Power is on’ state was entered via IPMI command 1024 uint3_t, // reserved 1025 1026 bool, // Chassis intrusion active 1027 bool, // Front Panel Lockout active 1028 bool, // Drive Fault 1029 bool, // Cooling/fan fault detected 1030 uint2_t, // Chassis Identify State 1031 bool, // Chassis Identify command and state info supported 1032 bool, // reserved 1033 1034 bool, // Power off button disabled 1035 bool, // Reset button disabled 1036 bool, // Diagnostic Interrupt button disabled 1037 bool, // Standby (sleep) button disabled 1038 bool, // Power off button disable allowed 1039 bool, // Reset button disable allowed 1040 bool, // Diagnostic Interrupt button disable allowed 1041 bool // Standby (sleep) button disable allowed 1042 > 1043 ipmiGetChassisStatus() 1044 { 1045 using namespace chassis::internal; 1046 std::optional<uint2_t> restorePolicy = 1047 power_policy::getPowerRestorePolicy(); 1048 std::optional<bool> powerGood = power_policy::getPowerStatus(); 1049 if (!restorePolicy || !powerGood) 1050 { 1051 return ipmi::responseUnspecifiedError(); 1052 } 1053 1054 // Front Panel Button Capabilities and disable/enable status(Optional) 1055 std::optional<bool> powerButtonReading = 1056 getButtonEnabled(powerButtonPath, powerButtonIntf); 1057 // allow disable if the interface is present 1058 bool powerButtonDisableAllow = static_cast<bool>(powerButtonReading); 1059 // default return the button is enabled (not disabled) 1060 bool powerButtonDisabled = false; 1061 if (powerButtonDisableAllow) 1062 { 1063 // return the real value of the button status, if present 1064 powerButtonDisabled = *powerButtonReading; 1065 } 1066 1067 std::optional<bool> resetButtonReading = 1068 getButtonEnabled(resetButtonPath, resetButtonIntf); 1069 // allow disable if the interface is present 1070 bool resetButtonDisableAllow = static_cast<bool>(resetButtonReading); 1071 // default return the button is enabled (not disabled) 1072 bool resetButtonDisabled = false; 1073 if (resetButtonDisableAllow) 1074 { 1075 // return the real value of the button status, if present 1076 resetButtonDisabled = *resetButtonReading; 1077 } 1078 1079 bool powerDownAcFailed = power_policy::getACFailStatus(); 1080 1081 // This response has a lot of hard-coded, unsupported fields 1082 // They are set to false or 0 1083 constexpr bool powerOverload = false; 1084 constexpr bool chassisInterlock = false; 1085 constexpr bool powerFault = false; 1086 constexpr bool powerControlFault = false; 1087 constexpr bool powerDownOverload = false; 1088 constexpr bool powerDownInterlock = false; 1089 constexpr bool powerDownPowerFault = false; 1090 constexpr bool powerStatusIPMI = false; 1091 constexpr bool chassisIntrusionActive = false; 1092 constexpr bool frontPanelLockoutActive = false; 1093 constexpr bool driveFault = false; 1094 constexpr bool coolingFanFault = false; 1095 // chassisIdentifySupport set because this command is implemented 1096 constexpr bool chassisIdentifySupport = true; 1097 uint2_t chassisIdentifyState = static_cast<uint2_t>(chassisIDState); 1098 constexpr bool diagButtonDisabled = false; 1099 constexpr bool sleepButtonDisabled = false; 1100 constexpr bool diagButtonDisableAllow = false; 1101 constexpr bool sleepButtonDisableAllow = false; 1102 1103 return ipmi::responseSuccess( 1104 *powerGood, powerOverload, chassisInterlock, powerFault, 1105 powerControlFault, *restorePolicy, 1106 false, // reserved 1107 1108 powerDownAcFailed, powerDownOverload, powerDownInterlock, 1109 powerDownPowerFault, powerStatusIPMI, 1110 uint3_t(0), // reserved 1111 1112 chassisIntrusionActive, frontPanelLockoutActive, driveFault, 1113 coolingFanFault, chassisIdentifyState, chassisIdentifySupport, 1114 false, // reserved 1115 1116 powerButtonDisabled, resetButtonDisabled, diagButtonDisabled, 1117 sleepButtonDisabled, powerButtonDisableAllow, resetButtonDisableAllow, 1118 diagButtonDisableAllow, sleepButtonDisableAllow); 1119 } 1120 1121 enum class IpmiRestartCause 1122 { 1123 Unknown = 0x0, 1124 RemoteCommand = 0x1, 1125 ResetButton = 0x2, 1126 PowerButton = 0x3, 1127 WatchdogTimer = 0x4, 1128 PowerPolicyAlwaysOn = 0x6, 1129 PowerPolicyPreviousState = 0x7, 1130 SoftReset = 0xa, 1131 }; 1132 1133 static IpmiRestartCause 1134 restartCauseToIpmiRestartCause(State::Host::RestartCause cause) 1135 { 1136 switch (cause) 1137 { 1138 case State::Host::RestartCause::Unknown: 1139 { 1140 return IpmiRestartCause::Unknown; 1141 } 1142 case State::Host::RestartCause::RemoteCommand: 1143 { 1144 return IpmiRestartCause::RemoteCommand; 1145 } 1146 case State::Host::RestartCause::ResetButton: 1147 { 1148 return IpmiRestartCause::ResetButton; 1149 } 1150 case State::Host::RestartCause::PowerButton: 1151 { 1152 return IpmiRestartCause::PowerButton; 1153 } 1154 case State::Host::RestartCause::WatchdogTimer: 1155 { 1156 return IpmiRestartCause::WatchdogTimer; 1157 } 1158 case State::Host::RestartCause::PowerPolicyAlwaysOn: 1159 { 1160 return IpmiRestartCause::PowerPolicyAlwaysOn; 1161 } 1162 case State::Host::RestartCause::PowerPolicyPreviousState: 1163 { 1164 return IpmiRestartCause::PowerPolicyPreviousState; 1165 } 1166 case State::Host::RestartCause::SoftReset: 1167 { 1168 return IpmiRestartCause::SoftReset; 1169 } 1170 default: 1171 { 1172 return IpmiRestartCause::Unknown; 1173 } 1174 } 1175 } 1176 1177 /* 1178 * getRestartCause 1179 * helper function for Get Host restart cause Command 1180 * return - optional value for RestartCause (no value on error) 1181 */ 1182 static std::optional<uint4_t> getRestartCause(ipmi::Context::ptr ctx) 1183 { 1184 constexpr const char* restartCausePath = 1185 "/xyz/openbmc_project/control/host0/restart_cause"; 1186 constexpr const char* restartCauseIntf = 1187 "xyz.openbmc_project.Control.Host.RestartCause"; 1188 1189 std::string service; 1190 boost::system::error_code ec = 1191 ipmi::getService(ctx, restartCauseIntf, restartCausePath, service); 1192 if (!ec) 1193 { 1194 std::string restartCauseStr; 1195 ec = ipmi::getDbusProperty<std::string>( 1196 ctx, service, restartCausePath, restartCauseIntf, "RestartCause", 1197 restartCauseStr); 1198 if (!ec) 1199 { 1200 auto cause = 1201 State::Host::convertRestartCauseFromString(restartCauseStr); 1202 return restartCauseToIpmiRestartCause(cause); 1203 } 1204 } 1205 1206 log<level::ERR>("Failed to fetch RestartCause property", 1207 entry("ERROR=%s", ec.message().c_str()), 1208 entry("PATH=%s", restartCausePath), 1209 entry("INTERFACE=%s", restartCauseIntf)); 1210 return std::nullopt; 1211 } 1212 1213 ipmi::RspType<uint4_t, // Restart Cause 1214 uint4_t, // reserved 1215 uint8_t // channel number (not supported) 1216 > 1217 ipmiGetSystemRestartCause(ipmi::Context::ptr ctx) 1218 { 1219 std::optional<uint4_t> cause = getRestartCause(ctx); 1220 if (!cause) 1221 { 1222 return ipmi::responseUnspecifiedError(); 1223 } 1224 1225 return ipmi::responseSuccess(cause.value(), RESERVED, 1226 CHANNEL_NOT_SUPPORTED); 1227 } 1228 1229 //------------------------------------------------------------- 1230 // Send a command to SoftPowerOff application to stop any timer 1231 //------------------------------------------------------------- 1232 int stop_soft_off_timer() 1233 { 1234 constexpr auto iface = "org.freedesktop.DBus.Properties"; 1235 constexpr auto soft_off_iface = "xyz.openbmc_project.Ipmi.Internal." 1236 "SoftPowerOff"; 1237 1238 constexpr auto property = "ResponseReceived"; 1239 constexpr auto value = "xyz.openbmc_project.Ipmi.Internal." 1240 "SoftPowerOff.HostResponse.HostShutdown"; 1241 1242 // Get the system bus where most system services are provided. 1243 auto bus = ipmid_get_sd_bus_connection(); 1244 1245 // Get the service name 1246 // TODO openbmc/openbmc#1661 - Mapper refactor 1247 // 1248 // See openbmc/openbmc#1743 for some details but high level summary is that 1249 // for now the code will directly call the soft off interface due to a 1250 // race condition with mapper usage 1251 // 1252 // char *busname = nullptr; 1253 // auto r = mapper_get_service(bus, SOFTOFF_OBJPATH, &busname); 1254 // if (r < 0) 1255 //{ 1256 // fprintf(stderr, "Failed to get %s bus name: %s\n", 1257 // SOFTOFF_OBJPATH, -r); 1258 // return r; 1259 //} 1260 1261 // No error object or reply expected. 1262 int rc = sd_bus_call_method(bus, SOFTOFF_BUSNAME, SOFTOFF_OBJPATH, iface, 1263 "Set", nullptr, nullptr, "ssv", soft_off_iface, 1264 property, "s", value); 1265 if (rc < 0) 1266 { 1267 log<level::ERR>("Failed to set property in SoftPowerOff object", 1268 entry("ERRNO=0x%X", -rc)); 1269 } 1270 1271 // TODO openbmc/openbmc#1661 - Mapper refactor 1272 // free(busname); 1273 return rc; 1274 } 1275 1276 //---------------------------------------------------------------------- 1277 // Create file to indicate there is no need for softoff notification to host 1278 //---------------------------------------------------------------------- 1279 void indicate_no_softoff_needed() 1280 { 1281 fs::path path{HOST_INBAND_REQUEST_DIR}; 1282 if (!fs::is_directory(path)) 1283 { 1284 fs::create_directory(path); 1285 } 1286 1287 // Add the host instance (default 0 for now) to the file name 1288 std::string file{HOST_INBAND_REQUEST_FILE}; 1289 auto size = std::snprintf(nullptr, 0, file.c_str(), 0); 1290 size++; // null 1291 std::unique_ptr<char[]> buf(new char[size]); 1292 std::snprintf(buf.get(), size, file.c_str(), 0); 1293 1294 // Append file name to directory and create it 1295 path /= buf.get(); 1296 std::ofstream(path.c_str()); 1297 } 1298 1299 /** @brief Implementation of chassis control command 1300 * 1301 * @param - chassisControl command byte 1302 * 1303 * @return Success or InvalidFieldRequest. 1304 */ 1305 ipmi::RspType<> ipmiChassisControl(uint8_t chassisControl) 1306 { 1307 int rc = 0; 1308 switch (chassisControl) 1309 { 1310 case CMD_POWER_ON: 1311 rc = initiate_state_transition(State::Host::Transition::On); 1312 break; 1313 case CMD_POWER_OFF: 1314 // This path would be hit in 2 conditions. 1315 // 1: When user asks for power off using ipmi chassis command 0x04 1316 // 2: Host asking for power off post shutting down. 1317 1318 // If it's a host requested power off, then need to nudge Softoff 1319 // application that it needs to stop the watchdog timer if running. 1320 // If it is a user requested power off, then this is not really 1321 // needed. But then we need to differentiate between user and host 1322 // calling this same command 1323 1324 // For now, we are going ahead with trying to nudge the soft off and 1325 // interpret the failure to do so as a non softoff case 1326 rc = stop_soft_off_timer(); 1327 1328 // Only request the Off transition if the soft power off 1329 // application is not running 1330 if (rc < 0) 1331 { 1332 // First create a file to indicate to the soft off application 1333 // that it should not run. Not doing this will result in State 1334 // manager doing a default soft power off when asked for power 1335 // off. 1336 indicate_no_softoff_needed(); 1337 1338 // Now request the shutdown 1339 rc = initiate_state_transition(State::Host::Transition::Off); 1340 } 1341 else 1342 { 1343 log<level::INFO>("Soft off is running, so let shutdown target " 1344 "stop the host"); 1345 } 1346 break; 1347 1348 case CMD_HARD_RESET: 1349 case CMD_POWER_CYCLE: 1350 // SPEC has a section that says certain implementations can trigger 1351 // PowerOn if power is Off when a command to power cycle is 1352 // requested 1353 1354 // First create a file to indicate to the soft off application 1355 // that it should not run since this is a direct user initiated 1356 // power reboot request (i.e. a reboot request that is not 1357 // originating via a soft power off SMS request) 1358 indicate_no_softoff_needed(); 1359 1360 rc = initiate_state_transition(State::Host::Transition::Reboot); 1361 break; 1362 1363 case CMD_SOFT_OFF_VIA_OVER_TEMP: 1364 // Request Host State Manager to do a soft power off 1365 rc = initiate_state_transition(State::Host::Transition::Off); 1366 break; 1367 1368 case CMD_PULSE_DIAGNOSTIC_INTR: 1369 rc = setNmiProperty(true); 1370 break; 1371 1372 default: 1373 { 1374 log<level::ERR>("Invalid Chassis Control command", 1375 entry("CMD=0x%X", chassisControl)); 1376 return ipmi::responseInvalidFieldRequest(); 1377 } 1378 } 1379 1380 return ((rc < 0) ? ipmi::responseUnspecifiedError() 1381 : ipmi::responseSuccess()); 1382 } 1383 1384 /** @brief Return D-Bus connection string to enclosure identify LED object 1385 * 1386 * @param[in, out] connection - connection to D-Bus object 1387 * @return a IPMI return code 1388 */ 1389 std::string getEnclosureIdentifyConnection() 1390 { 1391 // lookup enclosure_identify group owner(s) in mapper 1392 auto mapperCall = chassis::internal::dbus.new_method_call( 1393 ipmi::MAPPER_BUS_NAME, ipmi::MAPPER_OBJ, ipmi::MAPPER_INTF, 1394 "GetObject"); 1395 1396 mapperCall.append(identify_led_object_name); 1397 static const std::vector<std::string> interfaces = { 1398 "xyz.openbmc_project.Led.Group"}; 1399 mapperCall.append(interfaces); 1400 auto mapperReply = chassis::internal::dbus.call(mapperCall); 1401 if (mapperReply.is_method_error()) 1402 { 1403 log<level::ERR>("Chassis Identify: Error communicating to mapper."); 1404 elog<InternalFailure>(); 1405 } 1406 std::vector<std::pair<std::string, std::vector<std::string>>> mapperResp; 1407 mapperReply.read(mapperResp); 1408 1409 if (mapperResp.size() != encIdentifyObjectsSize) 1410 { 1411 log<level::ERR>( 1412 "Invalid number of enclosure identify objects.", 1413 entry("ENC_IDENTITY_OBJECTS_SIZE=%d", mapperResp.size())); 1414 elog<InternalFailure>(); 1415 } 1416 auto pair = mapperResp[encIdentifyObjectsSize - 1]; 1417 return pair.first; 1418 } 1419 1420 /** @brief Turn On/Off enclosure identify LED 1421 * 1422 * @param[in] flag - true to turn on LED, false to turn off 1423 * @return a IPMI return code 1424 */ 1425 void enclosureIdentifyLed(bool flag) 1426 { 1427 using namespace chassis::internal; 1428 std::string connection = std::move(getEnclosureIdentifyConnection()); 1429 auto msg = std::string("enclosureIdentifyLed(") + 1430 boost::lexical_cast<std::string>(flag) + ")"; 1431 log<level::DEBUG>(msg.c_str()); 1432 auto led = 1433 dbus.new_method_call(connection.c_str(), identify_led_object_name, 1434 "org.freedesktop.DBus.Properties", "Set"); 1435 led.append("xyz.openbmc_project.Led.Group", "Asserted", 1436 std::variant<bool>(flag)); 1437 auto ledReply = dbus.call(led); 1438 if (ledReply.is_method_error()) 1439 { 1440 log<level::ERR>("Chassis Identify: Error Setting State On/Off\n", 1441 entry("LED_STATE=%d", flag)); 1442 elog<InternalFailure>(); 1443 } 1444 } 1445 1446 /** @brief Callback method to turn off LED 1447 */ 1448 void enclosureIdentifyLedOff() 1449 { 1450 try 1451 { 1452 chassisIDState = ChassisIDState::off; 1453 enclosureIdentifyLed(false); 1454 } 1455 catch (const InternalFailure& e) 1456 { 1457 report<InternalFailure>(); 1458 } 1459 } 1460 1461 /** @brief Create timer to turn on and off the enclosure LED 1462 */ 1463 void createIdentifyTimer() 1464 { 1465 if (!identifyTimer) 1466 { 1467 identifyTimer = 1468 std::make_unique<phosphor::Timer>(enclosureIdentifyLedOff); 1469 } 1470 } 1471 1472 ipmi::RspType<> ipmiChassisIdentify(std::optional<uint8_t> interval, 1473 std::optional<uint8_t> force) 1474 { 1475 uint8_t identifyInterval = interval.value_or(DEFAULT_IDENTIFY_TIME_OUT); 1476 bool forceIdentify = force.value_or(0) & 0x01; 1477 1478 if (identifyInterval || forceIdentify) 1479 { 1480 // stop the timer if already started; 1481 // for force identify we should not turn off LED 1482 identifyTimer->stop(); 1483 try 1484 { 1485 chassisIDState = ChassisIDState::temporaryOn; 1486 enclosureIdentifyLed(true); 1487 } 1488 catch (const InternalFailure& e) 1489 { 1490 report<InternalFailure>(); 1491 return ipmi::responseResponseError(); 1492 } 1493 1494 if (forceIdentify) 1495 { 1496 chassisIDState = ChassisIDState::indefiniteOn; 1497 return ipmi::responseSuccess(); 1498 } 1499 // start the timer 1500 auto time = std::chrono::duration_cast<std::chrono::microseconds>( 1501 std::chrono::seconds(identifyInterval)); 1502 identifyTimer->start(time); 1503 } 1504 else if (!identifyInterval) 1505 { 1506 identifyTimer->stop(); 1507 enclosureIdentifyLedOff(); 1508 } 1509 return ipmi::responseSuccess(); 1510 } 1511 1512 namespace boot_options 1513 { 1514 1515 using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server; 1516 using IpmiValue = uint8_t; 1517 constexpr auto ipmiDefault = 0; 1518 1519 std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = { 1520 {0x01, Source::Sources::Network}, 1521 {0x02, Source::Sources::Disk}, 1522 {0x05, Source::Sources::ExternalMedia}, 1523 {0x0f, Source::Sources::RemovableMedia}, 1524 {ipmiDefault, Source::Sources::Default}}; 1525 1526 std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = { 1527 #ifdef ENABLE_BOOT_FLAG_SAFE_MODE_SUPPORT 1528 {0x03, Mode::Modes::Safe}, 1529 #endif // ENABLE_BOOT_SAFE_MODE_SUPPORT 1530 {0x06, Mode::Modes::Setup}, 1531 {ipmiDefault, Mode::Modes::Regular}}; 1532 1533 std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = { 1534 {Source::Sources::Network, 0x01}, 1535 {Source::Sources::Disk, 0x02}, 1536 {Source::Sources::ExternalMedia, 0x05}, 1537 {Source::Sources::RemovableMedia, 0x0f}, 1538 {Source::Sources::Default, ipmiDefault}}; 1539 1540 std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = { 1541 #ifdef ENABLE_BOOT_FLAG_SAFE_MODE_SUPPORT 1542 {Mode::Modes::Safe, 0x03}, 1543 #endif // ENABLE_BOOT_SAFE_MODE_SUPPORT 1544 {Mode::Modes::Setup, 0x06}, 1545 {Mode::Modes::Regular, ipmiDefault}}; 1546 1547 } // namespace boot_options 1548 1549 /** @brief Set the property value for boot source 1550 * @param[in] source - boot source value 1551 * @return On failure return IPMI error. 1552 */ 1553 static ipmi_ret_t setBootSource(const Source::Sources& source) 1554 { 1555 using namespace chassis::internal; 1556 using namespace chassis::internal::cache; 1557 std::variant<std::string> property = convertForMessage(source); 1558 settings::Objects& objects = getObjects(); 1559 auto bootSetting = settings::boot::setting(objects, bootSourceIntf); 1560 const auto& bootSourceSetting = std::get<settings::Path>(bootSetting); 1561 auto method = dbus.new_method_call( 1562 objects.service(bootSourceSetting, bootSourceIntf).c_str(), 1563 bootSourceSetting.c_str(), ipmi::PROP_INTF, "Set"); 1564 method.append(bootSourceIntf, "BootSource", property); 1565 auto reply = dbus.call(method); 1566 if (reply.is_method_error()) 1567 { 1568 log<level::ERR>("Error in BootSource Set"); 1569 report<InternalFailure>(); 1570 return IPMI_CC_UNSPECIFIED_ERROR; 1571 } 1572 return IPMI_CC_OK; 1573 } 1574 1575 /** @brief Set the property value for boot mode 1576 * @param[in] mode - boot mode value 1577 * @return On failure return IPMI error. 1578 */ 1579 static ipmi_ret_t setBootMode(const Mode::Modes& mode) 1580 { 1581 using namespace chassis::internal; 1582 using namespace chassis::internal::cache; 1583 std::variant<std::string> property = convertForMessage(mode); 1584 settings::Objects& objects = getObjects(); 1585 auto bootSetting = settings::boot::setting(objects, bootModeIntf); 1586 const auto& bootModeSetting = std::get<settings::Path>(bootSetting); 1587 auto method = dbus.new_method_call( 1588 objects.service(bootModeSetting, bootModeIntf).c_str(), 1589 bootModeSetting.c_str(), ipmi::PROP_INTF, "Set"); 1590 method.append(bootModeIntf, "BootMode", property); 1591 auto reply = dbus.call(method); 1592 if (reply.is_method_error()) 1593 { 1594 log<level::ERR>("Error in BootMode Set"); 1595 report<InternalFailure>(); 1596 return IPMI_CC_UNSPECIFIED_ERROR; 1597 } 1598 return IPMI_CC_OK; 1599 } 1600 1601 ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 1602 ipmi_request_t request, 1603 ipmi_response_t response, 1604 ipmi_data_len_t data_len, 1605 ipmi_context_t context) 1606 { 1607 using namespace boot_options; 1608 ipmi_ret_t rc = IPMI_CC_PARM_NOT_SUPPORTED; 1609 char* p = NULL; 1610 get_sys_boot_options_response_t* resp = 1611 (get_sys_boot_options_response_t*)response; 1612 get_sys_boot_options_t* reqptr = (get_sys_boot_options_t*)request; 1613 IpmiValue bootOption = ipmiDefault; 1614 1615 std::memset(resp, 0, sizeof(*resp)); 1616 resp->version = SET_PARM_VERSION; 1617 resp->parm = 5; 1618 resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME; 1619 1620 /* 1621 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. 1622 * This is the only parameter used by petitboot. 1623 */ 1624 if (reqptr->parameter == 1625 static_cast<uint8_t>(BootOptionParameter::BOOT_FLAGS)) 1626 { 1627 1628 *data_len = static_cast<uint8_t>(BootOptionResponseSize::BOOT_FLAGS); 1629 using namespace chassis::internal; 1630 using namespace chassis::internal::cache; 1631 1632 try 1633 { 1634 settings::Objects& objects = getObjects(); 1635 auto bootSetting = settings::boot::setting(objects, bootSourceIntf); 1636 const auto& bootSourceSetting = 1637 std::get<settings::Path>(bootSetting); 1638 auto oneTimeEnabled = 1639 std::get<settings::boot::OneTimeEnabled>(bootSetting); 1640 auto method = dbus.new_method_call( 1641 objects.service(bootSourceSetting, bootSourceIntf).c_str(), 1642 bootSourceSetting.c_str(), ipmi::PROP_INTF, "Get"); 1643 method.append(bootSourceIntf, "BootSource"); 1644 auto reply = dbus.call(method); 1645 if (reply.is_method_error()) 1646 { 1647 log<level::ERR>("Error in BootSource Get"); 1648 report<InternalFailure>(); 1649 *data_len = 0; 1650 return IPMI_CC_UNSPECIFIED_ERROR; 1651 } 1652 std::variant<std::string> result; 1653 reply.read(result); 1654 auto bootSource = 1655 Source::convertSourcesFromString(std::get<std::string>(result)); 1656 1657 bootSetting = settings::boot::setting(objects, bootModeIntf); 1658 const auto& bootModeSetting = std::get<settings::Path>(bootSetting); 1659 method = dbus.new_method_call( 1660 objects.service(bootModeSetting, bootModeIntf).c_str(), 1661 bootModeSetting.c_str(), ipmi::PROP_INTF, "Get"); 1662 method.append(bootModeIntf, "BootMode"); 1663 reply = dbus.call(method); 1664 if (reply.is_method_error()) 1665 { 1666 log<level::ERR>("Error in BootMode Get"); 1667 report<InternalFailure>(); 1668 *data_len = 0; 1669 return IPMI_CC_UNSPECIFIED_ERROR; 1670 } 1671 reply.read(result); 1672 auto bootMode = 1673 Mode::convertModesFromString(std::get<std::string>(result)); 1674 1675 bootOption = sourceDbusToIpmi.at(bootSource); 1676 if ((Mode::Modes::Regular == bootMode) && 1677 (Source::Sources::Default == bootSource)) 1678 { 1679 bootOption = ipmiDefault; 1680 } 1681 else if (Source::Sources::Default == bootSource) 1682 { 1683 bootOption = modeDbusToIpmi.at(bootMode); 1684 } 1685 resp->data[1] = (bootOption << 2); 1686 1687 resp->data[0] = oneTimeEnabled 1688 ? SET_PARM_BOOT_FLAGS_VALID_ONE_TIME 1689 : SET_PARM_BOOT_FLAGS_VALID_PERMANENT; 1690 1691 rc = IPMI_CC_OK; 1692 } 1693 catch (InternalFailure& e) 1694 { 1695 cache::objectsPtr.reset(); 1696 report<InternalFailure>(); 1697 *data_len = 0; 1698 return IPMI_CC_UNSPECIFIED_ERROR; 1699 } 1700 } 1701 else if (reqptr->parameter == 1702 static_cast<uint8_t>(BootOptionParameter::OPAL_NETWORK_SETTINGS)) 1703 { 1704 1705 *data_len = 1706 static_cast<uint8_t>(BootOptionResponseSize::OPAL_NETWORK_SETTINGS); 1707 1708 resp->parm = 1709 static_cast<uint8_t>(BootOptionParameter::OPAL_NETWORK_SETTINGS); 1710 1711 int ret = getHostNetworkData(resp); 1712 1713 if (ret < 0) 1714 { 1715 1716 log<level::ERR>( 1717 "getHostNetworkData failed for get_sys_boot_options."); 1718 rc = IPMI_CC_UNSPECIFIED_ERROR; 1719 } 1720 else 1721 rc = IPMI_CC_OK; 1722 } 1723 1724 else 1725 { 1726 log<level::ERR>("Unsupported parameter", 1727 entry("PARAM=0x%x", reqptr->parameter)); 1728 } 1729 1730 if (p) 1731 free(p); 1732 1733 if (rc == IPMI_CC_OK) 1734 { 1735 *data_len += 2; 1736 } 1737 1738 return rc; 1739 } 1740 1741 ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 1742 ipmi_request_t request, 1743 ipmi_response_t response, 1744 ipmi_data_len_t data_len, 1745 ipmi_context_t context) 1746 { 1747 using namespace boot_options; 1748 ipmi_ret_t rc = IPMI_CC_OK; 1749 set_sys_boot_options_t* reqptr = (set_sys_boot_options_t*)request; 1750 1751 std::printf("IPMI SET_SYS_BOOT_OPTIONS reqptr->parameter =[%d]\n", 1752 reqptr->parameter); 1753 1754 // This IPMI command does not have any resposne data 1755 *data_len = 0; 1756 1757 /* 000101 1758 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. 1759 * This is the only parameter used by petitboot. 1760 */ 1761 1762 if (reqptr->parameter == (uint8_t)BootOptionParameter::BOOT_FLAGS) 1763 { 1764 IpmiValue bootOption = ((reqptr->data[1] & 0x3C) >> 2); 1765 using namespace chassis::internal; 1766 using namespace chassis::internal::cache; 1767 auto oneTimeEnabled = false; 1768 constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable"; 1769 constexpr auto oneTimePath = 1770 "/xyz/openbmc_project/control/host0/boot/one_time"; 1771 1772 try 1773 { 1774 bool permanent = 1775 (reqptr->data[0] & SET_PARM_BOOT_FLAGS_PERMANENT) == 1776 SET_PARM_BOOT_FLAGS_PERMANENT; 1777 1778 settings::Objects& objects = getObjects(); 1779 1780 auto bootSetting = settings::boot::setting(objects, bootSourceIntf); 1781 1782 oneTimeEnabled = 1783 std::get<settings::boot::OneTimeEnabled>(bootSetting); 1784 1785 /* 1786 * Check if the current boot setting is onetime or permanent, if the 1787 * request in the command is otherwise, then set the "Enabled" 1788 * property in one_time object path to 'True' to indicate onetime 1789 * and 'False' to indicate permanent. 1790 * 1791 * Once the onetime/permanent setting is applied, then the bootMode 1792 * and bootSource is updated for the corresponding object. 1793 */ 1794 if ((permanent && oneTimeEnabled) || 1795 (!permanent && !oneTimeEnabled)) 1796 { 1797 auto service = ipmi::getService(dbus, enabledIntf, oneTimePath); 1798 1799 ipmi::setDbusProperty(dbus, service, oneTimePath, enabledIntf, 1800 "Enabled", !permanent); 1801 } 1802 1803 auto modeItr = modeIpmiToDbus.find(bootOption); 1804 auto sourceItr = sourceIpmiToDbus.find(bootOption); 1805 if (sourceIpmiToDbus.end() != sourceItr) 1806 { 1807 rc = setBootSource(sourceItr->second); 1808 if (rc != IPMI_CC_OK) 1809 { 1810 *data_len = 0; 1811 return rc; 1812 } 1813 // If a set boot device is mapping to a boot source, then reset 1814 // the boot mode D-Bus property to default. 1815 // This way the ipmid code can determine which property is not 1816 // at the default value 1817 if (sourceItr->second != Source::Sources::Default) 1818 { 1819 setBootMode(Mode::Modes::Regular); 1820 } 1821 } 1822 if (modeIpmiToDbus.end() != modeItr) 1823 { 1824 rc = setBootMode(modeItr->second); 1825 if (rc != IPMI_CC_OK) 1826 { 1827 *data_len = 0; 1828 return rc; 1829 } 1830 // If a set boot device is mapping to a boot mode, then reset 1831 // the boot source D-Bus property to default. 1832 // This way the ipmid code can determine which property is not 1833 // at the default value 1834 if (modeItr->second != Mode::Modes::Regular) 1835 { 1836 setBootSource(Source::Sources::Default); 1837 } 1838 } 1839 if ((modeIpmiToDbus.end() == modeItr) && 1840 (sourceIpmiToDbus.end() == sourceItr)) 1841 { 1842 // return error if boot option is not supported 1843 *data_len = 0; 1844 return IPMI_CC_INVALID_FIELD_REQUEST; 1845 } 1846 } 1847 catch (InternalFailure& e) 1848 { 1849 objectsPtr.reset(); 1850 report<InternalFailure>(); 1851 *data_len = 0; 1852 return IPMI_CC_UNSPECIFIED_ERROR; 1853 } 1854 } 1855 else if (reqptr->parameter == 1856 (uint8_t)BootOptionParameter::OPAL_NETWORK_SETTINGS) 1857 { 1858 1859 int ret = setHostNetworkData(reqptr); 1860 if (ret < 0) 1861 { 1862 log<level::ERR>( 1863 "setHostNetworkData failed for set_sys_boot_options"); 1864 rc = IPMI_CC_UNSPECIFIED_ERROR; 1865 } 1866 } 1867 else if (reqptr->parameter == 1868 static_cast<uint8_t>(BootOptionParameter::BOOT_INFO)) 1869 { 1870 // Handle parameter #4 and return command completed normally 1871 // (IPMI_CC_OK). There is no implementation in OpenBMC for this 1872 // parameter. This is added to support the ipmitool command `chassis 1873 // bootdev` which sends set on parameter #4, before setting the boot 1874 // flags. 1875 rc = IPMI_CC_OK; 1876 } 1877 else 1878 { 1879 log<level::ERR>("Unsupported parameter", 1880 entry("PARAM=0x%x", reqptr->parameter)); 1881 rc = IPMI_CC_PARM_NOT_SUPPORTED; 1882 } 1883 1884 return rc; 1885 } 1886 1887 /** @brief implements Get POH counter command 1888 * @parameter 1889 * - none 1890 * @returns IPMI completion code plus response data 1891 * - minPerCount - Minutes per count 1892 * - counterReading - counter reading 1893 */ 1894 ipmi::RspType<uint8_t, // Minutes per count 1895 uint32_t // Counter reading 1896 > 1897 ipmiGetPOHCounter() 1898 { 1899 // sd_bus error 1900 try 1901 { 1902 return ipmi::responseSuccess(static_cast<uint8_t>(poh::minutesPerCount), 1903 getPOHCounter()); 1904 } 1905 catch (std::exception& e) 1906 { 1907 log<level::ERR>(e.what()); 1908 return ipmi::responseUnspecifiedError(); 1909 } 1910 } 1911 1912 ipmi::RspType<uint3_t, // policy support 1913 uint5_t // reserved 1914 > 1915 ipmiChassisSetPowerRestorePolicy(boost::asio::yield_context yield, 1916 uint3_t policy, uint5_t reserved) 1917 { 1918 power_policy::DbusValue value = 1919 power_policy::RestorePolicy::Policy::AlwaysOff; 1920 1921 if (reserved || (policy > power_policy::noChange)) 1922 { 1923 phosphor::logging::log<level::ERR>( 1924 "Reserved request parameter", 1925 entry("REQ=0x%x", static_cast<int>(policy))); 1926 return ipmi::responseInvalidFieldRequest(); 1927 } 1928 1929 if (policy == power_policy::noChange) 1930 { 1931 // just return the supported policy 1932 return ipmi::responseSuccess(power_policy::allSupport, reserved); 1933 } 1934 1935 for (auto const& it : power_policy::dbusToIpmi) 1936 { 1937 if (it.second == policy) 1938 { 1939 value = it.first; 1940 break; 1941 } 1942 } 1943 1944 try 1945 { 1946 settings::Objects& objects = chassis::internal::cache::getObjects(); 1947 const settings::Path& powerRestoreSetting = 1948 objects.map.at(chassis::internal::powerRestoreIntf).front(); 1949 std::variant<std::string> property = convertForMessage(value); 1950 1951 auto sdbusp = getSdBus(); 1952 boost::system::error_code ec; 1953 sdbusp->yield_method_call<void>( 1954 yield, ec, 1955 objects 1956 .service(powerRestoreSetting, 1957 chassis::internal::powerRestoreIntf) 1958 .c_str(), 1959 powerRestoreSetting, ipmi::PROP_INTF, "Set", 1960 chassis::internal::powerRestoreIntf, "PowerRestorePolicy", 1961 property); 1962 if (ec) 1963 { 1964 phosphor::logging::log<level::ERR>("Unspecified Error"); 1965 return ipmi::responseUnspecifiedError(); 1966 } 1967 } 1968 catch (InternalFailure& e) 1969 { 1970 chassis::internal::cache::objectsPtr.reset(); 1971 report<InternalFailure>(); 1972 return ipmi::responseUnspecifiedError(); 1973 } 1974 1975 return ipmi::responseSuccess(power_policy::allSupport, reserved); 1976 } 1977 1978 ipmi::RspType<> ipmiSetFrontPanelButtonEnables( 1979 ipmi::Context::ptr ctx, bool disablePowerButton, bool disableResetButton, 1980 bool disableDiagButton, bool disableSleepButton, uint4_t reserved) 1981 { 1982 using namespace chassis::internal; 1983 1984 // set power button Enabled property 1985 bool success = setButtonEnabled(ctx, powerButtonPath, powerButtonIntf, 1986 !disablePowerButton); 1987 1988 // set reset button Enabled property 1989 success &= setButtonEnabled(ctx, resetButtonPath, resetButtonIntf, 1990 !disableResetButton); 1991 1992 if (!success) 1993 { 1994 // not all buttons were successfully set 1995 return ipmi::responseUnspecifiedError(); 1996 } 1997 return ipmi::responseSuccess(); 1998 } 1999 2000 void register_netfn_chassis_functions() 2001 { 2002 createIdentifyTimer(); 2003 2004 // Get Chassis Capabilities 2005 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnChassis, 2006 ipmi::chassis::cmdGetChassisCapabilities, 2007 ipmi::Privilege::User, ipmiGetChassisCap); 2008 2009 // Set Front Panel Button Enables 2010 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnChassis, 2011 ipmi::chassis::cmdSetFrontPanelButtonEnables, 2012 ipmi::Privilege::Admin, 2013 ipmiSetFrontPanelButtonEnables); 2014 2015 // Set Chassis Capabilities 2016 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnChassis, 2017 ipmi::chassis::cmdSetChassisCapabilities, 2018 ipmi::Privilege::User, ipmiSetChassisCap); 2019 2020 // <Get System Boot Options> 2021 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS, NULL, 2022 ipmi_chassis_get_sys_boot_options, 2023 PRIVILEGE_OPERATOR); 2024 2025 // <Get Chassis Status> 2026 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnChassis, 2027 ipmi::chassis::cmdGetChassisStatus, 2028 ipmi::Privilege::User, ipmiGetChassisStatus); 2029 2030 // <Chassis Get System Restart Cause> 2031 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnChassis, 2032 ipmi::chassis::cmdGetSystemRestartCause, 2033 ipmi::Privilege::User, ipmiGetSystemRestartCause); 2034 2035 // <Chassis Control> 2036 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnChassis, 2037 ipmi::chassis::cmdChassisControl, 2038 ipmi::Privilege::Operator, ipmiChassisControl); 2039 2040 // <Chassis Identify> 2041 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnChassis, 2042 ipmi::chassis::cmdChassisIdentify, 2043 ipmi::Privilege::Operator, ipmiChassisIdentify); 2044 2045 // <Set System Boot Options> 2046 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS, NULL, 2047 ipmi_chassis_set_sys_boot_options, 2048 PRIVILEGE_OPERATOR); 2049 // <Get POH Counter> 2050 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnChassis, 2051 ipmi::chassis::cmdGetPohCounter, 2052 ipmi::Privilege::User, ipmiGetPOHCounter); 2053 2054 // <Set Power Restore Policy> 2055 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnChassis, 2056 ipmi::chassis::cmdSetPowerRestorePolicy, 2057 ipmi::Privilege::Operator, 2058 ipmiChassisSetPowerRestorePolicy); 2059 } 2060