blob: 9edc1b8fed3c966681c550e4af6cbcd0288eac86 [file] [log] [blame]
Patrick Venture46470a32018-09-07 19:26:25 -07001#include "config.h"
2
3#include "selutility.hpp"
4
William A. Kennington III194375f2018-12-14 02:14:33 -08005#include <ipmid/api.h>
Patrick Venture3a5071a2018-09-12 13:27:42 -07006
Tom Joseph6b7a1432017-05-19 10:43:36 +05307#include <chrono>
Vernon Mauery33250242019-03-12 16:49:26 -07008#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -07009#include <ipmid/utils.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070010#include <phosphor-logging/elog-errors.hpp>
Tom Joseph6b7a1432017-05-19 10:43:36 +053011#include <vector>
Patrick Venture3a5071a2018-09-12 13:27:42 -070012#include <xyz/openbmc_project/Common/error.hpp>
Patrick Venture46470a32018-09-07 19:26:25 -070013
Vernon Mauery185b9f82018-07-20 10:52:36 -070014#if __has_include(<filesystem>)
15#include <filesystem>
16#elif __has_include(<experimental/filesystem>)
Tom Joseph232f5292017-07-07 20:14:02 +053017#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070018namespace std
19{
20// splice experimental::filesystem into std
21namespace filesystem = std::experimental::filesystem;
22} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070023#else
Patrick Venture0b02be92018-08-31 11:55:55 -070024#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070025#endif
Patrick Venture0b02be92018-08-31 11:55:55 -070026
Tom Joseph6b7a1432017-05-19 10:43:36 +053027extern const ipmi::sensor::InvObjectIDMap invSensors;
28using namespace phosphor::logging;
29using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070030 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6b7a1432017-05-19 10:43:36 +053031
32namespace ipmi
33{
34
35namespace sel
36{
37
38namespace internal
39{
40
Patrick Venture0b02be92018-08-31 11:55:55 -070041GetSELEntryResponse
42 prepareSELEntry(const std::string& objPath,
43 ipmi::sensor::InvObjectIDMap::const_iterator iter)
Tom Joseph6b7a1432017-05-19 10:43:36 +053044{
Patrick Venture0b02be92018-08-31 11:55:55 -070045 GetSELEntryResponse record{};
Tom Joseph6b7a1432017-05-19 10:43:36 +053046
47 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
48 auto service = ipmi::getService(bus, logEntryIntf, objPath);
49
50 // Read all the log entry properties.
Patrick Venture0b02be92018-08-31 11:55:55 -070051 auto methodCall = bus.new_method_call(service.c_str(), objPath.c_str(),
52 propIntf, "GetAll");
Tom Joseph6b7a1432017-05-19 10:43:36 +053053 methodCall.append(logEntryIntf);
54
55 auto reply = bus.call(methodCall);
56 if (reply.is_method_error())
57 {
58 log<level::ERR>("Error in reading logging property entries");
59 elog<InternalFailure>();
60 }
61
Tom Joseph306878b2017-07-10 19:30:54 +053062 std::map<PropertyName, PropertyType> entryData;
Tom Joseph6b7a1432017-05-19 10:43:36 +053063 reply.read(entryData);
64
65 // Read Id from the log entry.
66 static constexpr auto propId = "Id";
67 auto iterId = entryData.find(propId);
68 if (iterId == entryData.end())
69 {
70 log<level::ERR>("Error in reading Id of logging entry");
71 elog<InternalFailure>();
72 }
73
74 record.recordID = static_cast<uint16_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -070075 sdbusplus::message::variant_ns::get<uint32_t>(iterId->second));
Tom Joseph6b7a1432017-05-19 10:43:36 +053076
77 // Read Timestamp from the log entry.
78 static constexpr auto propTimeStamp = "Timestamp";
79 auto iterTimeStamp = entryData.find(propTimeStamp);
80 if (iterTimeStamp == entryData.end())
81 {
82 log<level::ERR>("Error in reading Timestamp of logging entry");
83 elog<InternalFailure>();
84 }
85
86 std::chrono::milliseconds chronoTimeStamp(
Patrick Venture0b02be92018-08-31 11:55:55 -070087 sdbusplus::message::variant_ns::get<uint64_t>(iterTimeStamp->second));
88 record.timeStamp = static_cast<uint32_t>(
89 std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp)
90 .count());
Tom Joseph6b7a1432017-05-19 10:43:36 +053091
92 static constexpr auto systemEventRecord = 0x02;
93 static constexpr auto generatorID = 0x2000;
94 static constexpr auto eventMsgRevision = 0x04;
95
96 record.recordType = systemEventRecord;
97 record.generatorID = generatorID;
98 record.eventMsgRevision = eventMsgRevision;
99
100 record.sensorType = iter->second.sensorType;
101 record.sensorNum = iter->second.sensorID;
102 record.eventData1 = iter->second.eventOffset;
103
104 // Read Resolved from the log entry.
105 static constexpr auto propResolved = "Resolved";
106 auto iterResolved = entryData.find(propResolved);
107 if (iterResolved == entryData.end())
108 {
109 log<level::ERR>("Error in reading Resolved field of logging entry");
110 elog<InternalFailure>();
111 }
112
113 static constexpr auto deassertEvent = 0x80;
114
115 // Evaluate if the event is assertion or deassertion event
116 if (sdbusplus::message::variant_ns::get<bool>(iterResolved->second))
117 {
118 record.eventType = deassertEvent | iter->second.eventReadingType;
119 }
120 else
121 {
122 record.eventType = iter->second.eventReadingType;
123 }
124
125 return record;
126}
127
128} // namespace internal
129
Tom Joseph6edc8a02017-06-30 18:52:56 +0530130GetSELEntryResponse convertLogEntrytoSEL(const std::string& objPath)
131{
132 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
133
134 static constexpr auto assocIntf = "org.openbmc.Associations";
135 static constexpr auto assocProp = "associations";
136
137 auto service = ipmi::getService(bus, assocIntf, objPath);
138
139 // Read the Associations interface.
Patrick Venture0b02be92018-08-31 11:55:55 -0700140 auto methodCall =
141 bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
Tom Joseph6edc8a02017-06-30 18:52:56 +0530142 methodCall.append(assocIntf);
143 methodCall.append(assocProp);
144
145 auto reply = bus.call(methodCall);
146 if (reply.is_method_error())
147 {
148 log<level::ERR>("Error in reading Associations interface");
149 elog<InternalFailure>();
150 }
151
Patrick Venture0b02be92018-08-31 11:55:55 -0700152 using AssociationList =
153 std::vector<std::tuple<std::string, std::string, std::string>>;
Tom Joseph6edc8a02017-06-30 18:52:56 +0530154
155 sdbusplus::message::variant<AssociationList> list;
156 reply.read(list);
157
Patrick Venture0b02be92018-08-31 11:55:55 -0700158 auto& assocs = sdbusplus::message::variant_ns::get<AssociationList>(list);
Tom Joseph6edc8a02017-06-30 18:52:56 +0530159
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 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700169 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 }
Tom Joseph6edc8a02017-06-30 18:52:56 +0530179
Patrick Venture0b02be92018-08-31 11:55:55 -0700180 return internal::prepareSELEntry(objPath, iter);
Tom Joseph6edc8a02017-06-30 18:52:56 +0530181 }
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
Patrick Venture0b02be92018-08-31 11:55:55 -0700205 auto methodCall =
206 bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
Tom Joseph399fd922017-06-30 18:40:30 +0530207 methodCall.append(logEntryIntf);
208 methodCall.append(propTimeStamp);
209
210 auto reply = bus.call(methodCall);
211 if (reply.is_method_error())
212 {
213 log<level::ERR>("Error in reading Timestamp from Entry interface");
214 elog<InternalFailure>();
215 }
216
217 sdbusplus::message::variant<uint64_t> timeStamp;
218 reply.read(timeStamp);
219
220 std::chrono::milliseconds chronoTimeStamp(
Patrick Venture0b02be92018-08-31 11:55:55 -0700221 sdbusplus::message::variant_ns::get<uint64_t>(timeStamp));
Tom Joseph399fd922017-06-30 18:40:30 +0530222
223 return std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp);
224}
225
Tom Joseph232f5292017-07-07 20:14:02 +0530226void readLoggingObjectPaths(ObjectPaths& paths)
227{
228 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
229 auto depth = 0;
230 paths.clear();
231
Patrick Venture0b02be92018-08-31 11:55:55 -0700232 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
233 mapperIntf, "GetSubTreePaths");
Tom Joseph232f5292017-07-07 20:14:02 +0530234 mapperCall.append(logBasePath);
235 mapperCall.append(depth);
236 mapperCall.append(ObjectPaths({logEntryIntf}));
237
238 auto reply = bus.call(mapperCall);
239 if (reply.is_method_error())
240 {
241 log<level::INFO>("Error in reading logging entry object paths");
242 }
243 else
244 {
245 reply.read(paths);
246
Patrick Venture0b02be92018-08-31 11:55:55 -0700247 std::sort(paths.begin(), paths.end(),
248 [](const std::string& a, const std::string& b) {
249 namespace fs = std::filesystem;
250 fs::path pathA(a);
251 fs::path pathB(b);
252 auto idA = std::stoul(pathA.filename().string());
253 auto idB = std::stoul(pathB.filename().string());
Tom Joseph232f5292017-07-07 20:14:02 +0530254
Patrick Venture0b02be92018-08-31 11:55:55 -0700255 return idA < idB;
256 });
Tom Joseph232f5292017-07-07 20:14:02 +0530257 }
258}
259
Tom Joseph6b7a1432017-05-19 10:43:36 +0530260} // namespace sel
261
262} // namespace ipmi