blob: b9bf7ed68c9ee4f138f7c04cabb0bd6ea511cdaa [file] [log] [blame]
Patrick Venture46470a32018-09-07 19:26:25 -07001#include "config.h"
2
3#include "selutility.hpp"
4
Patrick Venture3a5071a2018-09-12 13:27:42 -07005#include "types.hpp"
6#include "utils.hpp"
7
William A. Kennington III194375f2018-12-14 02:14:33 -08008#include <ipmid/api.h>
Patrick Venture3a5071a2018-09-12 13:27:42 -07009
Tom Joseph6b7a1432017-05-19 10:43:36 +053010#include <chrono>
Patrick Venture3a5071a2018-09-12 13:27:42 -070011#include <phosphor-logging/elog-errors.hpp>
Tom Joseph6b7a1432017-05-19 10:43:36 +053012#include <vector>
Patrick Venture3a5071a2018-09-12 13:27:42 -070013#include <xyz/openbmc_project/Common/error.hpp>
Patrick Venture46470a32018-09-07 19:26:25 -070014
Vernon Mauery185b9f82018-07-20 10:52:36 -070015#if __has_include(<filesystem>)
16#include <filesystem>
17#elif __has_include(<experimental/filesystem>)
Tom Joseph232f5292017-07-07 20:14:02 +053018#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070019namespace std
20{
21// splice experimental::filesystem into std
22namespace filesystem = std::experimental::filesystem;
23} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070024#else
Patrick Venture0b02be92018-08-31 11:55:55 -070025#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070026#endif
Patrick Venture0b02be92018-08-31 11:55:55 -070027
Tom Joseph6b7a1432017-05-19 10:43:36 +053028extern const ipmi::sensor::InvObjectIDMap invSensors;
29using namespace phosphor::logging;
30using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070031 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6b7a1432017-05-19 10:43:36 +053032
33namespace ipmi
34{
35
36namespace sel
37{
38
39namespace internal
40{
41
Patrick Venture0b02be92018-08-31 11:55:55 -070042GetSELEntryResponse
43 prepareSELEntry(const std::string& objPath,
44 ipmi::sensor::InvObjectIDMap::const_iterator iter)
Tom Joseph6b7a1432017-05-19 10:43:36 +053045{
Patrick Venture0b02be92018-08-31 11:55:55 -070046 GetSELEntryResponse record{};
Tom Joseph6b7a1432017-05-19 10:43:36 +053047
48 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
49 auto service = ipmi::getService(bus, logEntryIntf, objPath);
50
51 // Read all the log entry properties.
Patrick Venture0b02be92018-08-31 11:55:55 -070052 auto methodCall = bus.new_method_call(service.c_str(), objPath.c_str(),
53 propIntf, "GetAll");
Tom Joseph6b7a1432017-05-19 10:43:36 +053054 methodCall.append(logEntryIntf);
55
56 auto reply = bus.call(methodCall);
57 if (reply.is_method_error())
58 {
59 log<level::ERR>("Error in reading logging property entries");
60 elog<InternalFailure>();
61 }
62
Tom Joseph306878b2017-07-10 19:30:54 +053063 std::map<PropertyName, PropertyType> entryData;
Tom Joseph6b7a1432017-05-19 10:43:36 +053064 reply.read(entryData);
65
66 // Read Id from the log entry.
67 static constexpr auto propId = "Id";
68 auto iterId = entryData.find(propId);
69 if (iterId == entryData.end())
70 {
71 log<level::ERR>("Error in reading Id of logging entry");
72 elog<InternalFailure>();
73 }
74
75 record.recordID = static_cast<uint16_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -070076 sdbusplus::message::variant_ns::get<uint32_t>(iterId->second));
Tom Joseph6b7a1432017-05-19 10:43:36 +053077
78 // Read Timestamp from the log entry.
79 static constexpr auto propTimeStamp = "Timestamp";
80 auto iterTimeStamp = entryData.find(propTimeStamp);
81 if (iterTimeStamp == entryData.end())
82 {
83 log<level::ERR>("Error in reading Timestamp of logging entry");
84 elog<InternalFailure>();
85 }
86
87 std::chrono::milliseconds chronoTimeStamp(
Patrick Venture0b02be92018-08-31 11:55:55 -070088 sdbusplus::message::variant_ns::get<uint64_t>(iterTimeStamp->second));
89 record.timeStamp = static_cast<uint32_t>(
90 std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp)
91 .count());
Tom Joseph6b7a1432017-05-19 10:43:36 +053092
93 static constexpr auto systemEventRecord = 0x02;
94 static constexpr auto generatorID = 0x2000;
95 static constexpr auto eventMsgRevision = 0x04;
96
97 record.recordType = systemEventRecord;
98 record.generatorID = generatorID;
99 record.eventMsgRevision = eventMsgRevision;
100
101 record.sensorType = iter->second.sensorType;
102 record.sensorNum = iter->second.sensorID;
103 record.eventData1 = iter->second.eventOffset;
104
105 // Read Resolved from the log entry.
106 static constexpr auto propResolved = "Resolved";
107 auto iterResolved = entryData.find(propResolved);
108 if (iterResolved == entryData.end())
109 {
110 log<level::ERR>("Error in reading Resolved field of logging entry");
111 elog<InternalFailure>();
112 }
113
114 static constexpr auto deassertEvent = 0x80;
115
116 // Evaluate if the event is assertion or deassertion event
117 if (sdbusplus::message::variant_ns::get<bool>(iterResolved->second))
118 {
119 record.eventType = deassertEvent | iter->second.eventReadingType;
120 }
121 else
122 {
123 record.eventType = iter->second.eventReadingType;
124 }
125
126 return record;
127}
128
129} // namespace internal
130
Tom Joseph6edc8a02017-06-30 18:52:56 +0530131GetSELEntryResponse convertLogEntrytoSEL(const std::string& objPath)
132{
133 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
134
135 static constexpr auto assocIntf = "org.openbmc.Associations";
136 static constexpr auto assocProp = "associations";
137
138 auto service = ipmi::getService(bus, assocIntf, objPath);
139
140 // Read the Associations interface.
Patrick Venture0b02be92018-08-31 11:55:55 -0700141 auto methodCall =
142 bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
Tom Joseph6edc8a02017-06-30 18:52:56 +0530143 methodCall.append(assocIntf);
144 methodCall.append(assocProp);
145
146 auto reply = bus.call(methodCall);
147 if (reply.is_method_error())
148 {
149 log<level::ERR>("Error in reading Associations interface");
150 elog<InternalFailure>();
151 }
152
Patrick Venture0b02be92018-08-31 11:55:55 -0700153 using AssociationList =
154 std::vector<std::tuple<std::string, std::string, std::string>>;
Tom Joseph6edc8a02017-06-30 18:52:56 +0530155
156 sdbusplus::message::variant<AssociationList> list;
157 reply.read(list);
158
Patrick Venture0b02be92018-08-31 11:55:55 -0700159 auto& assocs = sdbusplus::message::variant_ns::get<AssociationList>(list);
Tom Joseph6edc8a02017-06-30 18:52:56 +0530160
161 /*
162 * Check if the log entry has any callout associations, if there is a
163 * callout association try to match the inventory path to the corresponding
164 * IPMI sensor.
165 */
166 for (const auto& item : assocs)
167 {
168 if (std::get<0>(item).compare(CALLOUT_FWD_ASSOCIATION) == 0)
169 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700170 auto iter = invSensors.find(std::get<2>(item));
171 if (iter == invSensors.end())
172 {
173 iter = invSensors.find(BOARD_SENSOR);
174 if (iter == invSensors.end())
175 {
176 log<level::ERR>("Motherboard sensor not found");
177 elog<InternalFailure>();
178 }
179 }
Tom Joseph6edc8a02017-06-30 18:52:56 +0530180
Patrick Venture0b02be92018-08-31 11:55:55 -0700181 return internal::prepareSELEntry(objPath, iter);
Tom Joseph6edc8a02017-06-30 18:52:56 +0530182 }
183 }
184
185 // If there are no callout associations link the log entry to system event
186 // sensor
187 auto iter = invSensors.find(SYSTEM_SENSOR);
188 if (iter == invSensors.end())
189 {
190 log<level::ERR>("System event sensor not found");
191 elog<InternalFailure>();
192 }
193
194 return internal::prepareSELEntry(objPath, iter);
195}
196
Tom Joseph399fd922017-06-30 18:40:30 +0530197std::chrono::seconds getEntryTimeStamp(const std::string& objPath)
198{
199 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
200
201 auto service = ipmi::getService(bus, logEntryIntf, objPath);
202
203 using namespace std::string_literals;
204 static const auto propTimeStamp = "Timestamp"s;
205
Patrick Venture0b02be92018-08-31 11:55:55 -0700206 auto methodCall =
207 bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
Tom Joseph399fd922017-06-30 18:40:30 +0530208 methodCall.append(logEntryIntf);
209 methodCall.append(propTimeStamp);
210
211 auto reply = bus.call(methodCall);
212 if (reply.is_method_error())
213 {
214 log<level::ERR>("Error in reading Timestamp from Entry interface");
215 elog<InternalFailure>();
216 }
217
218 sdbusplus::message::variant<uint64_t> timeStamp;
219 reply.read(timeStamp);
220
221 std::chrono::milliseconds chronoTimeStamp(
Patrick Venture0b02be92018-08-31 11:55:55 -0700222 sdbusplus::message::variant_ns::get<uint64_t>(timeStamp));
Tom Joseph399fd922017-06-30 18:40:30 +0530223
224 return std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp);
225}
226
Tom Joseph232f5292017-07-07 20:14:02 +0530227void readLoggingObjectPaths(ObjectPaths& paths)
228{
229 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
230 auto depth = 0;
231 paths.clear();
232
Patrick Venture0b02be92018-08-31 11:55:55 -0700233 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
234 mapperIntf, "GetSubTreePaths");
Tom Joseph232f5292017-07-07 20:14:02 +0530235 mapperCall.append(logBasePath);
236 mapperCall.append(depth);
237 mapperCall.append(ObjectPaths({logEntryIntf}));
238
239 auto reply = bus.call(mapperCall);
240 if (reply.is_method_error())
241 {
242 log<level::INFO>("Error in reading logging entry object paths");
243 }
244 else
245 {
246 reply.read(paths);
247
Patrick Venture0b02be92018-08-31 11:55:55 -0700248 std::sort(paths.begin(), paths.end(),
249 [](const std::string& a, const std::string& b) {
250 namespace fs = std::filesystem;
251 fs::path pathA(a);
252 fs::path pathB(b);
253 auto idA = std::stoul(pathA.filename().string());
254 auto idB = std::stoul(pathB.filename().string());
Tom Joseph232f5292017-07-07 20:14:02 +0530255
Patrick Venture0b02be92018-08-31 11:55:55 -0700256 return idA < idB;
257 });
Tom Joseph232f5292017-07-07 20:14:02 +0530258 }
259}
260
Tom Joseph6b7a1432017-05-19 10:43:36 +0530261} // namespace sel
262
263} // namespace ipmi