1 /*
2 * sel.c
3 *
4 * MontaVista IPMI code for handling the system event log
5 *
6 * Author: MontaVista Software, Inc.
7 * Corey Minyard <minyard@mvista.com>
8 * source@mvista.com
9 *
10 * Copyright 2002,2003,2004,2005 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 <stdio.h>
36
37 #include <OpenIPMI/ipmiif.h>
38 #include <OpenIPMI/ipmi_msgbits.h>
39 #include <OpenIPMI/ipmi_err.h>
40
41 #include <OpenIPMI/internal/opq.h>
42 #include <OpenIPMI/internal/ilist.h>
43 #include <OpenIPMI/internal/ipmi_int.h>
44 #include <OpenIPMI/internal/ipmi_event.h>
45 #include <OpenIPMI/internal/ipmi_sel.h>
46 #include <OpenIPMI/internal/ipmi_domain.h>
47 #include <OpenIPMI/internal/ipmi_mc.h>
48
49 #define MAX_SEL_FETCH_RETRIES 10
50
51 typedef struct sel_fetch_handler_s
52 {
53 ipmi_sel_info_t *sel;
54 ipmi_sels_fetched_t handler;
55 void *cb_data;
56 int rv;
57
58 struct sel_fetch_handler_s *next;
59 } sel_fetch_handler_t;
60
61 /* Holds an event in the list of events. */
62 typedef struct sel_event_holder_s
63 {
64 unsigned int deleted : 1;
65 unsigned int cancelled : 1;
66 unsigned int refcount;
67 ipmi_event_t *event;
68 } sel_event_holder_t;
69
70 static sel_event_holder_t *
sel_event_holder_alloc(void)71 sel_event_holder_alloc(void)
72 {
73 sel_event_holder_t *holder = ipmi_mem_alloc(sizeof(*holder));
74
75 if (!holder)
76 return NULL;
77 holder->deleted = 0;
78 holder->cancelled = 0;
79 holder->refcount = 1;
80 holder->event = NULL;
81 return holder;
82 }
83
84 static void
sel_event_holder_get(sel_event_holder_t * holder)85 sel_event_holder_get(sel_event_holder_t *holder)
86 {
87 holder->refcount++;
88 }
89
90 static void
sel_event_holder_put(sel_event_holder_t * holder)91 sel_event_holder_put(sel_event_holder_t *holder)
92 {
93 holder->refcount--;
94 if (holder->refcount == 0) {
95 ipmi_event_free(holder->event);
96 ipmi_mem_free(holder);
97 }
98 }
99
100 typedef struct sel_clear_req_s
101 {
102 ipmi_event_t *last_event;
103 struct sel_clear_req_s *next;
104 } sel_clear_req_t;
105
106 #define SEL_NAME_LEN (IPMI_MC_NAME_LEN + 32)
107
108 struct ipmi_sel_info_s
109 {
110 ipmi_mcid_t mc;
111
112 /* LUN we are attached with. */
113 int lun;
114
115 uint8_t major_version;
116 uint8_t minor_version;
117 uint16_t entries;
118 uint32_t last_addition_timestamp;
119 uint32_t last_erase_timestamp;
120
121 /* These are here to store the timestamps until the operation
122 completes. Successfully. Otherwise, if we restart the fetch,
123 it will have the timestamps set wrong and won't do the
124 fetch. */
125 uint32_t curr_addition_timestamp;
126 uint32_t curr_erase_timestamp;
127
128 uint16_t free_bytes;
129 unsigned int overflow : 1;
130 unsigned int supports_delete_sel : 1;
131 unsigned int supports_partial_add_sel : 1;
132 unsigned int supports_reserve_sel : 1;
133 unsigned int supports_get_sel_allocation : 1;
134
135 unsigned int fetched : 1;
136
137 /* Has the SEL been destroyed? This is here because of race
138 conditions in shutdown. If we are currently in the process of
139 fetching SELs, we will allow a destroy operation to complete,
140 but we don't actually destroy the data until the SEL fetch
141 reaches a point were it can be stopped safely. */
142 unsigned int destroyed : 1;
143 unsigned int in_destroy : 1;
144
145 /* Is a fetch in the queue or currently running? */
146 unsigned int in_fetch : 1;
147
148 /* Something to call when the destroy is complete. */
149 ipmi_sel_destroyed_t destroy_handler;
150 void *destroy_cb_data;
151
152
153 /* When fetching the data in event-driven mode, these are the
154 variables that track what is going on. */
155 unsigned int curr_rec_id;
156 unsigned int next_rec_id;
157 unsigned int reservation;
158 int sels_changed;
159 unsigned int fetch_retry_count;
160 sel_fetch_handler_t *fetch_handlers;
161
162 /* When we start a fetch, we start with this id. This is the last
163 one we successfully fetches (or 0 if it is not valid) so we can
164 find the next valid id to fetch. */
165 unsigned int start_rec_id;
166 unsigned char start_rec_id_data[14];
167
168 /* A lock, primarily for handling race conditions fetching the data. */
169 os_hnd_lock_t *sel_lock;
170
171 os_handler_t *os_hnd;
172
173 /* This is the actual list of events and the number of non-deleted
174 events and the number of deleted events. Note that events may
175 contain more items than num_sels, num_sels only counts the
176 number of non-deleted events in the list. del_sels+num_sels
177 should be the number of events. */
178 ilist_t *events;
179 unsigned int num_sels;
180 unsigned int del_sels;
181
182 /* We serialize operations through here, since we are dealing with
183 a locked resource. */
184 opq_t *opq;
185
186 ipmi_sel_new_event_handler_cb new_event_handler;
187 void *new_event_cb_data;
188
189 char name[SEL_NAME_LEN];
190
191 ipmi_domain_stat_t *sel_good_scans;
192 ipmi_domain_stat_t *sel_scan_lost_reservation;
193 ipmi_domain_stat_t *sel_fail_scan_lost_reservation;
194 ipmi_domain_stat_t *sel_received_events;
195 ipmi_domain_stat_t *sel_fetch_errors;
196
197 ipmi_domain_stat_t *sel_good_clears;
198 ipmi_domain_stat_t *sel_clear_lost_reservation;
199 ipmi_domain_stat_t *sel_clear_errors;
200
201 ipmi_domain_stat_t *sel_good_deletes;
202 ipmi_domain_stat_t *sel_delete_lost_reservation;
203 ipmi_domain_stat_t *sel_fail_delete_lost_reservation;
204 ipmi_domain_stat_t *sel_delete_errors;
205 };
206
sel_lock(ipmi_sel_info_t * sel)207 static inline void sel_lock(ipmi_sel_info_t *sel)
208 {
209 if (sel->os_hnd->lock)
210 sel->os_hnd->lock(sel->os_hnd, sel->sel_lock);
211 }
212
sel_unlock(ipmi_sel_info_t * sel)213 static inline void sel_unlock(ipmi_sel_info_t *sel)
214 {
215 if (sel->os_hnd->lock)
216 sel->os_hnd->unlock(sel->os_hnd, sel->sel_lock);
217 }
218
219 static void
free_event(ilist_iter_t * iter,void * item,void * cb_data)220 free_event(ilist_iter_t *iter, void *item, void *cb_data)
221 {
222 sel_event_holder_t *holder = item;
223 sel_event_holder_put(holder);
224 }
225
226 static void
free_events(ilist_t * events)227 free_events(ilist_t *events)
228 {
229 ilist_iter(events, free_event, NULL);
230 }
231
232 static int
recid_search_cmp(void * item,void * cb_data)233 recid_search_cmp(void *item, void *cb_data)
234 {
235 sel_event_holder_t *holder = item;
236 unsigned int recid = *((unsigned int *) cb_data);
237
238 return ipmi_event_get_record_id(holder->event) == recid;
239 }
240 static sel_event_holder_t *
find_event(ilist_t * list,unsigned int recid)241 find_event(ilist_t *list, unsigned int recid)
242 {
243 return ilist_search(list, recid_search_cmp, &recid);
244 }
245
246 static int
event_cmp(ipmi_event_t * event1,ipmi_event_t * event2)247 event_cmp(ipmi_event_t *event1, ipmi_event_t *event2)
248 {
249 int rv;
250 unsigned int record_id1, record_id2;
251 unsigned int type1, type2;
252 unsigned int data_len1, data_len2;
253 const unsigned char *ptr1, *ptr2;
254
255 rv = ipmi_cmp_mc_id(ipmi_event_get_mcid(event1),
256 ipmi_event_get_mcid(event2));
257 if (rv)
258 return rv;
259 record_id1 = ipmi_event_get_record_id(event1);
260 record_id2 = ipmi_event_get_record_id(event2);
261 if (record_id1 > record_id2)
262 return 1;
263 if (record_id1 < record_id2)
264 return -1;
265 type1 = ipmi_event_get_type(event1);
266 type2 = ipmi_event_get_type(event2);
267 if (type1 > type2)
268 return 1;
269 if (type1 < type2)
270 return -1;
271 data_len1 = ipmi_event_get_data_len(event1);
272 data_len2 = ipmi_event_get_data_len(event2);
273 if (data_len1 > data_len2)
274 return 1;
275 if (data_len1 < data_len2)
276 return -1;
277 ptr1 = ipmi_event_get_data_ptr(event1);
278 ptr2 = ipmi_event_get_data_ptr(event2);
279 return memcmp(ptr1, ptr2, data_len1);
280 }
281
282 int
ipmi_sel_alloc(ipmi_mc_t * mc,unsigned int lun,ipmi_sel_info_t ** new_sel)283 ipmi_sel_alloc(ipmi_mc_t *mc,
284 unsigned int lun,
285 ipmi_sel_info_t **new_sel)
286 {
287 ipmi_sel_info_t *sel = NULL;
288 int rv = 0;
289 ipmi_domain_t *domain;
290 int i;
291
292 CHECK_MC_LOCK(mc);
293
294 domain = ipmi_mc_get_domain(mc);
295
296 if (lun >= 4)
297 return EINVAL;
298
299 sel = ipmi_mem_alloc(sizeof(*sel));
300 if (!sel) {
301 rv = ENOMEM;
302 goto out;
303 }
304 memset(sel, 0, sizeof(*sel));
305
306 i = ipmi_mc_get_name(mc, sel->name, sizeof(sel->name));
307 snprintf(sel->name+i, sizeof(sel->name)-i, "(sel)");
308
309 sel->events = alloc_ilist();
310 if (!sel->events) {
311 rv = ENOMEM;
312 goto out;
313 }
314
315 sel->mc = ipmi_mc_convert_to_id(mc);
316 sel->destroyed = 0;
317 sel->in_destroy = 0;
318 sel->os_hnd = ipmi_domain_get_os_hnd(domain);
319 sel->sel_lock = NULL;
320 sel->fetched = 0;
321 sel->in_fetch = 0;
322 sel->num_sels = 0;
323 sel->del_sels = 0;
324 sel->destroy_handler = NULL;
325 sel->lun = lun;
326 sel->fetch_handlers = NULL;
327 sel->new_event_handler = NULL;
328
329 sel->opq = opq_alloc(sel->os_hnd);
330 if (!sel->opq) {
331 rv = ENOMEM;
332 goto out;
333 }
334
335 if (sel->os_hnd->create_lock) {
336 rv = sel->os_hnd->create_lock(sel->os_hnd, &sel->sel_lock);
337 if (rv)
338 goto out;
339 }
340
341 out:
342 if (rv) {
343 if (sel) {
344 if (sel->events)
345 free_ilist(sel->events);
346 if (sel->opq)
347 opq_destroy(sel->opq);
348 if (sel->sel_lock)
349 sel->os_hnd->destroy_lock(sel->os_hnd, sel->sel_lock);
350 ipmi_mem_free(sel);
351 }
352 } else {
353 ipmi_domain_stat_register(domain, "sel_good_scans",
354 i_ipmi_mc_name(mc),
355 &sel->sel_good_scans);
356 ipmi_domain_stat_register(domain, "sel_scan_lost_reservation",
357 i_ipmi_mc_name(mc),
358 &sel->sel_scan_lost_reservation);
359 ipmi_domain_stat_register(domain, "sel_fail_scan_lost_reservation",
360 i_ipmi_mc_name(mc),
361 &sel->sel_fail_scan_lost_reservation);
362 ipmi_domain_stat_register(domain, "sel_received_events",
363 i_ipmi_mc_name(mc),
364 &sel->sel_received_events);
365 ipmi_domain_stat_register(domain, "sel_fetch_errors",
366 i_ipmi_mc_name(mc),
367 &sel->sel_fetch_errors);
368 ipmi_domain_stat_register(domain, "sel_good_clears",
369 i_ipmi_mc_name(mc),
370 &sel->sel_good_clears);
371 ipmi_domain_stat_register(domain, "sel_clear_lost_reservation",
372 i_ipmi_mc_name(mc),
373 &sel->sel_clear_lost_reservation);
374 ipmi_domain_stat_register(domain, "sel_clear_errors",
375 i_ipmi_mc_name(mc),
376 &sel->sel_clear_errors);
377 ipmi_domain_stat_register(domain, "sel_good_deletes",
378 i_ipmi_mc_name(mc),
379 &sel->sel_good_deletes);
380 ipmi_domain_stat_register(domain, "sel_delete_lost_reservation",
381 i_ipmi_mc_name(mc),
382 &sel->sel_delete_lost_reservation);
383 ipmi_domain_stat_register(domain, "sel_fail_delete_lost_reservation",
384 i_ipmi_mc_name(mc),
385 &sel->sel_fail_delete_lost_reservation);
386 ipmi_domain_stat_register(domain, "sel_delete_errors",
387 i_ipmi_mc_name(mc),
388 &sel->sel_delete_errors);
389 *new_sel = sel;
390 }
391 return rv;
392 }
393
394 static void
internal_destroy_sel(ipmi_sel_info_t * sel)395 internal_destroy_sel(ipmi_sel_info_t *sel)
396 {
397 sel->in_destroy = 1;
398
399 /* We don't have to have a valid ipmi to destroy an SEL, the are
400 designed to live after the ipmi has been destroyed. */
401
402 if (sel->events) {
403 free_events(sel->events);
404 free_ilist(sel->events);
405 }
406 sel_unlock(sel);
407
408 if (sel->opq)
409 opq_destroy(sel->opq);
410
411 if (sel->sel_lock)
412 sel->os_hnd->destroy_lock(sel->os_hnd, sel->sel_lock);
413
414 if (sel->sel_good_scans)
415 ipmi_domain_stat_put(sel->sel_good_scans);
416 if (sel->sel_scan_lost_reservation)
417 ipmi_domain_stat_put(sel->sel_scan_lost_reservation);
418 if (sel->sel_fail_scan_lost_reservation)
419 ipmi_domain_stat_put(sel->sel_fail_scan_lost_reservation);
420 if (sel->sel_received_events)
421 ipmi_domain_stat_put(sel->sel_received_events);
422 if (sel->sel_fetch_errors)
423 ipmi_domain_stat_put(sel->sel_fetch_errors);
424 if (sel->sel_good_clears)
425 ipmi_domain_stat_put(sel->sel_good_clears);
426 if (sel->sel_clear_lost_reservation)
427 ipmi_domain_stat_put(sel->sel_clear_lost_reservation);
428 if (sel->sel_clear_errors)
429 ipmi_domain_stat_put(sel->sel_clear_errors);
430 if (sel->sel_good_deletes)
431 ipmi_domain_stat_put(sel->sel_good_deletes);
432 if (sel->sel_delete_lost_reservation)
433 ipmi_domain_stat_put(sel->sel_delete_lost_reservation);
434 if (sel->sel_fail_delete_lost_reservation)
435 ipmi_domain_stat_put(sel->sel_fail_delete_lost_reservation);
436 if (sel->sel_delete_errors)
437 ipmi_domain_stat_put(sel->sel_delete_errors);
438
439 /* Do this after we have gotten rid of all external dependencies,
440 but before it is free. */
441 if (sel->destroy_handler)
442 sel->destroy_handler(sel, sel->destroy_cb_data);
443
444 ipmi_mem_free(sel);
445 }
446
447 int
ipmi_sel_destroy(ipmi_sel_info_t * sel,ipmi_sel_destroyed_t handler,void * cb_data)448 ipmi_sel_destroy(ipmi_sel_info_t *sel,
449 ipmi_sel_destroyed_t handler,
450 void *cb_data)
451 {
452 /* We don't need the read lock, because the sels are stand-alone
453 after they are created (except for fetching SELs, of course). */
454 sel_lock(sel);
455 if (sel->destroyed) {
456 sel_unlock(sel);
457 return EINVAL;
458 }
459 sel->destroyed = 1;
460 sel->destroy_handler = handler;
461 sel->destroy_cb_data = cb_data;
462 if (opq_stuff_in_progress(sel->opq)) {
463 /* It's currently doing something with callbacks, so let it be
464 destroyed in the handler, since we can't cancel the handler
465 or operation. */
466 sel_unlock(sel);
467 return 0;
468 }
469
470 /* This unlocks the lock. */
471 internal_destroy_sel(sel);
472 return 0;
473 }
474
475 /* This should be called with the sel locked. It will unlock the sel
476 before returning. */
477 static void
fetch_complete(ipmi_sel_info_t * sel,int err,int do_opq_done)478 fetch_complete(ipmi_sel_info_t *sel, int err, int do_opq_done)
479 {
480 sel_fetch_handler_t *elem, *next;
481 int sels_changed;
482 unsigned int num_sels;
483
484 if (sel->in_destroy)
485 goto out;
486
487 sels_changed = sel->sels_changed;
488 num_sels = sel->num_sels;
489
490 elem = sel->fetch_handlers;
491 sel->fetch_handlers = NULL;
492 sel->fetched = 1;
493 sel->in_fetch = 0;
494 sel_unlock(sel);
495
496 while (elem) {
497 next = elem->next;
498 elem->next = NULL;
499 if (elem->handler)
500 elem->handler(sel,
501 err,
502 sels_changed,
503 num_sels,
504 elem->cb_data);
505 ipmi_mem_free(elem);
506 elem = next;
507 }
508
509 if (sel->destroyed) {
510 sel_lock(sel);
511 internal_destroy_sel(sel);
512 /* Previous call releases lock. */
513 return;
514 }
515
516 if (do_opq_done)
517 opq_op_done(sel->opq);
518 return;
519
520 out:
521 sel_unlock(sel);
522 }
523
524 static void
free_deleted_event(ilist_iter_t * iter,void * item,void * cb_data)525 free_deleted_event(ilist_iter_t *iter, void *item, void *cb_data)
526 {
527 sel_event_holder_t *holder = item;
528 ipmi_sel_info_t *sel = cb_data;
529
530 if (holder->deleted) {
531 ilist_delete(iter);
532 holder->cancelled = 1;
533 sel->del_sels--;
534 sel_event_holder_put(holder);
535 }
536 }
537
538 static void
free_deleted_events(ipmi_sel_info_t * sel)539 free_deleted_events(ipmi_sel_info_t *sel)
540 {
541 ilist_iter(sel->events, free_deleted_event, sel);
542 }
543
544 static void
handle_sel_clear(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)545 handle_sel_clear(ipmi_mc_t *mc,
546 ipmi_msg_t *rsp,
547 void *rsp_data)
548 {
549 sel_fetch_handler_t *elem = rsp_data;
550 ipmi_sel_info_t *sel = elem->sel;
551
552 sel_lock(sel);
553 if (sel->destroyed) {
554 ipmi_log(IPMI_LOG_ERR_INFO,
555 "%ssel.c(handle_sel_clear): "
556 "SEL info was destroyed while an operation was in"
557 " progress(1)", sel->name);
558 fetch_complete(sel, ECANCELED, 1);
559 goto out;
560 }
561
562 if (!mc) {
563 ipmi_log(IPMI_LOG_ERR_INFO,
564 "%ssel.c(handle_sel_clear): "
565 "MC went away while SEL op was in progress",
566 sel->name);
567 fetch_complete(sel, ECANCELED, 1);
568 goto out;
569 }
570
571 if (rsp->data[0] == 0) {
572 if (sel->sel_good_clears)
573 ipmi_domain_stat_add(sel->sel_good_clears, 1);
574
575 /* Success! We can free the data. */
576 free_deleted_events(sel);
577 sel->del_sels = 0;
578 } else if (rsp->data[0] == IPMI_INVALID_RESERVATION_CC) {
579 if (sel->sel_clear_lost_reservation)
580 ipmi_domain_stat_add(sel->sel_clear_lost_reservation, 1);
581 } else {
582 if (sel->sel_clear_errors)
583 ipmi_domain_stat_add(sel->sel_clear_errors, 1);
584 }
585
586 fetch_complete(sel, 0, 1);
587 out:
588 return;
589 }
590
591 static int
send_sel_clear(sel_fetch_handler_t * elem,ipmi_mc_t * mc)592 send_sel_clear(sel_fetch_handler_t *elem, ipmi_mc_t *mc)
593 {
594 ipmi_sel_info_t *sel = elem->sel;
595 unsigned char cmd_data[MAX_IPMI_DATA_SIZE];
596 ipmi_msg_t cmd_msg;
597
598 cmd_msg.data = cmd_data;
599 cmd_msg.netfn = IPMI_STORAGE_NETFN;
600 cmd_msg.cmd = IPMI_CLEAR_SEL_CMD;
601 cmd_msg.data_len = 6;
602 ipmi_set_uint16(cmd_msg.data, sel->reservation);
603 cmd_msg.data[2] = 'C';
604 cmd_msg.data[3] = 'L';
605 cmd_msg.data[4] = 'R';
606 cmd_msg.data[5] = 0xaa;
607
608 return ipmi_mc_send_command(mc, sel->lun, &cmd_msg,
609 handle_sel_clear, elem);
610 }
611
612 static int start_fetch(void *cb_data, int shutdown);
613
614 static void
handle_sel_data(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)615 handle_sel_data(ipmi_mc_t *mc,
616 ipmi_msg_t *rsp,
617 void *rsp_data)
618 {
619 sel_fetch_handler_t *elem = rsp_data;
620 ipmi_sel_info_t *sel = elem->sel;
621 unsigned char cmd_data[MAX_IPMI_DATA_SIZE];
622 ipmi_msg_t cmd_msg;
623 int rv;
624 int event_is_new = 0;
625 ipmi_event_t *del_event;
626 unsigned int record_id;
627 ipmi_time_t timestamp;
628 sel_event_holder_t *holder;
629
630
631 sel_lock(sel);
632 if (sel->destroyed) {
633 ipmi_log(IPMI_LOG_ERR_INFO,
634 "%ssel.c(handle_sel_data): "
635 "SEL info was destroyed while an operation was in"
636 " progress(2)", sel->name);
637 fetch_complete(sel, ECANCELED, 1);
638 goto out;
639 }
640
641 if (!mc) {
642 ipmi_log(IPMI_LOG_ERR_INFO,
643 "%ssel.c(handle_sel_data): "
644 "handle_sel_data: MC went away while SEL op was in progress",
645 sel->name);
646 fetch_complete(sel, ECANCELED, 1);
647 goto out;
648 }
649
650 if (rsp->data[0] == IPMI_INVALID_RESERVATION_CC) {
651 /* We lost our reservation, restart the operation. Only do
652 this so many times, in order to guarantee that this
653 completes. Note that we do this so many times *per fetch*,
654 we do not reset the counter if we get a successful
655 operation. This is because if this happens a lot during a
656 fetch, there is heavy contention for the SEL and someone
657 needs to drop out to allow everyone else to continue. */
658 sel->fetch_retry_count++;
659 if (sel->sel_scan_lost_reservation)
660 ipmi_domain_stat_add(sel->sel_scan_lost_reservation, 1);
661 if (sel->fetch_retry_count > MAX_SEL_FETCH_RETRIES) {
662 if (sel->sel_fail_scan_lost_reservation)
663 ipmi_domain_stat_add(sel->sel_fail_scan_lost_reservation, 1);
664 ipmi_log(IPMI_LOG_ERR_INFO,
665 "%ssel.c(handle_sel_data): "
666 "Too many lost reservations in SEL fetch",
667 sel->name);
668 fetch_complete(sel, EAGAIN, 1);
669 goto out;
670 } else {
671 sel_unlock(sel);
672 start_fetch(elem, 0);
673 goto out;
674 }
675 }
676 if ((rsp->data[0] == 0) && (rsp->data_len < 19)) {
677 ipmi_log(IPMI_LOG_ERR_INFO,
678 "%ssel.c(handle_sel_data): "
679 "Received a short SEL data message",
680 sel->name);
681 fetch_complete(sel, EINVAL, 1);
682 goto out;
683 }
684
685 if ((rsp->data[0] != 0)
686 || ((sel->start_rec_id != 0) && (sel->start_rec_id == sel->curr_rec_id)
687 && (memcmp(sel->start_rec_id_data, rsp->data+5, 14) != 0)))
688 {
689 /* We got an error fetching the current id, or the current
690 id's data was for our "start" record and it doesn't match
691 the one we fetched, so it has changed. We have to start
692 over or handle the error. */
693 if (sel->start_rec_id != 0) {
694 /* If we get a fetch error and it is not a lost
695 reservation, it may be that another system deleted our
696 "current" record. Start over from the beginning of the
697 SEL. */
698 sel->start_rec_id = 0;
699 sel->curr_rec_id = 0;
700 del_event = NULL;
701 goto start_request_sel_data;
702 }
703 if (sel->sel_fetch_errors)
704 ipmi_domain_stat_add(sel->sel_fetch_errors, 1);
705 ipmi_log(IPMI_LOG_ERR_INFO,
706 "%ssel.c(handle_sel_data): "
707 "IPMI error from SEL fetch: %x",
708 sel->name, rsp->data[0]);
709 fetch_complete(sel, IPMI_IPMI_ERR_VAL(rsp->data[0]), 1);
710 goto out;
711 }
712
713 sel->next_rec_id = ipmi_get_uint16(rsp->data+1);
714
715 record_id = ipmi_get_uint16(rsp->data+3);
716
717 if (rsp->data[5] < 0xe0)
718 timestamp = ipmi_seconds_to_time(ipmi_get_uint32(rsp->data+6));
719 else
720 timestamp = -1;
721 del_event = ipmi_event_alloc(ipmi_mc_convert_to_id(mc),
722 record_id,
723 rsp->data[5],
724 timestamp,
725 rsp->data+6,
726 13);
727 if (!del_event) {
728 ipmi_log(IPMI_LOG_ERR_INFO,
729 "%ssel.c(handle_sel_data): "
730 "Could not allocate event for SEL",
731 sel->name);
732 fetch_complete(sel, ENOMEM, 1);
733 goto out;
734 }
735
736 if ((timestamp > 0) && (timestamp < ipmi_mc_get_startup_SEL_time(mc)))
737 ipmi_event_set_is_old(del_event, 1);
738
739 holder = find_event(sel->events, record_id);
740 if (!holder) {
741 holder = sel_event_holder_alloc();
742 if (!holder) {
743 ipmi_log(IPMI_LOG_ERR_INFO,
744 "%ssel.c(handle_sel_data): "
745 "Could not allocate log information for SEL",
746 sel->name);
747 fetch_complete(sel, ENOMEM, 1);
748 goto out;
749 }
750 if (!ilist_add_tail(sel->events, holder, NULL)) {
751 ipmi_mem_free(holder);
752 ipmi_log(IPMI_LOG_ERR_INFO,
753 "%ssel.c(handle_sel_data): "
754 "Could not link log onto the log linked list",
755 sel->name);
756 fetch_complete(sel, ENOMEM, 1);
757 goto out;
758 }
759 holder->event = del_event;
760 holder->deleted = 0;
761 event_is_new = 1;
762 sel->num_sels++;
763 if (sel->sel_received_events)
764 ipmi_domain_stat_add(sel->sel_received_events, 1);
765 } else if (event_cmp(del_event, holder->event) != 0) {
766 /* It's a new event in an old slot, so overwrite the old
767 event. */
768
769 ipmi_event_free(holder->event);
770 holder->event = del_event;
771 if (holder->deleted) {
772 holder->deleted = 0;
773 sel->num_sels++;
774 sel->del_sels--;
775 }
776 event_is_new = 1;
777 if (sel->sel_received_events)
778 ipmi_domain_stat_add(sel->sel_received_events, 1);
779 } else {
780 ipmi_event_free(del_event);
781 }
782
783 if (sel->next_rec_id == 0xFFFF) {
784 /* Only set the timestamps if the SEL fetch completed
785 successfully. If we were unsuccessful, we want to redo the
786 operation so don't set the timestamps. */
787 sel->last_addition_timestamp = sel->curr_addition_timestamp;
788 sel->last_erase_timestamp = sel->curr_erase_timestamp;
789
790 /* To avoid confusion, deliver the event before we deliver fetch
791 complete. */
792 if (event_is_new && sel->new_event_handler) {
793 ipmi_sel_new_event_handler_cb handler = sel->new_event_handler;
794 void *cb_data = sel->new_event_cb_data;
795 sel_unlock(sel);
796 handler(sel, mc, del_event, cb_data);
797 sel_lock(sel);
798 }
799
800 if (sel->sel_good_scans)
801 ipmi_domain_stat_add(sel->sel_good_scans, 1);
802
803 /* If the operation completed successfully and everything in
804 our SEL is deleted, then clear it with our old reservation.
805 We also do the clear if the overflow flag is set; on some
806 systems this operation clears the overflow flag. */
807 if ((sel->num_sels == 0)
808 && ((!ilist_empty(sel->events)) || sel->overflow))
809 {
810 /* We don't care if this fails, because it will just
811 happen again later if it does. */
812 rv = send_sel_clear(elem, mc);
813 if (rv) {
814 fetch_complete(sel, 0, 1);
815 goto out;
816 }
817 rv = 0;
818 goto out_unlock;
819 } else {
820 fetch_complete(sel, 0, 1);
821 goto out;
822 }
823 }
824 sel->start_rec_id = sel->curr_rec_id;
825 memcpy(sel->start_rec_id_data, rsp->data+5, 14);
826 sel->curr_rec_id = sel->next_rec_id;
827
828 start_request_sel_data:
829 /* Request some more data. */
830 cmd_msg.data = cmd_data;
831 cmd_msg.netfn = IPMI_STORAGE_NETFN;
832 cmd_msg.cmd = IPMI_GET_SEL_ENTRY_CMD;
833 cmd_msg.data_len = 6;
834 ipmi_set_uint16(cmd_msg.data, sel->reservation);
835 ipmi_set_uint16(cmd_msg.data+2, sel->curr_rec_id);
836 cmd_msg.data[4] = 0;
837 cmd_msg.data[5] = 0xff;
838 rv = ipmi_mc_send_command(mc, sel->lun, &cmd_msg, handle_sel_data, elem);
839 if (rv) {
840 ipmi_log(IPMI_LOG_ERR_INFO,
841 "%ssel.c(handle_sel_clear): "
842 "Could not send SEL fetch command: %x", sel->name, rv);
843 fetch_complete(sel, rv, 1);
844 goto out;
845 }
846
847 if (event_is_new && sel->new_event_handler) {
848 ipmi_sel_new_event_handler_cb handler = sel->new_event_handler;
849 void *cb_data = sel->new_event_cb_data;
850 sel_unlock(sel);
851 handler(sel, mc, del_event, cb_data);
852 sel_lock(sel);
853 }
854 out_unlock:
855 sel_unlock(sel);
856 out:
857 return;
858 }
859
860 /* Cheap hacks for broken hardware. */
861 static void
sel_fixups(ipmi_mc_t * mc,ipmi_sel_info_t * sel)862 sel_fixups(ipmi_mc_t *mc, ipmi_sel_info_t *sel)
863 {
864 unsigned int mfg_id, product_id;
865
866 /* Fixups */
867 mfg_id = ipmi_mc_manufacturer_id(mc);
868 product_id = ipmi_mc_product_id(mc);
869 if ((mfg_id == 0x157) && (product_id == 0x841))
870 /* Intel ATCA CMM mistakenly reports that it supports delete SEL */
871 sel->supports_delete_sel = 0;
872 }
873
874 static void
handle_sel_info(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)875 handle_sel_info(ipmi_mc_t *mc,
876 ipmi_msg_t *rsp,
877 void *rsp_data)
878 {
879 sel_fetch_handler_t *elem = rsp_data;
880 ipmi_sel_info_t *sel = elem->sel;
881 unsigned char cmd_data[MAX_IPMI_DATA_SIZE];
882 ipmi_msg_t cmd_msg;
883 int rv;
884 uint32_t add_timestamp;
885 uint32_t erase_timestamp;
886 int fetched_num_sels;
887
888 sel_lock(sel);
889 if (sel->destroyed) {
890 ipmi_log(IPMI_LOG_ERR_INFO,
891 "%ssel.c(handle_sel_info): "
892 "SEL info was destroyed while an operation was in progress",
893 sel->name);
894 fetch_complete(sel, ECANCELED, 1);
895 goto out;
896 }
897
898 if (!mc) {
899 ipmi_log(IPMI_LOG_ERR_INFO,
900 "%ssel.c(handle_sel_info): "
901 "MC went away while SEL op was in progress",
902 sel->name);
903 fetch_complete(sel, ECANCELED, 1);
904 goto out;
905 }
906
907 if (rsp->data[0] != 0) {
908 if (sel->sel_fetch_errors)
909 ipmi_domain_stat_add(sel->sel_fetch_errors, 1);
910 ipmi_log(IPMI_LOG_ERR_INFO,
911 "%ssel.c(handle_sel_info): "
912 "IPMI error from SEL info fetch: %x",
913 sel->name, rsp->data[0]);
914 fetch_complete(sel, IPMI_IPMI_ERR_VAL(rsp->data[0]), 1);
915 goto out;
916 }
917
918 if (rsp->data_len < 15) {
919 if (sel->sel_fetch_errors)
920 ipmi_domain_stat_add(sel->sel_fetch_errors, 1);
921 ipmi_log(IPMI_LOG_ERR_INFO,
922 "%ssel.c(handle_sel_info): SEL info too short", sel->name);
923 fetch_complete(sel, EINVAL, 1);
924 goto out;
925 }
926
927 /* Pull pertinant info from the response. */
928 sel->major_version = rsp->data[1] & 0xf;
929 sel->minor_version = (rsp->data[1] >> 4) & 0xf;
930 fetched_num_sels = ipmi_get_uint16(rsp->data+2);
931 sel->entries = fetched_num_sels;
932 sel->free_bytes = ipmi_get_uint16(rsp->data+4);
933 sel->overflow = (rsp->data[14] & 0x80) == 0x80;
934 sel->supports_delete_sel = (rsp->data[14] & 0x08) == 0x08;
935 sel->supports_partial_add_sel = (rsp->data[14] & 0x04) == 0x04;
936 sel->supports_reserve_sel = (rsp->data[14] & 0x02) == 0x02;
937 sel->supports_get_sel_allocation = (rsp->data[14] & 0x01) == 0x01;
938
939 add_timestamp = ipmi_get_uint32(rsp->data + 6);
940 erase_timestamp = ipmi_get_uint32(rsp->data + 10);
941
942 sel_fixups(mc, sel);
943
944 /* If the timestamps still match, no need to re-fetch the
945 repository. Note that we only check the add timestamp. We
946 don't care if things were deleted. */
947 if (sel->fetched && (add_timestamp == sel->last_addition_timestamp)) {
948 /* If the operation completed successfully and everything in
949 our SEL is deleted, then clear it with our old reservation.
950 We also do the clear if the overflow flag is set; on some
951 systems this operation clears the overflow flag. */
952 if ((sel->num_sels == 0)
953 && ((!ilist_empty(sel->events)) || sel->overflow))
954 {
955 /* We don't care if this fails, because it will just
956 happen again later if it does. */
957 rv = send_sel_clear(elem, mc);
958 if (rv) {
959 fetch_complete(sel, 0, 1);
960 goto out;
961 }
962 goto out_unlock;
963 } else {
964 fetch_complete(sel, 0, 1);
965 goto out;
966 }
967 }
968
969 sel->curr_addition_timestamp = add_timestamp;
970 sel->curr_erase_timestamp = erase_timestamp;
971
972 sel->sels_changed = 1;
973 sel->next_rec_id = 0;
974
975 if (fetched_num_sels == 0) {
976 /* No sels, so there's nothing to do. */
977
978 /* Set the timestamps here, because they are not the same, but
979 there was nothing to do. */
980 sel->last_addition_timestamp = sel->curr_addition_timestamp;
981 sel->last_erase_timestamp = sel->curr_erase_timestamp;
982 sel->start_rec_id = 0;
983 sel->curr_rec_id = 0;
984
985 fetch_complete(sel, 0, 1);
986 goto out;
987 }
988
989 /* Fetch the first SEL entry. */
990 sel->curr_rec_id = sel->start_rec_id;
991 cmd_msg.data = cmd_data;
992 cmd_msg.netfn = IPMI_STORAGE_NETFN;
993 cmd_msg.cmd = IPMI_GET_SEL_ENTRY_CMD;
994 cmd_msg.data_len = 6;
995 ipmi_set_uint16(cmd_msg.data, sel->reservation);
996 ipmi_set_uint16(cmd_msg.data+2, sel->curr_rec_id);
997 cmd_msg.data[4] = 0;
998 cmd_msg.data[5] = 0xff;
999 rv = ipmi_mc_send_command(mc, sel->lun, &cmd_msg, handle_sel_data, elem);
1000 if (rv) {
1001 ipmi_log(IPMI_LOG_ERR_INFO,
1002 "%ssel.c(handle_sel_info): "
1003 "Could not send first SEL fetch command: %x",
1004 sel->name, rv);
1005 fetch_complete(sel, rv, 1);
1006 goto out;
1007 }
1008 out_unlock:
1009 sel_unlock(sel);
1010 out:
1011 return;
1012 }
1013
1014 static int
send_get_sel_info(sel_fetch_handler_t * elem,ipmi_mc_t * mc)1015 send_get_sel_info(sel_fetch_handler_t *elem, ipmi_mc_t *mc)
1016 {
1017 ipmi_sel_info_t *sel = elem->sel;
1018 ipmi_msg_t cmd_msg;
1019
1020 /* Fetch the repository info. */
1021 cmd_msg.netfn = IPMI_STORAGE_NETFN;
1022 cmd_msg.cmd = IPMI_GET_SEL_INFO_CMD;
1023 cmd_msg.data = NULL;
1024 cmd_msg.data_len = 0;
1025 return ipmi_mc_send_command(mc, sel->lun, &cmd_msg, handle_sel_info, elem);
1026 }
1027
1028 static void
sel_handle_reservation(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)1029 sel_handle_reservation(ipmi_mc_t *mc,
1030 ipmi_msg_t *rsp,
1031 void *rsp_data)
1032 {
1033 sel_fetch_handler_t *elem = rsp_data;
1034 ipmi_sel_info_t *sel = elem->sel;
1035 int rv;
1036
1037 sel_lock(sel);
1038 if (sel->destroyed) {
1039 ipmi_log(IPMI_LOG_ERR_INFO,
1040 "%ssel.c(sel_handle_reservation): "
1041 "SEL info was destroyed while an operation was in progress",
1042 sel->name);
1043 fetch_complete(sel, ECANCELED, 1);
1044 goto out;
1045 }
1046
1047 if (!mc) {
1048 ipmi_log(IPMI_LOG_ERR_INFO,
1049 "%ssel.c(sel_handle_reservation): "
1050 "MC went away while SEL op was in progress",
1051 sel->name);
1052 fetch_complete(sel, ECANCELED, 1);
1053 goto out;
1054 }
1055
1056 if (rsp->data[0] != 0) {
1057 if (sel->sel_fetch_errors)
1058 ipmi_domain_stat_add(sel->sel_fetch_errors, 1);
1059 ipmi_log(IPMI_LOG_ERR_INFO,
1060 "%ssel.c(sel_handle_reservation): "
1061 "Failed getting reservation", sel->name);
1062 fetch_complete(sel, ENOSYS, 1);
1063 goto out;
1064 } else if (rsp->data_len < 3) {
1065 if (sel->sel_fetch_errors)
1066 ipmi_domain_stat_add(sel->sel_fetch_errors, 1);
1067 ipmi_log(IPMI_LOG_ERR_INFO,
1068 "%ssel.c(sel_handle_reservation): "
1069 "got invalid reservation length", sel->name);
1070 fetch_complete(sel, EINVAL, 1);
1071 goto out;
1072 }
1073
1074 sel->reservation = ipmi_get_uint16(rsp->data+1);
1075
1076 rv = send_get_sel_info(elem, mc);
1077 if (rv) {
1078 ipmi_log(IPMI_LOG_ERR_INFO,
1079 "%ssel.c(sel_handle_reservation): "
1080 "Could not send SEL info command: %x", sel->name, rv);
1081 fetch_complete(sel, rv, 1);
1082 goto out;
1083 }
1084 sel_unlock(sel);
1085 out:
1086 return;
1087 }
1088
1089 static void
start_fetch_cb(ipmi_mc_t * mc,void * cb_data)1090 start_fetch_cb(ipmi_mc_t *mc, void *cb_data)
1091 {
1092 sel_fetch_handler_t *elem = cb_data;
1093 ipmi_sel_info_t *sel = elem->sel;
1094 unsigned char cmd_data[MAX_IPMI_DATA_SIZE];
1095 ipmi_msg_t cmd_msg;
1096 int rv;
1097
1098 if (sel->destroyed) {
1099 ipmi_log(IPMI_LOG_ERR_INFO,
1100 "%ssel.c(start_fetch_cb): "
1101 "SEL info was destroyed while an operation was in progress",
1102 sel->name);
1103 elem->rv = ECANCELED;
1104 goto out;
1105 }
1106
1107 if (sel->supports_reserve_sel) {
1108 /* Get a reservation first. */
1109 cmd_msg.data = cmd_data;
1110 cmd_msg.netfn = IPMI_STORAGE_NETFN;
1111 cmd_msg.cmd = IPMI_RESERVE_SEL_CMD;
1112 cmd_msg.data_len = 0;
1113 rv = ipmi_mc_send_command_sideeff(mc, sel->lun, &cmd_msg,
1114 sel_handle_reservation, elem);
1115 } else {
1116 /* Bypass the reservation, it's not supported. */
1117 sel->reservation = 0;
1118
1119 /* Fetch the repository info. */
1120 cmd_msg.data = cmd_data;
1121 cmd_msg.netfn = IPMI_STORAGE_NETFN;
1122 cmd_msg.cmd = IPMI_GET_SEL_INFO_CMD;
1123 cmd_msg.data_len = 0;
1124 rv = ipmi_mc_send_command(mc, sel->lun,
1125 &cmd_msg, handle_sel_info, elem);
1126 }
1127
1128 if (rv) {
1129 ipmi_log(IPMI_LOG_ERR_INFO,
1130 "%ssel.c(start_fetch_cb): could not send cmd: %x",
1131 sel->name, rv);
1132 elem->rv = rv;
1133 goto out;
1134 }
1135
1136 out:
1137 return;
1138 }
1139
1140 static int
start_fetch(void * cb_data,int shutdown)1141 start_fetch(void *cb_data, int shutdown)
1142 {
1143 sel_fetch_handler_t *elem = cb_data;
1144 int rv;
1145
1146 sel_lock(elem->sel);
1147 if (shutdown) {
1148 ipmi_log(IPMI_LOG_ERR_INFO,
1149 "%ssel.c(start_fetch): "
1150 "SEL info was destroyed while an operation was in progress",
1151 elem->sel->name);
1152 fetch_complete(elem->sel, ECANCELED, 0);
1153 return OPQ_HANDLER_ABORTED;
1154 }
1155
1156 /* The read lock must be claimed before the sel lock to avoid
1157 deadlock. */
1158 rv = ipmi_mc_pointer_cb(elem->sel->mc, start_fetch_cb, elem);
1159 if (rv)
1160 ipmi_log(IPMI_LOG_ERR_INFO,
1161 "%ssel.c(start_fetch): MC is not valid", elem->sel->name);
1162 else
1163 rv = elem->rv;
1164
1165 if (rv) {
1166 fetch_complete(elem->sel, rv, 0);
1167 return OPQ_HANDLER_ABORTED;
1168 }
1169
1170 sel_unlock(elem->sel);
1171
1172 return OPQ_HANDLER_STARTED;
1173 }
1174
1175 /* We have to have this because the allocate element can go away (the
1176 operation can complete) before returning to the user. */
1177 typedef struct sel_get_cb_s
1178 {
1179 sel_fetch_handler_t *elem;
1180 int rv;
1181 } sel_get_cb_t;
1182
1183 static void
ipmi_sel_get_cb(ipmi_mc_t * mc,void * cb_data)1184 ipmi_sel_get_cb(ipmi_mc_t *mc, void *cb_data)
1185 {
1186 sel_get_cb_t *info = cb_data;
1187 sel_fetch_handler_t *elem = info->elem;
1188 ipmi_sel_info_t *sel = elem->sel;
1189
1190 if (!ipmi_mc_sel_device_support(mc)) {
1191 ipmi_log(IPMI_LOG_ERR_INFO,
1192 "%ssel.c(ipmi_sel_get_cb): "
1193 "No support for the system event log", sel->name);
1194 info->rv = ENOSYS;
1195 return;
1196 }
1197
1198 sel_lock(sel);
1199 if (! sel->in_fetch) {
1200 /* If we are not currently fetching sels, then start the
1201 process. If we are already fetching sels, then the current
1202 fetch process will handle it. */
1203 sel->fetch_retry_count = 0;
1204 sel->in_fetch = 1;
1205 sel->sels_changed = 0;
1206
1207 elem->next = NULL;
1208 sel->fetch_handlers = elem;
1209 sel_unlock(sel);
1210 /* Always put a fetch ahead of everything else. If there are
1211 deletes in progress and a clear gets done, we can complete
1212 all the deletes. */
1213 if (!opq_new_op_prio(sel->opq, start_fetch, elem, 0, OPQ_ADD_HEAD,
1214 NULL))
1215 {
1216 sel->fetch_handlers = NULL;
1217 info->rv = ENOMEM;
1218 }
1219 goto out;
1220 } else if (elem->handler) {
1221 /* Add it to the list of waiting fetch handlers, if it has a
1222 handler. */
1223 elem->next = sel->fetch_handlers;
1224 sel->fetch_handlers = elem;
1225 } else {
1226 /* No handler and fetch was already in progress. Return an
1227 error so the caller knows what happened. */
1228 info->rv = EEXIST;
1229 }
1230
1231 sel_unlock(sel);
1232 out:
1233 return;
1234 }
1235
1236 int
ipmi_sel_get(ipmi_sel_info_t * sel,ipmi_sels_fetched_t handler,void * cb_data)1237 ipmi_sel_get(ipmi_sel_info_t *sel,
1238 ipmi_sels_fetched_t handler,
1239 void *cb_data)
1240 {
1241 sel_get_cb_t info;
1242 sel_fetch_handler_t *elem;
1243 int rv;
1244
1245 elem = ipmi_mem_alloc(sizeof(*elem));
1246 if (!elem) {
1247 ipmi_log(IPMI_LOG_ERR_INFO,
1248 "%ssel.c(ipmi_sel_get): "
1249 "could not allocate the sel element", sel->name);
1250 return ENOMEM;
1251 }
1252
1253 elem->handler = handler;
1254 elem->cb_data = cb_data;
1255 elem->sel = sel;
1256 elem->rv = 0;
1257 info.elem = elem;
1258 info.rv = 0;
1259
1260 rv = ipmi_mc_pointer_cb(sel->mc, ipmi_sel_get_cb, &info);
1261 if (!rv)
1262 rv = info.rv;
1263 if (rv)
1264 ipmi_mem_free(elem);
1265 if (rv == EEXIST)
1266 /* EEXIST means that a operation was already running, and no
1267 handler was given. We want to free the element, but we
1268 still want to return success. */
1269 rv = 0;
1270
1271 return rv;
1272 }
1273
1274 /* Don't do this forever. */
1275 #define MAX_DEL_RESERVE_RETRIES 10
1276
1277 typedef struct sel_del_handler_data_s
1278 {
1279 ipmi_sel_info_t *sel;
1280 ipmi_sel_op_done_cb_t handler;
1281 void *cb_data;
1282 unsigned int reservation;
1283 unsigned int record_id;
1284 unsigned int lun;
1285 unsigned int count;
1286 ipmi_event_t *event;
1287 sel_event_holder_t *holder;
1288
1289 /* If true, we do a clear operation if the given record is the
1290 last record in the SEL. */
1291 int do_clear;
1292 } sel_del_handler_data_t;
1293
1294 static int send_reserve_sel_for_delete(sel_del_handler_data_t *data,
1295 ipmi_mc_t *mc);
1296
1297 static void
sel_op_done(sel_del_handler_data_t * data,int rv,int do_op_done)1298 sel_op_done(sel_del_handler_data_t *data,
1299 int rv,
1300 int do_op_done)
1301 {
1302 ipmi_sel_info_t *sel = data->sel;
1303
1304 if (data->holder)
1305 sel_event_holder_put(data->holder);
1306
1307 sel_unlock(sel);
1308
1309 if (data->handler)
1310 data->handler(sel, data->cb_data, rv);
1311
1312 sel_lock(sel);
1313
1314 if (sel->in_destroy) {
1315 /* Nothing to do */
1316 sel_unlock(sel);
1317 } else if (sel->destroyed) {
1318 /* This will unlock the lock. */
1319 internal_destroy_sel(sel);
1320 } else {
1321 sel_unlock(sel);
1322 if (do_op_done)
1323 opq_op_done(sel->opq);
1324 }
1325 if (data->event)
1326 ipmi_event_free(data->event);
1327 ipmi_mem_free(data);
1328 }
1329
1330 static void
free_all_event(ilist_iter_t * iter,void * item,void * cb_data)1331 free_all_event(ilist_iter_t *iter, void *item, void *cb_data)
1332 {
1333 sel_event_holder_t *holder = item;
1334 ipmi_sel_info_t *sel = cb_data;
1335
1336 if (holder->deleted) {
1337 sel->del_sels--;
1338 holder->cancelled = 1;
1339 }
1340 ilist_delete(iter);
1341 sel_event_holder_put(holder);
1342 }
1343
1344 static void
free_all_events(ipmi_sel_info_t * sel)1345 free_all_events(ipmi_sel_info_t *sel)
1346 {
1347 ilist_iter(sel->events, free_all_event, sel);
1348 }
1349
1350 static void
handle_del_sel_clear(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)1351 handle_del_sel_clear(ipmi_mc_t *mc,
1352 ipmi_msg_t *rsp,
1353 void *rsp_data)
1354 {
1355 sel_del_handler_data_t *data = rsp_data;
1356 ipmi_sel_info_t *sel = data->sel;
1357
1358 sel_lock(sel);
1359 if (sel->destroyed) {
1360 ipmi_log(IPMI_LOG_ERR_INFO,
1361 "%ssel.c(handle_del_sel_clear): "
1362 "SEL info was destroyed while an operation was in progress",
1363 sel->name);
1364 sel_op_done(data, ECANCELED, 1);
1365 goto out;
1366 }
1367
1368 if (!mc) {
1369 ipmi_log(IPMI_LOG_ERR_INFO,
1370 "%ssel.c(handle_del_sel_clear): "
1371 "MC went away while SEL fetch was in progress",
1372 sel->name);
1373 sel_op_done(data, ECANCELED, 1);
1374 goto out;
1375 }
1376
1377 if (rsp->data[0]) {
1378 ipmi_log(IPMI_LOG_ERR_INFO,
1379 "%ssel.c(handle_del_sel_clear): "
1380 "IPMI error clearing SEL: 0x%x",
1381 sel->name, rsp->data[0]);
1382 sel_op_done(data, IPMI_IPMI_ERR_VAL(rsp->data[0]), 1);
1383 goto out;
1384 }
1385
1386 free_all_events(sel);
1387 sel->num_sels = 0;
1388
1389 sel_op_done(data, 0, 1);
1390
1391 out:
1392 return;
1393 }
1394
1395 static int
send_del_clear(sel_del_handler_data_t * data,ipmi_mc_t * mc)1396 send_del_clear(sel_del_handler_data_t *data, ipmi_mc_t *mc)
1397 {
1398 ipmi_sel_info_t *sel = data->sel;
1399 unsigned char cmd_data[MAX_IPMI_DATA_SIZE];
1400 ipmi_msg_t cmd_msg;
1401
1402 cmd_msg.data = cmd_data;
1403 cmd_msg.netfn = IPMI_STORAGE_NETFN;
1404 cmd_msg.cmd = IPMI_CLEAR_SEL_CMD;
1405 cmd_msg.data_len = 6;
1406 ipmi_set_uint16(cmd_msg.data, data->reservation);
1407 cmd_msg.data[2] = 'C';
1408 cmd_msg.data[3] = 'L';
1409 cmd_msg.data[4] = 'R';
1410 cmd_msg.data[5] = 0xaa;
1411
1412 return ipmi_mc_send_command(mc, sel->lun, &cmd_msg,
1413 handle_del_sel_clear, data);
1414 }
1415
1416 static void
handle_sel_delete(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)1417 handle_sel_delete(ipmi_mc_t *mc,
1418 ipmi_msg_t *rsp,
1419 void *rsp_data)
1420 {
1421 sel_del_handler_data_t *data = rsp_data;
1422 ipmi_sel_info_t *sel = data->sel;
1423 int rv = 0;
1424
1425 sel_lock(sel);
1426 if (sel->destroyed) {
1427 ipmi_log(IPMI_LOG_ERR_INFO,
1428 "%ssel.c(handle_sel_delete): "
1429 "SEL info was destroyed while an operation was in progress",
1430 sel->name);
1431 sel_op_done(data, ECANCELED, 1);
1432 goto out;
1433 }
1434
1435 if (!mc) {
1436 ipmi_log(IPMI_LOG_ERR_INFO,
1437 "%ssel.c(handle_sel_delete): "
1438 "MC went away while SEL fetch was in progress",
1439 sel->name);
1440 sel_op_done(data, ECANCELED, 1);
1441 goto out;
1442 }
1443
1444 /* Special return codes. */
1445 if (rsp->data[0] == 0x80) {
1446 ipmi_log(IPMI_LOG_ERR_INFO,
1447 "%ssel.c(handle_sel_delete): "
1448 "Operation not supported on SEL delete",
1449 sel->name);
1450 rv = ENOSYS;
1451 } else if (rsp->data[0] == 0x81) {
1452 /* The SEL is being erased, so by definition the log will be
1453 gone. */
1454 rv = 0;
1455 } else if (rsp->data[0] == IPMI_NOT_PRESENT_CC) {
1456 /* The entry is already gone, so just return no error. */
1457 rv = 0;
1458 } else if ((data->count < MAX_DEL_RESERVE_RETRIES)
1459 && (rsp->data[0] == IPMI_INVALID_RESERVATION_CC))
1460 {
1461 if (sel->sel_delete_lost_reservation)
1462 ipmi_domain_stat_add(sel->sel_delete_lost_reservation, 1);
1463 /* Lost our reservation, retry the operation. */
1464 data->count++;
1465 rv = send_reserve_sel_for_delete(data, mc);
1466 if (!rv)
1467 goto out_unlock;
1468 } else if (rsp->data[0]) {
1469 if (rsp->data[0] == IPMI_INVALID_RESERVATION_CC) {
1470 if (sel->sel_fail_delete_lost_reservation)
1471 ipmi_domain_stat_add(sel->sel_fail_delete_lost_reservation, 1);
1472 } else {
1473 if (sel->sel_delete_errors)
1474 ipmi_domain_stat_add(sel->sel_delete_errors, 1);
1475 }
1476 ipmi_log(IPMI_LOG_ERR_INFO,
1477 "%ssel.c(handle_sel_delete): "
1478 "IPMI error from SEL delete: %x", sel->name, rsp->data[0]);
1479 rv = IPMI_IPMI_ERR_VAL(rsp->data[0]);
1480 } else {
1481 /* We deleted the entry, so remove it from our database. */
1482 sel_event_holder_t *real_holder;
1483 ilist_iter_t iter;
1484
1485 ilist_init_iter(&iter, sel->events);
1486 ilist_unpositioned(&iter);
1487 real_holder = ilist_search_iter(&iter, recid_search_cmp,
1488 &(data->record_id));
1489 if (real_holder) {
1490 ilist_delete(&iter);
1491 sel_event_holder_put(real_holder);
1492 sel->del_sels--;
1493 }
1494 }
1495
1496 sel_op_done(data, rv, 1);
1497
1498 out:
1499 return;
1500
1501 out_unlock:
1502 sel_unlock(sel);
1503 }
1504
1505 static int
send_del_sel(sel_del_handler_data_t * data,ipmi_mc_t * mc)1506 send_del_sel(sel_del_handler_data_t *data, ipmi_mc_t *mc)
1507 {
1508 unsigned char cmd_data[MAX_IPMI_DATA_SIZE];
1509 ipmi_msg_t cmd_msg;
1510 int rv;
1511
1512 cmd_msg.data = cmd_data;
1513 cmd_msg.netfn = IPMI_STORAGE_NETFN;
1514 cmd_msg.cmd = IPMI_DELETE_SEL_ENTRY_CMD;
1515 cmd_msg.data_len = 4;
1516 ipmi_set_uint16(cmd_msg.data, data->reservation);
1517 ipmi_set_uint16(cmd_msg.data+2, data->record_id);
1518 rv = ipmi_mc_send_command(mc, data->lun,
1519 &cmd_msg, handle_sel_delete, data);
1520
1521 return rv;
1522 }
1523
1524 static void
handle_sel_check(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)1525 handle_sel_check(ipmi_mc_t *mc,
1526 ipmi_msg_t *rsp,
1527 void *rsp_data)
1528 {
1529 sel_del_handler_data_t *data = rsp_data;
1530 ipmi_sel_info_t *sel = data->sel;
1531 int rv = 0;
1532
1533 sel_lock(sel);
1534 if (sel->destroyed) {
1535 ipmi_log(IPMI_LOG_ERR_INFO,
1536 "%ssel.c(handle_sel_check): "
1537 "SEL info was destroyed while SEL delete element was in"
1538 " progress",
1539 sel->name);
1540 sel_op_done(data, ECANCELED, 1);
1541 goto out;
1542 }
1543
1544 if (!mc) {
1545 ipmi_log(IPMI_LOG_ERR_INFO,
1546 "%ssel.c(handle_sel_check): "
1547 "MC went away while SEL delete element was in progress",
1548 sel->name);
1549 sel_op_done(data, ECANCELED, 1);
1550 goto out;
1551 }
1552
1553 /* Special return codes. */
1554 if (rsp->data[0] == IPMI_NOT_PRESENT_CC) {
1555 /* The entry is already gone, so just return no error. */
1556 sel_op_done(data, 0, 1);
1557 goto out;
1558 } else if (rsp->data[0]) {
1559 if (sel->sel_delete_errors)
1560 ipmi_domain_stat_add(sel->sel_delete_errors, 1);
1561 ipmi_log(IPMI_LOG_ERR_INFO,
1562 "%ssel.c(handle_sel_check): IPMI error from SEL check: %x",
1563 sel->name, rsp->data[0]);
1564 sel_op_done(data, IPMI_IPMI_ERR_VAL(rsp->data[0]), 1);
1565 goto out;
1566 } else {
1567 ipmi_event_t *ch_event;
1568 ipmi_time_t timestamp;
1569
1570 if (rsp->data[5] < 0xe0)
1571 timestamp = ipmi_get_uint32(rsp->data+6);
1572 else
1573 timestamp = -1;
1574 ch_event = ipmi_event_alloc(ipmi_mc_convert_to_id(mc),
1575 ipmi_get_uint16(rsp->data+3),
1576 rsp->data[5],
1577 timestamp,
1578 rsp->data+6,
1579 13);
1580 if (!ch_event) {
1581 ipmi_log(IPMI_LOG_ERR_INFO,
1582 "%ssel.c(handle_sel_check): Could not allocate memory",
1583 sel->name);
1584 sel_op_done(data, ENOMEM, 1);
1585 goto out;
1586 }
1587
1588 if (data->event && (event_cmp(ch_event, data->event) != 0)) {
1589 /* The event's don't match, so just finish. */
1590 ipmi_event_free(ch_event);
1591 sel_op_done(data, 0, 1);
1592 goto out;
1593 }
1594 ipmi_event_free(ch_event);
1595
1596 if (data->do_clear) {
1597 /* Make sure that there is no next event. */
1598 uint16_t next_ev = ipmi_get_uint16(rsp->data+1);
1599
1600 if (next_ev != 0xffff) {
1601 /* A new event was added after this one. Fail the op. */
1602 ipmi_log(IPMI_LOG_ERR_INFO,
1603 "%ssel.c(handle_sel_check): "
1604 "Clear SEL failed, new events in SEL",
1605 sel->name);
1606 sel_op_done(data, EAGAIN, 1);
1607 goto out;
1608 }
1609
1610 rv = send_del_clear(data, mc);
1611 if (rv) {
1612 ipmi_log(IPMI_LOG_ERR_INFO,
1613 "%ssel.c(handle_sel_check): "
1614 "Could not send SEL clear command: %x",
1615 sel->name, rv);
1616 sel_op_done(data, rv, 1);
1617 goto out;
1618 }
1619 } else {
1620 rv = send_del_sel(data, mc);
1621 if (rv) {
1622 ipmi_log(IPMI_LOG_ERR_INFO,
1623 "%ssel.c(handle_sel_check): "
1624 "Could not send SEL delete command: %x",
1625 sel->name, rv);
1626 sel_op_done(data, rv, 1);
1627 goto out;
1628 } else if (data->record_id == sel->start_rec_id)
1629 /* We are deleting our "current" record (used for finding
1630 the next record), make sure we start again from
1631 scratch on the next fetch. */
1632 sel->start_rec_id = 0;
1633 }
1634 }
1635
1636
1637 sel_unlock(sel);
1638
1639 out:
1640 return;
1641 }
1642
1643 /* First get the entry, to make sure we are deleting the right one. */
1644 static int
send_check_sel(sel_del_handler_data_t * data,ipmi_mc_t * mc)1645 send_check_sel(sel_del_handler_data_t *data, ipmi_mc_t *mc)
1646 {
1647 unsigned char cmd_data[MAX_IPMI_DATA_SIZE];
1648 ipmi_msg_t cmd_msg;
1649 int rv;
1650
1651 cmd_msg.data = cmd_data;
1652 cmd_msg.netfn = IPMI_STORAGE_NETFN;
1653 cmd_msg.cmd = IPMI_GET_SEL_ENTRY_CMD;
1654 cmd_msg.data_len = 6;
1655 ipmi_set_uint16(cmd_msg.data, 0);
1656 ipmi_set_uint16(cmd_msg.data+2, data->record_id);
1657 cmd_msg.data[4] = 0;
1658 cmd_msg.data[5] = 0xff;
1659 rv = ipmi_mc_send_command(mc, data->lun,
1660 &cmd_msg, handle_sel_check, data);
1661
1662 return rv;
1663 }
1664
1665 static void
sel_reserved_for_delete(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)1666 sel_reserved_for_delete(ipmi_mc_t *mc,
1667 ipmi_msg_t *rsp,
1668 void *rsp_data)
1669 {
1670 sel_del_handler_data_t *data = rsp_data;
1671 ipmi_sel_info_t *sel = data->sel;
1672 int rv;
1673
1674 sel_lock(sel);
1675 if (sel->destroyed) {
1676 ipmi_log(IPMI_LOG_ERR_INFO,
1677 "%ssel.c(sel_reserved_for_delete): "
1678 "SEL info was destroyed while SEL delete element was in"
1679 " progress",
1680 sel->name);
1681 sel_op_done(data, ECANCELED, 1);
1682 goto out;
1683 }
1684 if (!mc) {
1685 ipmi_log(IPMI_LOG_ERR_INFO,
1686 "%ssel.c(sel_reserved_for_delete): "
1687 "MC went away while SEL delete element was in progress",
1688 sel->name);
1689 sel_op_done(data, ECANCELED, 1);
1690 goto out;
1691 }
1692
1693 if (rsp->data[0] != 0) {
1694 if (sel->sel_delete_errors)
1695 ipmi_domain_stat_add(sel->sel_delete_errors, 1);
1696 ipmi_log(IPMI_LOG_ERR_INFO,
1697 "%ssel.c(sel_reserved_for_delete): "
1698 "IPMI error from SEL delete reservation: %x",
1699 sel->name, rsp->data[0]);
1700 sel_op_done(data, IPMI_IPMI_ERR_VAL(rsp->data[0]), 1);
1701 goto out;
1702 }
1703
1704 data->reservation = ipmi_get_uint16(rsp->data+1);
1705 if (!data->do_clear || data->event) {
1706 rv = send_check_sel(data, mc);
1707 if (rv) {
1708 ipmi_log(IPMI_LOG_ERR_INFO,
1709 "%ssel.c(sel_reserved_for_delete): "
1710 "Could not send SEL get command: %x", sel->name, rv);
1711 sel_op_done(data, rv, 1);
1712 goto out;
1713 }
1714 } else {
1715 /* We are clearing the SEL and the user didn't supply an
1716 event. Don't worry about checking anything. */
1717 rv = send_del_clear(data, mc);
1718 if (rv) {
1719 ipmi_log(IPMI_LOG_ERR_INFO,
1720 "%ssel.c(sel_reserved_for_delete): "
1721 "Could not send SEL clear command: %x", sel->name, rv);
1722 sel_op_done(data, rv, 1);
1723 goto out;
1724 }
1725 }
1726
1727 sel_unlock(sel);
1728 out:
1729 return;
1730 }
1731
1732 static int
send_reserve_sel_for_delete(sel_del_handler_data_t * data,ipmi_mc_t * mc)1733 send_reserve_sel_for_delete(sel_del_handler_data_t *data, ipmi_mc_t *mc)
1734 {
1735 unsigned char cmd_data[MAX_IPMI_DATA_SIZE];
1736 ipmi_msg_t cmd_msg;
1737 int rv;
1738
1739 cmd_msg.data = cmd_data;
1740 cmd_msg.netfn = IPMI_STORAGE_NETFN;
1741 cmd_msg.cmd = IPMI_RESERVE_SEL_CMD;
1742 cmd_msg.data_len = 0;
1743 rv = ipmi_mc_send_command_sideeff(mc, data->lun,
1744 &cmd_msg, sel_reserved_for_delete, data);
1745
1746 return rv;
1747 }
1748
1749 static void
start_del_sel_cb(ipmi_mc_t * mc,void * cb_data)1750 start_del_sel_cb(ipmi_mc_t *mc, void *cb_data)
1751 {
1752 sel_del_handler_data_t *data = cb_data;
1753 ipmi_sel_info_t *sel = data->sel;
1754 int rv;
1755
1756 /* Called with SEL lock held. */
1757 if (sel->destroyed) {
1758 ipmi_log(IPMI_LOG_ERR_INFO,
1759 "%ssel.c(start_del_sel_cb): "
1760 "SEL info was destroyed while an operation was in progress",
1761 sel->name);
1762 sel_op_done(data, ECANCELED, 1);
1763 goto out;
1764 }
1765
1766 if (data->sel->supports_reserve_sel)
1767 rv = send_reserve_sel_for_delete(data, mc);
1768 else
1769 rv = send_check_sel(data, mc);
1770
1771 if (rv) {
1772 ipmi_log(IPMI_LOG_ERR_INFO,
1773 "%ssel.c(start_del_sel_cb): could not send cmd: %x",
1774 sel->name, rv);
1775 sel_op_done(data, rv, 1);
1776 goto out;
1777 }
1778
1779 sel_unlock(sel);
1780 out:
1781 return;
1782 }
1783
1784 static int
start_del_sel(void * cb_data,int shutdown)1785 start_del_sel(void *cb_data, int shutdown)
1786 {
1787 sel_del_handler_data_t *data = cb_data;
1788 ipmi_sel_info_t *sel = data->sel;
1789 int rv;
1790
1791 sel_lock(sel);
1792 if (shutdown) {
1793 ipmi_log(IPMI_LOG_ERR_INFO,
1794 "%ssel.c(start_del_sel): "
1795 "SEL info was destroyed while an operation was in progress",
1796 sel->name);
1797 sel_op_done(data, ECANCELED, 0);
1798 return OPQ_HANDLER_ABORTED;
1799 }
1800
1801 if (data->holder && data->holder->cancelled) {
1802 /* Deleted by a clear, everything is ok. */
1803 sel_op_done(data, 0, 0);
1804 return OPQ_HANDLER_ABORTED;
1805 }
1806
1807 rv = ipmi_mc_pointer_cb(sel->mc, start_del_sel_cb, data);
1808 if (rv) {
1809 ipmi_log(IPMI_LOG_ERR_INFO,
1810 "%ssel.c(start_del_sel_cb): MC went away during delete",
1811 sel->name);
1812 sel_op_done(data, ECANCELED, 0);
1813 return OPQ_HANDLER_ABORTED;
1814 }
1815
1816 return OPQ_HANDLER_STARTED;
1817 }
1818
1819 typedef struct sel_del_event_info_s
1820 {
1821 ipmi_sel_info_t *sel;
1822 ipmi_event_t *event;
1823 unsigned int record_id;
1824 ipmi_sel_op_done_cb_t handler;
1825 void *cb_data;
1826 int cmp_event;
1827 int rv;
1828 int do_clear;
1829 } sel_del_event_info_t;
1830
1831 static void
sel_del_event_cb(ipmi_mc_t * mc,void * cb_data)1832 sel_del_event_cb(ipmi_mc_t *mc, void *cb_data)
1833 {
1834 sel_del_event_info_t *info = cb_data;
1835 ipmi_sel_info_t *sel = info->sel;
1836 ipmi_event_t *event = info->event;
1837 int cmp_event = info->cmp_event;
1838 sel_event_holder_t *real_holder = NULL;
1839 ilist_iter_t iter;
1840 int start_fetch = 0;
1841
1842 sel_lock(sel);
1843 if (sel->destroyed) {
1844 info->rv = EINVAL;
1845 goto out_unlock;
1846 }
1847
1848 if (event) {
1849 ilist_init_iter(&iter, sel->events);
1850 ilist_unpositioned(&iter);
1851 real_holder = ilist_search_iter(&iter, recid_search_cmp,
1852 &info->record_id);
1853 if (!real_holder) {
1854 info->rv = EINVAL;
1855 goto out_unlock;
1856 }
1857
1858 if (cmp_event && (event_cmp(event, real_holder->event) != 0)) {
1859 info->rv = EINVAL;
1860 goto out_unlock;
1861 }
1862
1863 if (! info->do_clear) {
1864 if (real_holder->deleted) {
1865 info->rv = EINVAL;
1866 goto out_unlock;
1867 }
1868
1869 real_holder->deleted = 1;
1870 sel->num_sels--;
1871 sel->del_sels++;
1872
1873 start_fetch = (sel->num_sels == 0) && (sel->del_sels > 1);
1874 }
1875 }
1876
1877 /* Note that at this point we cannot check num_sels to see if it
1878 is zero and do a bulk clear. A new event might be added to the
1879 SEL after this point, thus failing the bulk clear, and that
1880 would prevent the individual delete from happening. But we can
1881 start a fetch if the value reaches zero, which is just as
1882 good. */
1883
1884 if (sel->supports_delete_sel || info->do_clear) {
1885 sel_del_handler_data_t *data;
1886 opq_elem_t *elem;
1887
1888 /* We can delete the entry immediately, just do it. */
1889 data = ipmi_mem_alloc(sizeof(*data));
1890 elem = opq_alloc_elem();
1891 if (!data || !elem) {
1892 if (! info->do_clear) {
1893 real_holder->deleted = 0;
1894 sel->num_sels++;
1895 sel->del_sels--;
1896 }
1897 info->rv = ENOMEM;
1898 if (data)
1899 ipmi_mem_free(data);
1900 if (elem)
1901 opq_free_elem(elem);
1902 goto out_unlock;
1903 }
1904
1905 data->sel = sel;
1906 data->handler = info->handler;
1907 data->cb_data = info->cb_data;
1908 data->lun = sel->lun;
1909 data->record_id = info->record_id;
1910 data->count = 0;
1911 data->event = event;
1912 data->holder = real_holder;
1913 if (real_holder)
1914 sel_event_holder_get(real_holder);
1915 data->do_clear = info->do_clear;
1916 event = NULL;
1917
1918 sel_unlock(sel);
1919 opq_new_op_prio(sel->opq, start_del_sel, data, 0, OPQ_ADD_TAIL, elem);
1920 } else {
1921 sel_unlock(sel);
1922 /* Don't really delete the event, but report is as done. */
1923 info->handler(sel, info->cb_data, 0);
1924 ipmi_event_free(event);
1925 }
1926
1927 if (start_fetch)
1928 ipmi_sel_get(sel, NULL, NULL);
1929 return;
1930
1931 out_unlock:
1932 sel_unlock(sel);
1933 }
1934
1935 static int
sel_del_event(ipmi_sel_info_t * sel,ipmi_event_t * event,unsigned int record_id,ipmi_sel_op_done_cb_t handler,void * cb_data,int cmp_event,int do_clear)1936 sel_del_event(ipmi_sel_info_t *sel,
1937 ipmi_event_t *event,
1938 unsigned int record_id,
1939 ipmi_sel_op_done_cb_t handler,
1940 void *cb_data,
1941 int cmp_event,
1942 int do_clear)
1943 {
1944 sel_del_event_info_t info;
1945 int rv;
1946
1947 info.sel = sel;
1948 info.event = ipmi_event_dup(event);
1949 info.record_id = record_id;
1950 info.handler = handler;
1951 info.cb_data = cb_data;
1952 info.cmp_event = cmp_event;
1953 info.rv = 0;
1954 info.do_clear = do_clear;
1955 rv = ipmi_mc_pointer_cb(sel->mc, sel_del_event_cb, &info);
1956 if (!rv)
1957 rv = info.rv;
1958 if (rv)
1959 ipmi_event_free(info.event);
1960 return rv;
1961 }
1962
1963 int
ipmi_sel_del_event(ipmi_sel_info_t * sel,ipmi_event_t * event,ipmi_sel_op_done_cb_t handler,void * cb_data)1964 ipmi_sel_del_event(ipmi_sel_info_t *sel,
1965 ipmi_event_t *event,
1966 ipmi_sel_op_done_cb_t handler,
1967 void *cb_data)
1968 {
1969 return sel_del_event(sel, event, ipmi_event_get_record_id(event),
1970 handler, cb_data, 1, 0);
1971 }
1972
1973 int
ipmi_sel_del_event_by_recid(ipmi_sel_info_t * sel,unsigned int record_id,ipmi_sel_op_done_cb_t handler,void * cb_data)1974 ipmi_sel_del_event_by_recid(ipmi_sel_info_t *sel,
1975 unsigned int record_id,
1976 ipmi_sel_op_done_cb_t handler,
1977 void *cb_data)
1978 {
1979 return sel_del_event(sel, NULL, record_id, handler, cb_data, 0, 0);
1980 }
1981
1982 int
ipmi_sel_clear(ipmi_sel_info_t * sel,ipmi_event_t * last_event,ipmi_sel_op_done_cb_t handler,void * cb_data)1983 ipmi_sel_clear(ipmi_sel_info_t *sel,
1984 ipmi_event_t *last_event,
1985 ipmi_sel_op_done_cb_t handler,
1986 void *cb_data)
1987 {
1988 int cmp_event = (last_event != NULL);
1989 unsigned int record_id = 0;
1990 if (last_event)
1991 record_id = ipmi_event_get_record_id(last_event);
1992 return sel_del_event(sel, last_event, record_id, handler, cb_data,
1993 cmp_event, 1);
1994 }
1995
1996 int
ipmi_get_sel_count(ipmi_sel_info_t * sel,unsigned int * count)1997 ipmi_get_sel_count(ipmi_sel_info_t *sel,
1998 unsigned int *count)
1999 {
2000 sel_lock(sel);
2001 if (sel->destroyed) {
2002 sel_unlock(sel);
2003 return EINVAL;
2004 }
2005
2006 *count = sel->num_sels;
2007
2008 sel_unlock(sel);
2009 return 0;
2010 }
2011
2012 int
ipmi_get_sel_entries_used(ipmi_sel_info_t * sel,unsigned int * count)2013 ipmi_get_sel_entries_used(ipmi_sel_info_t *sel,
2014 unsigned int *count)
2015 {
2016 sel_lock(sel);
2017 if (sel->destroyed) {
2018 sel_unlock(sel);
2019 return EINVAL;
2020 }
2021
2022 *count = sel->num_sels + sel->del_sels;
2023
2024 sel_unlock(sel);
2025 return 0;
2026 }
2027
2028 ipmi_event_t *
ipmi_sel_get_first_event(ipmi_sel_info_t * sel)2029 ipmi_sel_get_first_event(ipmi_sel_info_t *sel)
2030 {
2031 ilist_iter_t iter;
2032 ipmi_event_t *rv = NULL;
2033
2034 sel_lock(sel);
2035 if (sel->destroyed) {
2036 sel_unlock(sel);
2037 return NULL;
2038 }
2039 ilist_init_iter(&iter, sel->events);
2040 if (ilist_first(&iter)) {
2041 sel_event_holder_t *holder = ilist_get(&iter);
2042
2043 while (holder->deleted) {
2044 if (! ilist_next(&iter))
2045 goto out;
2046 holder = ilist_get(&iter);
2047 }
2048 rv = ipmi_event_dup(holder->event);
2049 }
2050 out:
2051 sel_unlock(sel);
2052 return rv;
2053 }
2054
2055 ipmi_event_t *
ipmi_sel_get_last_event(ipmi_sel_info_t * sel)2056 ipmi_sel_get_last_event(ipmi_sel_info_t *sel)
2057 {
2058 ilist_iter_t iter;
2059 ipmi_event_t *rv = NULL;
2060
2061 sel_lock(sel);
2062 if (sel->destroyed) {
2063 sel_unlock(sel);
2064 return NULL;
2065 }
2066 ilist_init_iter(&iter, sel->events);
2067 if (ilist_last(&iter)) {
2068 sel_event_holder_t *holder = ilist_get(&iter);
2069
2070 while (holder->deleted) {
2071 if (! ilist_prev(&iter))
2072 goto out;
2073 holder = ilist_get(&iter);
2074 }
2075 rv = ipmi_event_dup(holder->event);
2076 }
2077 out:
2078 sel_unlock(sel);
2079 return rv;
2080 }
2081
2082 ipmi_event_t *
ipmi_sel_get_next_event(ipmi_sel_info_t * sel,const ipmi_event_t * event)2083 ipmi_sel_get_next_event(ipmi_sel_info_t *sel, const ipmi_event_t *event)
2084 {
2085 ilist_iter_t iter;
2086 ipmi_event_t *rv = NULL;
2087 unsigned int record_id;
2088
2089 sel_lock(sel);
2090 if (sel->destroyed) {
2091 sel_unlock(sel);
2092 return NULL;
2093 }
2094 ilist_init_iter(&iter, sel->events);
2095 ilist_unpositioned(&iter);
2096 record_id = ipmi_event_get_record_id(event);
2097 if (ilist_search_iter(&iter, recid_search_cmp, &record_id)) {
2098 if (ilist_next(&iter)) {
2099 sel_event_holder_t *holder = ilist_get(&iter);
2100
2101 while (holder->deleted) {
2102 if (! ilist_next(&iter))
2103 goto out;
2104 holder = ilist_get(&iter);
2105 }
2106 rv = ipmi_event_dup(holder->event);
2107 }
2108 }
2109 out:
2110 sel_unlock(sel);
2111 return rv;
2112 }
2113
2114 ipmi_event_t *
ipmi_sel_get_prev_event(ipmi_sel_info_t * sel,const ipmi_event_t * event)2115 ipmi_sel_get_prev_event(ipmi_sel_info_t *sel, const ipmi_event_t *event)
2116 {
2117 ilist_iter_t iter;
2118 ipmi_event_t *rv = NULL;
2119 unsigned int record_id;
2120
2121 sel_lock(sel);
2122 if (sel->destroyed) {
2123 sel_unlock(sel);
2124 return NULL;
2125 }
2126 ilist_init_iter(&iter, sel->events);
2127 ilist_unpositioned(&iter);
2128 record_id = ipmi_event_get_record_id(event);
2129 if (ilist_search_iter(&iter, recid_search_cmp, &record_id)) {
2130 if (ilist_prev(&iter)) {
2131 sel_event_holder_t *holder = ilist_get(&iter);
2132
2133 while (holder->deleted) {
2134 if (! ilist_prev(&iter))
2135 goto out;
2136 holder = ilist_get(&iter);
2137 }
2138 rv = ipmi_event_dup(holder->event);
2139 }
2140 }
2141 out:
2142 sel_unlock(sel);
2143 return rv;
2144 }
2145
2146 ipmi_event_t *
ipmi_sel_get_event_by_recid(ipmi_sel_info_t * sel,unsigned int record_id)2147 ipmi_sel_get_event_by_recid(ipmi_sel_info_t *sel,
2148 unsigned int record_id)
2149 {
2150 ipmi_event_t *rv = NULL;
2151 sel_event_holder_t *holder;
2152
2153 sel_lock(sel);
2154 if (sel->destroyed) {
2155 sel_unlock(sel);
2156 return NULL;
2157 }
2158
2159 holder = find_event(sel->events, record_id);
2160 if (!holder)
2161 goto out_unlock;
2162
2163 if (holder->deleted)
2164 goto out_unlock;
2165
2166 rv = ipmi_event_dup(holder->event);
2167
2168 out_unlock:
2169 sel_unlock(sel);
2170 return rv;
2171 }
2172
2173 int
ipmi_get_all_sels(ipmi_sel_info_t * sel,int * array_size,ipmi_event_t ** array)2174 ipmi_get_all_sels(ipmi_sel_info_t *sel,
2175 int *array_size,
2176 ipmi_event_t **array)
2177 {
2178 unsigned int i;
2179 int rv = 0;
2180
2181 sel_lock(sel);
2182 if (sel->destroyed) {
2183 sel_unlock(sel);
2184 return EINVAL;
2185 }
2186
2187 if (*array_size < (int) sel->num_sels) {
2188 rv = E2BIG;
2189 } else if (sel->num_sels == 0) {
2190 rv = 0;
2191 } else {
2192 ilist_iter_t iter;
2193
2194 ilist_init_iter(&iter, sel->events);
2195 if (! ilist_first(&iter)) {
2196 rv = EINVAL;
2197 goto out_unlock;
2198 }
2199 for (i = 0; ; ) {
2200 sel_event_holder_t *holder = ilist_get(&iter);
2201
2202 if (!holder->deleted)
2203 array[i++] = ipmi_event_dup(holder->event);
2204 if (i < sel->num_sels) {
2205 if (! ilist_next(&iter)) {
2206 rv = EINVAL;
2207 while (i > 0)
2208 ipmi_event_free(array[--i]);
2209 goto out_unlock;
2210 }
2211 } else
2212 break;
2213 }
2214 *array_size = i;
2215 }
2216
2217 out_unlock:
2218 sel_unlock(sel);
2219 return rv;
2220 }
2221
2222 int
ipmi_sel_get_major_version(ipmi_sel_info_t * sel,int * val)2223 ipmi_sel_get_major_version(ipmi_sel_info_t *sel, int *val)
2224 {
2225 sel_lock(sel);
2226 if (sel->destroyed) {
2227 sel_unlock(sel);
2228 return EINVAL;
2229 }
2230
2231 *val = sel->major_version;
2232
2233 sel_unlock(sel);
2234 return 0;
2235 }
2236
2237 int
ipmi_sel_get_minor_version(ipmi_sel_info_t * sel,int * val)2238 ipmi_sel_get_minor_version(ipmi_sel_info_t *sel, int *val)
2239 {
2240 sel_lock(sel);
2241 if (sel->destroyed) {
2242 sel_unlock(sel);
2243 return EINVAL;
2244 }
2245
2246 *val = sel->minor_version;
2247
2248 sel_unlock(sel);
2249 return 0;
2250 }
2251
2252 int
ipmi_sel_get_num_entries(ipmi_sel_info_t * sel,int * val)2253 ipmi_sel_get_num_entries(ipmi_sel_info_t *sel, int *val)
2254 {
2255 sel_lock(sel);
2256 if (sel->destroyed) {
2257 sel_unlock(sel);
2258 return EINVAL;
2259 }
2260
2261 *val = sel->entries;
2262
2263 sel_unlock(sel);
2264 return 0;
2265 }
2266
2267 int
ipmi_sel_get_free_bytes(ipmi_sel_info_t * sel,int * val)2268 ipmi_sel_get_free_bytes(ipmi_sel_info_t *sel, int *val)
2269 {
2270 sel_lock(sel);
2271 if (sel->destroyed) {
2272 sel_unlock(sel);
2273 return EINVAL;
2274 }
2275
2276 *val = sel->free_bytes;
2277
2278 sel_unlock(sel);
2279 return 0;
2280 }
2281
2282 int
ipmi_sel_get_overflow(ipmi_sel_info_t * sel,int * val)2283 ipmi_sel_get_overflow(ipmi_sel_info_t *sel, int *val)
2284 {
2285 sel_lock(sel);
2286 if (sel->destroyed) {
2287 sel_unlock(sel);
2288 return EINVAL;
2289 }
2290
2291 *val = sel->overflow;
2292
2293 sel_unlock(sel);
2294 return 0;
2295 }
2296
2297 int
ipmi_sel_get_supports_delete_sel(ipmi_sel_info_t * sel,int * val)2298 ipmi_sel_get_supports_delete_sel(ipmi_sel_info_t *sel, int *val)
2299 {
2300 sel_lock(sel);
2301 if (sel->destroyed) {
2302 sel_unlock(sel);
2303 return EINVAL;
2304 }
2305
2306 *val = sel->supports_delete_sel;
2307
2308 sel_unlock(sel);
2309 return 0;
2310 }
2311
2312 int
ipmi_sel_get_supports_partial_add_sel(ipmi_sel_info_t * sel,int * val)2313 ipmi_sel_get_supports_partial_add_sel(ipmi_sel_info_t *sel, int *val)
2314 {
2315 sel_lock(sel);
2316 if (sel->destroyed) {
2317 sel_unlock(sel);
2318 return EINVAL;
2319 }
2320
2321 *val = sel->supports_partial_add_sel;
2322
2323 sel_unlock(sel);
2324 return 0;
2325 }
2326
2327 int
ipmi_sel_get_supports_reserve_sel(ipmi_sel_info_t * sel,int * val)2328 ipmi_sel_get_supports_reserve_sel(ipmi_sel_info_t *sel, int *val)
2329 {
2330 sel_lock(sel);
2331 if (sel->destroyed) {
2332 sel_unlock(sel);
2333 return EINVAL;
2334 }
2335
2336 *val = sel->supports_reserve_sel;
2337
2338 sel_unlock(sel);
2339 return 0;
2340 }
2341
2342 int
ipmi_sel_get_supports_get_sel_allocation(ipmi_sel_info_t * sel,int * val)2343 ipmi_sel_get_supports_get_sel_allocation(ipmi_sel_info_t *sel,
2344 int *val)
2345 {
2346 sel_lock(sel);
2347 if (sel->destroyed) {
2348 sel_unlock(sel);
2349 return EINVAL;
2350 }
2351
2352 *val = sel->supports_get_sel_allocation;
2353
2354 sel_unlock(sel);
2355 return 0;
2356 }
2357
2358 int
ipmi_sel_get_last_addition_timestamp(ipmi_sel_info_t * sel,int * val)2359 ipmi_sel_get_last_addition_timestamp(ipmi_sel_info_t *sel,
2360 int *val)
2361 {
2362 sel_lock(sel);
2363 if (sel->destroyed) {
2364 sel_unlock(sel);
2365 return EINVAL;
2366 }
2367
2368 *val = sel->last_addition_timestamp;
2369
2370 sel_unlock(sel);
2371 return 0;
2372 }
2373
2374 int
ipmi_sel_set_new_event_handler(ipmi_sel_info_t * sel,ipmi_sel_new_event_handler_cb handler,void * cb_data)2375 ipmi_sel_set_new_event_handler(ipmi_sel_info_t *sel,
2376 ipmi_sel_new_event_handler_cb handler,
2377 void *cb_data)
2378 {
2379 sel_lock(sel);
2380 sel->new_event_handler = handler;
2381 sel->new_event_cb_data = cb_data;
2382 sel_unlock(sel);
2383 return 0;
2384 }
2385
2386 int
ipmi_sel_event_add(ipmi_sel_info_t * sel,ipmi_event_t * new_event)2387 ipmi_sel_event_add(ipmi_sel_info_t *sel,
2388 ipmi_event_t *new_event)
2389 {
2390 int rv = 0;
2391 sel_event_holder_t *holder;
2392 unsigned int record_id;
2393
2394 sel_lock(sel);
2395 if (sel->destroyed) {
2396 sel_unlock(sel);
2397 return EINVAL;
2398 }
2399
2400 record_id = ipmi_event_get_record_id(new_event);
2401 holder = find_event(sel->events, record_id);
2402 if (!holder) {
2403 holder = sel_event_holder_alloc();
2404 if (!holder) {
2405 rv = ENOMEM;
2406 goto out_unlock;
2407 }
2408 if (!ilist_add_tail(sel->events, holder, NULL)) {
2409 rv = ENOMEM;
2410 goto out_unlock;
2411 }
2412 holder->event = ipmi_event_dup(new_event);
2413 sel->num_sels++;
2414 } else if (event_cmp(holder->event, new_event) == 0) {
2415 /* A duplicate event, just ignore it and return the right
2416 error. */
2417 rv = EEXIST;
2418 } else {
2419 ipmi_event_free(holder->event);
2420 holder->event = ipmi_event_dup(new_event);
2421 if (holder->deleted) {
2422 holder->deleted = 0;
2423 sel->num_sels++;
2424 sel->del_sels--;
2425 }
2426 }
2427
2428 out_unlock:
2429 sel_unlock(sel);
2430 return rv;
2431 }
2432
2433 typedef struct sel_add_cb_handler_data_s
2434 {
2435 ipmi_sel_info_t *sel;
2436 ipmi_sel_add_op_done_cb_t handler;
2437 void *cb_data;
2438 unsigned int record_id;
2439 ipmi_event_t *event;
2440 int rv;
2441 } sel_add_cb_handler_data_t;
2442
2443 static void
sel_add_op_done(sel_add_cb_handler_data_t * data,int rv)2444 sel_add_op_done(sel_add_cb_handler_data_t *data,
2445 int rv)
2446 {
2447 ipmi_sel_info_t *sel = data->sel;
2448
2449 if (data->handler)
2450 data->handler(sel, data->cb_data, rv, data->record_id);
2451
2452 if (sel->in_destroy) {
2453 /* Nothing to do */
2454 sel_unlock(sel);
2455 } else if (sel->destroyed) {
2456 /* This will unlock the lock. */
2457 internal_destroy_sel(sel);
2458 } else {
2459 sel_unlock(sel);
2460 opq_op_done(sel->opq);
2461 }
2462 if (data->event)
2463 ipmi_event_free(data->event);
2464 ipmi_mem_free(data);
2465 }
2466
2467 static void
sel_add_event_done(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)2468 sel_add_event_done(ipmi_mc_t *mc,
2469 ipmi_msg_t *rsp,
2470 void *rsp_data)
2471 {
2472 sel_add_cb_handler_data_t *info = rsp_data;
2473 ipmi_sel_info_t *sel = info->sel;
2474
2475 sel_lock(sel);
2476 if (sel->destroyed) {
2477 ipmi_log(IPMI_LOG_ERR_INFO,
2478 "%ssel.c(sel_add_event_done): "
2479 "SEL info was destroyed while an operation was in progress",
2480 sel->name);
2481 sel_add_op_done(info, ECANCELED);
2482 goto out;
2483 }
2484
2485 if (!mc) {
2486 ipmi_log(IPMI_LOG_ERR_INFO,
2487 "%ssel.c(sel_add_event_done): "
2488 "MC went away while SEL op was in progress", sel->name);
2489 sel_add_op_done(info, ECANCELED);
2490 goto out;
2491 }
2492
2493 if (rsp->data[0] != 0) {
2494 ipmi_log(IPMI_LOG_ERR_INFO,
2495 "%ssel.c(sel_add_event_done): "
2496 "IPMI error from SEL info fetch: %x",
2497 sel->name, rsp->data[0]);
2498 sel_add_op_done(info, IPMI_IPMI_ERR_VAL(rsp->data[0]));
2499 goto out;
2500 }
2501
2502 if (rsp->data_len < 3) {
2503 ipmi_log(IPMI_LOG_ERR_INFO,
2504 "%ssel.c(sel_add_event_done): SEL add response too short",
2505 sel->name);
2506 sel_add_op_done(info, EINVAL);
2507 goto out;
2508 }
2509
2510 info->record_id = ipmi_get_uint16(rsp->data+1);
2511 sel_add_op_done(info, 0);
2512 out:
2513 return;
2514 }
2515
2516 static void
sel_add_event_cb(ipmi_mc_t * mc,void * cb_data)2517 sel_add_event_cb(ipmi_mc_t *mc, void *cb_data)
2518 {
2519 sel_add_cb_handler_data_t *info = cb_data;
2520 ipmi_sel_info_t *sel = info->sel;
2521 ipmi_event_t *event = info->event;
2522 unsigned char data[16];
2523 ipmi_msg_t msg;
2524
2525 msg.netfn = IPMI_STORAGE_NETFN;
2526 msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
2527 msg.data = data;
2528 msg.data_len = 16;
2529
2530 ipmi_set_uint16(data, ipmi_event_get_record_id(event));
2531 data[2] = ipmi_event_get_type(event);
2532 memcpy(data+3, ipmi_event_get_data_ptr(event), 13);
2533
2534 info->rv = ipmi_mc_send_command(mc, sel->lun, &msg, sel_add_event_done,
2535 info);
2536 }
2537
2538 static int
sel_add_event_op(void * cb_data,int shutdown)2539 sel_add_event_op(void *cb_data, int shutdown)
2540 {
2541 sel_add_cb_handler_data_t *info = cb_data;
2542 ipmi_sel_info_t *sel = info->sel;
2543 int rv;
2544
2545 sel_lock(sel);
2546 if (shutdown) {
2547 ipmi_log(IPMI_LOG_ERR_INFO,
2548 "%ssel.c(sel_add_event_op): "
2549 "SEL info was destroyed while an operation was in progress",
2550 sel->name);
2551 sel_add_op_done(info, ECANCELED);
2552 goto out;
2553 }
2554
2555 rv = ipmi_mc_pointer_cb(sel->mc, sel_add_event_cb, info);
2556 if (rv) {
2557 ipmi_log(IPMI_LOG_ERR_INFO,
2558 "%ssel.c(sel_add_event_op): MC went away during delete",
2559 sel->name);
2560 sel_add_op_done(info, ECANCELED);
2561 goto out;
2562 } else if (info->rv) {
2563 ipmi_log(IPMI_LOG_ERR_INFO,
2564 "%ssel.c(sel_add_event_cb): could not send cmd: %x",
2565 sel->name, rv);
2566 sel_add_op_done(info, info->rv);
2567 goto out;
2568 }
2569
2570 sel_unlock(sel);
2571 out:
2572 return OPQ_HANDLER_STARTED;
2573 }
2574
2575 int
ipmi_sel_add_event_to_sel(ipmi_sel_info_t * sel,ipmi_event_t * event_to_add,ipmi_sel_add_op_done_cb_t done,void * cb_data)2576 ipmi_sel_add_event_to_sel(ipmi_sel_info_t *sel,
2577 ipmi_event_t *event_to_add,
2578 ipmi_sel_add_op_done_cb_t done,
2579 void *cb_data)
2580 {
2581 sel_add_cb_handler_data_t *info = cb_data;
2582 int rv = 0;
2583
2584 info = ipmi_mem_alloc(sizeof(*info));
2585 if (!info)
2586 return ENOMEM;
2587
2588 info->sel = sel;
2589 info->event = ipmi_event_dup(event_to_add);
2590 info->handler = done;
2591 info->cb_data = cb_data;
2592 info->record_id = 0;
2593
2594 sel_lock(sel);
2595 if (sel->destroyed) {
2596 rv = EINVAL;
2597 goto out_unlock;
2598 }
2599
2600 sel_unlock(sel);
2601
2602 /* Schedule this to run at the end of the queue. */
2603 if (!opq_new_op(sel->opq, sel_add_event_op, info, 0)) {
2604 rv = ENOMEM;
2605 goto out_unlock;
2606 }
2607 goto out;
2608
2609 out_unlock:
2610 sel_unlock(sel);
2611
2612 out:
2613 if (rv)
2614 ipmi_mem_free(info);
2615 return rv;
2616 }
2617