blob: 82ac74bc2f4356935bd5682c911cacd18c450a57 [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"
Tomd700e762016-09-20 18:24:13 +053018
Chris Austen41a4b312015-10-25 03:45:42 -050019
20using namespace std;
Adriana Kobylak2efb3e72017-02-06 21:43:59 -060021using namespace phosphor::logging;
Tom Joseph448e74e2017-07-24 23:08:56 +053022extern const ipmi::sensor::InvObjectIDMap invSensors;
Chris Austen41a4b312015-10-25 03:45:42 -050023
Chris Austen41a4b312015-10-25 03:45:42 -050024//////////////////////////
25struct esel_section_headers_t {
26 uint8_t sectionid[2];
27 uint8_t sectionlength[2];
28 uint8_t version;
29 uint8_t subsectiontype;
30 uint8_t compid;
31};
32
33struct severity_values_t {
34 uint8_t type;
35 const char *description;
36};
37
38
39const std::vector<severity_values_t> g_sev_desc = {
40 {0x10, "recoverable error"},
41 {0x20, "predictive error"},
42 {0x40, "unrecoverable error"},
43 {0x50, "critical error"},
44 {0x60, "error from a diagnostic test"},
45 {0x70, "recovered symptom "},
46 {0xFF, "Unknown"},
47};
48
49const char* sev_lookup(uint8_t n) {
50 auto i = std::find_if(std::begin(g_sev_desc), std::end(g_sev_desc),
51 [n](auto p){ return p.type == n || p.type == 0xFF; });
52 return i->description;
53}
54
55
56
57
58int find_sensor_type_string(uint8_t sensor_number, char **s) {
59
60 dbus_interface_t a;
61 const char *p;
Matthew Barth56181052017-01-23 09:36:29 -060062 int r;
Chris Austen41a4b312015-10-25 03:45:42 -050063
Emily Shaffer2ae09b92017-04-05 15:09:41 -070064 r = find_openbmc_path(sensor_number, &a);
Chris Austen41a4b312015-10-25 03:45:42 -050065
66 if ((r < 0) || (a.bus[0] == 0)) {
67 // Just make a generic message for errors that
Gunnar Mills8991dd62017-10-25 17:11:29 -050068 // occur on sensors that don't exist
Matthew Barth56181052017-01-23 09:36:29 -060069 r = asprintf(s, "Unknown Sensor (0x%02x)", sensor_number);
Chris Austen41a4b312015-10-25 03:45:42 -050070 } else {
71
72 if ((p = strrchr (a.path, '/')) == NULL) {
73 p = "/Unknown Sensor";
74 }
75
Matthew Barth56181052017-01-23 09:36:29 -060076 *s = strdup(p+1);
Chris Austen41a4b312015-10-25 03:45:42 -050077 }
78
79 return 0;
80}
81
82
83size_t getfilestream(const char *fn, uint8_t **buffer) {
84
85 FILE *fp;
Matthew Barth8b470052016-09-21 10:02:57 -050086 ssize_t size = 0;
Nan Lidfe6e422016-05-13 21:46:26 +080087 int r;
Chris Austen41a4b312015-10-25 03:45:42 -050088
89 if ((fp = fopen(fn, "rb")) != NULL) {
90
Nan Lidfe6e422016-05-13 21:46:26 +080091 r = fseek(fp, 0, SEEK_END);
92 if (r) {
93 fprintf(stderr,"Fseek failed\n");
94 goto fclose_fp;
95 }
96
Chris Austen41a4b312015-10-25 03:45:42 -050097 size = ftell(fp);
Nan Lidfe6e422016-05-13 21:46:26 +080098 if (size == -1L) {
99 fprintf(stderr,"Ftell failed for %s\n", strerror(errno));
100 size = 0;
101 goto fclose_fp;
102 }
103
104 r = fseek(fp, 0, SEEK_SET);
105 if (r) {
106 fprintf(stderr,"Fseek failed\n");
107 size = 0;
108 goto fclose_fp;
109 }
Chris Austen41a4b312015-10-25 03:45:42 -0500110
Chris Austen41a4b312015-10-25 03:45:42 -0500111 *buffer = new uint8_t [size];
112
Nan Lidfe6e422016-05-13 21:46:26 +0800113 r = fread(*buffer, 1, size, fp);
114 if ( r != size) {
115 size = 0;
116 fprintf(stderr,"Fread failed\n");
117 }
118
119fclose_fp:
Chris Austen41a4b312015-10-25 03:45:42 -0500120 fclose(fp);
121 }
122
Matthew Barth8b470052016-09-21 10:02:57 -0500123 return static_cast<size_t>(size);
Chris Austen41a4b312015-10-25 03:45:42 -0500124}
125
126
127const char *create_esel_severity(const uint8_t *buffer) {
128
129 uint8_t severity;
130 // Dive in to the IBM log to find the severity
131 severity = (0xF0 & buffer[0x4A]);
132
133 return sev_lookup(severity);
134}
135
Tom Joseph448e74e2017-07-24 23:08:56 +0530136int create_esel_association(const uint8_t *buffer, std::string& inventoryPath)
137{
Chris Austen41a4b312015-10-25 03:45:42 -0500138 ipmi_add_sel_request_t *p;
Chris Austen41a4b312015-10-25 03:45:42 -0500139 uint8_t sensor;
140
141 p = ( ipmi_add_sel_request_t *) buffer;
142
143 sensor = p->sensornumber;
144
Tom Joseph448e74e2017-07-24 23:08:56 +0530145 inventoryPath = {};
Chris Austen41a4b312015-10-25 03:45:42 -0500146
Tom Joseph448e74e2017-07-24 23:08:56 +0530147 /*
148 * Search the sensor number to inventory path mapping to figure out the
149 * inventory associated with the ESEL.
150 */
151 for (auto const &iter : invSensors)
152 {
153 if (iter.second.sensorID == sensor)
154 {
155 inventoryPath = iter.first;
156 break;
157 }
158 }
Chris Austen41a4b312015-10-25 03:45:42 -0500159
160 return 0;
161}
162
163
164
165int create_esel_description(const uint8_t *buffer, const char *sev, char **message) {
166
167
168 ipmi_add_sel_request_t *p;
Chris Austen41a4b312015-10-25 03:45:42 -0500169 char *m;
Matthew Barth56181052017-01-23 09:36:29 -0600170 int r;
Chris Austen41a4b312015-10-25 03:45:42 -0500171
172 p = ( ipmi_add_sel_request_t *) buffer;
173
174 find_sensor_type_string(p->sensornumber,&m);
175
Matthew Barth56181052017-01-23 09:36:29 -0600176 r = asprintf(message, "A %s has experienced a %s", m, sev );
177 if (r == -1) {
178 fprintf(stderr,
179 "Failed to allocate memory for ESEL description\n");
180 }
Chris Austen41a4b312015-10-25 03:45:42 -0500181
182 free(m);
183
184 return 0;
185}
186
187
Tom Joseph448e74e2017-07-24 23:08:56 +0530188int send_esel_to_dbus(const char *desc,
189 const char *sev,
190 const std::string& inventoryPath,
191 uint8_t *debug,
192 size_t debuglen)
193{
Chris Austen41a4b312015-10-25 03:45:42 -0500194
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600195 // Allocate enough space to represent the data in hex separated by spaces,
196 // to mimic how IPMI would display the data.
Tom Josephb9ac6a42017-02-28 19:56:33 +0530197 unique_ptr<char[]> selData(new char[(debuglen*3) + 1]());
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600198 uint32_t i = 0;
199 for(i = 0; i < debuglen; i++)
200 {
201 sprintf(&selData[i*3], "%02x ", 0xFF & ((char*)debug)[i]);
202 }
Tom Josephb9ac6a42017-02-28 19:56:33 +0530203 selData[debuglen*3] = '\0';
204
Marri Devender Raob0b395b2017-10-24 10:14:14 -0500205 using error = sdbusplus::org::open_power::Host::Error::Event;
206 using metadata = org::open_power::Host::Event;
Tom Joseph448e74e2017-07-24 23:08:56 +0530207
208 report<error>(metadata::ESEL(selData.get()),
209 metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600210
Adriana Kobylak513d68e2017-02-15 11:36:28 -0600211 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -0500212}
213
214
215void send_esel(uint16_t recordid) {
Tom Joseph448e74e2017-07-24 23:08:56 +0530216 char *desc;
Chris Austen41a4b312015-10-25 03:45:42 -0500217 const char *sev;
218 uint8_t *buffer = NULL;
Chris Austen6dc2e912016-02-20 01:00:06 -0600219 const char *path = "/tmp/esel";
Matthew Barth8b470052016-09-21 10:02:57 -0500220 ssize_t sz;
Nan Lidfe6e422016-05-13 21:46:26 +0800221 int r;
Tom Joseph448e74e2017-07-24 23:08:56 +0530222 std::string inventoryPath;
Chris Austen41a4b312015-10-25 03:45:42 -0500223
Chris Austen41a4b312015-10-25 03:45:42 -0500224 sz = getfilestream(path, &buffer);
Chris Austen41a4b312015-10-25 03:45:42 -0500225 if (sz == 0) {
226 printf("Error file does not exist %d\n",__LINE__);
Chris Austen41a4b312015-10-25 03:45:42 -0500227 return;
228 }
229
Chris Austen41a4b312015-10-25 03:45:42 -0500230 sev = create_esel_severity(buffer);
Tom Joseph448e74e2017-07-24 23:08:56 +0530231 create_esel_association(buffer, inventoryPath);
Chris Austen41a4b312015-10-25 03:45:42 -0500232 create_esel_description(buffer, sev, &desc);
233
Tom Joseph448e74e2017-07-24 23:08:56 +0530234 r = send_esel_to_dbus(desc, sev, inventoryPath, buffer, sz);
Nan Lidfe6e422016-05-13 21:46:26 +0800235 if (r < 0) {
236 fprintf(stderr, "Failed to send esel to dbus\n");
237 }
Chris Austen41a4b312015-10-25 03:45:42 -0500238
Chris Austen41a4b312015-10-25 03:45:42 -0500239 free(desc);
Chris Austen41a4b312015-10-25 03:45:42 -0500240 delete[] buffer;
241
Chris Austen41a4b312015-10-25 03:45:42 -0500242 return;
243}
Tom Josephb647d5b2017-10-31 17:25:33 +0530244
245std::string readESEL(const char* fileName)
246{
247 std::string content;
248 std::ifstream handle(fileName);
249
250 if (handle.fail())
251 {
252 log<level::ERR>("Failed to open eSEL", entry("FILENAME=%s", fileName));
253 return content;
254 }
255
256 handle.seekg(0, std::ios::end);
257 content.resize(handle.tellg());
258 handle.seekg(0, std::ios::beg);
259 handle.read(&content[0], content.size());
260 handle.close();
261
262 return content;
263}
264
265void createProcedureLogEntry(uint8_t procedureNum)
266{
267 // Read the eSEL data from the file.
268 static constexpr auto eSELFile = "/tmp/esel";
269 auto eSELData = readESEL(eSELFile);
270
271 // Each byte in eSEL is formatted as %02x with a space between bytes and
272 // insert '/0' at the end of the character array.
273 static constexpr auto byteSeparator = 3;
274 std::unique_ptr<char[]> data(new char[
275 (eSELData.size() * byteSeparator) + 1]());
276
277 for (size_t i = 0; i < eSELData.size(); i++)
278 {
279 sprintf(&data[i * byteSeparator], "%02x ", eSELData[i]);
280 }
281 data[eSELData.size() * byteSeparator] = '\0';
282
283 using error = sdbusplus::org::open_power::Host::Error::MaintenanceProcedure;
284 using metadata = org::open_power::Host::MaintenanceProcedure;
285
286 report<error>(metadata::ESEL(data.get()),
287 metadata::PROCEDURE(static_cast<uint32_t>(procedureNum)));
288}