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/log.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 phosphor::logging; 31 using namespace sdbusplus::server::xyz::openbmc_project::control; 32 33 void SoftPowerOff::sendHostShutDownCmd() 34 { 35 auto ctrlHostPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + HOST_NAME + 36 '0'; 37 auto host = ::ipmi::getService(this->bus, CONTROL_HOST_BUSNAME, 38 ctrlHostPath.c_str()); 39 40 auto method = bus.new_method_call(host.c_str(), ctrlHostPath.c_str(), 41 CONTROL_HOST_BUSNAME, "Execute"); 42 43 method.append(convertForMessage(Host::Command::SoftOff).c_str()); 44 try 45 { 46 auto reply = bus.call(method); 47 } 48 catch (const std::exception& e) 49 { 50 log<level::ERR>("Error in call to control host Execute", 51 entry("ERROR=%s", e.what())); 52 // TODO openbmc/openbmc#851 - Once available, throw returned error 53 throw std::runtime_error("Error in call to control host Execute"); 54 } 55 } 56 57 // Function called on host control signals 58 void SoftPowerOff::hostControlEvent(sdbusplus::message_t& msg) 59 { 60 std::string cmdCompleted{}; 61 std::string cmdStatus{}; 62 63 msg.read(cmdCompleted, cmdStatus); 64 65 log<level::DEBUG>("Host control signal values", 66 entry("COMMAND=%s", cmdCompleted.c_str()), 67 entry("STATUS=%s", cmdStatus.c_str())); 68 69 if (Host::convertResultFromString(cmdStatus) == Host::Result::Success) 70 { 71 // Set our internal property indicating we got host attention 72 sdbusplus::server::xyz::openbmc_project::ipmi::internal::SoftPowerOff:: 73 responseReceived(HostResponse::SoftOffReceived); 74 75 // Start timer for host shutdown 76 using namespace std::chrono; 77 auto time = duration_cast<microseconds>( 78 seconds(IPMI_HOST_SHUTDOWN_COMPLETE_TIMEOUT_SECS)); 79 auto r = startTimer(time); 80 if (r < 0) 81 { 82 log<level::ERR>("Failure to start Host shutdown wait timer", 83 entry("ERRNO=0x%X", -r)); 84 } 85 else 86 { 87 log<level::INFO>( 88 "Timer started waiting for host to shutdown", 89 entry("TIMEOUT_IN_MSEC=%llu", 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 log<level::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 log<level::ERR>("Failure to STOP the timer", 124 entry("ERRNO=0x%X", -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