blob: ec33b1aee10ad4a9353a623013df6d4b747c199d [file] [log] [blame]
Chris Austen41a4b312015-10-25 03:45:42 -05001#include <stdint.h>
2#include <cstdlib>
3#include <cstring>
4#include <fstream>
5#include <iostream>
6#include <algorithm>
7#include <vector>
8#include <memory>
9#include <systemd/sd-bus.h>
Sergey Solomineb9b8142016-08-23 09:07:28 -050010#include <mapper.h>
Saqib Khand33a4af2017-02-20 15:23:27 -060011#include <phosphor-logging/elog.hpp>
Tomd700e762016-09-20 18:24:13 +053012#include "host-ipmid/ipmid-api.h"
Tom Joseph448e74e2017-07-24 23:08:56 +053013#include "elog-errors.hpp"
14#include "error-HostEvent.hpp"
Chris Austen41a4b312015-10-25 03:45:42 -050015#include "sensorhandler.h"
Tomd700e762016-09-20 18:24:13 +053016#include "storagehandler.h"
Tom Joseph448e74e2017-07-24 23:08:56 +053017#include "types.hpp"
Deepak Kodihalli3d230482018-04-03 07:00:45 -050018#include "xyz/openbmc_project/Logging/Entry/server.hpp"
Tomd700e762016-09-20 18:24:13 +053019
Chris Austen41a4b312015-10-25 03:45:42 -050020
21using namespace std;
Adriana Kobylak2efb3e72017-02-06 21:43:59 -060022using namespace phosphor::logging;
Deepak Kodihalli3d230482018-04-03 07:00:45 -050023using namespace sdbusplus::xyz::openbmc_project::Logging::server;
Tom Joseph448e74e2017-07-24 23:08:56 +053024extern const ipmi::sensor::InvObjectIDMap invSensors;
Chris Austen41a4b312015-10-25 03:45:42 -050025
Chris Austen41a4b312015-10-25 03:45:42 -050026//////////////////////////
27struct esel_section_headers_t {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050028 uint8_t sectionid[2];
29 uint8_t sectionlength[2];
30 uint8_t version;
31 uint8_t subsectiontype;
32 uint8_t compid;
Chris Austen41a4b312015-10-25 03:45:42 -050033};
34
35struct severity_values_t {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050036 uint8_t type;
37 Entry::Level level;
Chris Austen41a4b312015-10-25 03:45:42 -050038};
39
40
41const std::vector<severity_values_t> g_sev_desc = {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050042 {0x10, Entry::Level::Warning}, // recoverable error
43 {0x20, Entry::Level::Warning}, // predictive error
Deepak Kodihalli3d230482018-04-03 07:00:45 -050044 // TODO via github issue 3066 : map level below to Level::Unrecoverable
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050045 {0x40, Entry::Level::Error}, // unrecoverable error
Deepak Kodihalli3d230482018-04-03 07:00:45 -050046 // TODO via github issue 3066 : map level below to Level::Critical
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050047 {0x50, Entry::Level::Error}, // critical error
48 {0x60, Entry::Level::Error}, // error from a diagnostic test
49 {0x70, Entry::Level::Warning}, // recoverable symptom
50 {0xFF, Entry::Level::Error}, //unknown error
Chris Austen41a4b312015-10-25 03:45:42 -050051};
52
Deepak Kodihalli3d230482018-04-03 07:00:45 -050053Entry::Level sev_lookup(uint8_t n) {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050054 auto i = std::find_if(std::begin(g_sev_desc), std::end(g_sev_desc),
55 [n](auto p){ return p.type == n || p.type == 0xFF; });
56 return i->level;
Chris Austen41a4b312015-10-25 03:45:42 -050057}
58
59
60
61
62int find_sensor_type_string(uint8_t sensor_number, char **s) {
63
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050064 dbus_interface_t a;
65 const char *p;
66 int r;
Chris Austen41a4b312015-10-25 03:45:42 -050067
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050068 r = find_openbmc_path(sensor_number, &a);
Chris Austen41a4b312015-10-25 03:45:42 -050069
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050070 if ((r < 0) || (a.bus[0] == 0)) {
71 // Just make a generic message for errors that
72 // occur on sensors that don't exist
73 r = asprintf(s, "Unknown Sensor (0x%02x)", sensor_number);
74 } else {
Chris Austen41a4b312015-10-25 03:45:42 -050075
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050076 if ((p = strrchr (a.path, '/')) == NULL) {
77 p = "/Unknown Sensor";
78 }
Chris Austen41a4b312015-10-25 03:45:42 -050079
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050080 *s = strdup(p+1);
81 }
Chris Austen41a4b312015-10-25 03:45:42 -050082
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050083 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -050084}
85
86
87size_t getfilestream(const char *fn, uint8_t **buffer) {
88
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050089 FILE *fp;
90 ssize_t size = 0;
91 int r;
Chris Austen41a4b312015-10-25 03:45:42 -050092
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050093 if ((fp = fopen(fn, "rb")) != NULL) {
Chris Austen41a4b312015-10-25 03:45:42 -050094
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050095 r = fseek(fp, 0, SEEK_END);
96 if (r) {
97 log<level::ERR>("Fseek failed");
98 goto fclose_fp;
99 }
Nan Lidfe6e422016-05-13 21:46:26 +0800100
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500101 size = ftell(fp);
102 if (size == -1L) {
103 log<level::ERR>("Ftell failed",
104 entry("ERROR=%s", strerror(errno)));
105 size = 0;
106 goto fclose_fp;
107 }
Nan Lidfe6e422016-05-13 21:46:26 +0800108
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500109 r = fseek(fp, 0, SEEK_SET);
110 if (r) {
111 log<level::ERR>("Fseek failed");
112 size = 0;
113 goto fclose_fp;
114 }
Chris Austen41a4b312015-10-25 03:45:42 -0500115
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500116 *buffer = new uint8_t [size];
Chris Austen41a4b312015-10-25 03:45:42 -0500117
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500118 r = fread(*buffer, 1, size, fp);
119 if ( r != size) {
120 size = 0;
121 log<level::ERR>("Fread failed\n");
122 }
Nan Lidfe6e422016-05-13 21:46:26 +0800123
124fclose_fp:
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500125 fclose(fp);
126 }
Chris Austen41a4b312015-10-25 03:45:42 -0500127
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500128 return static_cast<size_t>(size);
Chris Austen41a4b312015-10-25 03:45:42 -0500129}
130
131
Deepak Kodihalli3d230482018-04-03 07:00:45 -0500132Entry::Level create_esel_severity(const uint8_t *buffer) {
Chris Austen41a4b312015-10-25 03:45:42 -0500133
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500134 uint8_t severity;
135 // Dive in to the IBM log to find the severity
136 severity = (0xF0 & buffer[0x4A]);
Chris Austen41a4b312015-10-25 03:45:42 -0500137
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500138 return sev_lookup(severity);
Chris Austen41a4b312015-10-25 03:45:42 -0500139}
140
Tom Joseph448e74e2017-07-24 23:08:56 +0530141int create_esel_association(const uint8_t *buffer, std::string& inventoryPath)
142{
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500143 ipmi_add_sel_request_t *p;
144 uint8_t sensor;
Chris Austen41a4b312015-10-25 03:45:42 -0500145
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500146 p = ( ipmi_add_sel_request_t *) buffer;
Chris Austen41a4b312015-10-25 03:45:42 -0500147
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500148 sensor = p->sensornumber;
Chris Austen41a4b312015-10-25 03:45:42 -0500149
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500150 inventoryPath = {};
Chris Austen41a4b312015-10-25 03:45:42 -0500151
Tom Joseph448e74e2017-07-24 23:08:56 +0530152 /*
153 * Search the sensor number to inventory path mapping to figure out the
154 * inventory associated with the ESEL.
155 */
156 for (auto const &iter : invSensors)
157 {
158 if (iter.second.sensorID == sensor)
159 {
160 inventoryPath = iter.first;
161 break;
162 }
163 }
Chris Austen41a4b312015-10-25 03:45:42 -0500164
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500165 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -0500166}
167
168
169
Deepak Kodihalli3d230482018-04-03 07:00:45 -0500170int create_esel_description(const uint8_t *buffer, Entry::Level level,
171 char **message) {
Chris Austen41a4b312015-10-25 03:45:42 -0500172
173
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500174 ipmi_add_sel_request_t *p;
175 char *m;
176 int r;
Chris Austen41a4b312015-10-25 03:45:42 -0500177
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500178 p = ( ipmi_add_sel_request_t *) buffer;
Chris Austen41a4b312015-10-25 03:45:42 -0500179
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500180 find_sensor_type_string(p->sensornumber,&m);
Chris Austen41a4b312015-10-25 03:45:42 -0500181
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500182 r = asprintf(message, "A %s has experienced an error of level %d",
Deepak Kodihalli3d230482018-04-03 07:00:45 -0500183 m, static_cast<uint32_t>(level) );
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500184 if (r == -1) {
185 log<level::ERR>("Failed to allocate memory for ESEL description");
186 }
Chris Austen41a4b312015-10-25 03:45:42 -0500187
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500188 free(m);
Chris Austen41a4b312015-10-25 03:45:42 -0500189
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500190 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -0500191}
192
193
Tom Joseph448e74e2017-07-24 23:08:56 +0530194int send_esel_to_dbus(const char *desc,
Deepak Kodihalli3d230482018-04-03 07:00:45 -0500195 Entry::Level level,
Tom Joseph448e74e2017-07-24 23:08:56 +0530196 const std::string& inventoryPath,
197 uint8_t *debug,
198 size_t debuglen)
199{
Chris Austen41a4b312015-10-25 03:45:42 -0500200
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600201 // Allocate enough space to represent the data in hex separated by spaces,
202 // to mimic how IPMI would display the data.
Tom Josephb9ac6a42017-02-28 19:56:33 +0530203 unique_ptr<char[]> selData(new char[(debuglen*3) + 1]());
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600204 uint32_t i = 0;
205 for(i = 0; i < debuglen; i++)
206 {
207 sprintf(&selData[i*3], "%02x ", 0xFF & ((char*)debug)[i]);
208 }
Tom Josephb9ac6a42017-02-28 19:56:33 +0530209 selData[debuglen*3] = '\0';
210
Marri Devender Raob0b395b2017-10-24 10:14:14 -0500211 using error = sdbusplus::org::open_power::Host::Error::Event;
212 using metadata = org::open_power::Host::Event;
Tom Joseph448e74e2017-07-24 23:08:56 +0530213
Deepak Kodihalli3d230482018-04-03 07:00:45 -0500214 report<error>(level,
215 metadata::ESEL(selData.get()),
Tom Joseph448e74e2017-07-24 23:08:56 +0530216 metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600217
Adriana Kobylak513d68e2017-02-15 11:36:28 -0600218 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -0500219}
220
221
222void send_esel(uint16_t recordid) {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500223 char *desc;
224 uint8_t *buffer = NULL;
225 const char *path = "/tmp/esel";
226 ssize_t sz;
227 int r;
228 std::string inventoryPath;
Chris Austen41a4b312015-10-25 03:45:42 -0500229
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500230 sz = getfilestream(path, &buffer);
231 if (sz == 0) {
232 log<level::ERR>("Error file does not exist",
233 entry("FILENAME=%s", path));
234 return;
235 }
Chris Austen41a4b312015-10-25 03:45:42 -0500236
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500237 auto sev = create_esel_severity(buffer);
238 create_esel_association(buffer, inventoryPath);
239 create_esel_description(buffer, sev, &desc);
Chris Austen41a4b312015-10-25 03:45:42 -0500240
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500241 r = send_esel_to_dbus(desc, sev, inventoryPath, buffer, sz);
242 if (r < 0) {
243 log<level::ERR>("Failed to send esel to dbus");
244 }
Chris Austen41a4b312015-10-25 03:45:42 -0500245
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500246 free(desc);
247 delete[] buffer;
Chris Austen41a4b312015-10-25 03:45:42 -0500248
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500249 return;
Chris Austen41a4b312015-10-25 03:45:42 -0500250}
Tom Josephb647d5b2017-10-31 17:25:33 +0530251
252std::string readESEL(const char* fileName)
253{
254 std::string content;
255 std::ifstream handle(fileName);
256
257 if (handle.fail())
258 {
259 log<level::ERR>("Failed to open eSEL", entry("FILENAME=%s", fileName));
260 return content;
261 }
262
263 handle.seekg(0, std::ios::end);
264 content.resize(handle.tellg());
265 handle.seekg(0, std::ios::beg);
266 handle.read(&content[0], content.size());
267 handle.close();
268
269 return content;
270}
271
272void createProcedureLogEntry(uint8_t procedureNum)
273{
274 // Read the eSEL data from the file.
275 static constexpr auto eSELFile = "/tmp/esel";
276 auto eSELData = readESEL(eSELFile);
277
278 // Each byte in eSEL is formatted as %02x with a space between bytes and
279 // insert '/0' at the end of the character array.
280 static constexpr auto byteSeparator = 3;
281 std::unique_ptr<char[]> data(new char[
282 (eSELData.size() * byteSeparator) + 1]());
283
284 for (size_t i = 0; i < eSELData.size(); i++)
285 {
286 sprintf(&data[i * byteSeparator], "%02x ", eSELData[i]);
287 }
288 data[eSELData.size() * byteSeparator] = '\0';
289
290 using error = sdbusplus::org::open_power::Host::Error::MaintenanceProcedure;
291 using metadata = org::open_power::Host::MaintenanceProcedure;
292
293 report<error>(metadata::ESEL(data.get()),
294 metadata::PROCEDURE(static_cast<uint32_t>(procedureNum)));
295}