1 #include "occ_status.hpp" 2 3 #include "occ_sensor.hpp" 4 #include "utils.hpp" 5 6 #include <fmt/core.h> 7 8 #include <phosphor-logging/log.hpp> 9 namespace open_power 10 { 11 namespace occ 12 { 13 using namespace phosphor::logging; 14 15 // Handles updates to occActive property 16 bool Status::occActive(bool value) 17 { 18 if (value != this->occActive()) 19 { 20 log<level::INFO>(fmt::format("Status::occActive OCC{} changed to {}", 21 instance, value) 22 .c_str()); 23 if (value) 24 { 25 // Bind the device 26 device.bind(); 27 28 // Start watching for errors 29 addErrorWatch(); 30 31 // Reset last OCC state 32 lastState = 0; 33 34 // Call into Manager to let know that we have bound 35 if (this->callBack) 36 { 37 this->callBack(value); 38 } 39 } 40 else 41 { 42 // Call into Manager to let know that we will unbind. 43 if (this->callBack) 44 { 45 this->callBack(value); 46 } 47 48 // Stop watching for errors 49 removeErrorWatch(); 50 51 // Do the unbind. 52 device.unBind(); 53 } 54 } 55 else if (value && !device.bound()) 56 { 57 // Existing error watch is on a dead file descriptor. 58 removeErrorWatch(); 59 60 /* 61 * In it's constructor, Status checks Device::bound() to see if OCC is 62 * active or not. 63 * Device::bound() checks for occX-dev0 directory. 64 * We will lose occX-dev0 directories during FSI rescan. 65 * So, if we start this application (and construct Status), and then 66 * later do FSI rescan, we will end up with occActive = true and device 67 * NOT bound. Lets correct that situation here. 68 */ 69 device.bind(); 70 71 // Add error watch again 72 addErrorWatch(); 73 } 74 else if (!value && device.bound()) 75 { 76 removeErrorWatch(); 77 78 // In the event that the application never receives the active signal 79 // even though the OCC is active (this can occur if the BMC is rebooted 80 // with the host on, since the initial OCC driver probe will discover 81 // the OCCs), this application needs to be able to unbind the device 82 // when we get the OCC inactive signal. 83 device.unBind(); 84 } 85 return Base::Status::occActive(value); 86 } 87 88 // Callback handler when a device error is reported. 89 void Status::deviceErrorHandler(bool error) 90 { 91 // Make sure we have an error 92 if (error) 93 { 94 // This would deem OCC inactive 95 this->occActive(false); 96 97 // Reset the OCC 98 this->resetOCC(); 99 } 100 } 101 102 // Sends message to host control command handler to reset OCC 103 void Status::resetOCC() 104 { 105 log<level::INFO>( 106 fmt::format(">>Status::resetOCC() - requesting reset for OCC{}", 107 instance) 108 .c_str()); 109 #ifdef PLDM 110 if (resetCallBack) 111 { 112 this->resetCallBack(instance); 113 } 114 #else 115 constexpr auto CONTROL_HOST_PATH = "/org/open_power/control/host0"; 116 constexpr auto CONTROL_HOST_INTF = "org.open_power.Control.Host"; 117 118 // This will throw exception on failure 119 auto service = utils::getService(CONTROL_HOST_PATH, CONTROL_HOST_INTF); 120 121 auto& bus = utils::getBus(); 122 auto method = bus.new_method_call(service.c_str(), CONTROL_HOST_PATH, 123 CONTROL_HOST_INTF, "Execute"); 124 // OCC Reset control command 125 method.append(convertForMessage(Control::Host::Command::OCCReset).c_str()); 126 127 // OCC Sensor ID for callout reasons 128 method.append(std::variant<uint8_t>(std::get<0>(sensorMap.at(instance)))); 129 bus.call_noreply(method); 130 return; 131 #endif 132 } 133 134 // Handler called by Host control command handler to convey the 135 // status of the executed command 136 void Status::hostControlEvent(sdbusplus::message::message& msg) 137 { 138 using namespace phosphor::logging; 139 140 std::string cmdCompleted{}; 141 std::string cmdStatus{}; 142 143 msg.read(cmdCompleted, cmdStatus); 144 145 log<level::DEBUG>("Host control signal values", 146 entry("COMMAND=%s", cmdCompleted.c_str()), 147 entry("STATUS=%s", cmdStatus.c_str())); 148 149 if (Control::Host::convertResultFromString(cmdStatus) != 150 Control::Host::Result::Success) 151 { 152 if (Control::Host::convertCommandFromString(cmdCompleted) == 153 Control::Host::Command::OCCReset) 154 { 155 // Must be a Timeout. Log an Error trace 156 log<level::ERR>( 157 "Error resetting the OCC.", entry("PATH=%s", path.c_str()), 158 entry("SENSORID=0x%X", std::get<0>(sensorMap.at(instance)))); 159 } 160 } 161 return; 162 } 163 164 void Status::readOccState() 165 { 166 unsigned int state; 167 const fs::path filename = 168 fs::path(DEV_PATH) / 169 fs::path(sysfsName + "." + std::to_string(instance + 1)) / "occ_state"; 170 171 log<level::DEBUG>( 172 fmt::format("Status::readOccState: reading OCC{} state from {}", 173 instance, filename.c_str()) 174 .c_str()); 175 176 std::ifstream file(filename, std::ios::in); 177 const int open_errno = errno; 178 if (file) 179 { 180 file >> state; 181 if (state != lastState) 182 { 183 // Trace OCC state changes 184 log<level::INFO>( 185 fmt::format("Status::readOccState: OCC{} state 0x{:02X}", 186 instance, state) 187 .c_str()); 188 lastState = state; 189 } 190 file.close(); 191 } 192 else 193 { 194 // If not able to read, OCC may be offline 195 log<level::DEBUG>( 196 fmt::format("Status::readOccState: open failed (errno={})", 197 open_errno) 198 .c_str()); 199 lastState = 0; 200 } 201 } 202 203 } // namespace occ 204 } // namespace open_power 205