1 #include <bitset> 2 #include <phosphor-logging/elog-errors.hpp> 3 #include <phosphor-logging/log.hpp> 4 #include "xyz/openbmc_project/Common/error.hpp" 5 #include "types.hpp" 6 #include "sensordatahandler.hpp" 7 8 namespace ipmi 9 { 10 namespace sensor 11 { 12 13 using namespace phosphor::logging; 14 using InternalFailure = 15 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 16 17 static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper"; 18 static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper"; 19 static constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper"; 20 21 /** @brief get the D-Bus service and service path 22 * @param[in] bus - The Dbus bus object 23 * @param[in] interface - interface to the service 24 * @param[in] path - interested path in the list of objects 25 * @return pair of service path and service 26 */ 27 ServicePath getServiceAndPath(sdbusplus::bus::bus& bus, 28 const std::string& interface, 29 const std::string& path) 30 { 31 auto depth = 0; 32 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, 33 MAPPER_PATH, 34 MAPPER_INTERFACE, 35 "GetSubTree"); 36 mapperCall.append("/"); 37 mapperCall.append(depth); 38 mapperCall.append(std::vector<Interface>({interface})); 39 40 auto mapperResponseMsg = bus.call(mapperCall); 41 if (mapperResponseMsg.is_method_error()) 42 { 43 log<level::ERR>("Mapper GetSubTree failed", 44 entry("PATH=%s", path), 45 entry("INTERFACE=%s", interface)); 46 elog<InternalFailure>(); 47 } 48 49 MapperResponseType mapperResponse; 50 mapperResponseMsg.read(mapperResponse); 51 if (mapperResponse.empty()) 52 { 53 log<level::ERR>("Invalid mapper response", 54 entry("PATH=%s", path), 55 entry("INTERFACE=%s", interface)); 56 elog<InternalFailure>(); 57 } 58 59 if (path.empty()) 60 { 61 //Get the first one if the path is not in list. 62 return std::make_pair(mapperResponse.begin()->first, 63 mapperResponse.begin()->second.begin()->first); 64 } 65 const auto& iter = mapperResponse.find(path); 66 if (iter == mapperResponse.end()) 67 { 68 log<level::ERR>("Coudn't find d-bus path", 69 entry("PATH=%s", path), 70 entry("INTERFACE=%s", interface)); 71 elog<InternalFailure>(); 72 } 73 return std::make_pair(iter->first, iter->second.begin()->first); 74 } 75 76 AssertionSet getAssertionSet(const SetSensorReadingReq& cmdData) 77 { 78 Assertion assertionStates = 79 (static_cast<Assertion>(cmdData.assertOffset8_14)) << 8 | 80 cmdData.assertOffset0_7; 81 Deassertion deassertionStates = 82 (static_cast<Deassertion>(cmdData.deassertOffset8_14)) << 8 | 83 cmdData.deassertOffset0_7; 84 return std::make_pair(assertionStates, deassertionStates); 85 } 86 87 ipmi_ret_t updateToDbus(IpmiUpdateData& msg) 88 { 89 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 90 try 91 { 92 auto serviceResponseMsg = bus.call(msg); 93 if (serviceResponseMsg.is_method_error()) 94 { 95 log<level::ERR>("Error in D-Bus call"); 96 return IPMI_CC_UNSPECIFIED_ERROR; 97 } 98 } 99 catch (InternalFailure& e) 100 { 101 commit<InternalFailure>(); 102 return IPMI_CC_UNSPECIFIED_ERROR; 103 } 104 return IPMI_CC_OK; 105 } 106 107 namespace set 108 { 109 110 IpmiUpdateData makeDbusMsg(const std::string& updateInterface, 111 const std::string& sensorPath, 112 const std::string& command, 113 const std::string& sensorInterface) 114 { 115 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 116 using namespace std::string_literals; 117 118 std::string dbusService; 119 std::string dbusPath; 120 121 std::tie(dbusPath, dbusService) = getServiceAndPath(bus, 122 sensorInterface, 123 sensorPath); 124 return bus.new_method_call(dbusService.c_str(), 125 dbusPath.c_str(), 126 updateInterface.c_str(), 127 command.c_str()); 128 } 129 130 ipmi_ret_t appendDiscreteSignalData(IpmiUpdateData& msg, 131 const DbusInterfaceMap& interfaceMap, 132 uint8_t data) 133 { 134 const auto& interface = interfaceMap.begin(); 135 msg.append(interface->first); 136 for (const auto& property : interface->second) 137 { 138 msg.append(property.first); 139 const auto& iter = property.second.find(data); 140 if (iter == property.second.end()) 141 { 142 log<level::ERR>("Invalid event data"); 143 return IPMI_CC_PARM_OUT_OF_RANGE; 144 } 145 msg.append(iter->second.assert); 146 } 147 return IPMI_CC_OK; 148 } 149 150 ipmi_ret_t appendReadingData(IpmiUpdateData& msg, 151 const DbusInterfaceMap& interfaceMap, 152 const Value &data) 153 { 154 const auto& interface = interfaceMap.begin(); 155 msg.append(interface->first); 156 for (const auto& property : interface->second) 157 { 158 msg.append(property.first); 159 msg.append(data); 160 } 161 return IPMI_CC_OK; 162 } 163 164 ipmi_ret_t appendAssertion(IpmiUpdateData& msg, 165 const DbusInterfaceMap& interfaceMap, 166 const std::string& sensorPath, 167 const SetSensorReadingReq& cmdData) 168 { 169 std::bitset<16> assertionSet(getAssertionSet(cmdData).first); 170 std::bitset<16> deassertionSet(getAssertionSet(cmdData).second); 171 172 const auto& interface = interfaceMap.begin(); 173 msg.append(interface->first); 174 for (const auto& property : interface->second) 175 { 176 msg.append(property.first); 177 for (const auto& value : property.second) 178 { 179 if (assertionSet.test(value.first)) 180 { 181 msg.append(value.second.assert); 182 } 183 if (deassertionSet.test(value.first)) 184 { 185 msg.append(value.second.deassert); 186 } 187 } 188 } 189 return IPMI_CC_OK; 190 } 191 }//namespace set 192 193 namespace notify 194 { 195 196 IpmiUpdateData makeDbusMsg(const std::string& updateInterface, 197 const std::string& sensorPath, 198 const std::string& command, 199 const std::string& sensorInterface) 200 { 201 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 202 using namespace std::string_literals; 203 204 std::string dbusService; 205 std::string dbusPath; 206 207 std::tie(dbusPath, dbusService) = getServiceAndPath(bus, 208 updateInterface); 209 210 return bus.new_method_call(dbusService.c_str(), 211 dbusPath.c_str(), 212 updateInterface.c_str(), 213 command.c_str()); 214 } 215 216 ipmi_ret_t appendAssertion(IpmiUpdateData& msg, 217 const DbusInterfaceMap& interfaceMap, 218 const std::string& sensorPath, 219 const SetSensorReadingReq& cmdData) 220 { 221 std::bitset<16> assertionSet(getAssertionSet(cmdData).first); 222 std::bitset<16> deassertionSet(getAssertionSet(cmdData).second); 223 ipmi::sensor::ObjectMap objects; 224 ipmi::sensor::InterfaceMap interfaces; 225 for (const auto& interface : interfaceMap) 226 { 227 for (const auto& property : interface.second) 228 { 229 ipmi::sensor::PropertyMap props; 230 bool valid = false; 231 for (const auto& value : property.second) 232 { 233 if (assertionSet.test(value.first)) 234 { 235 props.emplace(property.first, value.second.assert); 236 valid = true; 237 } 238 else if (deassertionSet.test(value.first)) 239 { 240 props.emplace(property.first, value.second.deassert); 241 valid = true; 242 } 243 } 244 if (valid) 245 { 246 interfaces.emplace(interface.first, std::move(props)); 247 } 248 } 249 } 250 objects.emplace(sensorPath, std::move(interfaces)); 251 msg.append(std::move(objects)); 252 return IPMI_CC_OK; 253 } 254 }//namespace notify 255 }//namespace sensor 256 }//namespace ipmi 257