1 /*
2 * event.c
3 *
4 * MontaVista IPMI code for dealing with events.
5 *
6 * Author: MontaVista Software, Inc.
7 * Corey Minyard <minyard@mvista.com>
8 * source@mvista.com
9 *
10 * Copyright 2002,2003 MontaVista Software Inc.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this program; if not, write to the Free
31 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 */
33
34 #include <string.h>
35 #include <errno.h>
36
37 #include <OpenIPMI/ipmiif.h>
38
39 #include <OpenIPMI/internal/ipmi_event.h>
40 #include <OpenIPMI/internal/ipmi_int.h>
41 #include <OpenIPMI/internal/ipmi_mc.h>
42 #include <OpenIPMI/internal/ipmi_domain.h>
43
44 struct ipmi_event_s
45 {
46 ipmi_mcid_t mcid; /* The MC this event is stored in. */
47
48 ipmi_lock_t *lock;
49 unsigned int refcount;
50 unsigned int record_id;
51 unsigned int type;
52 ipmi_time_t timestamp;
53 unsigned int data_len;
54 unsigned char old;
55 unsigned char data[0];
56 };
57
58 ipmi_event_t *
ipmi_event_alloc(ipmi_mcid_t mcid,unsigned int record_id,unsigned int type,ipmi_time_t timestamp,unsigned char * data,unsigned int data_len)59 ipmi_event_alloc(ipmi_mcid_t mcid,
60 unsigned int record_id,
61 unsigned int type,
62 ipmi_time_t timestamp,
63 unsigned char *data,
64 unsigned int data_len)
65 {
66 ipmi_event_t *rv;
67
68 rv = ipmi_mem_alloc(sizeof(ipmi_event_t) + data_len);
69 if (!rv)
70 return NULL;
71
72 if (ipmi_create_global_lock(&rv->lock)) {
73 ipmi_mem_free(rv);
74 return NULL;
75 }
76 rv->mcid = mcid;
77 rv->record_id = record_id;
78 rv->type = type;
79 rv->timestamp = timestamp;
80 rv->data_len = data_len;
81 rv->old = 0;
82 if (data_len)
83 memcpy(rv->data, data, data_len);
84
85 rv->refcount = 1;
86 return rv;
87 }
88
89 ipmi_event_t *
ipmi_event_dup(ipmi_event_t * event)90 ipmi_event_dup(ipmi_event_t *event)
91 {
92 if (!event)
93 return NULL;
94 ipmi_lock(event->lock);
95 event->refcount++;
96 ipmi_unlock(event->lock);
97 return event;
98 }
99
100 void
ipmi_event_free(ipmi_event_t * event)101 ipmi_event_free(ipmi_event_t *event)
102 {
103 if (!event)
104 return;
105 ipmi_lock(event->lock);
106 event->refcount--;
107 if (event->refcount == 0) {
108 ipmi_unlock(event->lock);
109 ipmi_destroy_lock(event->lock);
110 ipmi_mem_free(event);
111 return;
112 }
113 ipmi_unlock(event->lock);
114 }
115
116 ipmi_mcid_t
ipmi_event_get_mcid(const ipmi_event_t * event)117 ipmi_event_get_mcid(const ipmi_event_t *event)
118 {
119 return event->mcid;
120 }
121
122 void
ipmi_event_set_mcid(ipmi_event_t * event,ipmi_mcid_t mcid)123 ipmi_event_set_mcid(ipmi_event_t *event, ipmi_mcid_t mcid)
124 {
125 event->mcid = mcid;
126 }
127
128 unsigned int
ipmi_event_get_record_id(const ipmi_event_t * event)129 ipmi_event_get_record_id(const ipmi_event_t *event)
130 {
131 return event->record_id;
132 }
133
134 unsigned int
ipmi_event_get_type(const ipmi_event_t * event)135 ipmi_event_get_type(const ipmi_event_t *event)
136 {
137 return event->type;
138 }
139
140 ipmi_time_t
ipmi_event_get_timestamp(const ipmi_event_t * event)141 ipmi_event_get_timestamp(const ipmi_event_t *event)
142 {
143 return event->timestamp;
144 }
145
146 unsigned int
ipmi_event_get_data_len(const ipmi_event_t * event)147 ipmi_event_get_data_len(const ipmi_event_t *event)
148 {
149 return event->data_len;
150 }
151
152 unsigned int
ipmi_event_get_data(const ipmi_event_t * event,unsigned char * data,unsigned int offset,unsigned int len)153 ipmi_event_get_data(const ipmi_event_t *event, unsigned char *data,
154 unsigned int offset, unsigned int len)
155 {
156 if (offset > event->data_len)
157 return 0;
158
159 if (offset+len > event->data_len)
160 len = event->data_len - offset;
161
162 memcpy(data, event->data+offset, len);
163
164 return len;
165 }
166
167 const unsigned char *
ipmi_event_get_data_ptr(const ipmi_event_t * event)168 ipmi_event_get_data_ptr(const ipmi_event_t *event)
169 {
170 return event->data;
171 }
172
173 int
ipmi_event_is_old(const ipmi_event_t * event)174 ipmi_event_is_old(const ipmi_event_t *event)
175 {
176 return event->old;
177 }
178
179 void
ipmi_event_set_is_old(ipmi_event_t * event,int val)180 ipmi_event_set_is_old(ipmi_event_t *event, int val)
181 {
182 event->old = val;
183 }
184
185 typedef struct del_event_info_s
186 {
187 ipmi_event_t *event;
188 ipmi_domain_cb done_handler;
189 void *cb_data;
190 int rv;
191 } del_event_info_t;
192
193 static void
mc_del_event_done(ipmi_mc_t * mc,int err,void * cb_data)194 mc_del_event_done(ipmi_mc_t *mc, int err, void *cb_data)
195 {
196 del_event_info_t *info = cb_data;
197
198 if (info->done_handler) {
199 ipmi_domain_t *domain = NULL;
200 if (mc)
201 domain = ipmi_mc_get_domain(mc);
202 info->done_handler(domain, err, info->cb_data);
203 }
204 ipmi_mem_free(info);
205 }
206
207 static void
del_event_handler(ipmi_mc_t * mc,void * cb_data)208 del_event_handler(ipmi_mc_t *mc, void *cb_data)
209 {
210 del_event_info_t *info = cb_data;
211 del_event_info_t *ninfo;
212
213 ninfo = ipmi_mem_alloc(sizeof(*ninfo));
214 if (!ninfo) {
215 info->rv = ENOMEM;
216 return;
217 }
218 *ninfo = *info;
219
220 info->rv = ipmi_mc_del_event(mc, info->event, mc_del_event_done, ninfo);
221 if (info->rv)
222 ipmi_mem_free(ninfo);
223 }
224
225 int
ipmi_event_delete(ipmi_event_t * event,ipmi_domain_cb done_handler,void * cb_data)226 ipmi_event_delete(ipmi_event_t *event,
227 ipmi_domain_cb done_handler,
228 void *cb_data)
229 {
230 int rv;
231 del_event_info_t info;
232 ipmi_mcid_t mcid = ipmi_event_get_mcid(event);
233
234 info.event = event;
235 info.done_handler = done_handler;
236 info.cb_data = cb_data;
237 info.rv = 0;
238 rv = ipmi_mc_pointer_cb(mcid, del_event_handler, &info);
239 if (!rv)
240 rv = info.rv;
241
242 return rv;
243 }
244
245 ipmi_mc_t *
i_ipmi_event_get_generating_mc(ipmi_domain_t * domain,ipmi_mc_t * sel_mc,const ipmi_event_t * event)246 i_ipmi_event_get_generating_mc(ipmi_domain_t *domain,
247 ipmi_mc_t *sel_mc,
248 const ipmi_event_t *event)
249 {
250 ipmi_ipmb_addr_t addr;
251 const unsigned char *data;
252 unsigned int type = ipmi_event_get_type(event);
253
254 if (type != 0x02)
255 /* It's not a standard IPMI event. */
256 return NULL;
257
258 data = ipmi_event_get_data_ptr(event);
259 addr.addr_type = IPMI_IPMB_ADDR_TYPE;
260 /* See if the MC has an OEM handler for this. */
261 if (data[6] == 0x03) {
262 addr.channel = 0;
263 } else {
264 addr.channel = data[5] >> 4;
265 }
266 if ((data[4] & 0x01) == 0) {
267 addr.slave_addr = data[4];
268 } else if (sel_mc) {
269 /* A software ID, assume it comes from the MC where we go it. */
270 ipmi_addr_t iaddr;
271
272 ipmi_mc_get_ipmi_address(sel_mc, &iaddr, NULL);
273 addr.slave_addr = ipmi_addr_get_slave_addr(&iaddr);
274 if (addr.slave_addr == 0)
275 /* A system interface, just assume it's the BMC. */
276 addr.slave_addr = 0x20;
277 } else {
278 return NULL;
279 }
280 addr.lun = 0;
281
282 return i_ipmi_find_mc_by_addr(domain, (ipmi_addr_t *) &addr, sizeof(addr));
283 }
284
285 ipmi_sensor_id_t
ipmi_event_get_generating_sensor_id(ipmi_domain_t * domain,ipmi_mc_t * sel_mc,const ipmi_event_t * event)286 ipmi_event_get_generating_sensor_id(ipmi_domain_t *domain,
287 ipmi_mc_t *sel_mc,
288 const ipmi_event_t *event)
289 {
290 ipmi_sensor_id_t id;
291 ipmi_mc_t *mc;
292 const unsigned char *data;
293 unsigned int type = ipmi_event_get_type(event);
294
295
296 if (type != 0x02)
297 /* It's not a standard IPMI event. */
298 goto out_invalid;
299
300 mc = i_ipmi_event_get_generating_mc(domain, sel_mc, event);
301 if (!mc)
302 goto out_invalid;
303
304 data = ipmi_event_get_data_ptr(event);
305 id.mcid = ipmi_mc_convert_to_id(mc);
306 id.lun = data[5] & 0x3;
307 id.sensor_num = data[8];
308
309 i_ipmi_mc_put(mc);
310
311 return id;
312
313 out_invalid:
314 ipmi_sensor_id_set_invalid(&id);
315 return id;
316 }
317
318 struct ipmi_event_handlers_s
319 {
320 ipmi_sensor_threshold_event_cb threshold;
321 ipmi_sensor_discrete_event_cb discrete;
322 };
323
324 ipmi_event_handlers_t *
ipmi_event_handlers_alloc(void)325 ipmi_event_handlers_alloc(void)
326 {
327 ipmi_event_handlers_t *rv;
328 rv = ipmi_mem_alloc(sizeof(*rv));
329 if (!rv)
330 return NULL;
331 memset(rv, 0, sizeof(*rv));
332 return rv;
333 }
334
335 void
ipmi_event_handlers_free(ipmi_event_handlers_t * handlers)336 ipmi_event_handlers_free(ipmi_event_handlers_t *handlers)
337 {
338 ipmi_mem_free(handlers);
339 }
340
341 void
ipmi_event_handlers_set_threshold(ipmi_event_handlers_t * handlers,ipmi_sensor_threshold_event_cb handler)342 ipmi_event_handlers_set_threshold(ipmi_event_handlers_t *handlers,
343 ipmi_sensor_threshold_event_cb handler)
344 {
345 handlers->threshold = handler;
346 }
347
348 void
ipmi_event_handlers_set_discrete(ipmi_event_handlers_t * handlers,ipmi_sensor_discrete_event_cb handler)349 ipmi_event_handlers_set_discrete(ipmi_event_handlers_t *handlers,
350 ipmi_sensor_discrete_event_cb handler)
351 {
352 handlers->discrete = handler;
353 }
354
355 typedef struct event_call_handlers_s
356 {
357 ipmi_domain_t *domain;
358 ipmi_event_handlers_t *handlers;
359 ipmi_event_t *event;
360 int rv;
361 void *cb_data;
362 } event_call_handlers_t;
363
364 static void
sensor_event_call(ipmi_sensor_t * sensor,void * cb_data)365 sensor_event_call(ipmi_sensor_t *sensor, void *cb_data)
366 {
367 event_call_handlers_t *info = cb_data;
368 int rv;
369
370 if (ipmi_sensor_get_event_reading_type(sensor)
371 == IPMI_EVENT_READING_TYPE_THRESHOLD)
372 {
373 enum ipmi_event_dir_e dir;
374 enum ipmi_thresh_e threshold;
375 enum ipmi_event_value_dir_e high_low;
376 enum ipmi_value_present_e value_present;
377 unsigned int raw_value;
378 double value;
379 const unsigned char *data;
380
381 data = ipmi_event_get_data_ptr(info->event);
382 dir = data[9] >> 7;
383 threshold = (data[10] >> 1) & 0x07;
384 high_low = data[10] & 1;
385 raw_value = data[11];
386 value = 0.0;
387
388 if ((data[10] >> 6) == 1) {
389 rv = ipmi_sensor_convert_from_raw(sensor, raw_value, &value);
390 if (rv)
391 value_present = IPMI_RAW_VALUE_PRESENT;
392 else
393 value_present = IPMI_BOTH_VALUES_PRESENT;
394 } else {
395 value_present = IPMI_NO_VALUES_PRESENT;
396 }
397 if (info->handlers->threshold)
398 info->handlers->threshold(sensor, dir,
399 threshold,
400 high_low,
401 value_present,
402 raw_value, value,
403 info->cb_data,
404 info->event);
405
406 else
407 info->rv = EAGAIN;
408 } else {
409 enum ipmi_event_dir_e dir;
410 int offset;
411 int severity = 0;
412 int prev_severity = 0;
413 const unsigned char *data;
414
415 data = ipmi_event_get_data_ptr(info->event);
416 dir = data[9] >> 7;
417 offset = data[10] & 0x0f;
418 if ((data[10] >> 6) == 2) {
419 severity = data[11] >> 4;
420 prev_severity = data[11] & 0xf;
421 if (severity == 0xf)
422 severity = -1;
423 if (prev_severity == 0xf)
424 prev_severity = -1;
425 }
426
427 if (info->handlers->discrete)
428 info->handlers->discrete(sensor, dir, offset,
429 severity,
430 prev_severity,
431 info->cb_data,
432 info->event);
433 else
434 info->rv = EAGAIN;
435 }
436 }
437
438 static void
sel_mc_handler(ipmi_mc_t * mc,void * cb_data)439 sel_mc_handler(ipmi_mc_t *mc, void *cb_data)
440 {
441 ipmi_sensor_id_t sensor_id;
442 event_call_handlers_t *info = cb_data;
443 int rv;
444
445 sensor_id = ipmi_event_get_generating_sensor_id(info->domain, mc,
446 info->event);
447 rv = ipmi_sensor_pointer_cb(sensor_id, sensor_event_call, info);
448 if (rv)
449 info->rv = rv;
450 }
451
452 int
ipmi_event_call_handler(ipmi_domain_t * domain,ipmi_event_handlers_t * handlers,ipmi_event_t * event,void * cb_data)453 ipmi_event_call_handler(ipmi_domain_t *domain,
454 ipmi_event_handlers_t *handlers,
455 ipmi_event_t *event,
456 void *cb_data)
457 {
458
459
460 ipmi_sensor_id_t sensor_id;
461 event_call_handlers_t info;
462 int rv = 0;
463 ipmi_mcid_t mc_id;
464
465 info.domain = domain;
466 info.handlers = handlers;
467 info.event = event;
468 info.rv = 0;
469 info.cb_data = cb_data;
470
471 /* We try first to get the MC the event is stored in. If that
472 doesn't work, then just attempt to do the sensor without an MC. */
473 mc_id = ipmi_event_get_mcid(event);
474 if (ipmi_mc_pointer_cb(mc_id, sel_mc_handler, &info) != 0) {
475 sensor_id = ipmi_event_get_generating_sensor_id(domain, NULL, event);
476 rv = ipmi_sensor_pointer_cb(sensor_id, sensor_event_call, &info);
477 }
478 if (!rv)
479 rv = info.rv;
480 return rv;
481 }
482