1 /** 2 * Copyright © 2016 IBM 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 #include "config.h" 17 18 #include "softoff.hpp" 19 20 #include <ipmid/utils.hpp> 21 #include <phosphor-logging/lg2.hpp> 22 #include <xyz/openbmc_project/Control/Host/server.hpp> 23 24 #include <chrono> 25 namespace phosphor 26 { 27 namespace ipmi 28 { 29 30 using namespace sdbusplus::server::xyz::openbmc_project::control; 31 32 void SoftPowerOff::sendHostShutDownCmd() 33 { 34 auto ctrlHostPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + HOST_NAME + 35 '0'; 36 auto host = ::ipmi::getService(this->bus, CONTROL_HOST_BUSNAME, 37 ctrlHostPath.c_str()); 38 39 auto method = bus.new_method_call(host.c_str(), ctrlHostPath.c_str(), 40 CONTROL_HOST_BUSNAME, "Execute"); 41 42 method.append(convertForMessage(Host::Command::SoftOff).c_str()); 43 try 44 { 45 auto reply = bus.call(method); 46 } 47 catch (const std::exception& e) 48 { 49 lg2::error("Error in call to control host Execute: {ERROR}", "ERROR", 50 e); 51 // TODO openbmc/openbmc#851 - Once available, throw returned error 52 throw std::runtime_error("Error in call to control host Execute"); 53 } 54 } 55 56 // Function called on host control signals 57 void SoftPowerOff::hostControlEvent(sdbusplus::message_t& msg) 58 { 59 std::string cmdCompleted{}; 60 std::string cmdStatus{}; 61 62 msg.read(cmdCompleted, cmdStatus); 63 64 lg2::debug( 65 "Host control signal values, command: {COMMAND}, status:{STATUS}", 66 "COMMAND", cmdCompleted, "STATUS", cmdStatus); 67 68 if (Host::convertResultFromString(cmdStatus) == Host::Result::Success) 69 { 70 // Set our internal property indicating we got host attention 71 sdbusplus::server::xyz::openbmc_project::ipmi::internal::SoftPowerOff:: 72 responseReceived(HostResponse::SoftOffReceived); 73 74 // Start timer for host shutdown 75 using namespace std::chrono; 76 auto time = duration_cast<microseconds>( 77 seconds(IPMI_HOST_SHUTDOWN_COMPLETE_TIMEOUT_SECS)); 78 auto r = startTimer(time); 79 if (r < 0) 80 { 81 lg2::error( 82 "Failure to start Host shutdown wait timer, ERRNO: {ERRNO}", 83 "ERRNO", lg2::hex, -r); 84 } 85 else 86 { 87 lg2::info("Timer started waiting for host to shutdown, " 88 "TIMEOUT_IN_MSEC: {TIMEOUT_IN_MSEC}", 89 "TIMEOUT_IN_MSEC", 90 (duration_cast<milliseconds>( 91 seconds(IPMI_HOST_SHUTDOWN_COMPLETE_TIMEOUT_SECS))) 92 .count()); 93 } 94 } 95 else 96 { 97 // An error on the initial attention is not considered an error, just 98 // exit normally and allow remaining shutdown targets to run 99 lg2::info("Timeout on host attention, continue with power down"); 100 completed = true; 101 } 102 return; 103 } 104 105 // Starts a timer 106 int SoftPowerOff::startTimer(const std::chrono::microseconds& usec) 107 { 108 return timer.start(usec); 109 } 110 111 // Host Response handler 112 auto SoftPowerOff::responseReceived(HostResponse response) -> HostResponse 113 { 114 using namespace std::chrono; 115 116 if (response == HostResponse::HostShutdown) 117 { 118 // Disable the timer since Host has quiesced and we are 119 // done with soft power off part 120 auto r = timer.stop(); 121 if (r < 0) 122 { 123 lg2::error("Failure to STOP the timer, ERRNO: {ERRNO}", "ERRNO", 124 lg2::hex, -r); 125 } 126 127 // This marks the completion of soft power off sequence. 128 completed = true; 129 } 130 131 return sdbusplus::server::xyz::openbmc_project::ipmi::internal:: 132 SoftPowerOff::responseReceived(response); 133 } 134 135 } // namespace ipmi 136 } // namespace phosphor 137