1 #include "occ_status.hpp"
2 
3 #include "occ_sensor.hpp"
4 #include "utils.hpp"
5 
6 #include <phosphor-logging/log.hpp>
7 namespace open_power
8 {
9 namespace occ
10 {
11 
12 // Handles updates to occActive property
13 bool Status::occActive(bool value)
14 {
15     if (value != this->occActive())
16     {
17         if (value)
18         {
19             // Bind the device
20             device.bind();
21 
22             // Start watching for errors
23             addErrorWatch();
24 
25             // Call into Manager to let know that we have bound
26             if (this->callBack)
27             {
28                 this->callBack(value);
29             }
30         }
31         else
32         {
33             // Call into Manager to let know that we will unbind.
34             if (this->callBack)
35             {
36                 this->callBack(value);
37             }
38 
39             // Stop watching for errors
40             removeErrorWatch();
41 
42             // Do the unbind.
43             device.unBind();
44         }
45     }
46     else if (value && !device.bound())
47     {
48         // Existing error watch is on a dead file descriptor.
49         removeErrorWatch();
50 
51         /*
52          * In it's constructor, Status checks Device::bound() to see if OCC is
53          * active or not.
54          * Device::bound() checks for occX-dev0 directory.
55          * We will lose occX-dev0 directories during FSI rescan.
56          * So, if we start this application (and construct Status), and then
57          * later do FSI rescan, we will end up with occActive = true and device
58          * NOT bound. Lets correct that situation here.
59          */
60         device.bind();
61 
62         // Add error watch again
63         addErrorWatch();
64     }
65     return Base::Status::occActive(value);
66 }
67 
68 // Callback handler when a device error is reported.
69 void Status::deviceErrorHandler(bool error)
70 {
71     // Make sure we have an error
72     if (error)
73     {
74         // This would deem OCC inactive
75         this->occActive(false);
76 
77         // Reset the OCC
78         this->resetOCC();
79     }
80 }
81 
82 // Sends message to host control command handler to reset OCC
83 void Status::resetOCC()
84 {
85     using namespace phosphor::logging;
86     constexpr auto CONTROL_HOST_PATH = "/org/open_power/control/host0";
87     constexpr auto CONTROL_HOST_INTF = "org.open_power.Control.Host";
88 
89     // This will throw exception on failure
90     auto service = getService(bus, CONTROL_HOST_PATH, CONTROL_HOST_INTF);
91 
92     auto method = bus.new_method_call(service.c_str(), CONTROL_HOST_PATH,
93                                       CONTROL_HOST_INTF, "Execute");
94     // OCC Reset control command
95     method.append(convertForMessage(Control::Host::Command::OCCReset).c_str());
96 
97     // OCC Sensor ID for callout reasons
98     method.append(sdbusplus::message::variant<uint8_t>(
99         std::get<0>(sensorMap.at(instance))));
100     bus.call_noreply(method);
101     return;
102 }
103 
104 // Handler called by Host control command handler to convey the
105 // status of the executed command
106 void Status::hostControlEvent(sdbusplus::message::message& msg)
107 {
108     using namespace phosphor::logging;
109 
110     std::string cmdCompleted{};
111     std::string cmdStatus{};
112 
113     msg.read(cmdCompleted, cmdStatus);
114 
115     log<level::DEBUG>("Host control signal values",
116                       entry("COMMAND=%s", cmdCompleted.c_str()),
117                       entry("STATUS=%s", cmdStatus.c_str()));
118 
119     if (Control::Host::convertResultFromString(cmdStatus) !=
120         Control::Host::Result::Success)
121     {
122         if (Control::Host::convertCommandFromString(cmdCompleted) ==
123             Control::Host::Command::OCCReset)
124         {
125             // Must be a Timeout. Log an Error trace
126             log<level::ERR>(
127                 "Error resetting the OCC.", entry("PATH=%s", path.c_str()),
128                 entry("SENSORID=0x%X", std::get<0>(sensorMap.at(instance))));
129         }
130     }
131     return;
132 }
133 
134 } // namespace occ
135 } // namespace open_power
136