blob: 3c0424131aed42eb027629db1bb0d6505cfd5b6f [file] [log] [blame]
Andrew Jeffery275f7c32024-01-31 12:41:14 +10301#include "MCTPReactor.hpp"
2
3#include "MCTPDeviceRepository.hpp"
4#include "MCTPEndpoint.hpp"
5#include "Utils.hpp"
6
7#include <boost/system/detail/error_code.hpp>
8#include <phosphor-logging/lg2.hpp>
9
Andrew Jeffery275f7c32024-01-31 12:41:14 +103010#include <memory>
11#include <optional>
12#include <string>
13#include <system_error>
14#include <utility>
15#include <vector>
16
17PHOSPHOR_LOG2_USING;
18
19void MCTPReactor::deferSetup(const std::shared_ptr<MCTPDevice>& dev)
20{
21 debug("Deferring setup for MCTP device at [ {MCTP_DEVICE} ]", "MCTP_DEVICE",
22 dev->describe());
23
24 deferred.emplace(dev);
25}
26
27void MCTPReactor::untrackEndpoint(const std::shared_ptr<MCTPEndpoint>& ep)
28{
29 server.disassociate(MCTPDEndpoint::path(ep));
30}
31
32void MCTPReactor::trackEndpoint(const std::shared_ptr<MCTPEndpoint>& ep)
33{
34 info("Added MCTP endpoint to device: [ {MCTP_ENDPOINT} ]", "MCTP_ENDPOINT",
35 ep->describe());
36
37 ep->subscribe(
38 // Degraded
39 [](const std::shared_ptr<MCTPEndpoint>& ep) {
40 debug("Endpoint entered degraded state: [ {MCTP_ENDPOINT} ]",
41 "MCTP_ENDPOINT", ep->describe());
42 },
43 // Available
44 [](const std::shared_ptr<MCTPEndpoint>& ep) {
45 debug("Endpoint entered available state: [ {MCTP_ENDPOINT} ]",
46 "MCTP_ENDPOINT", ep->describe());
47 },
48 // Removed
49 [weak{weak_from_this()}](const std::shared_ptr<MCTPEndpoint>& ep) {
50 info("Removed MCTP endpoint from device: [ {MCTP_ENDPOINT} ]",
51 "MCTP_ENDPOINT", ep->describe());
52 if (auto self = weak.lock())
53 {
54 self->untrackEndpoint(ep);
55 // Only defer the setup if we know inventory is still present
56 if (self->devices.contains(ep->device()))
57 {
58 self->deferSetup(ep->device());
59 }
60 }
61 else
62 {
63 info(
64 "The reactor object was destroyed concurrent to the removal of the remove match for the endpoint '{MCTP_ENDPOINT}'",
65 "MCTP_ENDPOINT", ep->describe());
66 }
67 });
68
69 // Proxy-host the association back to the inventory at the same path as the
70 // endpoint in mctpd.
71 //
72 // clang-format off
73 // ```
Thu Nguyen19d1fda2024-12-05 08:43:06 +000074 // # busctl call xyz.openbmc_project.ObjectMapper /xyz/openbmc_project/object_mapper xyz.openbmc_project.ObjectMapper GetAssociatedSubTree ooias /au/com/codeconstruct/mctp1/networks/1/endpoints/9/configured_by / 0 1 xyz.openbmc_project.Configuration.MCTPDevice
Andrew Jeffery275f7c32024-01-31 12:41:14 +103075 // a{sa{sas}} 1 "/xyz/openbmc_project/inventory/system/nvme/NVMe_1/NVMe_1_Temp" 1 "xyz.openbmc_project.EntityManager" 1 "xyz.openbmc_project.Configuration.MCTPDevice"
76 // ```
77 // clang-format on
78 std::optional<std::string> item = devices.inventoryFor(ep->device());
79 if (!item)
80 {
81 error("Inventory missing for endpoint: [ {MCTP_ENDPOINT} ]",
82 "MCTP_ENDPOINT", ep->describe());
83 return;
84 }
85 std::vector<Association> associations{
86 {"configured_by", "configures", *item}};
87 server.associate(MCTPDEndpoint::path(ep), associations);
88}
89
90void MCTPReactor::setupEndpoint(const std::shared_ptr<MCTPDevice>& dev)
91{
92 debug(
93 "Attempting to setup up MCTP endpoint for device at [ {MCTP_DEVICE} ]",
94 "MCTP_DEVICE", dev->describe());
95 dev->setup([weak{weak_from_this()},
96 dev](const std::error_code& ec,
97 const std::shared_ptr<MCTPEndpoint>& ep) mutable {
98 auto self = weak.lock();
99 if (!self)
100 {
101 info(
102 "The reactor object was destroyed concurrent to the completion of the endpoint setup for '{MCTP_ENDPOINT}'",
103 "MCTP_ENDPOINT", ep->describe());
104 return;
105 }
106
107 if (ec)
108 {
109 debug(
110 "Setup failed for MCTP device at [ {MCTP_DEVICE} ]: {ERROR_MESSAGE}",
111 "MCTP_DEVICE", dev->describe(), "ERROR_MESSAGE", ec.message());
112
113 self->deferSetup(dev);
114 return;
115 }
116
117 try
118 {
119 self->trackEndpoint(ep);
120 }
121 catch (const MCTPException& e)
122 {
123 error("Failed to track endpoint '{MCTP_ENDPOINT}': {EXCEPTION}",
124 "MCTP_ENDPOINT", ep->describe(), "EXCEPTION", e);
125 self->deferSetup(dev);
126 }
127 });
128}
129
130void MCTPReactor::tick()
131{
132 auto toSetup = std::exchange(deferred, {});
133 for (const auto& entry : toSetup)
134 {
135 setupEndpoint(entry);
136 }
137}
138
139void MCTPReactor::manageMCTPDevice(const std::string& path,
140 const std::shared_ptr<MCTPDevice>& device)
141{
142 if (!device)
143 {
144 return;
145 }
146
147 try
148 {
149 devices.add(path, device);
150 debug("MCTP device inventory added at '{INVENTORY_PATH}'",
151 "INVENTORY_PATH", path);
152 setupEndpoint(device);
153 }
154 catch (const std::system_error& e)
155 {
156 if (e.code() != std::errc::device_or_resource_busy)
157 {
158 throw e;
159 }
160
161 auto current = devices.deviceFor(path);
162 if (!current)
163 {
164 warning(
165 "Invalid state: Failed to manage device for inventory at '{INVENTORY_PATH}', but the inventory item is unrecognised",
166 "INVENTORY_PATH", path);
167 return;
168 }
169
170 // TODO: Ensure remove completion happens-before add. For now this
171 // happens unsynchronised. Make some noise about it.
172 warning(
173 "Unsynchronised endpoint reinitialsation due to configuration change at '{INVENTORY_PATH}': Removing '{MCTP_DEVICE}'",
174 "INVENTORY_PATH", path, "MCTP_DEVICE", current->describe());
175
176 unmanageMCTPDevice(path);
177
178 devices.add(path, device);
179
180 // Pray (this is the unsynchronised bit)
181 deferSetup(device);
182 }
183}
184
185void MCTPReactor::unmanageMCTPDevice(const std::string& path)
186{
187 auto device = devices.deviceFor(path);
188 if (!device)
189 {
190 debug("Unrecognised inventory item: {INVENTORY_PATH}", "INVENTORY_PATH",
191 path);
192 return;
193 }
194
195 debug("MCTP device inventory removed at '{INVENTORY_PATH}'",
196 "INVENTORY_PATH", path);
197
198 deferred.erase(device);
199
200 // Remove the device from the repository before notifying the device itself
201 // of removal so we don't defer its setup
202 devices.remove(device);
203
204 debug("Stopping management of MCTP device at [ {MCTP_DEVICE} ]",
205 "MCTP_DEVICE", device->describe());
206
207 device->remove();
208}