blob: 228bf62f03b9e192930aa1f10441c3f173b2d006 [file] [log] [blame]
Patrick Venture46470a32018-09-07 19:26:25 -07001#include "config.h"
2
3#include "selutility.hpp"
4
Tom Joseph6b7a1432017-05-19 10:43:36 +05305#include <chrono>
6#include <vector>
Patrick Venture46470a32018-09-07 19:26:25 -07007
Vernon Mauery185b9f82018-07-20 10:52:36 -07008#if __has_include(<filesystem>)
9#include <filesystem>
10#elif __has_include(<experimental/filesystem>)
Tom Joseph232f5292017-07-07 20:14:02 +053011#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070012namespace std
13{
14// splice experimental::filesystem into std
15namespace filesystem = std::experimental::filesystem;
16} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070017#else
Patrick Venture0b02be92018-08-31 11:55:55 -070018#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070019#endif
Patrick Venture0b02be92018-08-31 11:55:55 -070020
Tom Joseph6b7a1432017-05-19 10:43:36 +053021#include "types.hpp"
22#include "utils.hpp"
23
Patrick Venture46470a32018-09-07 19:26:25 -070024#include <host-ipmid/ipmid-api.h>
25
Patrick Venture0b02be92018-08-31 11:55:55 -070026#include <phosphor-logging/elog-errors.hpp>
27#include <xyz/openbmc_project/Common/error.hpp>
28
Tom Joseph6b7a1432017-05-19 10:43:36 +053029extern const ipmi::sensor::InvObjectIDMap invSensors;
30using namespace phosphor::logging;
31using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070032 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6b7a1432017-05-19 10:43:36 +053033
34namespace ipmi
35{
36
37namespace sel
38{
39
40namespace internal
41{
42
Patrick Venture0b02be92018-08-31 11:55:55 -070043GetSELEntryResponse
44 prepareSELEntry(const std::string& objPath,
45 ipmi::sensor::InvObjectIDMap::const_iterator iter)
Tom Joseph6b7a1432017-05-19 10:43:36 +053046{
Patrick Venture0b02be92018-08-31 11:55:55 -070047 GetSELEntryResponse record{};
Tom Joseph6b7a1432017-05-19 10:43:36 +053048
49 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
50 auto service = ipmi::getService(bus, logEntryIntf, objPath);
51
52 // Read all the log entry properties.
Patrick Venture0b02be92018-08-31 11:55:55 -070053 auto methodCall = bus.new_method_call(service.c_str(), objPath.c_str(),
54 propIntf, "GetAll");
Tom Joseph6b7a1432017-05-19 10:43:36 +053055 methodCall.append(logEntryIntf);
56
57 auto reply = bus.call(methodCall);
58 if (reply.is_method_error())
59 {
60 log<level::ERR>("Error in reading logging property entries");
61 elog<InternalFailure>();
62 }
63
Tom Joseph306878b2017-07-10 19:30:54 +053064 std::map<PropertyName, PropertyType> entryData;
Tom Joseph6b7a1432017-05-19 10:43:36 +053065 reply.read(entryData);
66
67 // Read Id from the log entry.
68 static constexpr auto propId = "Id";
69 auto iterId = entryData.find(propId);
70 if (iterId == entryData.end())
71 {
72 log<level::ERR>("Error in reading Id of logging entry");
73 elog<InternalFailure>();
74 }
75
76 record.recordID = static_cast<uint16_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -070077 sdbusplus::message::variant_ns::get<uint32_t>(iterId->second));
Tom Joseph6b7a1432017-05-19 10:43:36 +053078
79 // Read Timestamp from the log entry.
80 static constexpr auto propTimeStamp = "Timestamp";
81 auto iterTimeStamp = entryData.find(propTimeStamp);
82 if (iterTimeStamp == entryData.end())
83 {
84 log<level::ERR>("Error in reading Timestamp of logging entry");
85 elog<InternalFailure>();
86 }
87
88 std::chrono::milliseconds chronoTimeStamp(
Patrick Venture0b02be92018-08-31 11:55:55 -070089 sdbusplus::message::variant_ns::get<uint64_t>(iterTimeStamp->second));
90 record.timeStamp = static_cast<uint32_t>(
91 std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp)
92 .count());
Tom Joseph6b7a1432017-05-19 10:43:36 +053093
94 static constexpr auto systemEventRecord = 0x02;
95 static constexpr auto generatorID = 0x2000;
96 static constexpr auto eventMsgRevision = 0x04;
97
98 record.recordType = systemEventRecord;
99 record.generatorID = generatorID;
100 record.eventMsgRevision = eventMsgRevision;
101
102 record.sensorType = iter->second.sensorType;
103 record.sensorNum = iter->second.sensorID;
104 record.eventData1 = iter->second.eventOffset;
105
106 // Read Resolved from the log entry.
107 static constexpr auto propResolved = "Resolved";
108 auto iterResolved = entryData.find(propResolved);
109 if (iterResolved == entryData.end())
110 {
111 log<level::ERR>("Error in reading Resolved field of logging entry");
112 elog<InternalFailure>();
113 }
114
115 static constexpr auto deassertEvent = 0x80;
116
117 // Evaluate if the event is assertion or deassertion event
118 if (sdbusplus::message::variant_ns::get<bool>(iterResolved->second))
119 {
120 record.eventType = deassertEvent | iter->second.eventReadingType;
121 }
122 else
123 {
124 record.eventType = iter->second.eventReadingType;
125 }
126
127 return record;
128}
129
130} // namespace internal
131
Tom Joseph6edc8a02017-06-30 18:52:56 +0530132GetSELEntryResponse convertLogEntrytoSEL(const std::string& objPath)
133{
134 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
135
136 static constexpr auto assocIntf = "org.openbmc.Associations";
137 static constexpr auto assocProp = "associations";
138
139 auto service = ipmi::getService(bus, assocIntf, objPath);
140
141 // Read the Associations interface.
Patrick Venture0b02be92018-08-31 11:55:55 -0700142 auto methodCall =
143 bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
Tom Joseph6edc8a02017-06-30 18:52:56 +0530144 methodCall.append(assocIntf);
145 methodCall.append(assocProp);
146
147 auto reply = bus.call(methodCall);
148 if (reply.is_method_error())
149 {
150 log<level::ERR>("Error in reading Associations interface");
151 elog<InternalFailure>();
152 }
153
Patrick Venture0b02be92018-08-31 11:55:55 -0700154 using AssociationList =
155 std::vector<std::tuple<std::string, std::string, std::string>>;
Tom Joseph6edc8a02017-06-30 18:52:56 +0530156
157 sdbusplus::message::variant<AssociationList> list;
158 reply.read(list);
159
Patrick Venture0b02be92018-08-31 11:55:55 -0700160 auto& assocs = sdbusplus::message::variant_ns::get<AssociationList>(list);
Tom Joseph6edc8a02017-06-30 18:52:56 +0530161
162 /*
163 * Check if the log entry has any callout associations, if there is a
164 * callout association try to match the inventory path to the corresponding
165 * IPMI sensor.
166 */
167 for (const auto& item : assocs)
168 {
169 if (std::get<0>(item).compare(CALLOUT_FWD_ASSOCIATION) == 0)
170 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700171 auto iter = invSensors.find(std::get<2>(item));
172 if (iter == invSensors.end())
173 {
174 iter = invSensors.find(BOARD_SENSOR);
175 if (iter == invSensors.end())
176 {
177 log<level::ERR>("Motherboard sensor not found");
178 elog<InternalFailure>();
179 }
180 }
Tom Joseph6edc8a02017-06-30 18:52:56 +0530181
Patrick Venture0b02be92018-08-31 11:55:55 -0700182 return internal::prepareSELEntry(objPath, iter);
Tom Joseph6edc8a02017-06-30 18:52:56 +0530183 }
184 }
185
186 // If there are no callout associations link the log entry to system event
187 // sensor
188 auto iter = invSensors.find(SYSTEM_SENSOR);
189 if (iter == invSensors.end())
190 {
191 log<level::ERR>("System event sensor not found");
192 elog<InternalFailure>();
193 }
194
195 return internal::prepareSELEntry(objPath, iter);
196}
197
Tom Joseph399fd922017-06-30 18:40:30 +0530198std::chrono::seconds getEntryTimeStamp(const std::string& objPath)
199{
200 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
201
202 auto service = ipmi::getService(bus, logEntryIntf, objPath);
203
204 using namespace std::string_literals;
205 static const auto propTimeStamp = "Timestamp"s;
206
Patrick Venture0b02be92018-08-31 11:55:55 -0700207 auto methodCall =
208 bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
Tom Joseph399fd922017-06-30 18:40:30 +0530209 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(
Patrick Venture0b02be92018-08-31 11:55:55 -0700223 sdbusplus::message::variant_ns::get<uint64_t>(timeStamp));
Tom Joseph399fd922017-06-30 18:40:30 +0530224
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
Patrick Venture0b02be92018-08-31 11:55:55 -0700234 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
235 mapperIntf, "GetSubTreePaths");
Tom Joseph232f5292017-07-07 20:14:02 +0530236 mapperCall.append(logBasePath);
237 mapperCall.append(depth);
238 mapperCall.append(ObjectPaths({logEntryIntf}));
239
240 auto reply = bus.call(mapperCall);
241 if (reply.is_method_error())
242 {
243 log<level::INFO>("Error in reading logging entry object paths");
244 }
245 else
246 {
247 reply.read(paths);
248
Patrick Venture0b02be92018-08-31 11:55:55 -0700249 std::sort(paths.begin(), paths.end(),
250 [](const std::string& a, const std::string& b) {
251 namespace fs = std::filesystem;
252 fs::path pathA(a);
253 fs::path pathB(b);
254 auto idA = std::stoul(pathA.filename().string());
255 auto idB = std::stoul(pathB.filename().string());
Tom Joseph232f5292017-07-07 20:14:02 +0530256
Patrick Venture0b02be92018-08-31 11:55:55 -0700257 return idA < idB;
258 });
Tom Joseph232f5292017-07-07 20:14:02 +0530259 }
260}
261
Tom Joseph6b7a1432017-05-19 10:43:36 +0530262} // namespace sel
263
264} // namespace ipmi