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