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