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