blob: 83a8bd28326ed3c299987388400ae98921be2a30 [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>
Vernon Mauerybdda8002019-02-26 10:18:51 -08006#include <filesystem>
Vernon Mauerye08fbff2019-04-03 09:19:34 -07007#include <ipmid/api.hpp>
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
Tom Joseph6b7a1432017-05-19 10:43:36 +053014extern const ipmi::sensor::InvObjectIDMap invSensors;
15using namespace phosphor::logging;
16using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070017 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6b7a1432017-05-19 10:43:36 +053018
19namespace ipmi
20{
21
22namespace sel
23{
24
25namespace internal
26{
27
Patrick Venture0b02be92018-08-31 11:55:55 -070028GetSELEntryResponse
29 prepareSELEntry(const std::string& objPath,
30 ipmi::sensor::InvObjectIDMap::const_iterator iter)
Tom Joseph6b7a1432017-05-19 10:43:36 +053031{
Patrick Venture0b02be92018-08-31 11:55:55 -070032 GetSELEntryResponse record{};
Tom Joseph6b7a1432017-05-19 10:43:36 +053033
34 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
35 auto service = ipmi::getService(bus, logEntryIntf, objPath);
36
37 // Read all the log entry properties.
Patrick Venture0b02be92018-08-31 11:55:55 -070038 auto methodCall = bus.new_method_call(service.c_str(), objPath.c_str(),
39 propIntf, "GetAll");
Tom Joseph6b7a1432017-05-19 10:43:36 +053040 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
Tom Joseph6b7a1432017-05-19 10:43:36 +053061 // Read Timestamp from the log entry.
62 static constexpr auto propTimeStamp = "Timestamp";
63 auto iterTimeStamp = entryData.find(propTimeStamp);
64 if (iterTimeStamp == entryData.end())
65 {
66 log<level::ERR>("Error in reading Timestamp of logging entry");
67 elog<InternalFailure>();
68 }
Tom Joseph6b7a1432017-05-19 10:43:36 +053069 std::chrono::milliseconds chronoTimeStamp(
Vernon Maueryf442e112019-04-09 11:44:36 -070070 std::get<uint64_t>(iterTimeStamp->second));
Tom Joseph6b7a1432017-05-19 10:43:36 +053071
Lei YUaf378fa2020-12-02 16:28:57 +080072 if (iter == invSensors.end())
Tom Joseph6b7a1432017-05-19 10:43:36 +053073 {
Lei YUaf378fa2020-12-02 16:28:57 +080074 // It is expected to be a custom SEL entry
75 // TODO
Tom Joseph6b7a1432017-05-19 10:43:36 +053076 }
77 else
78 {
Lei YUaf378fa2020-12-02 16:28:57 +080079
80 record.event.eventRecord.recordID =
81 static_cast<uint16_t>(std::get<uint32_t>(iterId->second));
82 record.event.eventRecord.timeStamp = static_cast<uint32_t>(
83 std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp)
84 .count());
85
86 static constexpr auto systemEventRecord = 0x02;
87 static constexpr auto generatorID = 0x2000;
88 static constexpr auto eventMsgRevision = 0x04;
89
90 record.event.eventRecord.recordType = systemEventRecord;
91 record.event.eventRecord.generatorID = generatorID;
92 record.event.eventRecord.eventMsgRevision = eventMsgRevision;
93
94 record.event.eventRecord.sensorType = iter->second.sensorType;
95 record.event.eventRecord.sensorNum = iter->second.sensorID;
96 record.event.eventRecord.eventData1 = iter->second.eventOffset;
97
98 // Read Resolved from the log entry.
99 static constexpr auto propResolved = "Resolved";
100 auto iterResolved = entryData.find(propResolved);
101 if (iterResolved == entryData.end())
102 {
103 log<level::ERR>("Error in reading Resolved field of logging entry");
104 elog<InternalFailure>();
105 }
106
107 static constexpr auto deassertEvent = 0x80;
108
109 // Evaluate if the event is assertion or deassertion event
110 if (std::get<bool>(iterResolved->second))
111 {
112 record.event.eventRecord.eventType =
113 deassertEvent | iter->second.eventReadingType;
114 }
115 else
116 {
117 record.event.eventRecord.eventType = iter->second.eventReadingType;
118 }
Tom Joseph6b7a1432017-05-19 10:43:36 +0530119 }
120
121 return record;
122}
123
124} // namespace internal
125
Tom Joseph6edc8a02017-06-30 18:52:56 +0530126GetSELEntryResponse convertLogEntrytoSEL(const std::string& objPath)
127{
128 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
129
Vernon Mauerya7f81cc2019-11-06 12:51:43 -0800130 static constexpr auto assocIntf =
131 "xyz.openbmc_project.Association.Definitions";
132 static constexpr auto assocProp = "Associations";
Tom Joseph6edc8a02017-06-30 18:52:56 +0530133
134 auto service = ipmi::getService(bus, assocIntf, objPath);
135
136 // Read the Associations interface.
Patrick Venture0b02be92018-08-31 11:55:55 -0700137 auto methodCall =
138 bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
Tom Joseph6edc8a02017-06-30 18:52:56 +0530139 methodCall.append(assocIntf);
140 methodCall.append(assocProp);
141
142 auto reply = bus.call(methodCall);
143 if (reply.is_method_error())
144 {
145 log<level::ERR>("Error in reading Associations interface");
146 elog<InternalFailure>();
147 }
148
Patrick Venture0b02be92018-08-31 11:55:55 -0700149 using AssociationList =
150 std::vector<std::tuple<std::string, std::string, std::string>>;
Tom Joseph6edc8a02017-06-30 18:52:56 +0530151
Vernon Mauery16b86932019-05-01 08:36:11 -0700152 std::variant<AssociationList> list;
Tom Joseph6edc8a02017-06-30 18:52:56 +0530153 reply.read(list);
154
Vernon Maueryf442e112019-04-09 11:44:36 -0700155 auto& assocs = std::get<AssociationList>(list);
Tom Joseph6edc8a02017-06-30 18:52:56 +0530156
157 /*
158 * Check if the log entry has any callout associations, if there is a
159 * callout association try to match the inventory path to the corresponding
160 * IPMI sensor.
161 */
162 for (const auto& item : assocs)
163 {
164 if (std::get<0>(item).compare(CALLOUT_FWD_ASSOCIATION) == 0)
165 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700166 auto iter = invSensors.find(std::get<2>(item));
167 if (iter == invSensors.end())
168 {
169 iter = invSensors.find(BOARD_SENSOR);
170 if (iter == invSensors.end())
171 {
172 log<level::ERR>("Motherboard sensor not found");
173 elog<InternalFailure>();
174 }
175 }
Tom Joseph6edc8a02017-06-30 18:52:56 +0530176
Patrick Venture0b02be92018-08-31 11:55:55 -0700177 return internal::prepareSELEntry(objPath, iter);
Tom Joseph6edc8a02017-06-30 18:52:56 +0530178 }
179 }
180
181 // If there are no callout associations link the log entry to system event
182 // sensor
183 auto iter = invSensors.find(SYSTEM_SENSOR);
Tom Joseph6edc8a02017-06-30 18:52:56 +0530184 return internal::prepareSELEntry(objPath, iter);
185}
186
Tom Joseph399fd922017-06-30 18:40:30 +0530187std::chrono::seconds getEntryTimeStamp(const std::string& objPath)
188{
189 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
190
191 auto service = ipmi::getService(bus, logEntryIntf, objPath);
192
193 using namespace std::string_literals;
194 static const auto propTimeStamp = "Timestamp"s;
195
Patrick Venture0b02be92018-08-31 11:55:55 -0700196 auto methodCall =
197 bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
Tom Joseph399fd922017-06-30 18:40:30 +0530198 methodCall.append(logEntryIntf);
199 methodCall.append(propTimeStamp);
200
201 auto reply = bus.call(methodCall);
202 if (reply.is_method_error())
203 {
204 log<level::ERR>("Error in reading Timestamp from Entry interface");
205 elog<InternalFailure>();
206 }
207
Vernon Mauery16b86932019-05-01 08:36:11 -0700208 std::variant<uint64_t> timeStamp;
Tom Joseph399fd922017-06-30 18:40:30 +0530209 reply.read(timeStamp);
210
Vernon Maueryf442e112019-04-09 11:44:36 -0700211 std::chrono::milliseconds chronoTimeStamp(std::get<uint64_t>(timeStamp));
Tom Joseph399fd922017-06-30 18:40:30 +0530212
213 return std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp);
214}
215
Tom Joseph232f5292017-07-07 20:14:02 +0530216void readLoggingObjectPaths(ObjectPaths& paths)
217{
218 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
219 auto depth = 0;
220 paths.clear();
221
Patrick Venture0b02be92018-08-31 11:55:55 -0700222 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
223 mapperIntf, "GetSubTreePaths");
Tom Joseph232f5292017-07-07 20:14:02 +0530224 mapperCall.append(logBasePath);
225 mapperCall.append(depth);
226 mapperCall.append(ObjectPaths({logEntryIntf}));
227
228 auto reply = bus.call(mapperCall);
229 if (reply.is_method_error())
230 {
231 log<level::INFO>("Error in reading logging entry object paths");
232 }
233 else
234 {
235 reply.read(paths);
236
Patrick Venture0b02be92018-08-31 11:55:55 -0700237 std::sort(paths.begin(), paths.end(),
238 [](const std::string& a, const std::string& b) {
239 namespace fs = std::filesystem;
240 fs::path pathA(a);
241 fs::path pathB(b);
242 auto idA = std::stoul(pathA.filename().string());
243 auto idB = std::stoul(pathB.filename().string());
Tom Joseph232f5292017-07-07 20:14:02 +0530244
Patrick Venture0b02be92018-08-31 11:55:55 -0700245 return idA < idB;
246 });
Tom Joseph232f5292017-07-07 20:14:02 +0530247 }
248}
249
Tom Joseph6b7a1432017-05-19 10:43:36 +0530250} // namespace sel
251
252} // namespace ipmi