xref: /openbmc/phosphor-bmc-code-mgmt/eeprom-device/eeprom_device.cpp (revision a2eb951f7384c2b4fa494f90e78295f615c12a56)
1994a77ffSKevin Tung #include "eeprom_device.hpp"
2994a77ffSKevin Tung 
3994a77ffSKevin Tung #include "common/include/software.hpp"
4*a2eb951fSKevin Tung #include "common/include/utils.hpp"
5994a77ffSKevin Tung 
6994a77ffSKevin Tung #include <phosphor-logging/lg2.hpp>
7994a77ffSKevin Tung #include <sdbusplus/async.hpp>
8994a77ffSKevin Tung #include <sdbusplus/message.hpp>
9994a77ffSKevin Tung 
10994a77ffSKevin Tung #include <filesystem>
11994a77ffSKevin Tung #include <fstream>
12994a77ffSKevin Tung 
13994a77ffSKevin Tung PHOSPHOR_LOG2_USING;
14994a77ffSKevin Tung 
15994a77ffSKevin Tung namespace fs = std::filesystem;
16994a77ffSKevin Tung namespace MatchRules = sdbusplus::bus::match::rules;
17994a77ffSKevin Tung namespace State = sdbusplus::common::xyz::openbmc_project::state;
requestMuxGPIOs(const std::vector<std::string> & gpioLines,const std::vector<bool> & gpioPolarities,bool inverted)18994a77ffSKevin Tung 
19994a77ffSKevin Tung static std::vector<std::unique_ptr<::gpiod::line_bulk>> requestMuxGPIOs(
20994a77ffSKevin Tung     const std::vector<std::string>& gpioLines,
21994a77ffSKevin Tung     const std::vector<bool>& gpioPolarities, bool inverted)
22994a77ffSKevin Tung {
23994a77ffSKevin Tung     std::map<std::string, std::vector<std::string>> groupLineNames;
24994a77ffSKevin Tung     std::map<std::string, std::vector<int>> groupValues;
25994a77ffSKevin Tung 
26994a77ffSKevin Tung     for (size_t i = 0; i < gpioLines.size(); ++i)
27994a77ffSKevin Tung     {
28994a77ffSKevin Tung         auto line = ::gpiod::find_line(gpioLines[i]);
29994a77ffSKevin Tung 
30994a77ffSKevin Tung         if (!line)
31994a77ffSKevin Tung         {
32994a77ffSKevin Tung             error("Failed to find GPIO line: {LINE}", "LINE", gpioLines[i]);
33994a77ffSKevin Tung             return {};
34994a77ffSKevin Tung         }
35994a77ffSKevin Tung 
36994a77ffSKevin Tung         if (line.is_used())
37994a77ffSKevin Tung         {
38994a77ffSKevin Tung             error("GPIO line {LINE} was still used", "LINE", gpioLines[i]);
39994a77ffSKevin Tung             return {};
40994a77ffSKevin Tung         }
41994a77ffSKevin Tung 
42994a77ffSKevin Tung         std::string chipName = line.get_chip().name();
43994a77ffSKevin Tung         groupLineNames[chipName].push_back(gpioLines[i]);
44994a77ffSKevin Tung         groupValues[chipName].push_back(gpioPolarities[i] ^ inverted ? 1 : 0);
45994a77ffSKevin Tung     }
46994a77ffSKevin Tung 
47994a77ffSKevin Tung     std::vector<std::unique_ptr<::gpiod::line_bulk>> lineBulks;
48994a77ffSKevin Tung     ::gpiod::line_request config{"", ::gpiod::line_request::DIRECTION_OUTPUT,
49994a77ffSKevin Tung                                  0};
50994a77ffSKevin Tung 
51994a77ffSKevin Tung     for (auto& [chipName, lineNames] : groupLineNames)
52994a77ffSKevin Tung     {
53994a77ffSKevin Tung         ::gpiod::chip chip(chipName);
54994a77ffSKevin Tung         std::vector<::gpiod::line> lines;
55994a77ffSKevin Tung 
56994a77ffSKevin Tung         for (size_t i = 0; i < lineNames.size(); ++i)
57994a77ffSKevin Tung         {
58994a77ffSKevin Tung             const auto& name = lineNames[i];
59994a77ffSKevin Tung             auto line = chip.find_line(name);
60994a77ffSKevin Tung 
61994a77ffSKevin Tung             if (!line)
62994a77ffSKevin Tung             {
63994a77ffSKevin Tung                 error("Failed to get {LINE} from chip {CHIP}", "LINE", name,
64994a77ffSKevin Tung                       "CHIP", chipName);
65994a77ffSKevin Tung                 return {};
66994a77ffSKevin Tung             }
67994a77ffSKevin Tung 
68994a77ffSKevin Tung             debug("Requesting chip {CHIP}, GPIO line {LINE} to {VALUE}", "CHIP",
69994a77ffSKevin Tung                   chip.name(), "LINE", line.name(), "VALUE",
70994a77ffSKevin Tung                   groupValues[chipName][i]);
71994a77ffSKevin Tung 
72994a77ffSKevin Tung             lines.push_back(std::move(line));
73994a77ffSKevin Tung         }
74994a77ffSKevin Tung 
75994a77ffSKevin Tung         auto lineBulk = std::make_unique<::gpiod::line_bulk>(lines);
76994a77ffSKevin Tung 
77994a77ffSKevin Tung         if (!lineBulk)
78994a77ffSKevin Tung         {
79994a77ffSKevin Tung             error("Failed to create line bulk for chip={CHIP}", "CHIP",
80994a77ffSKevin Tung                   chipName);
81994a77ffSKevin Tung             return {};
82994a77ffSKevin Tung         }
83994a77ffSKevin Tung 
84994a77ffSKevin Tung         lineBulk->request(config, groupValues[chipName]);
85994a77ffSKevin Tung 
86994a77ffSKevin Tung         lineBulks.push_back(std::move(lineBulk));
87994a77ffSKevin Tung     }
88994a77ffSKevin Tung 
89994a77ffSKevin Tung     return lineBulks;
90994a77ffSKevin Tung }
asyncSystem(sdbusplus::async::context & ctx,const std::string & cmd)91994a77ffSKevin Tung 
92994a77ffSKevin Tung static std::string getDriverPath(const std::string& chipModel)
93994a77ffSKevin Tung {
94994a77ffSKevin Tung     // Currently, only EEPROM chips with the model AT24 are supported.
95994a77ffSKevin Tung     if (chipModel.find("EEPROM_24C") == std::string::npos)
96994a77ffSKevin Tung     {
97994a77ffSKevin Tung         error("Invalid EEPROM chip model: {CHIP}", "CHIP", chipModel);
98994a77ffSKevin Tung         return "";
99994a77ffSKevin Tung     }
100994a77ffSKevin Tung 
101994a77ffSKevin Tung     std::string path = "/sys/bus/i2c/drivers/at24";
102994a77ffSKevin Tung     return std::filesystem::exists(path) ? path : "";
103994a77ffSKevin Tung }
104994a77ffSKevin Tung 
105994a77ffSKevin Tung static std::string getI2CDeviceId(const uint16_t bus, const uint8_t address)
106994a77ffSKevin Tung {
107994a77ffSKevin Tung     std::ostringstream oss;
108994a77ffSKevin Tung     oss << bus << "-" << std::hex << std::setfill('0') << std::setw(4)
109994a77ffSKevin Tung         << static_cast<int>(address);
110994a77ffSKevin Tung     return oss.str();
111994a77ffSKevin Tung }
112994a77ffSKevin Tung 
113994a77ffSKevin Tung static std::string getEEPROMPath(const uint16_t bus, const uint8_t address)
114994a77ffSKevin Tung {
115994a77ffSKevin Tung     std::string devicePath =
116994a77ffSKevin Tung         "/sys/bus/i2c/devices/" + getI2CDeviceId(bus, address) + "/eeprom";
117994a77ffSKevin Tung 
118994a77ffSKevin Tung     if (fs::exists(devicePath) && fs::is_regular_file(devicePath))
119994a77ffSKevin Tung     {
120994a77ffSKevin Tung         debug("Found EEPROM device path: {PATH}", "PATH", devicePath);
121994a77ffSKevin Tung         return devicePath;
122994a77ffSKevin Tung     }
123994a77ffSKevin Tung 
124994a77ffSKevin Tung     return "";
125994a77ffSKevin Tung }
126994a77ffSKevin Tung 
127994a77ffSKevin Tung EEPROMDevice::EEPROMDevice(
128994a77ffSKevin Tung     sdbusplus::async::context& ctx, const uint16_t bus, const uint8_t address,
129994a77ffSKevin Tung     const std::string& chipModel, const std::vector<std::string>& gpioLines,
130994a77ffSKevin Tung     const std::vector<bool>& gpioPolarities,
131994a77ffSKevin Tung     std::unique_ptr<DeviceVersion> deviceVersion, SoftwareConfig& config,
132994a77ffSKevin Tung     ManagerInf::SoftwareManager* parent) :
133994a77ffSKevin Tung     Device(ctx, config, parent,
134994a77ffSKevin Tung            {RequestedApplyTimes::Immediate, RequestedApplyTimes::OnReset}),
135994a77ffSKevin Tung     bus(bus), address(address), chipModel(chipModel), gpioLines(gpioLines),
136994a77ffSKevin Tung     gpioPolarities(gpioPolarities), deviceVersion(std::move(deviceVersion)),
137994a77ffSKevin Tung     hostPower(ctx)
138994a77ffSKevin Tung {
139994a77ffSKevin Tung     // Some EEPROM devices require the host to be in a specific state before
getDriverPath(const std::string & chipModel)140994a77ffSKevin Tung     // retrieving the version. To handle this, set up a match to listen for
141994a77ffSKevin Tung     // property changes on the host state. Once the host reaches the required
142994a77ffSKevin Tung     // condition, the version can be updated accordingly.
143994a77ffSKevin Tung     ctx.spawn(processHostStateChange());
144994a77ffSKevin Tung 
145994a77ffSKevin Tung     debug("Initialized EEPROM device instance on dbus");
146994a77ffSKevin Tung }
147994a77ffSKevin Tung 
148994a77ffSKevin Tung sdbusplus::async::task<bool> EEPROMDevice::updateDevice(const uint8_t* image,
149994a77ffSKevin Tung                                                         size_t image_size)
150994a77ffSKevin Tung {
151994a77ffSKevin Tung     std::vector<std::unique_ptr<::gpiod::line_bulk>> lineBulks;
152994a77ffSKevin Tung 
getI2CDeviceId(const uint16_t bus,const uint8_t address)153994a77ffSKevin Tung     if (!gpioLines.empty())
154994a77ffSKevin Tung     {
155994a77ffSKevin Tung         debug("Requesting GPIOs to mux EEPROM to BMC");
156994a77ffSKevin Tung 
157994a77ffSKevin Tung         lineBulks = requestMuxGPIOs(gpioLines, gpioPolarities, false);
158994a77ffSKevin Tung 
159994a77ffSKevin Tung         if (lineBulks.empty())
160994a77ffSKevin Tung         {
161994a77ffSKevin Tung             error("Failed to mux EEPROM to BMC");
162994a77ffSKevin Tung             co_return false;
163994a77ffSKevin Tung         }
164994a77ffSKevin Tung     }
165994a77ffSKevin Tung 
166994a77ffSKevin Tung     setUpdateProgress(20);
167994a77ffSKevin Tung 
168994a77ffSKevin Tung     if (!co_await bindEEPROM())
169994a77ffSKevin Tung     {
170994a77ffSKevin Tung         co_return false;
171994a77ffSKevin Tung     }
172994a77ffSKevin Tung 
173994a77ffSKevin Tung     setUpdateProgress(40);
174994a77ffSKevin Tung 
EEPROMDevice(sdbusplus::async::context & ctx,const uint16_t bus,const uint8_t address,const std::string & chipModel,const std::vector<std::string> & gpioLines,const std::vector<bool> & gpioPolarities,std::unique_ptr<DeviceVersion> deviceVersion,SoftwareConfig & config,ManagerInf::SoftwareManager * parent)175*a2eb951fSKevin Tung     auto success = co_await writeEEPROM(image, image_size);
176994a77ffSKevin Tung 
177994a77ffSKevin Tung     if (success)
178994a77ffSKevin Tung     {
179994a77ffSKevin Tung         debug("Successfully wrote EEPROM");
180994a77ffSKevin Tung         setUpdateProgress(60);
181994a77ffSKevin Tung     }
182994a77ffSKevin Tung     else
183994a77ffSKevin Tung     {
184994a77ffSKevin Tung         error("Failed to write EEPROM");
185994a77ffSKevin Tung     }
186994a77ffSKevin Tung 
187994a77ffSKevin Tung     success = success && co_await unbindEEPROM();
188994a77ffSKevin Tung 
189994a77ffSKevin Tung     if (success)
190994a77ffSKevin Tung     {
191994a77ffSKevin Tung         setUpdateProgress(80);
192994a77ffSKevin Tung     }
193994a77ffSKevin Tung 
194994a77ffSKevin Tung     if (!gpioLines.empty())
195994a77ffSKevin Tung     {
updateDevice(const uint8_t * image,size_t image_size)196994a77ffSKevin Tung         for (auto& lineBulk : lineBulks)
197994a77ffSKevin Tung         {
198994a77ffSKevin Tung             lineBulk->release();
199994a77ffSKevin Tung         }
200994a77ffSKevin Tung 
201994a77ffSKevin Tung         debug("Requesting GPIOs to mux EEPROM back to device");
202994a77ffSKevin Tung 
203994a77ffSKevin Tung         lineBulks = requestMuxGPIOs(gpioLines, gpioPolarities, true);
204994a77ffSKevin Tung 
205994a77ffSKevin Tung         if (lineBulks.empty())
206994a77ffSKevin Tung         {
207994a77ffSKevin Tung             error("Failed to mux EEPROM back to device");
208994a77ffSKevin Tung             co_return false;
209994a77ffSKevin Tung         }
210994a77ffSKevin Tung 
211994a77ffSKevin Tung         for (auto& lineBulk : lineBulks)
212994a77ffSKevin Tung         {
213994a77ffSKevin Tung             lineBulk->release();
214994a77ffSKevin Tung         }
215994a77ffSKevin Tung     }
216994a77ffSKevin Tung 
217994a77ffSKevin Tung     if (success)
218994a77ffSKevin Tung     {
219994a77ffSKevin Tung         debug("EEPROM device successfully updated");
220994a77ffSKevin Tung         setUpdateProgress(100);
221994a77ffSKevin Tung     }
222994a77ffSKevin Tung     else
223994a77ffSKevin Tung     {
224994a77ffSKevin Tung         error("Failed to update EEPROM device");
225994a77ffSKevin Tung     }
226994a77ffSKevin Tung 
227994a77ffSKevin Tung     co_return success;
228994a77ffSKevin Tung }
229994a77ffSKevin Tung 
230994a77ffSKevin Tung sdbusplus::async::task<bool> EEPROMDevice::bindEEPROM()
231994a77ffSKevin Tung {
232994a77ffSKevin Tung     auto i2cDeviceId = getI2CDeviceId(bus, address);
233994a77ffSKevin Tung 
234994a77ffSKevin Tung     debug("Binding {I2CDEVICE} EEPROM", "I2CDEVICE", i2cDeviceId);
235994a77ffSKevin Tung 
236994a77ffSKevin Tung     if (isEEPROMBound())
237994a77ffSKevin Tung     {
238994a77ffSKevin Tung         debug("EEPROM was already bound, unbinding it now");
239994a77ffSKevin Tung         if (!co_await unbindEEPROM())
240994a77ffSKevin Tung         {
241994a77ffSKevin Tung             error("Error unbinding EEPROM");
242994a77ffSKevin Tung             co_return false;
243994a77ffSKevin Tung         }
244994a77ffSKevin Tung     }
245994a77ffSKevin Tung 
246994a77ffSKevin Tung     auto driverPath = getDriverPath(chipModel);
247994a77ffSKevin Tung     if (driverPath.empty())
248994a77ffSKevin Tung     {
249994a77ffSKevin Tung         error("Driver path not found for chip model: {CHIP}", "CHIP",
250994a77ffSKevin Tung               chipModel);
251994a77ffSKevin Tung         co_return false;
252994a77ffSKevin Tung     }
253994a77ffSKevin Tung 
254994a77ffSKevin Tung     auto bindPath = driverPath + "/bind";
255994a77ffSKevin Tung     std::ofstream ofbind(bindPath, std::ofstream::out);
256994a77ffSKevin Tung     if (!ofbind)
257994a77ffSKevin Tung     {
258994a77ffSKevin Tung         error("Failed to open bind file: {PATH}", "PATH", bindPath);
259994a77ffSKevin Tung         co_return false;
260994a77ffSKevin Tung     }
261994a77ffSKevin Tung 
262994a77ffSKevin Tung     ofbind << i2cDeviceId;
263994a77ffSKevin Tung     ofbind.close();
264994a77ffSKevin Tung 
265994a77ffSKevin Tung     // wait for kernel
266994a77ffSKevin Tung     co_await sdbusplus::async::sleep_for(ctx, std::chrono::seconds(2));
267994a77ffSKevin Tung 
268994a77ffSKevin Tung     auto bound = isEEPROMBound();
269994a77ffSKevin Tung     if (!bound)
270994a77ffSKevin Tung     {
271994a77ffSKevin Tung         error("Failed to bind {I2CDEVICE} EEPROM", "I2CDEVICE", i2cDeviceId);
272994a77ffSKevin Tung     }
273994a77ffSKevin Tung 
274994a77ffSKevin Tung     co_return bound;
275994a77ffSKevin Tung }
276994a77ffSKevin Tung sdbusplus::async::task<bool> EEPROMDevice::unbindEEPROM()
277994a77ffSKevin Tung {
278994a77ffSKevin Tung     auto i2cDeviceId = getI2CDeviceId(bus, address);
279994a77ffSKevin Tung 
280994a77ffSKevin Tung     debug("Unbinding EEPROM device {I2CDEVICE}", "I2CDEVICE", i2cDeviceId);
281994a77ffSKevin Tung 
282994a77ffSKevin Tung     auto driverPath = getDriverPath(chipModel);
283994a77ffSKevin Tung     if (driverPath.empty())
bindEEPROM()284994a77ffSKevin Tung     {
285994a77ffSKevin Tung         error("Failed to unbind EEPROM, driver path not found for chip {CHIP}",
286994a77ffSKevin Tung               "CHIP", chipModel);
287994a77ffSKevin Tung         co_return false;
288994a77ffSKevin Tung     }
289994a77ffSKevin Tung 
290994a77ffSKevin Tung     auto unbindPath = driverPath + "/unbind";
291994a77ffSKevin Tung     std::ofstream ofunbind(unbindPath, std::ofstream::out);
292994a77ffSKevin Tung     if (!ofunbind)
293994a77ffSKevin Tung     {
294994a77ffSKevin Tung         error("Failed to open unbind file: {PATH}", "PATH", unbindPath);
295994a77ffSKevin Tung         co_return false;
296994a77ffSKevin Tung     }
297994a77ffSKevin Tung     ofunbind << i2cDeviceId;
298994a77ffSKevin Tung     ofunbind.close();
299994a77ffSKevin Tung 
300994a77ffSKevin Tung     // wait for kernel
301994a77ffSKevin Tung     co_await sdbusplus::async::sleep_for(ctx, std::chrono::seconds(2));
302994a77ffSKevin Tung 
303994a77ffSKevin Tung     auto bound = isEEPROMBound();
304994a77ffSKevin Tung     if (bound)
305994a77ffSKevin Tung     {
306994a77ffSKevin Tung         error("Failed to unbind {I2CDEVICE} EEPROM", "I2CDEVICE", i2cDeviceId);
307994a77ffSKevin Tung     }
308994a77ffSKevin Tung 
309994a77ffSKevin Tung     co_return !bound;
310994a77ffSKevin Tung }
311994a77ffSKevin Tung 
312994a77ffSKevin Tung bool EEPROMDevice::isEEPROMBound()
313994a77ffSKevin Tung {
314994a77ffSKevin Tung     auto driverPath = getDriverPath(chipModel);
315994a77ffSKevin Tung 
316994a77ffSKevin Tung     if (driverPath.empty())
317994a77ffSKevin Tung     {
318994a77ffSKevin Tung         error("Failed to check if EEPROM is bound");
319994a77ffSKevin Tung         return false;
320994a77ffSKevin Tung     }
321994a77ffSKevin Tung 
322994a77ffSKevin Tung     auto i2cDeviceId = getI2CDeviceId(bus, address);
323994a77ffSKevin Tung 
324994a77ffSKevin Tung     return std::filesystem::exists(driverPath + "/" + i2cDeviceId);
325994a77ffSKevin Tung }
326994a77ffSKevin Tung 
327*a2eb951fSKevin Tung sdbusplus::async::task<bool> EEPROMDevice::writeEEPROM(const uint8_t* image,
328994a77ffSKevin Tung                                                        size_t image_size) const
329994a77ffSKevin Tung {
unbindEEPROM()330994a77ffSKevin Tung     auto eepromPath = getEEPROMPath(bus, address);
331994a77ffSKevin Tung     if (eepromPath.empty())
332994a77ffSKevin Tung     {
333994a77ffSKevin Tung         error("EEPROM file not found for device: {DEVICE}", "DEVICE",
334994a77ffSKevin Tung               getI2CDeviceId(bus, address));
335994a77ffSKevin Tung         co_return -1;
336994a77ffSKevin Tung     }
337994a77ffSKevin Tung     const std::string path =
338994a77ffSKevin Tung         "/tmp/eeprom-image-" +
339994a77ffSKevin Tung         std::to_string(SoftwareInf::Software::getRandomId()) + ".bin";
340994a77ffSKevin Tung 
341994a77ffSKevin Tung     int fd = open(path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
342994a77ffSKevin Tung     if (fd < 0)
343994a77ffSKevin Tung     {
344994a77ffSKevin Tung         error("Failed to open file: {PATH}", "PATH", path);
345994a77ffSKevin Tung         co_return -1;
346994a77ffSKevin Tung     }
347994a77ffSKevin Tung 
348994a77ffSKevin Tung     const ssize_t bytesWritten = write(fd, image, image_size);
349994a77ffSKevin Tung 
350994a77ffSKevin Tung     close(fd);
351994a77ffSKevin Tung 
352994a77ffSKevin Tung     if (bytesWritten < 0 || static_cast<size_t>(bytesWritten) != image_size)
353994a77ffSKevin Tung     {
354994a77ffSKevin Tung         error("Failed to write image to file");
355994a77ffSKevin Tung         co_return -1;
356994a77ffSKevin Tung     }
357994a77ffSKevin Tung 
358994a77ffSKevin Tung     debug("Wrote {SIZE} bytes to {PATH}", "SIZE", bytesWritten, "PATH", path);
359994a77ffSKevin Tung 
360994a77ffSKevin Tung     std::string cmd = "dd if=" + path + " of=" + eepromPath + " bs=1k";
361994a77ffSKevin Tung 
362994a77ffSKevin Tung     debug("Running {CMD}", "CMD", cmd);
363994a77ffSKevin Tung 
364*a2eb951fSKevin Tung     auto success = co_await asyncSystem(ctx, cmd);
365994a77ffSKevin Tung 
isEEPROMBound()366994a77ffSKevin Tung     std::filesystem::remove(path);
367994a77ffSKevin Tung 
368*a2eb951fSKevin Tung     co_return success;
369994a77ffSKevin Tung }
370994a77ffSKevin Tung 
371994a77ffSKevin Tung sdbusplus::async::task<> EEPROMDevice::processHostStateChange()
372994a77ffSKevin Tung {
373994a77ffSKevin Tung     auto requiredHostState = deviceVersion->getHostStateToQueryVersion();
374994a77ffSKevin Tung 
375994a77ffSKevin Tung     if (!requiredHostState)
376994a77ffSKevin Tung     {
377994a77ffSKevin Tung         error("Failed to get required host state");
378994a77ffSKevin Tung         co_return;
379994a77ffSKevin Tung     }
380994a77ffSKevin Tung 
writeEEPROM(const uint8_t * image,size_t image_size) const381994a77ffSKevin Tung     while (!ctx.stop_requested())
382994a77ffSKevin Tung     {
38301ba9562SAlexander Hansen         auto nextResult = co_await hostPower.stateChangedMatch.next<
38401ba9562SAlexander Hansen             std::string, std::map<std::string, std::variant<std::string>>>();
38501ba9562SAlexander Hansen 
38601ba9562SAlexander Hansen         auto [interfaceName, changedProperties] = nextResult;
387994a77ffSKevin Tung 
388994a77ffSKevin Tung         auto it = changedProperties.find("CurrentHostState");
389994a77ffSKevin Tung         if (it != changedProperties.end())
390994a77ffSKevin Tung         {
391994a77ffSKevin Tung             const auto& currentHostState = std::get<std::string>(it->second);
392994a77ffSKevin Tung 
393994a77ffSKevin Tung             if (currentHostState ==
394994a77ffSKevin Tung                 State::convertForMessage(*requiredHostState))
395994a77ffSKevin Tung             {
396994a77ffSKevin Tung                 debug("Host state {STATE} matches to retrieve the version",
397994a77ffSKevin Tung                       "STATE", currentHostState);
398994a77ffSKevin Tung                 std::string version = deviceVersion->getVersion();
399994a77ffSKevin Tung                 if (!version.empty())
400994a77ffSKevin Tung                 {
401994a77ffSKevin Tung                     softwareCurrent->setVersion(version);
402994a77ffSKevin Tung                 }
403994a77ffSKevin Tung             }
404994a77ffSKevin Tung         }
405994a77ffSKevin Tung     }
406994a77ffSKevin Tung 
407994a77ffSKevin Tung     co_return;
408994a77ffSKevin Tung }
409