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 <chrono> 17 #include <phosphor-logging/log.hpp> 18 #include <xyz/openbmc_project/Control/Host/server.hpp> 19 #include <utils.hpp> 20 #include "softoff.hpp" 21 #include "config.h" 22 namespace phosphor 23 { 24 namespace ipmi 25 { 26 27 using namespace phosphor::logging; 28 using namespace sdbusplus::xyz::openbmc_project::Control::server; 29 30 void SoftPowerOff::sendHostShutDownCmd() 31 { 32 auto ctrlHostPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + 33 HOST_NAME + '0'; 34 auto host = ::ipmi::getService(this->bus, 35 CONTROL_HOST_BUSNAME, 36 ctrlHostPath.c_str()); 37 38 auto method = bus.new_method_call(host.c_str(), 39 ctrlHostPath.c_str(), 40 CONTROL_HOST_BUSNAME, 41 "Execute"); 42 43 method.append(convertForMessage(Host::Command::SoftOff).c_str()); 44 45 auto reply = bus.call(method); 46 if (reply.is_method_error()) 47 { 48 log<level::ERR>("Error in call to control host Execute"); 49 // TODO openbmc/openbmc#851 - Once available, throw returned error 50 throw std::runtime_error("Error in call to control host Execute"); 51 } 52 53 return; 54 } 55 56 57 // Function called on host control signals 58 void SoftPowerOff::hostControlEvent(sdbusplus::message::message& 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::xyz::openbmc_project::Ipmi::Internal 73 ::server::SoftPowerOff::responseReceived( 74 HostResponse::SoftOffReceived); 75 76 // Start timer for host shutdown 77 using namespace std::chrono; 78 auto time = duration_cast<microseconds>( 79 seconds(IPMI_HOST_SHUTDOWN_COMPLETE_TIMEOUT_SECS)); 80 auto r = startTimer(time); 81 if (r < 0) 82 { 83 log<level::ERR>("Failure to start Host shutdown wait timer", 84 entry("ERRNO=0x%X", -r)); 85 } 86 else 87 { 88 log<level::INFO>("Timer started waiting for host to shutdown", 89 entry("TIMEOUT_IN_MSEC=%llu", 90 (duration_cast<milliseconds>(seconds 91 (IPMI_HOST_SHUTDOWN_COMPLETE_TIMEOUT_SECS))).count())); 92 } 93 } 94 else 95 { 96 // An error on the initial attention is not considered an error, just 97 // exit normally and allow remaining shutdown targets to run 98 log<level::INFO>("Timeout on host attention, continue with power down"); 99 completed = true; 100 } 101 return; 102 } 103 104 // Starts a timer 105 int SoftPowerOff::startTimer(const std::chrono::microseconds& usec) 106 { 107 return timer.startTimer(usec); 108 } 109 110 // Host Response handler 111 auto SoftPowerOff::responseReceived(HostResponse response) -> HostResponse 112 { 113 using namespace std::chrono; 114 115 if (response == HostResponse::HostShutdown) 116 { 117 // Disable the timer since Host has quiesced and we are 118 // done with soft power off part 119 auto r = timer.setTimer(SD_EVENT_OFF); 120 if (r < 0) 121 { 122 log<level::ERR>("Failure to STOP the timer", 123 entry("ERRNO=0x%X", -r)); 124 } 125 126 // This marks the completion of soft power off sequence. 127 completed = true; 128 } 129 130 return sdbusplus::xyz::openbmc_project::Ipmi::Internal 131 ::server::SoftPowerOff::responseReceived(response); 132 } 133 134 } // namespace ipmi 135 } // namespace phosphor 136