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