summaryrefslogtreecommitdiffstats
path: root/storageaddsel.cpp
blob: 0b40d470502a27ddc360b5318959408fec547ce4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#include <stdint.h>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <vector>
#include <memory>
#include <systemd/sd-bus.h>
#include <mapper.h>
#include <elog.hpp>
#include <elog-errors-HostEvent.hpp>
#include "host-ipmid/ipmid-api.h"
#include "sensorhandler.h"
#include "storagehandler.h"


using namespace std;
using namespace phosphor::logging;

//////////////////////////
struct esel_section_headers_t {
	uint8_t sectionid[2];
	uint8_t sectionlength[2];
	uint8_t version;
	uint8_t subsectiontype;
	uint8_t compid;
};

struct severity_values_t {
	uint8_t type;
	const char *description;
};


const std::vector<severity_values_t> g_sev_desc = {
	{0x10, "recoverable error"},
	{0x20, "predictive error"},
	{0x40, "unrecoverable error"},
	{0x50, "critical error"},
	{0x60, "error from a diagnostic test"},
	{0x70, "recovered symptom "},
	{0xFF, "Unknown"},
};

const char* sev_lookup(uint8_t n) {
	auto i = std::find_if(std::begin(g_sev_desc), std::end(g_sev_desc),
	                      [n](auto p){ return p.type == n || p.type == 0xFF; });
	return i->description;
}




int find_sensor_type_string(uint8_t sensor_number, char **s) {

	dbus_interface_t a;
	const char *p;
	int r;

	r = find_openbmc_path("SENSOR", sensor_number, &a);

	if ((r < 0) || (a.bus[0] == 0)) {
		// Just make a generic message for errors that
		// occur on sensors that dont exist
		r = asprintf(s, "Unknown Sensor (0x%02x)", sensor_number);
	} else {

		if ((p = strrchr (a.path, '/')) == NULL) {
			p = "/Unknown Sensor";
		}

		*s = strdup(p+1);
	}

	return 0;
}


size_t getfilestream(const char *fn, uint8_t **buffer) {

	FILE *fp;
	ssize_t size = 0;
	int r;

	if ((fp = fopen(fn, "rb")) != NULL) {

		r = fseek(fp, 0, SEEK_END);
		if (r) {
			fprintf(stderr,"Fseek failed\n");
			goto fclose_fp;
		}

		size = ftell(fp);
		if (size == -1L) {
			fprintf(stderr,"Ftell failed for %s\n", strerror(errno));
			size = 0;
			goto fclose_fp;
		}

		r = fseek(fp, 0, SEEK_SET);
		if (r) {
			fprintf(stderr,"Fseek failed\n");
			size = 0;
			goto fclose_fp;
		}

		*buffer = new uint8_t [size];

		r = fread(*buffer, 1, size, fp);
		if ( r != size) {
			size = 0;
			fprintf(stderr,"Fread failed\n");
		}

fclose_fp:
		fclose(fp);
	}

	return static_cast<size_t>(size);
}


const char *create_esel_severity(const uint8_t *buffer) {

	uint8_t severity;
	// Dive in to the IBM log to find the severity
	severity = (0xF0  & buffer[0x4A]);

	return sev_lookup(severity);
}

int create_esel_association(const uint8_t *buffer, char **m) {

	ipmi_add_sel_request_t *p;
	dbus_interface_t dbusint;
	uint8_t sensor;

	p = ( ipmi_add_sel_request_t *) buffer;

	sensor = p->sensornumber;

	find_openbmc_path("SENSOR", sensor, &dbusint);

	// Simply no associations if the sensor can not be found
	if (strlen(dbusint.path) < 1) {
		printf("Sensor 0x%x not found\n", sensor);
		memset(dbusint.path,0,sizeof(dbusint.path));
	}

	*m = strdup(dbusint.path);

	return 0;
}



