blob: 8e04ad471ee882e46f37d93d8a2f009c28a309fb [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>
Patrick Venture0b02be92018-08-31 11:55:55 -07007namespace std
8{
9// splice experimental::filesystem into std
10namespace filesystem = std::experimental::filesystem;
11} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070012#else
Patrick Venture0b02be92018-08-31 11:55:55 -070013#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070014#endif
Tom Joseph6edc8a02017-06-30 18:52:56 +053015#include "config.h"
Patrick Venture0b02be92018-08-31 11:55:55 -070016
Tom Joseph6b7a1432017-05-19 10:43:36 +053017#include "selutility.hpp"
18#include "types.hpp"
19#include "utils.hpp"
20
Patrick Venture0b02be92018-08-31 11:55:55 -070021#include <phosphor-logging/elog-errors.hpp>
22#include <xyz/openbmc_project/Common/error.hpp>
23
24#include "host-ipmid/ipmid-api.h"
25
Tom Joseph6b7a1432017-05-19 10:43:36 +053026extern const ipmi::sensor::InvObjectIDMap invSensors;
27using namespace phosphor::logging;
28using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070029 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6b7a1432017-05-19 10:43:36 +053030
31namespace ipmi
32{
33
34namespace sel
35{
36
37namespace internal
38{
39
Patrick Venture0b02be92018-08-31 11:55:55 -070040GetSELEntryResponse
41 prepareSELEntry(const std::string& objPath,
42 ipmi::sensor::InvObjectIDMap::const_iterator iter)
Tom Joseph6b7a1432017-05-19 10:43:36 +053043{
Patrick Venture0b02be92018-08-31 11:55:55 -070044 GetSELEntryResponse record{};
Tom Joseph6b7a1432017-05-19 10:43:36 +053045
46 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
47 auto service = ipmi::getService(bus, logEntryIntf, objPath);
48
49 // Read all the log entry properties.
Patrick Venture0b02be92018-08-31 11:55:55 -070050 auto methodCall = bus.new_method_call(service.c_str(), objPath.c_str(),
51 propIntf, "GetAll");
Tom Joseph6b7a1432017-05-19 10:43:36 +053052 methodCall.append(logEntryIntf);
53
54 auto reply = bus.call(methodCall);
55 if (reply.is_method_error())
56 {
57 log<level::ERR>("Error in reading logging property entries");
58 elog<InternalFailure>();
59 }
60
Tom Joseph306878b2017-07-10 19:30:54 +053061 std::map<PropertyName, PropertyType> entryData;
Tom Joseph6b7a1432017-05-19 10:43:36 +053062 reply.read(entryData);
63
64 // Read Id from the log entry.
65 static constexpr auto propId = "Id";
66 auto iterId = entryData.find(propId);
67 if (iterId == entryData.end())
68 {
69 log<level::ERR>("Error in reading Id of logging entry");
70 elog<InternalFailure>();
71 }
72
73 record.recordID = static_cast<uint16_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -070074 sdbusplus::message::variant_ns::get<uint32_t>(iterId->second));
Tom Joseph6b7a1432017-05-19 10:43:36 +053075
76 // Read Timestamp from the log entry.
77 static constexpr auto propTimeStamp = "Timestamp";
78 auto iterTimeStamp = entryData.find(propTimeStamp);
79 if (iterTimeStamp == entryData.end())
80 {
81 log<level::ERR>("Error in reading Timestamp of logging entry");
82 elog<InternalFailure>();
83 }
84
85 std::chrono::milliseconds chronoTimeStamp(
Patrick Venture0b02be92018-08-31 11:55:55 -070086 sdbusplus::message::variant_ns::get<uint64_t>(iterTimeStamp->second));
87 record.timeStamp = static_cast<uint32_t>(
88 std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp)
89 .count());
Tom Joseph6b7a1432017-05-19 10:43:36 +053090
91 static constexpr auto systemEventRecord = 0x02;
92 static constexpr auto generatorID = 0x2000;
93 static constexpr auto eventMsgRevision = 0x04;
94
95 record.recordType = systemEventRecord;
96 record.generatorID = generatorID;
97 record.eventMsgRevision = eventMsgRevision;
98
99 record.sensorType = iter->second.sensorType;
100 record.sensorNum = iter->second.sensorID;
101 record.eventData1 = iter->second.eventOffset;
102
103 // Read Resolved from the log entry.
104 static constexpr auto propResolved = "Resolved";
105 auto iterResolved = entryData.find(propResolved);
106 if (iterResolved == entryData.end())
107 {
108 log<level::ERR>("Error in reading Resolved field of logging entry");
109 elog<InternalFailure>();
110 }
111
112 static constexpr auto deassertEvent = 0x80;
113
114 // Evaluate if the event is assertion or deassertion event
115 if (sdbusplus::message::variant_ns::get<bool>(iterResolved->second))
116 {
117 record.eventType = deassertEvent | iter->second.eventReadingType;
118 }
119 else
120 {
121 record.eventType = iter->second.eventReadingType;
122 }
123
124 return record;
125}
126
127} // namespace internal
128
Tom Joseph6edc8a02017-06-30 18:52:56 +0530129GetSELEntryResponse convertLogEntrytoSEL(const std::string& objPath)
130{
131 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
132
133 static constexpr auto assocIntf = "org.openbmc.Associations";
134 static constexpr auto assocProp = "associations";
135
136 auto service = ipmi::getService(bus, assocIntf, objPath);
137
138 // Read the Associations interface.
Patrick Venture0b02be92018-08-31 11:55:55 -0700139 auto methodCall =
140 bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
Tom Joseph6edc8a02017-06-30 18:52:56 +0530141 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
Patrick Venture0b02be92018-08-31 11:55:55 -0700151 using AssociationList =
152 std::vector<std::tuple<std::string, std::string, std::string>>;
Tom Joseph6edc8a02017-06-30 18:52:56 +0530153
154 sdbusplus::message::variant<AssociationList> list;
155 reply.read(list);
156
Patrick Venture0b02be92018-08-31 11:55:55 -0700157 auto& assocs = sdbusplus::message::variant_ns::get<AssociationList>(list);
Tom Joseph6edc8a02017-06-30 18:52:56 +0530158
159 /*
160 * Check if the log entry has any callout associations, if there is a
161 * callout association try to match the inventory path to the corresponding
162 * IPMI sensor.
163 */
164 for (const auto& item : assocs)
165 {
166 if (std::get<0>(item).compare(CALLOUT_FWD_ASSOCIATION) == 0)
167 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700168 auto iter = invSensors.find(std::get<2>(item));
169 if (iter == invSensors.end())
170 {
171 iter = invSensors.find(BOARD_SENSOR);
172 if (iter == invSensors.end())
173 {
174 log<level::ERR>("Motherboard sensor not found");
175 elog<InternalFailure>();
176 }
177 }
Tom Joseph6edc8a02017-06-30 18:52:56 +0530178
Patrick Venture0b02be92018-08-31 11:55:55 -0700179 return internal::prepareSELEntry(objPath, iter);
Tom Joseph6edc8a02017-06-30 18:52:56 +0530180 }
181 }
182
183 // If there are no callout associations link the log entry to system event
184 // sensor
185 auto iter = invSensors.find(SYSTEM_SENSOR);
186 if (iter == invSensors.end())
187 {
188 log<level::ERR>("System event sensor not found");
189 elog<InternalFailure>();
190 }
191
192 return internal::prepareSELEntry(objPath, iter);
193}
194
Tom Joseph399fd922017-06-30 18:40:30 +0530195std::chrono::seconds getEntryTimeStamp(const std::string& objPath)
196{
197 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
198
199 auto service = ipmi::getService(bus, logEntryIntf, objPath);
200
201 using namespace std::string_literals;
202 static const auto propTimeStamp = "Timestamp"s;
203
Patrick Venture0b02be92018-08-31 11:55:55 -0700204 auto methodCall =
205 bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
Tom Joseph399fd922017-06-30 18:40:30 +0530206 methodCall.append(logEntryIntf);
207 methodCall.append(propTimeStamp);
208
209 auto reply = bus.call(methodCall);
210 if (reply.is_method_error())
211 {
212 log<level::ERR>("Error in reading Timestamp from Entry interface");
213 elog<InternalFailure>();
214 }
215
216 sdbusplus::message::variant<uint64_t> timeStamp;
217 reply.read(timeStamp);
218
219 std::chrono::milliseconds chronoTimeStamp(
Patrick Venture0b02be92018-08-31 11:55:55 -0700220 sdbusplus::message::variant_ns::get<uint64_t>(timeStamp));
Tom Joseph399fd922017-06-30 18:40:30 +0530221
222 return std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp);
223}
224
Tom Joseph232f5292017-07-07 20:14:02 +0530225void readLoggingObjectPaths(ObjectPaths& paths)
226{
227 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
228 auto depth = 0;
229 paths.clear();
230
Patrick Venture0b02be92018-08-31 11:55:55 -0700231 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
232 mapperIntf, "GetSubTreePaths");
Tom Joseph232f5292017-07-07 20:14:02 +0530233 mapperCall.append(logBasePath);
234 mapperCall.append(depth);
235 mapperCall.append(ObjectPaths({logEntryIntf}));
236
237 auto reply = bus.call(mapperCall);
238 if (reply.is_method_error())
239 {
240 log<level::INFO>("Error in reading logging entry object paths");
241 }
242 else
243 {
244 reply.read(paths);
245
Patrick Venture0b02be92018-08-31 11:55:55 -0700246 std::sort(paths.begin(), paths.end(),
247 [](const std::string& a, const std::string& b) {
248 namespace fs = std::filesystem;
249 fs::path pathA(a);
250 fs::path pathB(b);
251 auto idA = std::stoul(pathA.filename().string());
252 auto idB = std::stoul(pathB.filename().string());
Tom Joseph232f5292017-07-07 20:14:02 +0530253
Patrick Venture0b02be92018-08-31 11:55:55 -0700254 return idA < idB;
255 });
Tom Joseph232f5292017-07-07 20:14:02 +0530256 }
257}
258
Tom Joseph6b7a1432017-05-19 10:43:36 +0530259} // namespace sel
260
261} // namespace ipmi