diff options
Diffstat (limited to 'chassishandler.cpp')
-rw-r--r-- | chassishandler.cpp | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/chassishandler.cpp b/chassishandler.cpp index 0eef0a0..43c3fe3 100644 --- a/chassishandler.cpp +++ b/chassishandler.cpp @@ -17,6 +17,8 @@ #include <sstream> #include <array> #include <fstream> +#include <future> +#include <chrono> #include <experimental/filesystem> #include <string> #include <map> @@ -47,6 +49,7 @@ constexpr size_t SIZE_PREFIX = 7; constexpr size_t MAX_PREFIX_VALUE = 32; constexpr size_t SIZE_COOKIE = 4; constexpr size_t SIZE_VERSION = 2; +constexpr size_t DEFAULT_IDENTIFY_TIME_OUT = 15; //PetiBoot-Specific static constexpr uint8_t net_conf_initial_bytes[] = {0x80, 0x21, 0x70, 0x62, @@ -67,6 +70,8 @@ void register_netfn_chassis_functions() __attribute__((constructor)); const char *settings_object_name = "/org/openbmc/settings/host0"; const char *settings_intf_name = "org.freedesktop.DBus.Properties"; const char *host_intf_name = "org.openbmc.settings.Host"; +const char *identify_led_object_name = + "/xyz/openbmc_project/led/groups/enclosure_identify"; constexpr auto SETTINGS_ROOT = "/"; constexpr auto SETTINGS_MATCH = "host0"; @@ -1025,6 +1030,111 @@ ipmi_ret_t ipmi_chassis_control(ipmi_netfn_t netfn, ipmi_cmd_t cmd, return ( (rc < 0) ? IPMI_CC_INVALID : IPMI_CC_OK); } +ipmi_ret_t ipmi_chassis_identify(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, + ipmi_response_t response, + ipmi_data_len_t data_len, + ipmi_context_t context) +{ + static std::atomic_size_t currentCallerId(0); + static std::unique_ptr<std::future<void>> future; + static std::condition_variable condition; + static std::mutex timeoutMutex; + + if (*data_len > 2) + { + return IPMI_CC_REQ_DATA_LEN_INVALID; + } + uint8_t identifyInterval = *data_len > 0 ? + (static_cast<uint8_t*>(request))[0] : + DEFAULT_IDENTIFY_TIME_OUT; + bool forceIdentify = + *data_len == 2 ? (static_cast<uint8_t*>(request))[1] & 0x01 : false; + + currentCallerId++; + + // stop any threads currently running + condition.notify_all(); + + // lookup enclosure_identify group owner(s) in mapper + auto mapperCall = chassis::internal::dbus.new_method_call( + ipmi::MAPPER_BUS_NAME, + ipmi::MAPPER_OBJ, + ipmi::MAPPER_INTF, + "GetObject"); + + mapperCall.append(identify_led_object_name); + static const std::vector<std::string> interfaces = + { + "xyz.openbmc_project.Led.Group" + }; + mapperCall.append(interfaces); + auto mapperReply = chassis::internal::dbus.call(mapperCall); + if (mapperReply.is_method_error()) + { + log<level::ERR>("Chassis Identify: Error communicating to mapper."); + return IPMI_CC_RESPONSE_ERROR; + } + std::vector<std::pair<std::string, std::vector<std::string>>> mapperResp; + mapperReply.read(mapperResp); + + for (auto& object : mapperResp) + { + std::string& connection = object.first; + + if (identifyInterval || forceIdentify) + { + auto ledOn = chassis::internal::dbus.new_method_call( + connection.c_str(), + identify_led_object_name, + "org.freedesktop.DBus.Properties", "Set"); + ledOn.append( + "xyz.openbmc_project.Led.Group", "Asserted", + sdbusplus::message::variant<bool>( + true)); + auto ledReply = chassis::internal::dbus.call(ledOn); + if (ledReply.is_method_error()) + { + log<level::ERR>("Chassis Identify: Error Setting State On\n"); + return IPMI_CC_RESPONSE_ERROR; + } + if (forceIdentify) + { + return IPMI_CC_OK; + } + } + + size_t threadCallerId = currentCallerId; + future = std::make_unique<std::future<void>>( + std::async(std::launch::async, + [connection, + identifyInterval, + threadCallerId] + { + std::unique_lock<std::mutex> lock(timeoutMutex); + if (condition.wait_for(lock, + std::chrono::seconds(identifyInterval), + [&threadCallerId]{return currentCallerId != threadCallerId;})) + { + return; // another thread started. + } + auto ledOff = chassis::internal::dbus.new_method_call( + connection.c_str(), + identify_led_object_name, + "org.freedesktop.DBus.Properties", "Set"); + ledOff.append("xyz.openbmc_project.Led.Group", "Asserted", + sdbusplus::message::variant<bool>( + false)); + auto ledReply = chassis::internal::dbus.call(ledOff); + if (ledReply.is_method_error()) + { + log<level::ERR>("Chassis Identify: Error Setting State Off\n"); + } + })); + } + return IPMI_CC_OK; +} + namespace boot_options { @@ -1377,6 +1487,11 @@ void register_netfn_chassis_functions() ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL, NULL, ipmi_chassis_control, PRIVILEGE_OPERATOR); + // <Chassis Identify> + printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_CHASSIS_IDENTIFY); + ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_IDENTIFY, NULL, + ipmi_chassis_identify, PRIVILEGE_OPERATOR); + // <Set System Boot Options> printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS); ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS, NULL, |