1 /**
2  * Copyright © 2022 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <nlohmann/json.hpp>
19 
20 #include <filesystem>
21 #include <optional>
22 #include <string>
23 #include <variant>
24 #include <vector>
25 
26 namespace phosphor::fan::control::json
27 {
28 
29 /**
30  * @class PCIeCardMetadata
31  *
32  * This class provides the ability for an action to look up a PCIe card's
33  * fan floor index or temp sensor name based on its metadata, which
34  * consists of 4 properties from the PCIeDevice D-Bus interface.
35  *
36  * The metadata is stored in one or more (see loadCards) JSON files, which
37  * look like:
38  *  {
39  *    "cards": [
40  *      {
41  *        "name": "TestCard",
42  *        "device_id": "0x1",
43  *        "vendor_id": "0x2",
44  *        "subsystem_id": "0x3",
45  *        "subsystem_vendor_id": "0x4",
46  *        "floor_index": 3
47  *      },
48  *      ...
49  *    ]
50  *  }
51  *
52  * If the card has a temperature sensor on it, then it doesn't
53  * need a floor index and instead will have:
54  *   "has_temp_sensor": true
55  */
56 class PCIeCardMetadata
57 {
58   public:
59     PCIeCardMetadata() = delete;
60     ~PCIeCardMetadata() = default;
61     PCIeCardMetadata(const PCIeCardMetadata&) = delete;
62     PCIeCardMetadata& operator=(const PCIeCardMetadata&) = delete;
63     PCIeCardMetadata(PCIeCardMetadata&&) = delete;
64     PCIeCardMetadata& operator=(PCIeCardMetadata&&) = delete;
65 
66     /**
67      * @brief Constructor
68      *
69      * @param[in] systemNames - The system names values
70      */
71     PCIeCardMetadata(const std::vector<std::string>& systemNames);
72 
73     /**
74      * @brief Look up a floor index based on a card's metadata
75      *
76      * @param[in] deviceID - Function0DeviceId value
77      * @param[in] vendorID - Function0VendorId value
78      * @param[in] subsystemID - Function0SubsystemId value
79      * @param[in] subsystemVendorID - Function0SubsystemVendorId value
80      *
81      * @return optional<variant<int32, bool>> -
82      *     Either the floor index for that entry, or true saying
83      *     it has a temp sensor.
84      *
85      *     If no entry is found, it will return std::nullopt.
86      */
87     std::optional<std::variant<int32_t, bool>>
88         lookup(uint16_t deviceID, uint16_t vendorID, uint16_t subsystemID,
89                uint16_t subsystemVendorID) const;
90 
91   private:
92     /**
93      * Structure to hold card metadata.
94      */
95     struct Metadata
96     {
97         uint16_t vendorID;
98         uint16_t deviceID;
99         uint16_t subsystemVendorID;
100         uint16_t subsystemID;
101         int32_t floorIndex;
102         bool hasTempSensor;
103 
104         bool operator==(const Metadata& other)
105         {
106             return (vendorID == other.vendorID) &&
107                    (deviceID == other.deviceID) &&
108                    (subsystemVendorID == other.subsystemVendorID) &&
109                    (subsystemID == other.subsystemID);
110         }
111     };
112 
113     /**
114      * @brief Loads the metadata from JSON files
115      *
116      * It will load a pcie_cards.json file in the default location if it
117      * is present.
118      *
119      * If systemNames isn't empty, it will load in any 'pcie_cards.json'
120      * files it finds in directories based on those names, overwriting any
121      * entries that were in any previous files.  This allows different
122      * floor indexes for some cards for the different systems in a flash
123      * image without needing to specify every possible card in every
124      * system specific JSON file.
125      *
126      * If no valid config files are found it will throw an exception.
127      *
128      * @param[in] systemNames - The system names values
129      */
130     void loadCards(const std::vector<std::string>& systemNames);
131 
132     /**
133      * @brief Loads in the card info from the JSON
134      *
135      * @param[in] json - The JSON containing a cards array
136      */
137     void load(const nlohmann::json& json);
138 
139     /**
140      * @brief Dumps the cards vector for debug
141      */
142     void dump() const;
143 
144     /**
145      * @brief The card metadata
146      */
147     std::vector<Metadata> _cards;
148 };
149 
150 } // namespace phosphor::fan::control::json
151