1 /*
2 // Copyright (c) 2019 Intel 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 
17 #include <systemd/sd-journal.h>
18 
19 #include <boost/algorithm/string/predicate.hpp>
20 #include <boost/asio/io_context.hpp>
21 #include <boost/asio/steady_timer.hpp>
22 #include <boost/container/flat_map.hpp>
23 #include <cstdint>
24 #include <iostream>
25 #include <sdbusplus/asio/connection.hpp>
26 #include <string>
27 #include <variant>
28 #include <vector>
29 
30 using GetSubTreeType = std::vector<
31     std::pair<std::string,
32               std::vector<std::pair<std::string, std::vector<std::string>>>>>;
33 using BasicVariantType =
34     std::variant<std::vector<std::string>, std::string, int64_t, uint64_t,
35                  double, int32_t, uint32_t, int16_t, uint16_t, uint8_t, bool>;
36 using Association = std::tuple<std::string, std::string, std::string>;
37 
38 namespace mapper
39 {
40 constexpr const char* busName = "xyz.openbmc_project.ObjectMapper";
41 constexpr const char* path = "/xyz/openbmc_project/object_mapper";
42 constexpr const char* interface = "xyz.openbmc_project.ObjectMapper";
43 constexpr const char* subtree = "GetSubTree";
44 } // namespace mapper
45 
46 namespace entityManager
47 {
48 constexpr const char* busName = "xyz.openbmc_project.EntityManager";
49 } // namespace entityManager
50 
51 namespace inventory
52 {
53 constexpr const char* interface = "xyz.openbmc_project.Inventory.Item";
54 } // namespace inventory
55 
56 namespace ledGroup
57 {
58 constexpr const char* interface = "xyz.openbmc_project.Led.Group";
59 constexpr const char* asserted = "Asserted";
60 } // namespace ledGroup
61 
62 namespace properties
63 {
64 constexpr const char* interface = "org.freedesktop.DBus.Properties";
65 constexpr const char* get = "Get";
66 } // namespace properties
67 
68 namespace power
69 {
70 const static constexpr char* busname = "xyz.openbmc_project.State.Host";
71 const static constexpr char* interface = "xyz.openbmc_project.State.Host";
72 const static constexpr char* path = "/xyz/openbmc_project/state/host0";
73 const static constexpr char* property = "CurrentHostState";
74 } // namespace power
75 
76 namespace association
77 {
78 const static constexpr char* interface =
79     "xyz.openbmc_project.Association.Definitions";
80 } // namespace association
81 
82 namespace hsbp
83 {
84 enum class registers : uint8_t
85 {
86     fpgaIdH = 0x0,
87     fpgaIdL = 0x1,
88     typeId = 0x2,
89     bootVer = 0x3,
90     fpgaVer = 0x4,
91     securityRev = 0x5,
92     funSupported = 0x6,
93     numDisks = 0x7,
94     presence = 0x8,
95     ssdIFDET = 0x9,
96     ifdetPart = 0xA,
97     statusLocate = 0xB,
98     statusFail = 0xC,
99     statusRebuild = 0xD,
100     ledOverride = 0xE,
101     ledStatus = 0xF,
102     ledPattern0 = 0x10,
103     ledPattern1 = 0x11,
104     ledPattern2 = 0x12,
105     ledPattern3 = 0x13,
106     ledPattern4 = 0x14,
107     ledPattern5 = 0x15,
108     ledPattern6 = 0x16,
109     ledPattern7 = 0x17,
110 };
111 
112 } // namespace hsbp
113 
114 static std::unique_ptr<sdbusplus::bus::match::match> powerMatch = nullptr;
115 static bool powerStatusOn = false;
116 
117 bool isPowerOn(void)
118 {
119     if (!powerMatch)
120     {
121         throw std::runtime_error("Power Match Not Created");
122     }
123     return powerStatusOn;
124 }
125 
126 void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn)
127 {
128     static boost::asio::steady_timer timer(conn->get_io_context());
129     // create a match for powergood changes, first time do a method call to
130     // cache the correct value
131     if (powerMatch)
132     {
133         return;
134     }
135 
136     powerMatch = std::make_unique<sdbusplus::bus::match::match>(
137         static_cast<sdbusplus::bus::bus&>(*conn),
138         "type='signal',interface='" + std::string(properties::interface) +
139             "',path='" + std::string(power::path) + "',arg0='" +
140             std::string(power::interface) + "'",
141         [](sdbusplus::message::message& message) {
142             std::string objectName;
143             boost::container::flat_map<std::string, std::variant<std::string>>
144                 values;
145             message.read(objectName, values);
146             auto findState = values.find(power::property);
147             if (findState != values.end())
148             {
149                 bool on = boost::ends_with(
150                     std::get<std::string>(findState->second), "Running");
151                 if (!on)
152                 {
153                     timer.cancel();
154                     powerStatusOn = false;
155                     return;
156                 }
157                 // on comes too quickly
158                 timer.expires_after(std::chrono::seconds(10));
159                 timer.async_wait([](boost::system::error_code ec) {
160                     if (ec == boost::asio::error::operation_aborted)
161                     {
162                         return;
163                     }
164                     else if (ec)
165                     {
166                         std::cerr << "Timer error " << ec.message() << "\n";
167                         return;
168                     }
169                     powerStatusOn = true;
170                 });
171             }
172         });
173 
174     conn->async_method_call(
175         [](boost::system::error_code ec,
176            const std::variant<std::string>& state) {
177             if (ec)
178             {
179                 // we commonly come up before power control, we'll capture the
180                 // property change later
181                 return;
182             }
183             powerStatusOn =
184                 boost::ends_with(std::get<std::string>(state), "Running");
185         },
186         power::busname, power::path, properties::interface, properties::get,
187         power::interface, power::property);
188 }
189 
190 inline void logDeviceAdded(const std::string& model, const std::string& type,
191                            const std::string& sn)
192 {
193     sd_journal_send("MESSAGE=%s", "Inventory Added", "PRIORITY=%i", LOG_ERR,
194                     "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.InventoryAdded",
195                     "REDFISH_MESSAGE_ARGS=%s,%s,%s", model.c_str(),
196                     type.c_str(), sn.c_str(), NULL);
197 }
198 
199 inline void logDeviceRemoved(const std::string& model, const std::string& type,
200                              const std::string& sn)
201 {
202     sd_journal_send("MESSAGE=%s", "Inventory Removed", "PRIORITY=%i", LOG_ERR,
203                     "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.InventoryRemoved",
204                     "REDFISH_MESSAGE_ARGS=%s,%s,%s", model.c_str(),
205                     type.c_str(), sn.c_str(), NULL);
206 }
207 
208 inline void logDriveError(const std::string& name)
209 {
210     sd_journal_send("MESSAGE=%s", "Drive Error", "PRIORITY=%i", LOG_ERR,
211                     "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.DriveError",
212                     "REDFISH_MESSAGE_ARGS=%s", name.c_str(), NULL);
213 }
214