blob: 5935de28fd8af596f074667375a575250302acae [file] [log] [blame]
Tom Joseph6b7a1432017-05-19 10:43:36 +05301#include <chrono>
2#include <vector>
Vernon Mauery185b9f82018-07-20 10:52:36 -07003#if __has_include(<filesystem>)
4#include <filesystem>
5#elif __has_include(<experimental/filesystem>)
Tom Joseph232f5292017-07-07 20:14:02 +05306#include <experimental/filesystem>
Vernon Mauery185b9f82018-07-20 10:52:36 -07007namespace std {
8 // splice experimental::filesystem into std
9 namespace filesystem = std::experimental::filesystem;
10}
11#else
12# error filesystem not available
13#endif
Tom Joseph6b7a1432017-05-19 10:43:36 +053014#include <phosphor-logging/elog-errors.hpp>
15#include "host-ipmid/ipmid-api.h"
16#include "xyz/openbmc_project/Common/error.hpp"
Tom Joseph6edc8a02017-06-30 18:52:56 +053017#include "config.h"
Tom Joseph6b7a1432017-05-19 10:43:36 +053018#include "selutility.hpp"
19#include "types.hpp"
20#include "utils.hpp"
21
22extern const ipmi::sensor::InvObjectIDMap invSensors;
23using namespace phosphor::logging;
24using InternalFailure =
25 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
26
27namespace ipmi
28{
29
30namespace sel
31{
32
33namespace internal
34{
35
36GetSELEntryResponse prepareSELEntry(
37 const std::string& objPath,
38 ipmi::sensor::InvObjectIDMap::const_iterator iter)
39{
Tom Joseph306878b2017-07-10 19:30:54 +053040 GetSELEntryResponse record {};
Tom Joseph6b7a1432017-05-19 10:43:36 +053041
42 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
43 auto service = ipmi::getService(bus, logEntryIntf, objPath);
44
45 // Read all the log entry properties.
46 auto methodCall = bus.new_method_call(service.c_str(),
47 objPath.c_str(),
48 propIntf,
49 "GetAll");
50 methodCall.append(logEntryIntf);
51
52 auto reply = bus.call(methodCall);
53 if (reply.is_method_error())
54 {
55 log<level::ERR>("Error in reading logging property entries");
56 elog<InternalFailure>();
57 }
58
Tom Joseph306878b2017-07-10 19:30:54 +053059 std::map<PropertyName, PropertyType> entryData;
Tom Joseph6b7a1432017-05-19 10:43:36 +053060 reply.read(entryData);
61
62 // Read Id from the log entry.
63 static constexpr auto propId = "Id";
64 auto iterId = entryData.find(propId);
65 if (iterId == entryData.end())
66 {
67 log<level::ERR>("Error in reading Id of logging entry");
68 elog<InternalFailure>();
69 }
70
71 record.recordID = static_cast<uint16_t>(
72 sdbusplus::message::variant_ns::get<uint32_t>(iterId->second));
73
74 // Read Timestamp from the log entry.
75 static constexpr auto propTimeStamp = "Timestamp";
76 auto iterTimeStamp = entryData.find(propTimeStamp);
77 if (iterTimeStamp == entryData.end())
78 {
79 log<level::ERR>("Error in reading Timestamp of logging entry");
80 elog<InternalFailure>();
81 }
82
83 std::chrono::milliseconds chronoTimeStamp(
84 sdbusplus::message::variant_ns::get<uint64_t>
85 (iterTimeStamp->second));
86 record.timeStamp = static_cast<uint32_t>(std::chrono::duration_cast<
87 std::chrono::seconds>(chronoTimeStamp).count());
88
89 static constexpr auto systemEventRecord = 0x02;
90 static constexpr auto generatorID = 0x2000;
91 static constexpr auto eventMsgRevision = 0x04;
92
93 record.recordType = systemEventRecord;
94 record.generatorID = generatorID;
95 record.eventMsgRevision = eventMsgRevision;
96
97 record.sensorType = iter->second.sensorType;
98 record.sensorNum = iter->second.sensorID;
99 record.eventData1 = iter->second.eventOffset;
100
101 // Read Resolved from the log entry.
102 static constexpr auto propResolved = "Resolved";
103 auto iterResolved = entryData.find(propResolved);
104 if (iterResolved == entryData.end())
105 {
106 log<level::ERR>("Error in reading Resolved field of logging entry");
107 elog<InternalFailure>();
108 }
109
110 static constexpr auto deassertEvent = 0x80;
111
112 // Evaluate if the event is assertion or deassertion event
113 if (sdbusplus::message::variant_ns::get<bool>(iterResolved->second))
114 {
115 record.eventType = deassertEvent | iter->second.eventReadingType;
116 }
117 else
118 {
119 record.eventType = iter->second.eventReadingType;
120 }
121
122 return record;
123}
124
125} // namespace internal
126
Tom Joseph6edc8a02017-06-30 18:52:56 +0530127GetSELEntryResponse convertLogEntrytoSEL(const std::string& objPath)
128{
129 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
130
131 static constexpr auto assocIntf = "org.openbmc.Associations";
132 static constexpr auto assocProp = "associations";
133
134 auto service = ipmi::getService(bus, assocIntf, objPath);
135
136 // Read the Associations interface.
137 auto methodCall = bus.new_method_call(service.c_str(),
138 objPath.c_str(),
139 propIntf,
140 "Get");
141 methodCall.append(assocIntf);
142 methodCall.append(assocProp);
143
144 auto reply = bus.call(methodCall);
145 if (reply.is_method_error())
146 {
147 log<level::ERR>("Error in reading Associations interface");
148 elog<InternalFailure>();
149 }
150
151 using AssociationList = std::vector<std::tuple<
152 std::string, std::string, std::string>>;
153
154 sdbusplus::message::variant<AssociationList> list;
155 reply.read(list);
156
157 auto& assocs = sdbusplus::message::variant_ns::get<AssociationList>
158 (list);
159
160 /*
161 * Check if the log entry has any callout associations, if there is a
162 * callout association try to match the inventory path to the corresponding
163 * IPMI sensor.
164 */
165 for (const auto& item : assocs)
166 {
167 if (std::get<0>(item).compare(CALLOUT_FWD_ASSOCIATION) == 0)
168 {
169 auto iter = invSensors.find(std::get<2>(item));
170 if (iter == invSensors.end())
171 {
172 iter = invSensors.find(BOARD_SENSOR);
173 if (iter == invSensors.end())
174 {
175 log<level::ERR>("Motherboard sensor not found");
176 elog<InternalFailure>();
177 }
178 }
179
180 return internal::prepareSELEntry(objPath, iter);
181 }
182 }
183
184 // If there are no callout associations link the log entry to system event
185 // sensor
186 auto iter = invSensors.find(SYSTEM_SENSOR);
187 if (iter == invSensors.end())
188 {
189 log<level::ERR>("System event sensor not found");
190 elog<InternalFailure>();
191 }
192
193 return internal::prepareSELEntry(objPath, iter);
194}
195
Tom Joseph399fd922017-06-30 18:40:30 +0530196std::chrono::seconds getEntryTimeStamp(const std::string& objPath)
197{
198 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
199
200 auto service = ipmi::getService(bus, logEntryIntf, objPath);
201
202 using namespace std::string_literals;
203 static const auto propTimeStamp = "Timestamp"s;
204
205 auto methodCall = bus.new_method_call(service.c_str(),
206 objPath.c_str(),
207 propIntf,
208 "Get");
209 methodCall.append(logEntryIntf);
210 methodCall.append(propTimeStamp);
211
212 auto reply = bus.call(methodCall);
213 if (reply.is_method_error())
214 {
215 log<level::ERR>("Error in reading Timestamp from Entry interface");
216 elog<InternalFailure>();
217 }
218
219 sdbusplus::message::variant<uint64_t> timeStamp;
220 reply.read(timeStamp);
221
222 std::chrono::milliseconds chronoTimeStamp(
223 sdbusplus::message::variant_ns::get<uint64_t>(timeStamp));
224
225 return std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp);
226}
227
Tom Joseph232f5292017-07-07 20:14:02 +0530228void readLoggingObjectPaths(ObjectPaths& paths)
229{
230 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
231 auto depth = 0;
232 paths.clear();
233
234 auto mapperCall = bus.new_method_call(mapperBusName,
235 mapperObjPath,
236 mapperIntf,
237 "GetSubTreePaths");
238 mapperCall.append(logBasePath);
239 mapperCall.append(depth);
240 mapperCall.append(ObjectPaths({logEntryIntf}));
241
242 auto reply = bus.call(mapperCall);
243 if (reply.is_method_error())
244 {
245 log<level::INFO>("Error in reading logging entry object paths");
246 }
247 else
248 {
249 reply.read(paths);
250
251 std::sort(paths.begin(), paths.end(), [](const std::string& a,
252 const std::string& b)
253 {
Vernon Mauery185b9f82018-07-20 10:52:36 -0700254 namespace fs = std::filesystem;
Tom Joseph232f5292017-07-07 20:14:02 +0530255 fs::path pathA(a);
256 fs::path pathB(b);
257 auto idA = std::stoul(pathA.filename().string());
258 auto idB = std::stoul(pathB.filename().string());
259
260 return idA < idB;
261 });
262 }
263}
264
Tom Joseph6b7a1432017-05-19 10:43:36 +0530265} // namespace sel
266
267} // namespace ipmi