blob: 95fcddfca7830c7d005321fa1dc48055278c454d [file] [log] [blame]
Patrick Venture0b02be92018-08-31 11:55:55 -07001#include "elog-errors.hpp"
2#include "error-HostEvent.hpp"
3#include "types.hpp"
4
5#include <mapper.h>
Chris Austen41a4b312015-10-25 03:45:42 -05006#include <stdint.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07007#include <systemd/sd-bus.h>
8
9#include <algorithm>
Chris Austen41a4b312015-10-25 03:45:42 -050010#include <cstdlib>
11#include <cstring>
12#include <fstream>
13#include <iostream>
Chris Austen41a4b312015-10-25 03:45:42 -050014#include <memory>
Saqib Khand33a4af2017-02-20 15:23:27 -060015#include <phosphor-logging/elog.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070016#include <vector>
17#include <xyz/openbmc_project/Logging/Entry/server.hpp>
18
Tomd700e762016-09-20 18:24:13 +053019#include "host-ipmid/ipmid-api.h"
Chris Austen41a4b312015-10-25 03:45:42 -050020#include "sensorhandler.h"
Tomd700e762016-09-20 18:24:13 +053021#include "storagehandler.h"
Chris Austen41a4b312015-10-25 03:45:42 -050022
23using namespace std;
Adriana Kobylak2efb3e72017-02-06 21:43:59 -060024using namespace phosphor::logging;
Deepak Kodihalli3d230482018-04-03 07:00:45 -050025using namespace sdbusplus::xyz::openbmc_project::Logging::server;
Tom Joseph448e74e2017-07-24 23:08:56 +053026extern const ipmi::sensor::InvObjectIDMap invSensors;
Chris Austen41a4b312015-10-25 03:45:42 -050027
Chris Austen41a4b312015-10-25 03:45:42 -050028//////////////////////////
Patrick Venture0b02be92018-08-31 11:55:55 -070029struct esel_section_headers_t
30{
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050031 uint8_t sectionid[2];
32 uint8_t sectionlength[2];
33 uint8_t version;
34 uint8_t subsectiontype;
35 uint8_t compid;
Chris Austen41a4b312015-10-25 03:45:42 -050036};
37
Patrick Venture0b02be92018-08-31 11:55:55 -070038struct severity_values_t
39{
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050040 uint8_t type;
41 Entry::Level level;
Chris Austen41a4b312015-10-25 03:45:42 -050042};
43
Chris Austen41a4b312015-10-25 03:45:42 -050044const std::vector<severity_values_t> g_sev_desc = {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050045 {0x10, Entry::Level::Warning}, // recoverable error
46 {0x20, Entry::Level::Warning}, // predictive error
Patrick Venture0b02be92018-08-31 11:55:55 -070047 // TODO via github issue 3066 : map level
48 // below to Level::Unrecoverable
49 {0x40, Entry::Level::Error}, // unrecoverable error
50 // TODO via github issue 3066 : map level below
51 // to Level::Critical
52 {0x50, Entry::Level::Error}, // critical error
53 {0x60, Entry::Level::Error}, // error from a diagnostic test
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050054 {0x70, Entry::Level::Warning}, // recoverable symptom
Patrick Venture0b02be92018-08-31 11:55:55 -070055 {0xFF, Entry::Level::Error}, // unknown error
Chris Austen41a4b312015-10-25 03:45:42 -050056};
57
Patrick Venture0b02be92018-08-31 11:55:55 -070058Entry::Level sev_lookup(uint8_t n)
59{
60 auto i =
61 std::find_if(std::begin(g_sev_desc), std::end(g_sev_desc),
62 [n](auto p) { return p.type == n || p.type == 0xFF; });
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050063 return i->level;
Chris Austen41a4b312015-10-25 03:45:42 -050064}
65
Patrick Venture0b02be92018-08-31 11:55:55 -070066int find_sensor_type_string(uint8_t sensor_number, char** s)
67{
Chris Austen41a4b312015-10-25 03:45:42 -050068
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050069 dbus_interface_t a;
Patrick Venture0b02be92018-08-31 11:55:55 -070070 const char* p;
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050071 int r;
Chris Austen41a4b312015-10-25 03:45:42 -050072
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050073 r = find_openbmc_path(sensor_number, &a);
Chris Austen41a4b312015-10-25 03:45:42 -050074
Patrick Venture0b02be92018-08-31 11:55:55 -070075 if ((r < 0) || (a.bus[0] == 0))
76 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050077 // Just make a generic message for errors that
78 // occur on sensors that don't exist
79 r = asprintf(s, "Unknown Sensor (0x%02x)", sensor_number);
Patrick Venture0b02be92018-08-31 11:55:55 -070080 }
81 else
82 {
Chris Austen41a4b312015-10-25 03:45:42 -050083
Patrick Venture0b02be92018-08-31 11:55:55 -070084 if ((p = strrchr(a.path, '/')) == NULL)
85 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050086 p = "/Unknown Sensor";
87 }
Chris Austen41a4b312015-10-25 03:45:42 -050088
Patrick Venture0b02be92018-08-31 11:55:55 -070089 *s = strdup(p + 1);
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050090 }
Chris Austen41a4b312015-10-25 03:45:42 -050091
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050092 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -050093}
94
Patrick Venture0b02be92018-08-31 11:55:55 -070095size_t getfilestream(const char* fn, uint8_t** buffer)
96{
Chris Austen41a4b312015-10-25 03:45:42 -050097
Patrick Venture0b02be92018-08-31 11:55:55 -070098 FILE* fp;
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050099 ssize_t size = 0;
100 int r;
Chris Austen41a4b312015-10-25 03:45:42 -0500101
Patrick Venture0b02be92018-08-31 11:55:55 -0700102 if ((fp = fopen(fn, "rb")) != NULL)
103 {
Chris Austen41a4b312015-10-25 03:45:42 -0500104
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500105 r = fseek(fp, 0, SEEK_END);
Patrick Venture0b02be92018-08-31 11:55:55 -0700106 if (r)
107 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500108 log<level::ERR>("Fseek failed");
109 goto fclose_fp;
110 }
Nan Lidfe6e422016-05-13 21:46:26 +0800111
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500112 size = ftell(fp);
Patrick Venture0b02be92018-08-31 11:55:55 -0700113 if (size == -1L)
114 {
115 log<level::ERR>("Ftell failed", entry("ERROR=%s", strerror(errno)));
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500116 size = 0;
117 goto fclose_fp;
118 }
Nan Lidfe6e422016-05-13 21:46:26 +0800119
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500120 r = fseek(fp, 0, SEEK_SET);
Patrick Venture0b02be92018-08-31 11:55:55 -0700121 if (r)
122 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500123 log<level::ERR>("Fseek failed");
124 size = 0;
125 goto fclose_fp;
126 }
Chris Austen41a4b312015-10-25 03:45:42 -0500127
Patrick Venture0b02be92018-08-31 11:55:55 -0700128 *buffer = new uint8_t[size];
Chris Austen41a4b312015-10-25 03:45:42 -0500129
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500130 r = fread(*buffer, 1, size, fp);
Patrick Venture0b02be92018-08-31 11:55:55 -0700131 if (r != size)
132 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500133 size = 0;
134 log<level::ERR>("Fread failed\n");
135 }
Nan Lidfe6e422016-05-13 21:46:26 +0800136
Patrick Venture0b02be92018-08-31 11:55:55 -0700137 fclose_fp:
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500138 fclose(fp);
139 }
Chris Austen41a4b312015-10-25 03:45:42 -0500140
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500141 return static_cast<size_t>(size);
Chris Austen41a4b312015-10-25 03:45:42 -0500142}
143
Patrick Venture0b02be92018-08-31 11:55:55 -0700144Entry::Level create_esel_severity(const uint8_t* buffer)
145{
Chris Austen41a4b312015-10-25 03:45:42 -0500146
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500147 uint8_t severity;
148 // Dive in to the IBM log to find the severity
Patrick Venture0b02be92018-08-31 11:55:55 -0700149 severity = (0xF0 & buffer[0x4A]);
Chris Austen41a4b312015-10-25 03:45:42 -0500150
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500151 return sev_lookup(severity);
Chris Austen41a4b312015-10-25 03:45:42 -0500152}
153
Patrick Venture0b02be92018-08-31 11:55:55 -0700154int create_esel_association(const uint8_t* buffer, std::string& inventoryPath)
Tom Joseph448e74e2017-07-24 23:08:56 +0530155{
Patrick Venture0b02be92018-08-31 11:55:55 -0700156 ipmi_add_sel_request_t* p;
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500157 uint8_t sensor;
Chris Austen41a4b312015-10-25 03:45:42 -0500158
Patrick Venture0b02be92018-08-31 11:55:55 -0700159 p = (ipmi_add_sel_request_t*)buffer;
Chris Austen41a4b312015-10-25 03:45:42 -0500160
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500161 sensor = p->sensornumber;
Chris Austen41a4b312015-10-25 03:45:42 -0500162
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500163 inventoryPath = {};
Chris Austen41a4b312015-10-25 03:45:42 -0500164
Tom Joseph448e74e2017-07-24 23:08:56 +0530165 /*
166 * Search the sensor number to inventory path mapping to figure out the
167 * inventory associated with the ESEL.
168 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700169 for (auto const& iter : invSensors)
Tom Joseph448e74e2017-07-24 23:08:56 +0530170 {
171 if (iter.second.sensorID == sensor)
172 {
173 inventoryPath = iter.first;
174 break;
175 }
176 }
Chris Austen41a4b312015-10-25 03:45:42 -0500177
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500178 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -0500179}
180
Patrick Venture0b02be92018-08-31 11:55:55 -0700181int create_esel_description(const uint8_t* buffer, Entry::Level level,
182 char** message)
183{
Chris Austen41a4b312015-10-25 03:45:42 -0500184
Patrick Venture0b02be92018-08-31 11:55:55 -0700185 ipmi_add_sel_request_t* p;
186 char* m;
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500187 int r;
Chris Austen41a4b312015-10-25 03:45:42 -0500188
Patrick Venture0b02be92018-08-31 11:55:55 -0700189 p = (ipmi_add_sel_request_t*)buffer;
Chris Austen41a4b312015-10-25 03:45:42 -0500190
Patrick Venture0b02be92018-08-31 11:55:55 -0700191 find_sensor_type_string(p->sensornumber, &m);
Chris Austen41a4b312015-10-25 03:45:42 -0500192
Patrick Venture0b02be92018-08-31 11:55:55 -0700193 r = asprintf(message, "A %s has experienced an error of level %d", m,
194 static_cast<uint32_t>(level));
195 if (r == -1)
196 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500197 log<level::ERR>("Failed to allocate memory for ESEL description");
198 }
Chris Austen41a4b312015-10-25 03:45:42 -0500199
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500200 free(m);
Chris Austen41a4b312015-10-25 03:45:42 -0500201
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500202 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -0500203}
204
Patrick Venture0b02be92018-08-31 11:55:55 -0700205int send_esel_to_dbus(const char* desc, Entry::Level level,
206 const std::string& inventoryPath, uint8_t* debug,
Tom Joseph448e74e2017-07-24 23:08:56 +0530207 size_t debuglen)
208{
Chris Austen41a4b312015-10-25 03:45:42 -0500209
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600210 // Allocate enough space to represent the data in hex separated by spaces,
211 // to mimic how IPMI would display the data.
Patrick Venture0b02be92018-08-31 11:55:55 -0700212 unique_ptr<char[]> selData(new char[(debuglen * 3) + 1]());
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600213 uint32_t i = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700214 for (i = 0; i < debuglen; i++)
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600215 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700216 sprintf(&selData[i * 3], "%02x ", 0xFF & ((char*)debug)[i]);
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600217 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700218 selData[debuglen * 3] = '\0';
Tom Josephb9ac6a42017-02-28 19:56:33 +0530219
Patrick Venture0b02be92018-08-31 11:55:55 -0700220 using error = sdbusplus::org::open_power::Host::Error::Event;
Marri Devender Raob0b395b2017-10-24 10:14:14 -0500221 using metadata = org::open_power::Host::Event;
Tom Joseph448e74e2017-07-24 23:08:56 +0530222
Patrick Venture0b02be92018-08-31 11:55:55 -0700223 report<error>(level, metadata::ESEL(selData.get()),
Tom Joseph448e74e2017-07-24 23:08:56 +0530224 metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600225
Adriana Kobylak513d68e2017-02-15 11:36:28 -0600226 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -0500227}
228
Patrick Venture0b02be92018-08-31 11:55:55 -0700229void send_esel(uint16_t recordid)
230{
231 char* desc;
232 uint8_t* buffer = NULL;
233 const char* path = "/tmp/esel";
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500234 ssize_t sz;
235 int r;
236 std::string inventoryPath;
Chris Austen41a4b312015-10-25 03:45:42 -0500237
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500238 sz = getfilestream(path, &buffer);
Patrick Venture0b02be92018-08-31 11:55:55 -0700239 if (sz == 0)
240 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500241 log<level::ERR>("Error file does not exist",
242 entry("FILENAME=%s", path));
243 return;
244 }
Chris Austen41a4b312015-10-25 03:45:42 -0500245
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500246 auto sev = create_esel_severity(buffer);
247 create_esel_association(buffer, inventoryPath);
248 create_esel_description(buffer, sev, &desc);
Chris Austen41a4b312015-10-25 03:45:42 -0500249
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500250 r = send_esel_to_dbus(desc, sev, inventoryPath, buffer, sz);
Patrick Venture0b02be92018-08-31 11:55:55 -0700251 if (r < 0)
252 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500253 log<level::ERR>("Failed to send esel to dbus");
254 }
Chris Austen41a4b312015-10-25 03:45:42 -0500255
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500256 free(desc);
257 delete[] buffer;
Chris Austen41a4b312015-10-25 03:45:42 -0500258
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500259 return;
Chris Austen41a4b312015-10-25 03:45:42 -0500260}
Tom Josephb647d5b2017-10-31 17:25:33 +0530261
262std::string readESEL(const char* fileName)
263{
264 std::string content;
265 std::ifstream handle(fileName);
266
267 if (handle.fail())
268 {
269 log<level::ERR>("Failed to open eSEL", entry("FILENAME=%s", fileName));
270 return content;
271 }
272
273 handle.seekg(0, std::ios::end);
274 content.resize(handle.tellg());
275 handle.seekg(0, std::ios::beg);
276 handle.read(&content[0], content.size());
277 handle.close();
278
279 return content;
280}
281
282void createProcedureLogEntry(uint8_t procedureNum)
283{
284 // Read the eSEL data from the file.
285 static constexpr auto eSELFile = "/tmp/esel";
286 auto eSELData = readESEL(eSELFile);
287
288 // Each byte in eSEL is formatted as %02x with a space between bytes and
289 // insert '/0' at the end of the character array.
290 static constexpr auto byteSeparator = 3;
Patrick Venture0b02be92018-08-31 11:55:55 -0700291 std::unique_ptr<char[]> data(
292 new char[(eSELData.size() * byteSeparator) + 1]());
Tom Josephb647d5b2017-10-31 17:25:33 +0530293
294 for (size_t i = 0; i < eSELData.size(); i++)
295 {
296 sprintf(&data[i * byteSeparator], "%02x ", eSELData[i]);
297 }
298 data[eSELData.size() * byteSeparator] = '\0';
299
Patrick Venture0b02be92018-08-31 11:55:55 -0700300 using error = sdbusplus::org::open_power::Host::Error::MaintenanceProcedure;
Tom Josephb647d5b2017-10-31 17:25:33 +0530301 using metadata = org::open_power::Host::MaintenanceProcedure;
302
303 report<error>(metadata::ESEL(data.get()),
304 metadata::PROCEDURE(static_cast<uint32_t>(procedureNum)));
305}