int create_esel_description(const uint8_t *buffer, const char *sev, char **message) {


	ipmi_add_sel_request_t *p;
	char *m;
	int r;

	p =  ( ipmi_add_sel_request_t *) buffer;

	find_sensor_type_string(p->sensornumber,&m);

	r = asprintf(message, "A %s has experienced a %s", m, sev );
	if (r == -1) {
		fprintf(stderr,
			"Failed to allocate memory for ESEL description\n");
	}

	free(m);

	return 0;
}


int send_esel_to_dbus(const char *desc, const char *sev, const char *details, uint8_t *debug, size_t debuglen) {

	sd_bus *mbus = NULL;
    sd_bus_error error = SD_BUS_ERROR_NULL;
    sd_bus_message *reply = NULL, *m=NULL;
    uint16_t x;
    int r;
    const char *object_name  =  "/org/openbmc/records/events";
    char *bus_name = NULL;

    // Allocate enough space to represent the data in hex separated by spaces,
    // to mimic how IPMI would display the data.
    unique_ptr<char[]> selData(new char[debuglen*3]());
    uint32_t i = 0;
    for(i = 0; i < debuglen; i++)
    {
        sprintf(&selData[i*3], "%02x ", 0xFF & ((char*)debug)[i]);
    }
    log<level::INFO>("Received Host Event", entry("ESEL=%s", selData.get()));

    try
    {
        elog<org::open_power::Error::Host::Event>(
            prev_entry<org::open_power::Error::Host::Event::ESEL>());
    }
    catch (elogException<org::open_power::Error::Host::Event>& e)
    {
        commit(e.name());
    }

    mbus = ipmid_get_sd_bus_connection();
    r = mapper_get_service(mbus, object_name, &bus_name);
    if (r < 0) {
        fprintf(stderr, "Failed to get %s connection: %s\n",
                object_name, strerror(-r));
        goto finish;
    }
    r = sd_bus_message_new_method_call(mbus,&m,
    									bus_name,
    									object_name,
    									"org.openbmc.recordlog",
    									"acceptHostMessage");
    if (r < 0) {
        fprintf(stderr, "Failed to add the method object: %s\n", strerror(-r));
        goto finish;
    }

    r = sd_bus_message_append(m, "sss", desc, sev, details);
    if (r < 0) {
        fprintf(stderr, "Failed add the message strings : %s\n", strerror(-r));
        goto finish;
    }

    r = sd_bus_message_append_array(m, 'y', debug, debuglen);
    if (r < 0) {
        fprintf(stderr, "Failed to add the raw array of bytes: %s\n", strerror(-r));
        goto finish;
    }
    // Call the IPMI responder on the bus so the message can be sent to the CEC
    r = sd_bus_call(mbus, m, 0, &error, &reply);
    if (r < 0) {
        fprintf(stderr, "Failed to call the method: %s %s\n", __FUNCTION__, strerror(-r));
        goto finish;
    }
    r = sd_bus_message_read(reply, "q", &x);
    if (r < 0) {
        fprintf(stderr, "Failed to get a rc from the method: %s\n", strerror(-r));
    }

finish:
    sd_bus_error_free(&error);
    m = sd_bus_message_unref(m);
    reply = sd_bus_message_unref(reply);
    free (bus_name);
    return r;
}


void send_esel(uint16_t recordid) {
	char *desc, *assoc;
	const char *sev;
	uint8_t *buffer = NULL;
	const char *path = "/tmp/esel";
	ssize_t sz;
	int r;

	sz = getfilestream(path, &buffer);
	if (sz == 0) {
		printf("Error file does not exist %d\n",__LINE__);
		return;
	}

	sev = create_esel_severity(buffer);
	create_esel_association(buffer, &assoc);
	create_esel_description(buffer, sev, &desc);

	r = send_esel_to_dbus(desc, sev, assoc, buffer, sz);
	if (r < 0) {
		fprintf(stderr, "Failed to send esel to dbus\n");
	}

	free(assoc);
	free(desc);
	delete[] buffer;

	return;
}
OpenPOWER on IntegriCloud