1 #include "file_io_type_power_control.hpp"
2
3 #include <phosphor-logging/lg2.hpp>
4 #include <xyz/openbmc_project/State/Host/client.hpp>
5
6 PHOSPHOR_LOG2_USING;
7
8 using HostState = sdbusplus::common::xyz::openbmc_project::state::Host;
9
10 namespace pldm::responder::oem_meta
11 {
12
13 uint8_t power_control_len = 1;
14 enum class POWER_CONTROL_OPTION
15 {
16 SLED_CYCLE = 0x00,
17 SLOT_12V_CYCLE = 0x01,
18 SLOT_DC_CYCLE = 0x02,
19 NIC0_POWER_CYCLE = 0x03,
20 NIC1_POWER_CYCLE = 0x04,
21 NIC2_POWER_CYCLE = 0x05,
22 NIC3_POWER_CYCLE = 0x06,
23 };
24
write(const message & data)25 int PowerControlHandler::write(const message& data)
26 {
27 if (data.size() != power_control_len)
28 {
29 error(
30 "Invalid incoming data for controlling power, data size {SIZE} bytes",
31 "SIZE", data.size());
32 return PLDM_ERROR;
33 }
34
35 std::string slotNum = pldm::oem_meta::getSlotNumberStringByTID(tid);
36 uint8_t option = data[0];
37 pldm::utils::DBusMapping dbusMapping;
38 dbusMapping.propertyType = "string";
39 std::string property{};
40 switch (option)
41 {
42 case static_cast<uint8_t>(POWER_CONTROL_OPTION::SLED_CYCLE):
43 dbusMapping.objectPath =
44 std::string("/xyz/openbmc_project/state/chassis0");
45 dbusMapping.interface = "xyz.openbmc_project.State.Chassis";
46 dbusMapping.propertyName = "RequestedPowerTransition";
47 property =
48 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
49 break;
50 case static_cast<uint8_t>(POWER_CONTROL_OPTION::SLOT_12V_CYCLE):
51 dbusMapping.objectPath =
52 std::string("/xyz/openbmc_project/state/chassis") + slotNum;
53 dbusMapping.interface = "xyz.openbmc_project.State.Chassis";
54 dbusMapping.propertyName = "RequestedPowerTransition";
55 property =
56 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
57 break;
58 case static_cast<uint8_t>(POWER_CONTROL_OPTION::SLOT_DC_CYCLE):
59 dbusMapping.objectPath =
60 std::format("{}/{}{}", HostState::namespace_path::value,
61 HostState::namespace_path::host, slotNum);
62 dbusMapping.interface = HostState::interface;
63 dbusMapping.propertyName =
64 HostState::property_names::requested_host_transition;
65 property = "xyz.openbmc_project.State.Host.Transition.Reboot";
66 break;
67 case static_cast<uint8_t>(POWER_CONTROL_OPTION::NIC0_POWER_CYCLE):
68 case static_cast<uint8_t>(POWER_CONTROL_OPTION::NIC1_POWER_CYCLE):
69 case static_cast<uint8_t>(POWER_CONTROL_OPTION::NIC2_POWER_CYCLE):
70 case static_cast<uint8_t>(POWER_CONTROL_OPTION::NIC3_POWER_CYCLE):
71 {
72 static constexpr auto systemd_busname = "org.freedesktop.systemd1";
73 static constexpr auto systemd_path = "/org/freedesktop/systemd1";
74 static constexpr auto systemd_interface =
75 "org.freedesktop.systemd1.Manager";
76 uint8_t nic_index =
77 option -
78 static_cast<uint8_t>(POWER_CONTROL_OPTION::NIC0_POWER_CYCLE);
79 try
80 {
81 auto& bus = pldm::utils::DBusHandler::getBus();
82 auto method =
83 bus.new_method_call(systemd_busname, systemd_path,
84 systemd_interface, "StartUnit");
85 method.append("nic-powercycle@" + std::to_string(nic_index) +
86 ".service",
87 "replace");
88 bus.call_noreply(method);
89 }
90 catch (const std::exception& e)
91 {
92 error("Control NIC{NUM} power fail. ERROR={ERROR}", "NUM",
93 nic_index, "ERROR", e);
94 return PLDM_ERROR;
95 }
96 return PLDM_SUCCESS;
97 }
98 default:
99 error("Get invalid power control option, option={OPTION}", "OPTION",
100 option);
101 return PLDM_ERROR;
102 }
103
104 try
105 {
106 dBusIntf->setDbusProperty(dbusMapping, property);
107 }
108 catch (const sdbusplus::exception_t& e)
109 {
110 error("Failed to execute Dbus call with error code {ERROR}", "ERROR",
111 e);
112 return PLDM_ERROR;
113 }
114 catch (const std::exception& e)
115 {
116 error("Failed to control power with error code {ERROR}", "ERROR", e);
117 return PLDM_ERROR;
118 }
119
120 return PLDM_SUCCESS;
121 }
122
123 } // namespace pldm::responder::oem_meta
124