xref: /openbmc/dbus-sensors/src/nvme/NVMeContext.hpp (revision 556e04b8f374a9eb8cf32bf0e36ac46c14873eba)
1 #pragma once
2 
3 #include "NVMeSensor.hpp"
4 
5 #include <boost/asio/io_context.hpp>
6 #include <boost/asio/steady_timer.hpp>
7 #include <boost/container/flat_map.hpp>
8 
9 #include <algorithm>
10 #include <cstddef>
11 #include <list>
12 #include <memory>
13 #include <optional>
14 #include <stdexcept>
15 #include <string>
16 
17 class NVMeContext : public std::enable_shared_from_this<NVMeContext>
18 {
19   public:
NVMeContext(boost::asio::io_context & io,int rootBus)20     NVMeContext(boost::asio::io_context& io, int rootBus) :
21         scanTimer(io), rootBus(rootBus), pollCursor(sensors.end())
22     {
23         if (rootBus < 0)
24         {
25             throw std::invalid_argument(
26                 "Invalid root bus: Bus ID must not be negative");
27         }
28     }
29 
~NVMeContext()30     virtual ~NVMeContext()
31     {
32         scanTimer.cancel();
33     }
34 
addSensor(const std::shared_ptr<NVMeSensor> & sensor)35     void addSensor(const std::shared_ptr<NVMeSensor>& sensor)
36     {
37         sensors.emplace_back(sensor);
38     }
39 
getSensorAtPath(const std::string & path)40     std::optional<std::shared_ptr<NVMeSensor>> getSensorAtPath(
41         const std::string& path)
42     {
43         for (auto& sensor : sensors)
44         {
45             if (sensor->configurationPath == path)
46             {
47                 return sensor;
48             }
49         }
50 
51         return std::nullopt;
52     }
53 
54     // Post-condition: The sensor list does not contain the provided sensor
55     // Post-condition: pollCursor is a valid iterator for the sensor list
removeSensor(const std::shared_ptr<NVMeSensor> & sensor)56     void removeSensor(const std::shared_ptr<NVMeSensor>& sensor)
57     {
58         // Locate the sensor that we're removing in the sensor list
59         auto found = std::find(sensors.begin(), sensors.end(), sensor);
60 
61         // If we failed to find the sensor in the list the post-condition is
62         // already satisfied
63         if (found == sensors.end())
64         {
65             return;
66         }
67 
68         // We've found the sensor in the list
69 
70         // If we're not actively polling the sensor list, then remove the sensor
71         if (pollCursor == sensors.end())
72         {
73             sensors.erase(found);
74             return;
75         }
76 
77         // We're actively polling the sensor list
78 
79         // If we're not polling the specific sensor that has been removed, then
80         // remove the sensor
81         if (*pollCursor != *found)
82         {
83             sensors.erase(found);
84             return;
85         }
86 
87         // We're polling the sensor that is being removed
88 
89         // Remove the sensor and update the poll cursor so the cursor remains
90         // valid
91         pollCursor = sensors.erase(found);
92     }
93 
close()94     virtual void close()
95     {
96         scanTimer.cancel();
97     }
98 
99     virtual void pollNVMeDevices() = 0;
100 
101     virtual void readAndProcessNVMeSensor() = 0;
102 
103     virtual void processResponse(std::shared_ptr<NVMeSensor>& sensor, void* msg,
104                                  size_t len) = 0;
105 
106   protected:
107     boost::asio::steady_timer scanTimer;
108     int rootBus; // Root bus for this drive
109     std::list<std::shared_ptr<NVMeSensor>> sensors;
110     std::list<std::shared_ptr<NVMeSensor>>::iterator pollCursor;
111 };
112 
113 using NVMEMap = boost::container::flat_map<int, std::shared_ptr<NVMeContext>>;
114 
115 NVMEMap& getNVMEMap();
116