1 #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>
10 #include <mapper.h>
11 #include <phosphor-logging/elog.hpp>
12 #include <phosphor-logging/elog-errors-HostEvent.hpp>
13 #include "host-ipmid/ipmid-api.h"
14 #include "sensorhandler.h"
15 #include "storagehandler.h"
16 
17 
18 using namespace std;
19 using namespace phosphor::logging;
20 
21 //////////////////////////
22 struct esel_section_headers_t {
23 	uint8_t sectionid[2];
24 	uint8_t sectionlength[2];
25 	uint8_t version;
26 	uint8_t subsectiontype;
27 	uint8_t compid;
28 };
29 
30 struct severity_values_t {
31 	uint8_t type;
32 	const char *description;
33 };
34 
35 
36 const std::vector<severity_values_t> g_sev_desc = {
37 	{0x10, "recoverable error"},
38 	{0x20, "predictive error"},
39 	{0x40, "unrecoverable error"},
40 	{0x50, "critical error"},
41 	{0x60, "error from a diagnostic test"},
42 	{0x70, "recovered symptom "},
43 	{0xFF, "Unknown"},
44 };
45 
46 const char* sev_lookup(uint8_t n) {
47 	auto i = std::find_if(std::begin(g_sev_desc), std::end(g_sev_desc),
48 	                      [n](auto p){ return p.type == n || p.type == 0xFF; });
49 	return i->description;
50 }
51 
52 
53 
54 
55 int find_sensor_type_string(uint8_t sensor_number, char **s) {
56 
57 	dbus_interface_t a;
58 	const char *p;
59 	int r;
60 
61 	r = find_openbmc_path("SENSOR", sensor_number, &a);
62 
63 	if ((r < 0) || (a.bus[0] == 0)) {
64 		// Just make a generic message for errors that
65 		// occur on sensors that dont exist
66 		r = asprintf(s, "Unknown Sensor (0x%02x)", sensor_number);
67 	} else {
68 
69 		if ((p = strrchr (a.path, '/')) == NULL) {
70 			p = "/Unknown Sensor";
71 		}
72 
73 		*s = strdup(p+1);
74 	}
75 
76 	return 0;
77 }
78 
79 
80 size_t getfilestream(const char *fn, uint8_t **buffer) {
81 
82 	FILE *fp;
83 	ssize_t size = 0;
84 	int r;
85 
86 	if ((fp = fopen(fn, "rb")) != NULL) {
87 
88 		r = fseek(fp, 0, SEEK_END);
89 		if (r) {
90 			fprintf(stderr,"Fseek failed\n");
91 			goto fclose_fp;
92 		}
93 
94 		size = ftell(fp);
95 		if (size == -1L) {
96 			fprintf(stderr,"Ftell failed for %s\n", strerror(errno));
97 			size = 0;
98 			goto fclose_fp;
99 		}
100 
101 		r = fseek(fp, 0, SEEK_SET);
102 		if (r) {
103 			fprintf(stderr,"Fseek failed\n");
104 			size = 0;
105 			goto fclose_fp;
106 		}
107 
108 		*buffer = new uint8_t [size];
109 
110 		r = fread(*buffer, 1, size, fp);
111 		if ( r != size) {
112 			size = 0;
113 			fprintf(stderr,"Fread failed\n");
114 		}
115 
116 fclose_fp:
117 		fclose(fp);
118 	}
119 
120 	return static_cast<size_t>(size);
121 }
122 
123 
124 const char *create_esel_severity(const uint8_t *buffer) {
125 
126 	uint8_t severity;
127 	// Dive in to the IBM log to find the severity
128 	severity = (0xF0  & buffer[0x4A]);
129 
130 	return sev_lookup(severity);
131 }
132 
133 int create_esel_association(const uint8_t *buffer, char **m) {
134 
135 	ipmi_add_sel_request_t *p;
136 	dbus_interface_t dbusint;
137 	uint8_t sensor;
138 
139 	p = ( ipmi_add_sel_request_t *) buffer;
140 
141 	sensor = p->sensornumber;
142 
143 	find_openbmc_path("SENSOR", sensor, &dbusint);
144 
145 	// Simply no associations if the sensor can not be found
146 	if (strlen(dbusint.path) < 1) {
147 		printf("Sensor 0x%x not found\n", sensor);
148 		memset(dbusint.path,0,sizeof(dbusint.path));
149 	}
150 
151 	*m = strdup(dbusint.path);
152 
153 	return 0;
154 }
155 
156 
157 
158 int create_esel_description(const uint8_t *buffer, const char *sev, char **message) {
159 
160 
161 	ipmi_add_sel_request_t *p;
162 	char *m;
163 	int r;
164 
165 	p =  ( ipmi_add_sel_request_t *) buffer;
166 
167 	find_sensor_type_string(p->sensornumber,&m);
168 
169 	r = asprintf(message, "A %s has experienced a %s", m, sev );
170 	if (r == -1) {
171 		fprintf(stderr,
172 			"Failed to allocate memory for ESEL description\n");
173 	}
174 
175 	free(m);
176 
177 	return 0;
178 }
179 
180 
181 int send_esel_to_dbus(const char *desc, const char *sev, const char *details, uint8_t *debug, size_t debuglen) {
182 
183     // Allocate enough space to represent the data in hex separated by spaces,
184     // to mimic how IPMI would display the data.
185     unique_ptr<char[]> selData(new char[(debuglen*3) + 1]());
186     uint32_t i = 0;
187     for(i = 0; i < debuglen; i++)
188     {
189         sprintf(&selData[i*3], "%02x ", 0xFF & ((char*)debug)[i]);
190     }
191     selData[debuglen*3] = '\0';
192 
193     using error = org::open_power::Error::Host::Event;
194     report<error>(error::ESEL(selData.get()));
195 
196     return 0;
197 }
198 
199 
200 void send_esel(uint16_t recordid) {
201 	char *desc, *assoc;
202 	const char *sev;
203 	uint8_t *buffer = NULL;
204 	const char *path = "/tmp/esel";
205 	ssize_t sz;
206 	int r;
207 
208 	sz = getfilestream(path, &buffer);
209 	if (sz == 0) {
210 		printf("Error file does not exist %d\n",__LINE__);
211 		return;
212 	}
213 
214 	sev = create_esel_severity(buffer);
215 	create_esel_association(buffer, &assoc);
216 	create_esel_description(buffer, sev, &desc);
217 
218 	r = send_esel_to_dbus(desc, sev, assoc, buffer, sz);
219 	if (r < 0) {
220 		fprintf(stderr, "Failed to send esel to dbus\n");
221 	}
222 
223 	free(assoc);
224 	free(desc);
225 	delete[] buffer;
226 
227 	return;
228 }
229