1 /*
2 * ipmi_entity.c
3 *
4 * MontaVista IPMI code for handling entities
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 <stdio.h>
36 #include <stdlib.h>
37
38 #include <OpenIPMI/ipmiif.h>
39 #include <OpenIPMI/ipmi_bits.h>
40 #include <OpenIPMI/ipmi_msgbits.h>
41 #include <OpenIPMI/ipmi_err.h>
42 #include <OpenIPMI/ipmi_fru.h>
43 #include <OpenIPMI/ipmi_sdr.h>
44
45 #include <OpenIPMI/internal/ipmi_mc.h>
46 #include <OpenIPMI/internal/ipmi_domain.h>
47 #include <OpenIPMI/internal/ipmi_int.h>
48 #include <OpenIPMI/internal/ipmi_entity.h>
49 #include <OpenIPMI/internal/locked_list.h>
50 #include <OpenIPMI/internal/ipmi_utils.h>
51 #include <OpenIPMI/internal/ipmi_control.h>
52 #include <OpenIPMI/internal/ipmi_sensor.h>
53
54 /* These are the versions of IPMI we write to the SDR repository */
55 #define IPMI_MAJOR_NUM_SDR 1
56 #define IPMI_MINOR_NUM_SDR 5
57
58 #define ENTITY_ID_LEN 32
59
60 /* Uniquely identifies a device in the system. If all the values are
61 zero, then it is not used (it's in the system-relative range). */
62 typedef struct ipmi_device_num_s
63 {
64 unsigned char channel;
65 unsigned char address;
66 } ipmi_device_num_t;
67
68 typedef struct dlr_ref_s
69 {
70 ipmi_device_num_t device_num;
71 uint8_t entity_id;
72 uint8_t entity_instance;
73 } dlr_ref_t;
74
75 typedef struct dlr_info_s
76 {
77 enum ipmi_dlr_type_e type;
78
79 entity_sdr_add_cb output_handler;
80
81 ipmi_device_num_t device_num;
82
83 /* Key fields. */
84 uint8_t access_address; /* Valid for FRU and Generic */
85 uint8_t fru_device_id; /* Valid for FRU */
86 uint8_t is_logical_fru; /* Valid for FRU */
87 uint8_t lun; /* Valid for FRU, MC, and Generic */
88 uint8_t private_bus_id; /* Valid for FRU and Generic */
89 uint8_t channel; /* Valid for FRU, MC, and Generic */
90 uint8_t slave_address; /* Valid for MC and Generic. */
91
92 /* General record fields. */
93 uint8_t oem;
94 uint8_t entity_id;
95 uint8_t entity_instance;
96 uint8_t device_type; /* Not in MC */
97 uint8_t device_type_modifier; /* Not in MC */
98
99 /* Note that the id is *not* nil terminated. */
100 unsigned int id_len;
101 enum ipmi_str_type_e id_type;
102 char id[ENTITY_ID_LEN];
103
104 /* MCDLR-specfic Record fields. */
105 unsigned int ACPI_system_power_notify_required : 1;
106 unsigned int ACPI_device_power_notify_required : 1;
107 unsigned int controller_logs_init_agent_errors : 1;
108 unsigned int log_init_agent_errors_accessing : 1;
109 unsigned int global_init : 2;
110
111 unsigned int chassis_device : 1;
112 unsigned int bridge : 1;
113 unsigned int IPMB_event_generator : 1;
114 unsigned int IPMB_event_receiver : 1;
115 unsigned int FRU_inventory_device : 1;
116 unsigned int SEL_device : 1;
117 unsigned int SDR_repository_device : 1;
118 unsigned int sensor_device : 1;
119
120 /* Generic Record fields. */
121 uint8_t address_span;
122
123 /* From an EAR or DREAR */
124 uint8_t is_list;
125 uint8_t linked;
126 uint8_t is_ranges;
127 uint8_t linked_ear_exists : 1;
128 uint8_t presence_sensor_always_there;
129 dlr_ref_t contained_entities[4];
130 } dlr_info_t;
131
132 typedef struct ent_timer_info_s
133 {
134 ipmi_lock_t *lock;
135 ipmi_entity_t *entity;
136 os_hnd_timer_id_t *timer;
137 int destroyed;
138 int running;
139 os_handler_t *os_hnd;
140 } ent_timer_info_t;
141
142 struct ipmi_entity_s
143 {
144 ipmi_domain_t *domain;
145 ipmi_domain_id_t domain_id;
146 long seq;
147
148 dlr_ref_t key;
149
150 /* Lock used for protecting misc data. */
151 ipmi_lock_t *elock;
152
153 int usecount;
154
155 /* Used to tell that the entity destroy is being reported to the
156 user. */
157 int destroyed;
158
159 /* Used to know if fully up has already been reported. */
160 int fully_up;
161
162 /* Have the SDRs been fully read? We use this to know when we
163 should report entity handling being fully done, because we
164 don't want to report fully done until we know we have
165 everything about the entity read in. */
166 int sdr_add_done;
167
168 /* After the entity is added, it will not be reported immediately.
169 Instead, it will wait until the usecount goes to zero before
170 being reported. This marks that the add report is pending */
171 int add_pending;
172
173 /* My domain's os handler. */
174 os_handler_t *os_hnd;
175
176 /* Info from the DLR. */
177 dlr_info_t info;
178
179 /* We don't install DLR info while the entity is in use, we hold
180 it here until the usecount goes to zero. */
181 dlr_info_t pending_info;
182 int pending_info_ready;
183
184 /* If the entity has changed and needs to be reported when the
185 entity is no longer in use, mark it here. */
186 int changed;
187
188 /* Number of users of this entity (not including sensors, this is
189 mainly for other SDRs that reference this entity). */
190 unsigned int ref_count;
191
192 locked_list_t *child_entities;
193 locked_list_t *parent_entities;
194
195 locked_list_t *sensors;
196 locked_list_t *controls;
197
198 const char *entity_id_string;
199
200 /* Function to detect presence. */
201 ipmi_entity_presence_detect_cb detect_presence;
202 void *detect_presence_data;
203
204 /* A standard presence sensor. This one overrides everything. */
205 ipmi_sensor_t *presence_sensor;
206 ipmi_sensor_id_t presence_sensor_id;
207
208 /* A discrete sensor where one of the bits is used for presence.
209 If one of these exists, it will be used unless there is a
210 presence sensor. */
211 ipmi_sensor_t *presence_bit_sensor;
212 ipmi_sensor_id_t presence_bit_sensor_id;
213
214 /* For a standard presence sensor, the offset of the present bit,
215 the absent bit will be !presence_bit. For a presence bit
216 sensor, the offset of the actual bit, it's always a present
217 bit. */
218 int presence_bit_offset;
219
220 int present;
221 int presence_possibly_changed;
222 unsigned int presence_event_count; /* Changed when presence
223 events are reported. */
224 /* Only allow one presence check at a time. */
225 int in_presence_check;
226
227 /* If the presence changes while the entity is in use, we store it
228 in here and the count instead of actually changing it. Then we
229 fix it up when the entity is set not in use. */
230 int curr_present;
231 int present_change_count;
232
233 /* Physical slot number info */
234 unsigned int slot_num;
235 int slot_num_present;
236
237 /* Hot-swap timing. */
238 ent_timer_info_t *hot_swap_act_info;
239 ipmi_timeout_t hot_swap_act_timeout;
240
241 ent_timer_info_t *hot_swap_deact_info;
242 ipmi_timeout_t hot_swap_deact_timeout;
243
244
245 /* Hot-swap sensors/controls */
246 ipmi_sensor_t *hot_swap_requester;
247 ipmi_sensor_id_t hot_swap_requester_id;
248 int hot_swap_offset;
249 int hot_swap_requesting_val;
250 enum ipmi_hot_swap_states hot_swap_state;
251 ipmi_control_t *hot_swap_power;
252 ipmi_control_id_t hot_swap_power_id;
253 ipmi_control_t *hot_swap_indicator;
254 ipmi_control_id_t hot_swap_indicator_id;
255 int hot_swap_ind_act;
256 int hot_swap_ind_req_act;
257 int hot_swap_ind_req_deact;
258 int hot_swap_ind_inact;
259
260 /* A handler for hot-swap. */
261 locked_list_t *hot_swap_handlers, *hot_swap_handlers_cl;
262
263 ipmi_entity_info_t *ents;
264
265 /* Allow only one internal fru fetch at a time. */
266 int in_fru_fetch;
267
268 ipmi_fru_t *fru;
269
270 int hot_swappable;
271 int supports_managed_hot_swap;
272 ipmi_entity_hot_swap_t hs_cb;
273
274 /* Callbacks for various events on an entity. */
275 locked_list_t *fru_handlers, *fru_handlers_cl;
276 locked_list_t *fru_handlers_werr, *fru_handlers_werr_cl;
277 locked_list_t *sensor_handlers, *sensor_handlers_cl;
278 locked_list_t *control_handlers, *control_handlers_cl;
279 locked_list_t *presence_handlers, *presence_handlers_cl;
280 locked_list_t *fully_up_handlers, *fully_up_handlers_cl;
281
282 /* Used for SDR output (not currently supported). */
283 entity_sdr_add_cb sdr_gen_output;
284 void *sdr_gen_cb_data;
285
286 /* Queue we use for operations. */
287 opq_t *waitq;
288
289 /* When using the FRU device to detect presence. */
290 int frudev_present;
291 ipmi_mc_t *frudev_mc; /* Note that the MC cannot be destroyed
292 while we have an active monitor on it, so
293 this is safe. */
294 int frudev_active;
295 int frudev_active_reported;
296
297 /* OEM info assigned to an entity, for use by plugins. */
298 void *oem_info;
299 ipmi_entity_cleanup_oem_info_cb oem_info_cleanup_handler;
300
301 /* Name we use for reporting. We add a ' ' onto the end, thus
302 the +1. */
303 char name[IPMI_ENTITY_NAME_LEN+1];
304
305
306 /* Cruft */
307 ipmi_entity_presence_nd_cb cruft_presence_handler;
308 void *cruft_presence_cb_data;
309
310 ipmi_entity_sensor_cb cruft_sensor_handler;
311 void *cruft_sensor_cb_data;
312
313 ipmi_entity_control_cb cruft_control_handler;
314 void *cruft_control_cb_data;
315
316 ipmi_entity_fru_cb cruft_fru_handler;
317 void *cruft_fru_cb_data;
318 };
319
320 struct ipmi_entity_info_s
321 {
322 locked_list_t *update_handlers;
323 locked_list_t *update_cl_handlers;
324 ipmi_domain_t *domain;
325 ipmi_domain_id_t domain_id;
326 locked_list_t *entities;
327 };
328
329 #define ent_lock(e) ipmi_lock(e->elock)
330 #define ent_unlock(e) ipmi_unlock(e->elock)
331
332 static void entity_mc_active(ipmi_mc_t *mc, int active, void *cb_data);
333 static void call_presence_handlers(ipmi_entity_t *ent, int present);
334 static void call_fully_up_handlers(ipmi_entity_t *ent);
335
336 /***********************************************************************
337 *
338 * The internal hot-swap callbacks.
339 *
340 **********************************************************************/
341 static int e_get_hot_swap_state(ipmi_entity_t *ent,
342 ipmi_entity_hot_swap_state_cb handler,
343 void *cb_data);
344
345 static int e_set_auto_activate(ipmi_entity_t *ent,
346 ipmi_timeout_t auto_act,
347 ipmi_entity_cb done,
348 void *cb_data);
349
350 static int e_get_auto_activate(ipmi_entity_t *ent,
351 ipmi_entity_time_cb handler,
352 void *cb_data);
353
354 static int e_set_auto_deactivate(ipmi_entity_t *ent,
355 ipmi_timeout_t auto_act,
356 ipmi_entity_cb done,
357 void *cb_data);
358
359 static int e_get_auto_deactivate(ipmi_entity_t *ent,
360 ipmi_entity_time_cb handler,
361 void *cb_data);
362
363 static int e_activate(ipmi_entity_t *ent,
364 ipmi_entity_cb done,
365 void *cb_data);
366
367 static int e_deactivate(ipmi_entity_t *ent,
368 ipmi_entity_cb done,
369 void *cb_data);
370
371 static int e_get_hot_swap_indicator(ipmi_entity_t *ent,
372 ipmi_entity_val_cb handler,
373 void *cb_data);
374
375 static int e_set_hot_swap_indicator(ipmi_entity_t *ent,
376 int val,
377 ipmi_entity_cb done,
378 void *cb_data);
379
380 static int e_get_hot_swap_requester(ipmi_entity_t *ent,
381 ipmi_entity_val_cb handler,
382 void *cb_data);
383
384 static int e_check_hot_swap_state(ipmi_entity_t *ent);
385
386 static ipmi_entity_hot_swap_t internal_hs_cb =
387 {
388 .get_hot_swap_state = e_get_hot_swap_state,
389 .set_auto_activate = e_set_auto_activate,
390 .get_auto_activate = e_get_auto_activate,
391 .set_auto_deactivate = e_set_auto_deactivate,
392 .get_auto_deactivate = e_get_auto_deactivate,
393 .activate = e_activate,
394 .deactivate = e_deactivate,
395 .get_hot_swap_indicator = e_get_hot_swap_indicator,
396 .set_hot_swap_indicator = e_set_hot_swap_indicator,
397 .get_hot_swap_requester = e_get_hot_swap_requester,
398 .check_hot_swap_state = e_check_hot_swap_state,
399 };
400
401 /***********************************************************************
402 *
403 * Entity iteration helpers
404 *
405 **********************************************************************/
406 static void
entities_lock(void * cb_data)407 entities_lock(void *cb_data)
408 {
409 ipmi_domain_t *domain = cb_data;
410 i_ipmi_domain_entity_lock(domain);
411 }
412
413 static void
entities_unlock(void * cb_data)414 entities_unlock(void *cb_data)
415 {
416 ipmi_domain_t *domain = cb_data;
417 i_ipmi_domain_entity_unlock(domain);
418 }
419
420 static int
iterate_entity_prefunc(void * cb_data,void * item1,void * item2)421 iterate_entity_prefunc(void *cb_data, void *item1, void *item2)
422 {
423 ipmi_entity_t *ent = item1;
424
425 i_ipmi_entity_get(ent);
426 return LOCKED_LIST_ITER_CONTINUE;
427 }
428
429 /***********************************************************************
430 *
431 * Entity allocation/destruction
432 *
433 **********************************************************************/
434 int
ipmi_entity_info_alloc(ipmi_domain_t * domain,ipmi_entity_info_t ** new_info)435 ipmi_entity_info_alloc(ipmi_domain_t *domain, ipmi_entity_info_t **new_info)
436 {
437 ipmi_entity_info_t *ents;
438
439 ents = ipmi_mem_alloc(sizeof(*ents));
440 if (!ents)
441 return ENOMEM;
442
443 ents->domain = domain;
444 ents->domain_id = ipmi_domain_convert_to_id(domain);
445 ents->entities = locked_list_alloc_my_lock(entities_lock,
446 entities_unlock,
447 domain);
448 if (! ents->entities) {
449 ipmi_mem_free(ents);
450 return ENOMEM;
451 }
452
453 ents->update_handlers = locked_list_alloc(ipmi_domain_get_os_hnd(domain));
454 if (! ents->update_handlers) {
455 locked_list_destroy(ents->entities);
456 ipmi_mem_free(ents);
457 return ENOMEM;
458 }
459
460 ents->update_cl_handlers
461 = locked_list_alloc(ipmi_domain_get_os_hnd(domain));
462 if (! ents->update_cl_handlers) {
463 locked_list_destroy(ents->update_handlers);
464 locked_list_destroy(ents->entities);
465 ipmi_mem_free(ents);
466 return ENOMEM;
467 }
468
469 *new_info = ents;
470
471 return 0;
472 }
473
474 static void
entity_start_timer(ent_timer_info_t * info,ipmi_timeout_t timeout,os_timed_out_t handler)475 entity_start_timer(ent_timer_info_t *info,
476 ipmi_timeout_t timeout,
477 os_timed_out_t handler)
478 {
479 /* Need to time the operation. */
480 struct timeval tv;
481
482 if (timeout == IPMI_TIMEOUT_FOREVER)
483 return;
484
485 tv.tv_sec = timeout / 1000000000;
486 tv.tv_usec = (timeout % 1000000000) / 1000;
487 ipmi_lock(info->lock);
488 if (!info->running) {
489 info->os_hnd->start_timer(info->os_hnd,
490 info->timer,
491 &tv,
492 handler,
493 info);
494 info->running = 1;
495 }
496 ipmi_unlock(info->lock);
497 }
498
499 static int
entity_alloc_timer(ipmi_entity_t * entity,ent_timer_info_t ** rinfo)500 entity_alloc_timer(ipmi_entity_t *entity,
501 ent_timer_info_t **rinfo)
502 {
503 ent_timer_info_t *info;
504 int rv;
505
506 info = ipmi_mem_alloc(sizeof(*info));
507 if (!info)
508 return ENOMEM;
509 memset(info, 0, sizeof(*info));
510
511 info->os_hnd = entity->os_hnd;
512 info->entity = entity;
513
514 rv = info->os_hnd->alloc_timer(info->os_hnd, &info->timer);
515 if (rv) {
516 ipmi_mem_free(info);
517 return rv;
518 }
519
520 rv = ipmi_create_lock(entity->domain, &info->lock);
521 if (rv) {
522 info->os_hnd->free_timer(info->os_hnd, info->timer);
523 ipmi_mem_free(info);
524 return rv;
525 }
526
527 *rinfo = info;
528
529 return 0;
530 }
531
532 static void
entity_destroy_timer(ent_timer_info_t * info)533 entity_destroy_timer(ent_timer_info_t *info)
534 {
535 int rv;
536
537 ipmi_lock(info->lock);
538 if (info->running) {
539 rv = info->os_hnd->stop_timer(info->os_hnd, info->timer);
540 if (!rv) {
541 info->destroyed = 1;
542 ipmi_unlock(info->lock);
543 return;
544 }
545 }
546 ipmi_unlock(info->lock);
547 info->os_hnd->free_timer(info->os_hnd, info->timer);
548 ipmi_destroy_lock(info->lock);
549 ipmi_mem_free(info);
550 }
551
552 typedef struct hot_swap_cl_info_s
553 {
554 ipmi_entity_hot_swap_cb handler;
555 void *handler_data;
556 } hot_swap_cl_info_t;
557
558 static int
iterate_hot_swap_cl(void * cb_data,void * item1,void * item2)559 iterate_hot_swap_cl(void *cb_data, void *item1, void *item2)
560 {
561 hot_swap_cl_info_t *info = cb_data;
562 ipmi_entity_hot_swap_cl_cb handler = item1;
563
564 handler(info->handler, info->handler_data, item2);
565 return LOCKED_LIST_ITER_CONTINUE;
566 }
567
568 static int
hot_swap_cleanup(void * cb_data,void * item1,void * item2)569 hot_swap_cleanup(void *cb_data, void *item1, void *item2)
570 {
571 ipmi_entity_t *ent = cb_data;
572 hot_swap_cl_info_t info;
573
574 info.handler = item1;
575 info.handler_data = item2;
576 locked_list_iterate(ent->hot_swap_handlers_cl, iterate_hot_swap_cl, &info);
577 return LOCKED_LIST_ITER_CONTINUE;
578 }
579
580 typedef struct presence_cl_info_s
581 {
582 ipmi_entity_presence_change_cb handler;
583 void *handler_data;
584 } presence_cl_info_t;
585
586 static int
iterate_presence_cl(void * cb_data,void * item1,void * item2)587 iterate_presence_cl(void *cb_data, void *item1, void *item2)
588 {
589 presence_cl_info_t *info = cb_data;
590 ipmi_entity_presence_cl_cb handler = item1;
591
592 handler(info->handler, info->handler_data, item2);
593 return LOCKED_LIST_ITER_CONTINUE;
594 }
595
596 static int
presence_cleanup(void * cb_data,void * item1,void * item2)597 presence_cleanup(void *cb_data, void *item1, void *item2)
598 {
599 ipmi_entity_t *ent = cb_data;
600 presence_cl_info_t info;
601
602 info.handler = item1;
603 info.handler_data = item2;
604 locked_list_iterate(ent->presence_handlers_cl, iterate_presence_cl, &info);
605 return LOCKED_LIST_ITER_CONTINUE;
606 }
607
608 typedef struct fully_up_cl_info_s
609 {
610 ipmi_entity_ptr_cb handler;
611 void *handler_data;
612 } fully_up_cl_info_t;
613
614 static int
iterate_fully_up_cl(void * cb_data,void * item1,void * item2)615 iterate_fully_up_cl(void *cb_data, void *item1, void *item2)
616 {
617 fully_up_cl_info_t *info = cb_data;
618 ipmi_entity_fully_up_cl_cb handler = item1;
619
620 handler(info->handler, info->handler_data, item2);
621 return LOCKED_LIST_ITER_CONTINUE;
622 }
623
624 static int
fully_up_cleanup(void * cb_data,void * item1,void * item2)625 fully_up_cleanup(void *cb_data, void *item1, void *item2)
626 {
627 ipmi_entity_t *ent = cb_data;
628 fully_up_cl_info_t info;
629
630 info.handler = item1;
631 info.handler_data = item2;
632 locked_list_iterate(ent->fully_up_handlers_cl, iterate_fully_up_cl, &info);
633 return LOCKED_LIST_ITER_CONTINUE;
634 }
635
636 typedef struct fru_cl_info_s
637 {
638 ipmi_entity_fru_cb handler;
639 void *handler_data;
640 } fru_cl_info_t;
641
642 static int
iterate_fru_cl(void * cb_data,void * item1,void * item2)643 iterate_fru_cl(void *cb_data, void *item1, void *item2)
644 {
645 fru_cl_info_t *info = cb_data;
646 ipmi_entity_fru_cl_cb handler = item1;
647
648 handler(info->handler, info->handler_data, item2);
649 return LOCKED_LIST_ITER_CONTINUE;
650 }
651
652 static int
fru_cleanup(void * cb_data,void * item1,void * item2)653 fru_cleanup(void *cb_data, void *item1, void *item2)
654 {
655 ipmi_entity_t *ent = cb_data;
656 fru_cl_info_t info;
657
658 info.handler = item1;
659 info.handler_data = item2;
660 locked_list_iterate(ent->fru_handlers_cl, iterate_fru_cl, &info);
661 return LOCKED_LIST_ITER_CONTINUE;
662 }
663
664 typedef struct fru_werr_cl_info_s
665 {
666 ipmi_entity_fru_werr_cb handler;
667 void *handler_data;
668 } fru_werr_cl_info_t;
669
670 static int
iterate_fru_werr_cl(void * cb_data,void * item1,void * item2)671 iterate_fru_werr_cl(void *cb_data, void *item1, void *item2)
672 {
673 fru_werr_cl_info_t *info = cb_data;
674 ipmi_entity_fru_werr_cl_cb handler = item1;
675
676 handler(info->handler, info->handler_data, item2);
677 return LOCKED_LIST_ITER_CONTINUE;
678 }
679
680 static int
fru_werr_cleanup(void * cb_data,void * item1,void * item2)681 fru_werr_cleanup(void *cb_data, void *item1, void *item2)
682 {
683 ipmi_entity_t *ent = cb_data;
684 fru_werr_cl_info_t info;
685
686 info.handler = item1;
687 info.handler_data = item2;
688 locked_list_iterate(ent->fru_handlers_werr_cl, iterate_fru_werr_cl, &info);
689 return LOCKED_LIST_ITER_CONTINUE;
690 }
691
692 typedef struct control_cl_info_s
693 {
694 ipmi_entity_control_cb handler;
695 void *handler_data;
696 } control_cl_info_t;
697
698 static int
iterate_control_cl(void * cb_data,void * item1,void * item2)699 iterate_control_cl(void *cb_data, void *item1, void *item2)
700 {
701 control_cl_info_t *info = cb_data;
702 ipmi_entity_control_cl_cb handler = item1;
703
704 handler(info->handler, info->handler_data, item2);
705 return LOCKED_LIST_ITER_CONTINUE;
706 }
707
708 static int
control_cleanup(void * cb_data,void * item1,void * item2)709 control_cleanup(void *cb_data, void *item1, void *item2)
710 {
711 ipmi_entity_t *ent = cb_data;
712 control_cl_info_t info;
713
714 info.handler = item1;
715 info.handler_data = item2;
716 locked_list_iterate(ent->control_handlers_cl, iterate_control_cl, &info);
717 return LOCKED_LIST_ITER_CONTINUE;
718 }
719
720 typedef struct sensor_cl_info_s
721 {
722 ipmi_entity_sensor_cb handler;
723 void *handler_data;
724 } sensor_cl_info_t;
725
726 static int
iterate_sensor_cl(void * cb_data,void * item1,void * item2)727 iterate_sensor_cl(void *cb_data, void *item1, void *item2)
728 {
729 sensor_cl_info_t *info = cb_data;
730 ipmi_entity_sensor_cl_cb handler = item1;
731
732 handler(info->handler, info->handler_data, item2);
733 return LOCKED_LIST_ITER_CONTINUE;
734 }
735
736 static int
sensor_cleanup(void * cb_data,void * item1,void * item2)737 sensor_cleanup(void *cb_data, void *item1, void *item2)
738 {
739 ipmi_entity_t *ent = cb_data;
740 sensor_cl_info_t info;
741
742 info.handler = item1;
743 info.handler_data = item2;
744 locked_list_iterate(ent->sensor_handlers_cl, iterate_sensor_cl, &info);
745 return LOCKED_LIST_ITER_CONTINUE;
746 }
747
748 static int
destroy_entity(void * cb_data,void * item1,void * item2)749 destroy_entity(void *cb_data, void *item1, void *item2)
750 {
751 ipmi_entity_t *ent = (ipmi_entity_t *) item1;
752
753 entity_destroy_timer(ent->hot_swap_act_info);
754 entity_destroy_timer(ent->hot_swap_deact_info);
755
756 if (ent->frudev_present) {
757 i_ipmi_domain_mc_lock(ent->domain);
758 i_ipmi_mc_get(ent->frudev_mc);
759 i_ipmi_domain_mc_unlock(ent->domain);
760 ipmi_mc_remove_active_handler(ent->frudev_mc, entity_mc_active, ent);
761 i_ipmi_mc_release(ent->frudev_mc);
762 i_ipmi_mc_put(ent->frudev_mc);
763 }
764
765 if (ent->oem_info_cleanup_handler)
766 ent->oem_info_cleanup_handler(ent, ent->oem_info);
767
768 if (ent->fru)
769 ipmi_fru_destroy_internal(ent->fru, NULL, NULL);
770
771 if (ent->waitq)
772 opq_destroy(ent->waitq);
773
774 locked_list_destroy(ent->parent_entities);
775 locked_list_destroy(ent->child_entities);
776 locked_list_destroy(ent->sensors);
777 locked_list_destroy(ent->controls);
778 locked_list_iterate(ent->hot_swap_handlers, hot_swap_cleanup, ent);
779 locked_list_destroy(ent->hot_swap_handlers);
780 locked_list_destroy(ent->hot_swap_handlers_cl);
781 locked_list_iterate(ent->presence_handlers, presence_cleanup, ent);
782 locked_list_destroy(ent->presence_handlers);
783 locked_list_destroy(ent->presence_handlers_cl);
784 locked_list_iterate(ent->fully_up_handlers, fully_up_cleanup, ent);
785 locked_list_destroy(ent->fully_up_handlers);
786 locked_list_destroy(ent->fully_up_handlers_cl);
787 locked_list_iterate(ent->fru_handlers, fru_cleanup, ent);
788 locked_list_iterate(ent->fru_handlers_werr, fru_werr_cleanup, ent);
789 locked_list_destroy(ent->fru_handlers);
790 locked_list_destroy(ent->fru_handlers_cl);
791 locked_list_destroy(ent->fru_handlers_werr);
792 locked_list_destroy(ent->fru_handlers_werr_cl);
793 locked_list_iterate(ent->control_handlers, control_cleanup, ent);
794 locked_list_destroy(ent->control_handlers);
795 locked_list_destroy(ent->control_handlers_cl);
796 locked_list_iterate(ent->sensor_handlers, sensor_cleanup, ent);
797 locked_list_destroy(ent->sensor_handlers);
798 locked_list_destroy(ent->sensor_handlers_cl);
799
800 ipmi_destroy_lock(ent->elock);
801
802 ipmi_mem_free(ent);
803
804 return LOCKED_LIST_ITER_CONTINUE;
805 }
806
807 typedef struct entity_update_cl_info_s
808 {
809 ipmi_domain_entity_cb handler;
810 void *handler_data;
811 } entity_update_cl_info_t;
812
813
814 static int
iterate_entity_update_cl(void * cb_data,void * item1,void * item2)815 iterate_entity_update_cl(void *cb_data, void *item1, void *item2)
816 {
817 entity_update_cl_info_t *info = cb_data;
818 ipmi_domain_entity_cl_cb handler = item1;
819
820 handler(info->handler, info->handler_data, item2);
821 return LOCKED_LIST_ITER_CONTINUE;
822 }
823
824 static int
entity_update_cleanup(void * cb_data,void * item1,void * item2)825 entity_update_cleanup(void *cb_data, void *item1, void *item2)
826 {
827 entity_update_cl_info_t info;
828 ipmi_entity_info_t *ents = cb_data;
829
830 info.handler = item1;
831 info.handler_data = item2;
832 locked_list_iterate(ents->update_cl_handlers, iterate_entity_update_cl,
833 &info);
834 return LOCKED_LIST_ITER_CONTINUE;
835 }
836
837 int
ipmi_entity_info_destroy(ipmi_entity_info_t * ents)838 ipmi_entity_info_destroy(ipmi_entity_info_t *ents)
839 {
840 locked_list_iterate(ents->update_handlers, entity_update_cleanup, ents);
841 locked_list_destroy(ents->update_handlers);
842 locked_list_destroy(ents->update_cl_handlers);
843 locked_list_iterate(ents->entities, destroy_entity, NULL);
844 locked_list_destroy(ents->entities);
845 ipmi_mem_free(ents);
846 return 0;
847 }
848
849 typedef struct ent_info_update_handler_info_s
850 {
851 enum ipmi_update_e op;
852 ipmi_domain_t *domain;
853 ipmi_entity_t *entity;
854 } ent_info_update_handler_info_t;
855
856 static int
call_entity_info_update_handler(void * cb_data,void * item1,void * item2)857 call_entity_info_update_handler(void *cb_data, void *item1, void *item2)
858 {
859 ent_info_update_handler_info_t *info = cb_data;
860 ipmi_domain_entity_cb handler = item1;
861
862 handler(info->op, info->domain, info->entity, item2);
863 return LOCKED_LIST_ITER_CONTINUE;
864 }
865
866 static void
call_entity_update_handlers(ipmi_entity_t * ent,enum ipmi_update_e op)867 call_entity_update_handlers(ipmi_entity_t *ent, enum ipmi_update_e op)
868 {
869 ent_info_update_handler_info_t info;
870
871 info.op = op;
872 info.entity = ent;
873 info.domain = ent->domain;
874 locked_list_iterate(ent->ents->update_handlers,
875 call_entity_info_update_handler,
876 &info);
877 }
878
879 /* Returns true if the entity was really deleted, false if not. Must
880 be called with the domain entity lock, unlocks it before return if
881 it destroys the entity. */
882 static int
cleanup_entity(ipmi_entity_t * ent)883 cleanup_entity(ipmi_entity_t *ent)
884 {
885 /* First see if the entity is ready for cleanup. */
886 if ((ent->ref_count)
887 || opq_stuff_in_progress(ent->waitq)
888 || (locked_list_num_entries_nolock(ent->child_entities) != 0)
889 || (locked_list_num_entries_nolock(ent->parent_entities) != 0)
890 || (locked_list_num_entries_nolock(ent->sensors) != 0)
891 || (locked_list_num_entries_nolock(ent->controls) != 0))
892 {
893 return 0;
894 }
895
896 ent->destroyed = 1;
897
898 i_ipmi_domain_entity_unlock(ent->domain);
899
900 /* Tell the user I was destroyed. */
901 /* Call the update handler list. */
902 call_entity_update_handlers(ent, IPMI_DELETED);
903
904 i_ipmi_domain_entity_lock(ent->domain);
905
906 if (ent->destroyed) {
907 /* The entity could have been resurrected, so don't do this
908 unless it has remained destroyed. */
909
910 /* Remove it from the entities list. */
911 locked_list_remove_nolock(ent->ents->entities, ent, NULL);
912
913 /* The sensor, control, parent, and child lists should be empty
914 now, we can just destroy it. */
915 destroy_entity(NULL, ent, NULL);
916 return 1;
917 } else {
918 return 0;
919 }
920 }
921
922 void
ipmi_entity_set_oem_info(ipmi_entity_t * entity,void * oem_info,ipmi_entity_cleanup_oem_info_cb cleanup_handler)923 ipmi_entity_set_oem_info(ipmi_entity_t *entity, void *oem_info,
924 ipmi_entity_cleanup_oem_info_cb cleanup_handler)
925 {
926 entity->oem_info = oem_info;
927 entity->oem_info_cleanup_handler = cleanup_handler;
928 }
929
930 void *
ipmi_entity_get_oem_info(ipmi_entity_t * entity)931 ipmi_entity_get_oem_info(ipmi_entity_t *entity)
932 {
933 CHECK_ENTITY_LOCK(entity);
934
935 return entity->oem_info;
936 }
937
938 static void
entity_set_name(ipmi_entity_t * entity)939 entity_set_name(ipmi_entity_t *entity)
940 {
941 int length = sizeof(entity->name);
942
943 ent_lock(entity);
944 length = ipmi_domain_get_name(entity->domain, entity->name, length);
945 entity->name[length] = '(';
946 length++;
947 if (entity->key.entity_instance >= 0x60) {
948 length += snprintf(entity->name+length, IPMI_ENTITY_NAME_LEN-length-3,
949 "r%d.%d.%d.%d",
950 entity->key.device_num.channel,
951 entity->key.device_num.address,
952 entity->key.entity_id,
953 entity->key.entity_instance - 0x60);
954 } else {
955 length += snprintf(entity->name+length, IPMI_ENTITY_NAME_LEN-length-3,
956 "%d.%d", entity->key.entity_id,
957 entity->key.entity_instance);
958 }
959 entity->name[length] = ')';
960 length++;
961 entity->name[length] = ' ';
962 length++;
963 entity->name[length] = '\0';
964 length++;
965 ent_unlock(entity);
966 }
967
968 const char *
i_ipmi_entity_name(const ipmi_entity_t * entity)969 i_ipmi_entity_name(const ipmi_entity_t *entity)
970 {
971 return entity->name;
972 }
973
974 static void
entity_get_name_cb(ipmi_entity_t * entity,void * cb_data)975 entity_get_name_cb(ipmi_entity_t *entity, void *cb_data)
976 {
977 char **name = cb_data;
978 *name = entity->name;
979 }
980
981 const char *
i_ipmi_entity_id_name(ipmi_entity_id_t entity_id)982 i_ipmi_entity_id_name(ipmi_entity_id_t entity_id)
983 {
984 char *name = "";
985 ipmi_entity_pointer_cb(entity_id, entity_get_name_cb, &name);
986 return name;
987 }
988
989 int
ipmi_entity_get_name(ipmi_entity_t * ent,char * name,int length)990 ipmi_entity_get_name(ipmi_entity_t *ent, char *name, int length)
991 {
992 int slen;
993
994 if (length <= 0)
995 return 0;
996
997 /* Never changes, no lock needed. */
998 slen = strlen(ent->name);
999 if (slen == 0) {
1000 if (name)
1001 *name = '\0';
1002 goto out;
1003 }
1004
1005 slen -= 1; /* Remove the trailing ' ' */
1006 if (slen >= length)
1007 slen = length - 1;
1008
1009 if (name) {
1010 memcpy(name, ent->name, slen);
1011 name[slen] = '\0';
1012 }
1013 out:
1014 return slen;
1015 }
1016
1017 static int
ent_use_frudev_for_presence(ipmi_entity_t * ent)1018 ent_use_frudev_for_presence(ipmi_entity_t *ent)
1019 {
1020 return ((!ent->presence_sensor) && (!ent->presence_bit_sensor)
1021 && (locked_list_num_entries_nolock(ent->controls) == 0)
1022 && (locked_list_num_entries_nolock(ent->sensors) == 0)
1023 && (locked_list_num_entries_nolock(ent->child_entities) == 0));
1024 }
1025
1026 /***********************************************************************
1027 *
1028 * Handling of adding/removing/searching entities, parents, and
1029 * children.
1030 *
1031 **********************************************************************/
1032
1033 static void
internal_fru_fetch_done(ipmi_entity_t * ent,void * cb_data)1034 internal_fru_fetch_done(ipmi_entity_t *ent, void *cb_data)
1035 {
1036 ent_lock(ent);
1037 ent->in_fru_fetch = 0;
1038 ent_unlock(ent);
1039 }
1040
1041 /* Must be called with the i_ipmi_domain_entity_lock() held. */
1042 int
i_ipmi_entity_get(ipmi_entity_t * ent)1043 i_ipmi_entity_get(ipmi_entity_t *ent)
1044 {
1045 ent->usecount++;
1046 return 0;
1047 }
1048
1049 void
i_ipmi_entity_put(ipmi_entity_t * ent)1050 i_ipmi_entity_put(ipmi_entity_t *ent)
1051 {
1052 ipmi_domain_t *domain = ent->domain;
1053 int entity_fru_fetch = 0;
1054 int report_fully_up = 0;
1055
1056 i_ipmi_domain_entity_lock(domain);
1057 retry:
1058 if (ent->usecount == 1) {
1059 if (ent->pending_info_ready) {
1060 int was_fru = ipmi_entity_get_is_fru(ent);
1061 ent->info = ent->pending_info;
1062 /* If the entity became a fru and is present, get its fru info. */
1063 if (!was_fru && ipmi_entity_get_is_fru(ent) && ent->present)
1064 entity_fru_fetch = 1;
1065 entity_set_name(ent);
1066 ent->pending_info_ready = 0;
1067 }
1068
1069 if (ent->add_pending) {
1070 ent->add_pending = 0;
1071 ent->changed = 0;
1072 i_ipmi_domain_entity_unlock(domain);
1073 call_entity_update_handlers(ent, IPMI_ADDED);
1074 i_ipmi_domain_entity_lock(domain);
1075
1076 /* Something grabbed the entity while the lock wasn't
1077 held, don't attempt the cleanup. */
1078 if (ent->usecount != 1)
1079 goto out;
1080 }
1081
1082 /* If the entity has changed, report it to the user. */
1083 if (ent->changed) {
1084 ent->changed = 0;
1085 i_ipmi_domain_entity_unlock(domain);
1086 call_entity_update_handlers(ent, IPMI_CHANGED);
1087 i_ipmi_domain_entity_lock(domain);
1088
1089 /* Something grabbed the entity while the lock wasn't
1090 held, don't attempt the cleanup. */
1091 if (ent->usecount != 1)
1092 goto out;
1093 }
1094
1095 if (ent->presence_possibly_changed) {
1096 i_ipmi_domain_entity_unlock(domain);
1097 ipmi_detect_entity_presence_change(ent, 0);
1098 i_ipmi_domain_entity_lock(domain);
1099
1100 if (ent->usecount != 1)
1101 goto out;
1102 }
1103
1104 while (ent->present_change_count) {
1105 int present;
1106 ent->present = !ent->present;
1107 present = ent->present;
1108 ent->present_change_count--;
1109 i_ipmi_domain_entity_unlock(domain);
1110 call_presence_handlers(ent, present);
1111 i_ipmi_domain_entity_lock(domain);
1112
1113 if (ipmi_entity_get_is_fru(ent) && ent->present)
1114 entity_fru_fetch = 1;
1115
1116 /* Something grabbed the entity while the lock wasn't
1117 held, don't attempt the cleanup. */
1118 if (ent->usecount != 1)
1119 goto out;
1120 }
1121
1122 if (cleanup_entity(ent))
1123 goto out2;
1124
1125 repend:
1126 if ((ent->add_pending)
1127 || (ent->changed)
1128 || (ent->present_change_count))
1129 {
1130 /* Something happened to the entity while we were working,
1131 retry the operation to report the new thing. */
1132 goto retry;
1133 }
1134 }
1135 out:
1136 /* Wait till here to start fetching FRUs, as we want to report the
1137 entity first before we start the fetch. */
1138 ent_lock(ent);
1139 if (ent->present && !ent->in_fru_fetch && entity_fru_fetch) {
1140 int rv;
1141
1142 entity_fru_fetch = 0;
1143 ent->in_fru_fetch = 1;
1144 ent_unlock(ent);
1145 rv = ipmi_entity_fetch_frus_cb(ent, internal_fru_fetch_done, NULL);
1146 if (rv) {
1147 ent_lock(ent);
1148 ent->in_fru_fetch = 0;
1149 ent_unlock(ent);
1150 }
1151 goto repend;
1152 }
1153
1154 if (ent->usecount == 1 && !ent->fully_up && ent->sdr_add_done &&
1155 !ent->in_presence_check && !ent->in_fru_fetch &&
1156 !(ent_use_frudev_for_presence(ent) && !ent->frudev_active_reported)) {
1157 ent->fully_up = 1;
1158 report_fully_up = 1;
1159 }
1160 ent_unlock(ent);
1161
1162 if (report_fully_up) {
1163 i_ipmi_domain_entity_unlock(domain);
1164 call_fully_up_handlers(ent);
1165 i_ipmi_domain_entity_lock(domain);
1166 if (ent->usecount != 1)
1167 goto retry;
1168 }
1169
1170 ent->usecount--;
1171
1172 out2:
1173 i_ipmi_domain_entity_unlock(domain);
1174 }
1175
1176 int
i_ipmi_entity_add_ref(ipmi_entity_t * ent)1177 i_ipmi_entity_add_ref(ipmi_entity_t *ent)
1178 {
1179 ent_lock(ent);
1180 ent->ref_count++;
1181 ent_unlock(ent);
1182 return 0;
1183 }
1184
1185 int
i_ipmi_entity_remove_ref(ipmi_entity_t * ent)1186 i_ipmi_entity_remove_ref(ipmi_entity_t *ent)
1187 {
1188 ent_lock(ent);
1189 ent->ref_count--;
1190 ent_unlock(ent);
1191 return 0;
1192 }
1193
1194 int
ipmi_entity_info_add_update_handler(ipmi_entity_info_t * ents,ipmi_domain_entity_cb handler,void * cb_data)1195 ipmi_entity_info_add_update_handler(ipmi_entity_info_t *ents,
1196 ipmi_domain_entity_cb handler,
1197 void *cb_data)
1198 {
1199 if (locked_list_add(ents->update_handlers, handler, cb_data))
1200 return 0;
1201 else
1202 return ENOMEM;
1203 }
1204
1205 int
ipmi_entity_info_remove_update_handler(ipmi_entity_info_t * ents,ipmi_domain_entity_cb handler,void * cb_data)1206 ipmi_entity_info_remove_update_handler(ipmi_entity_info_t *ents,
1207 ipmi_domain_entity_cb handler,
1208 void *cb_data)
1209 {
1210 if (locked_list_remove(ents->update_handlers, handler, cb_data))
1211 return 0;
1212 else
1213 return EINVAL;
1214 }
1215
1216 int
ipmi_entity_info_add_update_handler_cl(ipmi_entity_info_t * ents,ipmi_domain_entity_cl_cb handler,void * cb_data)1217 ipmi_entity_info_add_update_handler_cl(ipmi_entity_info_t *ents,
1218 ipmi_domain_entity_cl_cb handler,
1219 void *cb_data)
1220 {
1221 if (locked_list_add(ents->update_cl_handlers, handler, cb_data))
1222 return 0;
1223 else
1224 return ENOMEM;
1225 }
1226
1227 int
ipmi_entity_info_remove_update_handler_cl(ipmi_entity_info_t * ents,ipmi_domain_entity_cl_cb handler,void * cb_data)1228 ipmi_entity_info_remove_update_handler_cl(ipmi_entity_info_t *ents,
1229 ipmi_domain_entity_cl_cb handler,
1230 void *cb_data)
1231 {
1232 if (locked_list_remove(ents->update_cl_handlers, handler, cb_data))
1233 return 0;
1234 else
1235 return EINVAL;
1236 }
1237
1238 typedef struct search_info_s {
1239 dlr_ref_t key;
1240 ipmi_entity_t *ent;
1241 } search_info_t;
1242
1243 static int
search_entity(void * cb_data,void * item1,void * item2)1244 search_entity(void *cb_data, void *item1, void *item2)
1245 {
1246 ipmi_entity_t *ent = (ipmi_entity_t *) item1;
1247 search_info_t *info = (search_info_t *) cb_data;
1248 int same;
1249
1250 same = ((ent->key.device_num.channel == info->key.device_num.channel)
1251 && (ent->key.device_num.address == info->key.device_num.address)
1252 && (ent->key.entity_id == info->key.entity_id)
1253 && (ent->key.entity_instance == info->key.entity_instance));
1254 if (same) {
1255 info->ent = ent;
1256 return LOCKED_LIST_ITER_STOP;
1257 }
1258 return LOCKED_LIST_ITER_CONTINUE;
1259 }
1260
1261 static int
entity_find(ipmi_entity_info_t * ents,ipmi_device_num_t device_num,int entity_id,int entity_instance,ipmi_entity_t ** found_ent)1262 entity_find(ipmi_entity_info_t *ents,
1263 ipmi_device_num_t device_num,
1264 int entity_id,
1265 int entity_instance,
1266 ipmi_entity_t **found_ent)
1267 {
1268 search_info_t info = { {device_num, entity_id, entity_instance}, NULL};
1269 int rv = 0;
1270
1271 locked_list_iterate_nolock(ents->entities, search_entity, &info);
1272 if (info.ent == NULL) {
1273 rv = ENOENT;
1274 } else {
1275 info.ent->usecount++;
1276 if (found_ent)
1277 *found_ent = info.ent;
1278 }
1279
1280 return rv;
1281 }
1282
1283 int
ipmi_entity_find(ipmi_entity_info_t * ents,ipmi_mc_t * mc,int entity_id,int entity_instance,ipmi_entity_t ** found_ent)1284 ipmi_entity_find(ipmi_entity_info_t *ents,
1285 ipmi_mc_t *mc,
1286 int entity_id,
1287 int entity_instance,
1288 ipmi_entity_t **found_ent)
1289 {
1290 ipmi_device_num_t device_num;
1291 int rv;
1292 ipmi_entity_t *ent;
1293
1294 CHECK_DOMAIN_LOCK(ents->domain);
1295
1296 if (mc && entity_instance >= 0x60) {
1297 device_num.channel = ipmi_mc_get_channel(mc);
1298 device_num.address = ipmi_mc_get_address(mc);
1299 } else {
1300 device_num.channel = 0;
1301 device_num.address = 0;
1302 }
1303 i_ipmi_domain_entity_lock(ents->domain);
1304 rv = entity_find(ents, device_num, entity_id, entity_instance, &ent);
1305 if (!rv) {
1306 if (ent->destroyed)
1307 rv = ENOENT;
1308 else
1309 *found_ent = ent;
1310 }
1311 i_ipmi_domain_entity_unlock(ents->domain);
1312 return rv;
1313 }
1314
1315 /* Must be called with i_ipmi_domain_entity_lock(), this will release
1316 the lock. */
1317 static int
entity_add(ipmi_entity_info_t * ents,ipmi_device_num_t device_num,int entity_id,int entity_instance,entity_sdr_add_cb sdr_gen_output,void * sdr_gen_cb_data,ipmi_entity_t ** new_ent)1318 entity_add(ipmi_entity_info_t *ents,
1319 ipmi_device_num_t device_num,
1320 int entity_id,
1321 int entity_instance,
1322 entity_sdr_add_cb sdr_gen_output,
1323 void *sdr_gen_cb_data,
1324 ipmi_entity_t **new_ent)
1325 {
1326 int rv;
1327 ipmi_entity_t *ent;
1328 os_handler_t *os_hnd;
1329
1330 rv = entity_find(ents, device_num, entity_id, entity_instance, &ent);
1331 if (! rv) {
1332 if (ent->destroyed) {
1333 /* A destroy is currently being reported on the entity,
1334 resurrect it. */
1335 ent->destroyed = 0;
1336 ent->add_pending = 1;
1337 }
1338 i_ipmi_domain_entity_unlock(ents->domain);
1339 if (sdr_gen_output != NULL) {
1340 ent->sdr_gen_output = sdr_gen_output;
1341 ent->sdr_gen_cb_data = sdr_gen_cb_data;
1342 }
1343 *new_ent = ent;
1344 return 0;
1345 }
1346
1347 ent = ipmi_mem_alloc(sizeof(*ent));
1348 if (!ent)
1349 return ENOMEM;
1350 memset(ent, 0, sizeof(*ent));
1351
1352 os_hnd = ipmi_domain_get_os_hnd(ents->domain);
1353
1354 ent->sdr_gen_output = sdr_gen_output;
1355 ent->sdr_gen_cb_data = sdr_gen_cb_data;
1356
1357 ent->domain = ents->domain;
1358 ent->os_hnd = ipmi_domain_get_os_hnd(ent->domain);
1359 ent->domain_id = ents->domain_id;
1360 ent->seq = ipmi_get_seq();
1361 ent->child_entities = locked_list_alloc_my_lock(entities_lock,
1362 entities_unlock,
1363 ents->domain);
1364 if (!ent->child_entities)
1365 goto out_err;
1366
1367 ent->parent_entities = locked_list_alloc_my_lock(entities_lock,
1368 entities_unlock,
1369 ents->domain);
1370 if (!ent->parent_entities)
1371 goto out_err;
1372
1373 ent->sensors = locked_list_alloc_my_lock(entities_lock,
1374 entities_unlock,
1375 ents->domain);
1376 if (!ent->sensors)
1377 goto out_err;
1378
1379 ent->controls = locked_list_alloc_my_lock(entities_lock,
1380 entities_unlock,
1381 ents->domain);
1382 if (!ent->controls)
1383 goto out_err;
1384
1385 ent->hot_swap_handlers_cl = locked_list_alloc(ent->os_hnd);
1386 if (!ent->hot_swap_handlers_cl)
1387 goto out_err;
1388 ent->hot_swap_handlers = locked_list_alloc(ent->os_hnd);
1389 if (!ent->hot_swap_handlers)
1390 goto out_err;
1391
1392 ent->presence_handlers_cl = locked_list_alloc(ent->os_hnd);
1393 if (!ent->presence_handlers_cl)
1394 goto out_err;
1395 ent->presence_handlers = locked_list_alloc(ent->os_hnd);
1396 if (!ent->presence_handlers)
1397 goto out_err;
1398
1399 ent->fully_up_handlers_cl = locked_list_alloc(ent->os_hnd);
1400 if (!ent->fully_up_handlers_cl)
1401 goto out_err;
1402 ent->fully_up_handlers = locked_list_alloc(ent->os_hnd);
1403 if (!ent->fully_up_handlers)
1404 goto out_err;
1405
1406 ent->waitq = opq_alloc(os_hnd);
1407 if (! ent->waitq)
1408 return ENOMEM;
1409
1410 ent->fru_handlers_cl = locked_list_alloc(ent->os_hnd);
1411 if (!ent->fru_handlers_cl)
1412 goto out_err;
1413 ent->fru_handlers = locked_list_alloc(ent->os_hnd);
1414 if (!ent->fru_handlers)
1415 goto out_err;
1416
1417 ent->fru_handlers_werr_cl = locked_list_alloc(ent->os_hnd);
1418 if (!ent->fru_handlers_werr_cl)
1419 goto out_err;
1420 ent->fru_handlers_werr = locked_list_alloc(ent->os_hnd);
1421 if (!ent->fru_handlers_werr)
1422 goto out_err;
1423
1424 ent->sensor_handlers_cl = locked_list_alloc(ent->os_hnd);
1425 if (!ent->sensor_handlers_cl)
1426 goto out_err;
1427 ent->sensor_handlers = locked_list_alloc(ent->os_hnd);
1428 if (!ent->sensor_handlers)
1429 goto out_err;
1430
1431 ent->control_handlers_cl = locked_list_alloc(ent->os_hnd);
1432 if (!ent->control_handlers_cl)
1433 goto out_err;
1434 ent->control_handlers = locked_list_alloc(ent->os_hnd);
1435 if (!ent->control_handlers)
1436 goto out_err;
1437
1438 rv = ipmi_create_lock(ent->domain, &ent->elock);
1439 if (rv)
1440 goto out_err;
1441
1442 rv = entity_alloc_timer(ent, &ent->hot_swap_act_info);
1443 if (rv)
1444 goto out_err;
1445
1446 rv = entity_alloc_timer(ent, &ent->hot_swap_deact_info);
1447 if (rv)
1448 goto out_err;
1449
1450 ent->presence_sensor = NULL;
1451 ent->presence_bit_sensor = NULL;
1452 ent->present = 0;
1453 ent->presence_possibly_changed = 1;
1454
1455 ent->hot_swap_act_timeout = IPMI_TIMEOUT_FOREVER;
1456 ent->hot_swap_deact_timeout = IPMI_TIMEOUT_FOREVER;
1457
1458 ent->ents = ents;
1459
1460 ent->info.type = IPMI_ENTITY_UNKNOWN;
1461 ent->key.device_num = device_num;
1462 ent->key.entity_id = entity_id;
1463 ent->key.entity_instance = entity_instance;
1464 ent->info.id_type = IPMI_ASCII_STR;
1465
1466 ent->entity_id_string = ipmi_get_entity_id_string(entity_id);
1467
1468 ent->usecount = 1;
1469
1470 entity_set_name(ent);
1471
1472 if (! locked_list_add_nolock(ents->entities, ent, NULL))
1473 goto out_err;
1474
1475 i_ipmi_domain_entity_unlock(ent->domain);
1476
1477 /* Report the add when the entity is put. */
1478 ent->add_pending = 1;
1479
1480 if (new_ent)
1481 *new_ent = ent;
1482
1483 return 0;
1484
1485 out_err:
1486 i_ipmi_domain_entity_unlock(ent->domain);
1487 if (ent->hot_swap_act_info)
1488 entity_destroy_timer(ent->hot_swap_act_info);
1489 if (ent->hot_swap_deact_info)
1490 entity_destroy_timer(ent->hot_swap_deact_info);
1491 if (ent->elock)
1492 ipmi_destroy_lock(ent->elock);
1493 if (ent->presence_handlers)
1494 locked_list_destroy(ent->presence_handlers);
1495 if (ent->presence_handlers_cl)
1496 locked_list_destroy(ent->presence_handlers_cl);
1497 if (ent->fully_up_handlers)
1498 locked_list_destroy(ent->fully_up_handlers);
1499 if (ent->fully_up_handlers_cl)
1500 locked_list_destroy(ent->fully_up_handlers_cl);
1501 if (ent->waitq)
1502 opq_destroy(ent->waitq);
1503 if (ent->fru_handlers)
1504 locked_list_destroy(ent->fru_handlers);
1505 if (ent->fru_handlers_cl)
1506 locked_list_destroy(ent->fru_handlers_cl);
1507 if (ent->fru_handlers_werr)
1508 locked_list_destroy(ent->fru_handlers_werr);
1509 if (ent->fru_handlers_werr_cl)
1510 locked_list_destroy(ent->fru_handlers_werr_cl);
1511 if (ent->control_handlers)
1512 locked_list_destroy(ent->control_handlers);
1513 if (ent->control_handlers_cl)
1514 locked_list_destroy(ent->control_handlers_cl);
1515 if (ent->sensor_handlers)
1516 locked_list_destroy(ent->sensor_handlers);
1517 if (ent->sensor_handlers_cl)
1518 locked_list_destroy(ent->sensor_handlers_cl);
1519 if (ent->hot_swap_handlers)
1520 locked_list_destroy(ent->hot_swap_handlers);
1521 if (ent->hot_swap_handlers_cl)
1522 locked_list_destroy(ent->hot_swap_handlers_cl);
1523 if (ent->controls)
1524 locked_list_destroy(ent->controls);
1525 if (ent->sensors)
1526 locked_list_destroy(ent->sensors);
1527 if (ent->parent_entities)
1528 locked_list_destroy(ent->parent_entities);
1529 if (ent->child_entities)
1530 locked_list_destroy(ent->child_entities);
1531 ipmi_mem_free(ent);
1532 return ENOMEM;
1533 }
1534
1535 int
ipmi_entity_add(ipmi_entity_info_t * ents,ipmi_domain_t * domain,unsigned char mc_channel,unsigned char mc_slave_addr,int lun,int entity_id,int entity_instance,char * id,enum ipmi_str_type_e id_type,unsigned int id_len,entity_sdr_add_cb sdr_gen_output,void * sdr_gen_cb_data,ipmi_entity_t ** new_ent)1536 ipmi_entity_add(ipmi_entity_info_t *ents,
1537 ipmi_domain_t *domain,
1538 unsigned char mc_channel,
1539 unsigned char mc_slave_addr,
1540 int lun,
1541 int entity_id,
1542 int entity_instance,
1543 char *id,
1544 enum ipmi_str_type_e id_type,
1545 unsigned int id_len,
1546 entity_sdr_add_cb sdr_gen_output,
1547 void *sdr_gen_cb_data,
1548 ipmi_entity_t **new_ent)
1549 {
1550 ipmi_device_num_t device_num;
1551 int rv;
1552 ipmi_entity_t *ent;
1553
1554 CHECK_DOMAIN_LOCK(domain);
1555
1556 if (entity_instance >= 0x60) {
1557 device_num.channel = mc_channel;
1558 device_num.address = mc_slave_addr;
1559 } else {
1560 device_num.channel = 0;
1561 device_num.address = 0;
1562 }
1563
1564 i_ipmi_domain_entity_lock(domain);
1565
1566 /* This will release the lock. */
1567 rv = entity_add(ents, device_num, entity_id, entity_instance,
1568 sdr_gen_output, sdr_gen_cb_data, &ent);
1569 if (!rv) {
1570 ent_lock(ent);
1571 ent->sdr_add_done = 1; /* Not added by SDR, so fudge. */
1572 ent_unlock(ent);
1573 if (!ent->info.id_len)
1574 ipmi_entity_set_id(ent, id, id_type, id_len);
1575 if (new_ent)
1576 *new_ent = ent;
1577 }
1578
1579 return rv;
1580 }
1581
1582 /* Must be called with both the child and parent entities used and the
1583 domain entity lock held. */
1584 static void
add_child(ipmi_entity_t * ent,ipmi_entity_t * child,locked_list_entry_t * entry1,locked_list_entry_t * entry2)1585 add_child(ipmi_entity_t *ent,
1586 ipmi_entity_t *child,
1587 locked_list_entry_t *entry1,
1588 locked_list_entry_t *entry2)
1589 {
1590 locked_list_add_entry_nolock(ent->child_entities, child, NULL, entry1);
1591 locked_list_add_entry_nolock(child->parent_entities, ent, NULL, entry2);
1592
1593 ent->presence_possibly_changed = 1;
1594 }
1595
1596 int
ipmi_entity_add_child(ipmi_entity_t * ent,ipmi_entity_t * child)1597 ipmi_entity_add_child(ipmi_entity_t *ent,
1598 ipmi_entity_t *child)
1599 {
1600 locked_list_entry_t *entry1;
1601 locked_list_entry_t *entry2;
1602 int rv = 0;
1603
1604 CHECK_ENTITY_LOCK(ent);
1605 CHECK_ENTITY_LOCK(child);
1606
1607 i_ipmi_domain_entity_lock(ent->domain);
1608
1609 entry1 = locked_list_alloc_entry();
1610 if (!entry1) {
1611 rv = ENOMEM;
1612 goto out_unlock;
1613 }
1614 entry2 = locked_list_alloc_entry();
1615 if (!entry2) {
1616 locked_list_free_entry(entry1);
1617 rv = ENOMEM;
1618 goto out_unlock;
1619 }
1620
1621 add_child(ent, child, entry1, entry2);
1622
1623 ent->changed = 1;
1624 child->changed = 1;
1625
1626 i_ipmi_domain_entity_unlock(ent->domain);
1627
1628 return 0;
1629
1630 out_unlock:
1631 i_ipmi_domain_entity_unlock(ent->domain);
1632 return rv;
1633 }
1634
1635 static int
ipmi_entity_remove_child_internal(ipmi_entity_t * ent,ipmi_entity_t * child)1636 ipmi_entity_remove_child_internal(ipmi_entity_t *ent,
1637 ipmi_entity_t *child)
1638 {
1639 int rv = 0;
1640
1641 CHECK_ENTITY_LOCK(ent);
1642 CHECK_ENTITY_LOCK(child);
1643
1644 if (! locked_list_remove_nolock(ent->child_entities, child, NULL))
1645 rv = EINVAL;
1646 locked_list_remove_nolock(child->parent_entities, ent, NULL);
1647
1648 ent->presence_possibly_changed = 1;
1649
1650 if (!rv) {
1651 ent->changed = 1;
1652 child->changed = 1;
1653 }
1654
1655 return rv;
1656 }
1657
1658 int
ipmi_entity_remove_child(ipmi_entity_t * ent,ipmi_entity_t * child)1659 ipmi_entity_remove_child(ipmi_entity_t *ent,
1660 ipmi_entity_t *child)
1661 {
1662 int rv = 0;
1663
1664 CHECK_ENTITY_LOCK(ent);
1665 CHECK_ENTITY_LOCK(child);
1666
1667 i_ipmi_domain_entity_lock(ent->domain);
1668
1669 if (! locked_list_remove_nolock(ent->child_entities, child, NULL))
1670 rv = EINVAL;
1671 locked_list_remove_nolock(child->parent_entities, ent, NULL);
1672
1673 ent->presence_possibly_changed = 1;
1674
1675 i_ipmi_domain_entity_unlock(ent->domain);
1676
1677 if (!rv) {
1678 ent->changed = 1;
1679 child->changed = 1;
1680 }
1681
1682 return rv;
1683 }
1684
1685 typedef struct iterate_child_info_s
1686 {
1687 ipmi_entity_t *ent;
1688 ipmi_entity_iterate_child_cb handler;
1689 void *cb_data;
1690 } iterate_child_info_t;
1691
1692 static int
iterate_child_handler(void * cb_data,void * item1,void * item2)1693 iterate_child_handler(void *cb_data, void *item1, void *item2)
1694 {
1695 iterate_child_info_t *info = cb_data;
1696 ipmi_entity_t *ent = item1;
1697
1698 info->handler(info->ent, item1, info->cb_data);
1699 i_ipmi_entity_put(ent);
1700 return LOCKED_LIST_ITER_CONTINUE;
1701 }
1702
1703 void
ipmi_entity_iterate_children(ipmi_entity_t * ent,ipmi_entity_iterate_child_cb handler,void * cb_data)1704 ipmi_entity_iterate_children(ipmi_entity_t *ent,
1705 ipmi_entity_iterate_child_cb handler,
1706 void *cb_data)
1707 {
1708 iterate_child_info_t info = { ent, handler, cb_data };
1709
1710 locked_list_iterate_prefunc(ent->child_entities, iterate_entity_prefunc,
1711 iterate_child_handler, &info);
1712 }
1713
1714 typedef struct iterate_parent_info_s
1715 {
1716 ipmi_entity_t *ent;
1717 ipmi_entity_iterate_parent_cb handler;
1718 void *cb_data;
1719 } iterate_parent_info_t;
1720
1721 static int
iterate_parent_handler(void * cb_data,void * item1,void * item2)1722 iterate_parent_handler(void *cb_data, void *item1, void *item2)
1723 {
1724 iterate_parent_info_t *info = cb_data;
1725 ipmi_entity_t *ent = item1;
1726
1727 info->handler(info->ent, item1, info->cb_data);
1728 i_ipmi_entity_put(ent);
1729 return LOCKED_LIST_ITER_CONTINUE;
1730 }
1731
1732 void
ipmi_entity_iterate_parents(ipmi_entity_t * ent,ipmi_entity_iterate_parent_cb handler,void * cb_data)1733 ipmi_entity_iterate_parents(ipmi_entity_t *ent,
1734 ipmi_entity_iterate_parent_cb handler,
1735 void *cb_data)
1736 {
1737 iterate_parent_info_t info = { ent, handler, cb_data };
1738
1739 CHECK_ENTITY_LOCK(ent);
1740
1741 locked_list_iterate_prefunc(ent->parent_entities, iterate_entity_prefunc,
1742 iterate_parent_handler, &info);
1743 }
1744
1745 /***********************************************************************
1746 *
1747 * Entity presence handling.
1748 *
1749 **********************************************************************/
1750
1751 static int handle_hot_swap_presence(ipmi_entity_t *ent,
1752 int present,
1753 ipmi_event_t *event);
1754
1755 int
ipmi_entity_add_presence_handler(ipmi_entity_t * ent,ipmi_entity_presence_change_cb handler,void * cb_data)1756 ipmi_entity_add_presence_handler(ipmi_entity_t *ent,
1757 ipmi_entity_presence_change_cb handler,
1758 void *cb_data)
1759 {
1760 CHECK_ENTITY_LOCK(ent);
1761 if (locked_list_add(ent->presence_handlers, handler, cb_data))
1762 return 0;
1763 else
1764 return ENOMEM;
1765 }
1766
1767 int
ipmi_entity_remove_presence_handler(ipmi_entity_t * ent,ipmi_entity_presence_change_cb handler,void * cb_data)1768 ipmi_entity_remove_presence_handler(ipmi_entity_t *ent,
1769 ipmi_entity_presence_change_cb handler,
1770 void *cb_data)
1771 {
1772 CHECK_ENTITY_LOCK(ent);
1773 if (locked_list_remove(ent->presence_handlers, handler, cb_data))
1774 return 0;
1775 else
1776 return EINVAL;
1777 }
1778
1779 int
ipmi_entity_add_presence_handler_cl(ipmi_entity_t * ent,ipmi_entity_presence_cl_cb handler,void * cb_data)1780 ipmi_entity_add_presence_handler_cl(ipmi_entity_t *ent,
1781 ipmi_entity_presence_cl_cb handler,
1782 void *cb_data)
1783 {
1784 CHECK_ENTITY_LOCK(ent);
1785 if (locked_list_add(ent->presence_handlers_cl, handler, cb_data))
1786 return 0;
1787 else
1788 return ENOMEM;
1789 }
1790
1791 int
ipmi_entity_remove_presence_handler_cl(ipmi_entity_t * ent,ipmi_entity_presence_cl_cb handler,void * cb_data)1792 ipmi_entity_remove_presence_handler_cl(ipmi_entity_t *ent,
1793 ipmi_entity_presence_cl_cb handler,
1794 void *cb_data)
1795 {
1796 CHECK_ENTITY_LOCK(ent);
1797 if (locked_list_remove(ent->presence_handlers_cl, handler, cb_data))
1798 return 0;
1799 else
1800 return EINVAL;
1801 }
1802
1803 typedef struct presence_handler_info_s
1804 {
1805 ipmi_entity_t *ent;
1806 int present;
1807 } presence_handler_info_t;
1808
1809 static int
call_presence_handler(void * cb_data,void * item1,void * item2)1810 call_presence_handler(void *cb_data, void *item1, void *item2)
1811 {
1812 presence_handler_info_t *info = cb_data;
1813 ipmi_entity_presence_change_cb handler = item1;
1814
1815 handler(info->ent, info->present, item2, NULL);
1816 return LOCKED_LIST_ITER_CONTINUE;
1817 }
1818
1819 static void
call_presence_handlers(ipmi_entity_t * ent,int present)1820 call_presence_handlers(ipmi_entity_t *ent, int present)
1821 {
1822 presence_handler_info_t info;
1823
1824 info.ent = ent;
1825 info.present = present;
1826 ent_lock(ent);
1827 if (ent->cruft_presence_handler) {
1828 ipmi_entity_presence_nd_cb handler = ent->cruft_presence_handler;
1829 void *cb_data = ent->cruft_presence_cb_data;
1830 ent_unlock(ent);
1831 handler(ent, info.present, cb_data, NULL);
1832 } else
1833 ent_unlock(ent);
1834 locked_list_iterate(ent->presence_handlers, call_presence_handler,
1835 &info);
1836 }
1837
1838 /* This is for iterating the parents when a sensor's presence changes.
1839 The parent's presence may depend on it's childrens' presence, if it
1840 has no sensors. */
1841 static void
presence_parent_handler(ipmi_entity_t * ent,ipmi_entity_t * parent,void * cb_data)1842 presence_parent_handler(ipmi_entity_t *ent,
1843 ipmi_entity_t *parent,
1844 void *cb_data)
1845 {
1846 /* We only set the entity to check presence. We can't use the
1847 child directly because the algorithm is unfortunately
1848 complicated. */
1849 parent->presence_possibly_changed = 1;
1850 }
1851
1852 static void
presence_changed(ipmi_entity_t * ent,int present)1853 presence_changed(ipmi_entity_t *ent, int present)
1854 {
1855 ipmi_fru_t *fru;
1856 ipmi_domain_t *domain = ent->domain;
1857 int entity_fru_fetch = 0;
1858
1859 ent->presence_event_count++;
1860
1861 if (present != ent->curr_present) {
1862 ent->curr_present = present;
1863
1864 if (ent->hot_swappable
1865 &&(ent->hs_cb.get_hot_swap_state == e_get_hot_swap_state))
1866 {
1867 /* Do internal presence handling if we have the internal
1868 hot-swap machine installed. */
1869 handle_hot_swap_presence(ent, present, NULL);
1870 }
1871
1872 /* When the entity becomes present or absent, fetch or destroy
1873 its FRU info. */
1874 if (ipmi_entity_get_is_fru(ent)) {
1875 if (present) {
1876 entity_fru_fetch = 1;
1877 } else if (ent->fru != NULL) {
1878 fru = ent->fru;
1879 ent->fru = NULL;
1880 ipmi_fru_destroy_internal(fru, NULL, NULL);
1881
1882 i_ipmi_entity_call_fru_handlers(ent, IPMI_DELETED, 0);
1883 }
1884 }
1885
1886 /* Subtle stuff, we only report presence if no one else is
1887 using the entity. If someone else is, we save it for
1888 later. */
1889 i_ipmi_domain_entity_lock(domain);
1890 if (ent->usecount == 1) {
1891 ent->present = !ent->present;
1892 i_ipmi_domain_entity_unlock(domain);
1893 call_presence_handlers(ent, present);
1894 i_ipmi_domain_entity_lock(domain);
1895 while ((ent->usecount == 1) && (ent->present_change_count)) {
1896 ent->present = !ent->present;
1897 present = ent->present;
1898 ent->present_change_count--;
1899 i_ipmi_domain_entity_unlock(domain);
1900 call_presence_handlers(ent, present);
1901 i_ipmi_domain_entity_lock(domain);
1902 }
1903 } else {
1904 ent->present_change_count++;
1905 }
1906
1907 /* Wait till here to start fetching FRUs, as we want to report
1908 the entity first before we start the fetch. */
1909 ent_lock(ent);
1910 if (ent->present && !ent->in_fru_fetch && entity_fru_fetch) {
1911 int rv;
1912
1913 entity_fru_fetch = 0;
1914 ent->in_fru_fetch = 1;
1915 ent_unlock(ent);
1916 rv = ipmi_entity_fetch_frus_cb(ent, internal_fru_fetch_done, NULL);
1917 if (rv) {
1918 ent_lock(ent);
1919 ent->in_fru_fetch = 0;
1920 ent_unlock(ent);
1921 }
1922 } else {
1923 ent_unlock(ent);
1924 }
1925
1926 i_ipmi_domain_entity_unlock(domain);
1927
1928 /* If our presence changes, that can affect parents, too. So we
1929 rescan them. */
1930 ipmi_entity_iterate_parents(ent, presence_parent_handler, NULL);
1931 }
1932 }
1933
1934 static void
presence_child_handler(ipmi_entity_t * ent,ipmi_entity_t * child,void * cb_data)1935 presence_child_handler(ipmi_entity_t *ent,
1936 ipmi_entity_t *child,
1937 void *cb_data)
1938 {
1939 int *present = cb_data;
1940 int p = child->present;
1941
1942 if (ent->present_change_count % 2)
1943 p = !p;
1944 if (p)
1945 *present = p;
1946 }
1947
1948 static int
presence_sensor_changed(ipmi_sensor_t * sensor,enum ipmi_event_dir_e dir,int offset,int severity,int prev_severity,void * cb_data,ipmi_event_t * event)1949 presence_sensor_changed(ipmi_sensor_t *sensor,
1950 enum ipmi_event_dir_e dir,
1951 int offset,
1952 int severity,
1953 int prev_severity,
1954 void *cb_data,
1955 ipmi_event_t *event)
1956 {
1957 ipmi_entity_t *ent = cb_data;
1958
1959 /* zero offset is the "present" offset, 1 or 2 means it absent or
1960 disabled, coupled with the assertion/deassertion. */
1961 if (dir == IPMI_ASSERTION)
1962 presence_changed(ent, offset == ent->presence_bit_offset);
1963 else if (dir == IPMI_DEASSERTION)
1964 presence_changed(ent, offset != ent->presence_bit_offset);
1965 return IPMI_EVENT_NOT_HANDLED;
1966 }
1967
1968 static int
presence_bit_sensor_changed(ipmi_sensor_t * sensor,enum ipmi_event_dir_e dir,int offset,int severity,int prev_severity,void * cb_data,ipmi_event_t * event)1969 presence_bit_sensor_changed(ipmi_sensor_t *sensor,
1970 enum ipmi_event_dir_e dir,
1971 int offset,
1972 int severity,
1973 int prev_severity,
1974 void *cb_data,
1975 ipmi_event_t *event)
1976 {
1977 ipmi_entity_t *ent = cb_data;
1978
1979 if (offset != ent->presence_bit_offset)
1980 return IPMI_EVENT_NOT_HANDLED;
1981
1982 /* Assertion means present. */
1983 if (dir == IPMI_ASSERTION)
1984 presence_changed(ent, 1);
1985 else if (dir == IPMI_DEASSERTION)
1986 presence_changed(ent, 0);
1987 return IPMI_EVENT_NOT_HANDLED;
1988 }
1989
1990 typedef struct ent_detect_info_s
1991 {
1992 int force;
1993 } ent_detect_info_t;
1994
1995 typedef struct ent_active_detect_s
1996 {
1997 ipmi_lock_t *lock;
1998 ipmi_entity_id_t ent_id;
1999 int try_count;
2000 int done_count;
2001 int present;
2002 unsigned int start_presence_event_count;
2003 ipmi_msg_t *msg;
2004 } ent_active_detect_t;
2005
2006 static void
detect_cleanup(ent_active_detect_t * info,ipmi_entity_t * ent,ipmi_domain_t * domain)2007 detect_cleanup(ent_active_detect_t *info, ipmi_entity_t *ent,
2008 ipmi_domain_t *domain)
2009 {
2010 ipmi_unlock(info->lock);
2011 ipmi_destroy_lock(info->lock);
2012 ipmi_mem_free(info);
2013 if (ent) {
2014 ent_lock(ent);
2015 ent->in_presence_check = 0;
2016 ent_unlock(ent);
2017 }
2018 i_ipmi_put_domain_fully_up(domain, "detect_cleanup");
2019 }
2020
2021 static void
presence_finalize(ipmi_entity_t * ent,const char * source)2022 presence_finalize(ipmi_entity_t *ent, const char *source)
2023 {
2024 ent_lock(ent);
2025 ent->in_presence_check = 0;
2026 ent_unlock(ent);
2027 i_ipmi_put_domain_fully_up(ent->domain, source);
2028 }
2029
2030 static void
detect_done(ipmi_entity_t * ent,ent_active_detect_t * info)2031 detect_done(ipmi_entity_t *ent, ent_active_detect_t *info)
2032 {
2033 ipmi_unlock(info->lock);
2034 presence_changed(ent, info->present);
2035 ipmi_destroy_lock(info->lock);
2036 ipmi_mem_free(info);
2037 presence_finalize(ent, "detect_done");
2038 }
2039
2040 static void
detect_frudev_handler(ipmi_entity_t * ent,void * cb_data)2041 detect_frudev_handler(ipmi_entity_t *ent, void *cb_data)
2042 {
2043 ent_active_detect_t *info = cb_data;
2044
2045 if (info->start_presence_event_count != ent->presence_event_count) {
2046 /* Something else has changed the presence since we started
2047 the presence detection process, then don't change the
2048 value. There are races where the entity could have been
2049 set present and we detect it as not present. However, it
2050 is not possible to detect it as present and for something
2051 else to set it not present. */
2052 detect_cleanup(info, ent, ent->domain);
2053 return;
2054 }
2055
2056 if (info->msg->data[0] == 0)
2057 info->present = 1;
2058
2059 detect_done(ent, info);
2060 }
2061
2062 static void
detect_frudev(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)2063 detect_frudev(ipmi_mc_t *mc,
2064 ipmi_msg_t *rsp,
2065 void *rsp_data)
2066 {
2067 ent_active_detect_t *info = rsp_data;
2068
2069 ipmi_lock(info->lock);
2070 info->msg = rsp;
2071 if (ipmi_entity_pointer_cb(info->ent_id, detect_frudev_handler, info))
2072 /* We cheat and pull the domain from the entity id. The domain
2073 * still has to be around in the place, but we can't rely on the
2074 * MC as it may have gone away if it failed or the domain is in
2075 * shutdown. */
2076 detect_cleanup(info, NULL, info->ent_id.domain_id.domain);
2077 }
2078
2079 /* This is the end of the line on checks. We have to report something
2080 here. */
2081 static void
try_presence_frudev(ipmi_entity_t * ent,ent_active_detect_t * info)2082 try_presence_frudev(ipmi_entity_t *ent, ent_active_detect_t *info)
2083 {
2084 ipmi_msg_t msg;
2085 unsigned char data[1];
2086 int rv;
2087
2088 if ((!ent->frudev_present) || (!ent->frudev_active)) {
2089 detect_done(ent, info);
2090 return;
2091 }
2092
2093 msg.netfn = IPMI_STORAGE_NETFN;
2094 msg.cmd = IPMI_GET_FRU_INVENTORY_AREA_INFO_CMD;
2095 msg.data = data;
2096 data[0] = ent->info.fru_device_id; /* Will be 0 for MCs, so this
2097 is ok even though it is not
2098 in the MC record. */
2099 msg.data_len = 1;
2100
2101 /* Send a message to the FRU device and see if we can get some
2102 data. */
2103 i_ipmi_domain_mc_lock(ent->domain);
2104 i_ipmi_mc_get(ent->frudev_mc);
2105 i_ipmi_domain_mc_unlock(ent->domain);
2106 rv = ipmi_mc_send_command(ent->frudev_mc, ent->info.lun, &msg,
2107 detect_frudev, info);
2108 i_ipmi_mc_put(ent->frudev_mc);
2109 if (rv)
2110 detect_done(ent, info);
2111 else
2112 ipmi_unlock(info->lock);
2113 }
2114
2115 static int
try_presence_children(ipmi_entity_t * parent,ent_active_detect_t * info)2116 try_presence_children(ipmi_entity_t *parent, ent_active_detect_t *info)
2117 {
2118 if (! ipmi_entity_get_is_parent(parent))
2119 return ENOSYS;
2120
2121 ipmi_entity_iterate_children(parent, presence_child_handler,
2122 &info->present);
2123 detect_done(parent, info);
2124 return 0;
2125 }
2126
2127 static void
control_detect_handler(ipmi_entity_t * ent,void * cb_data)2128 control_detect_handler(ipmi_entity_t *ent, void *cb_data)
2129 {
2130 ent_active_detect_t *info = cb_data;
2131
2132 if (info->start_presence_event_count != ent->presence_event_count) {
2133 /* Something else has changed the presence since we started
2134 the presence detection process, then don't change the
2135 value. There are races where the entity could have been
2136 set present and we detect it as not present. However, it
2137 is not possible to detect it as present and for something
2138 else to set it not present. */
2139 detect_cleanup(info, ent, ent->domain);
2140 return;
2141 }
2142
2143 if (!info->present) {
2144 /* Nothing present from the sensors, try the children. */
2145 if (! try_presence_children(ent, info)) {
2146 /* Children got it, nothing to do */
2147 } else {
2148 try_presence_frudev(ent, info);
2149 }
2150 } else {
2151 detect_done(ent, info);
2152 }
2153 }
2154
2155 static void
detect_control_val(ipmi_control_t * control,int err,int * val,void * cb_data)2156 detect_control_val(ipmi_control_t *control,
2157 int err,
2158 int *val,
2159 void *cb_data)
2160 {
2161 ent_active_detect_t *info = cb_data;
2162
2163 ipmi_lock(info->lock);
2164 if (!err)
2165 info->present = 1;
2166
2167 info->done_count++;
2168 if (info->try_count == info->done_count) {
2169 if (ipmi_entity_pointer_cb(info->ent_id, control_detect_handler, info))
2170 detect_cleanup(info, NULL, ipmi_control_get_domain(control));
2171 } else
2172 ipmi_unlock(info->lock);
2173 }
2174
2175 static void
detect_control_light(ipmi_control_t * control,int err,ipmi_light_setting_t * settings,void * cb_data)2176 detect_control_light(ipmi_control_t *control,
2177 int err,
2178 ipmi_light_setting_t *settings,
2179 void *cb_data)
2180 {
2181 ent_active_detect_t *info = cb_data;
2182
2183 ipmi_lock(info->lock);
2184 if (!err)
2185 info->present = 1;
2186
2187 info->done_count++;
2188 if (info->try_count == info->done_count) {
2189 if (ipmi_entity_pointer_cb(info->ent_id, control_detect_handler, info))
2190 detect_cleanup(info, NULL, ipmi_control_get_domain(control));
2191 } else
2192 ipmi_unlock(info->lock);
2193 }
2194
2195 static void
detect_control_id(ipmi_control_t * control,int err,unsigned char * val,int length,void * cb_data)2196 detect_control_id(ipmi_control_t *control,
2197 int err,
2198 unsigned char *val,
2199 int length,
2200 void *cb_data)
2201 {
2202 ent_active_detect_t *info = cb_data;
2203
2204 ipmi_lock(info->lock);
2205 if (!err)
2206 info->present = 1;
2207
2208 info->done_count++;
2209 if (info->try_count == info->done_count) {
2210 if (ipmi_entity_pointer_cb(info->ent_id, control_detect_handler, info))
2211 detect_cleanup(info, NULL, ipmi_control_get_domain(control));
2212 } else
2213 ipmi_unlock(info->lock);
2214 }
2215
2216 static void
detect_control_display(ipmi_control_t * control,int err,char * str,unsigned int len,void * cb_data)2217 detect_control_display(ipmi_control_t *control,
2218 int err,
2219 char *str,
2220 unsigned int len,
2221 void *cb_data)
2222 {
2223 ent_active_detect_t *info = cb_data;
2224
2225 ipmi_lock(info->lock);
2226 if (!err)
2227 info->present = 1;
2228
2229 info->done_count++;
2230 if (info->try_count == info->done_count) {
2231 if (ipmi_entity_pointer_cb(info->ent_id, control_detect_handler, info))
2232 detect_cleanup(info, NULL, ipmi_control_get_domain(control));
2233 } else
2234 ipmi_unlock(info->lock);
2235 }
2236
2237 static void
control_detect_send(ipmi_entity_t * ent,ipmi_control_t * control,void * cb_data)2238 control_detect_send(ipmi_entity_t *ent,
2239 ipmi_control_t *control,
2240 void *cb_data)
2241 {
2242 ent_active_detect_t *info = cb_data;
2243 int rv;
2244
2245 if (ipmi_control_get_ignore_for_presence(control))
2246 /* Control should be ignored for presence. */
2247 return;
2248
2249 info->try_count++;
2250 ipmi_unlock(info->lock);
2251
2252 rv = ipmi_control_get_val(control, detect_control_val, info);
2253 if (rv)
2254 rv = ipmi_control_get_light(control, detect_control_light, info);
2255 if (rv)
2256 rv = ipmi_control_identifier_get_val(control, detect_control_id, info);
2257 if (rv)
2258 rv = ipmi_control_get_display_string(control, 0, 0, 1,
2259 detect_control_display,
2260 info);
2261 ipmi_lock(info->lock);
2262 if (rv)
2263 info->try_count--;
2264 }
2265
2266 static int
try_presence_controls(ipmi_entity_t * ent,ent_active_detect_t * info)2267 try_presence_controls(ipmi_entity_t *ent, ent_active_detect_t *info)
2268 {
2269 if (locked_list_num_entries(ent->controls) == 0)
2270 return ENOSYS;
2271
2272 /* It has sensors, try to see if any of those are active. Start
2273 the count at 1 so the callbacks don't do the call before we are
2274 done here. */
2275 info->try_count = 1;
2276 info->done_count = 0;
2277 ipmi_entity_iterate_controls(ent, control_detect_send, info);
2278
2279 /* I couldn't message any controls, go on. */
2280 if (info->try_count == 1)
2281 return ENOSYS;
2282 info->done_count++;
2283
2284 if (info->try_count == info->done_count)
2285 control_detect_handler(ent, info);
2286 else
2287 ipmi_unlock(info->lock);
2288 return 0;
2289 }
2290
2291 static void
sensor_detect_handler(ipmi_entity_t * ent,void * cb_data)2292 sensor_detect_handler(ipmi_entity_t *ent, void *cb_data)
2293 {
2294 ent_active_detect_t *info = cb_data;
2295
2296 if (info->start_presence_event_count != ent->presence_event_count) {
2297 /* Something else has changed the presence since we started
2298 the presence detection process, then don't change the
2299 value. There are races where the entity could have been
2300 set present and we detect it as not present. However, it
2301 is not possible to detect it as present and for something
2302 else to set it not present. */
2303 detect_cleanup(info, ent, ent->domain);
2304 return;
2305 }
2306
2307 if (!info->present) {
2308 /* Nothing present from the sensors, try other stuff. */
2309 if (! try_presence_controls(ent, info)) {
2310 /* Controls got it, nothing to do */
2311 } else if (! try_presence_children(ent, info)) {
2312 /* Children got it, nothing to do */
2313 } else {
2314 try_presence_frudev(ent, info);
2315 }
2316 } else {
2317 detect_done(ent, info);
2318 }
2319 }
2320
2321 static void
detect_states_read(ipmi_sensor_t * sensor,int err,ipmi_states_t * states,void * cb_data)2322 detect_states_read(ipmi_sensor_t *sensor,
2323 int err,
2324 ipmi_states_t *states,
2325 void *cb_data)
2326 {
2327 ent_active_detect_t *info = cb_data;
2328
2329 ipmi_lock(info->lock);
2330 if (!err && ipmi_is_sensor_scanning_enabled(states)
2331 && !ipmi_is_initial_update_in_progress(states))
2332 info->present = 1;
2333
2334 info->done_count++;
2335 if (info->try_count == info->done_count) {
2336 if (ipmi_entity_pointer_cb(info->ent_id, sensor_detect_handler, info))
2337 detect_cleanup(info, NULL, ipmi_sensor_get_domain(sensor));
2338 } else
2339 ipmi_unlock(info->lock);
2340 }
2341
2342 static void
detect_reading_read(ipmi_sensor_t * sensor,int err,enum ipmi_value_present_e value_present,unsigned int raw_val,double val,ipmi_states_t * states,void * cb_data)2343 detect_reading_read(ipmi_sensor_t *sensor,
2344 int err,
2345 enum ipmi_value_present_e value_present,
2346 unsigned int raw_val,
2347 double val,
2348 ipmi_states_t *states,
2349 void *cb_data)
2350 {
2351 ent_active_detect_t *info = cb_data;
2352
2353 ipmi_lock(info->lock);
2354 if (!err && ipmi_is_sensor_scanning_enabled(states)
2355 && !ipmi_is_initial_update_in_progress(states))
2356 info->present = 1;
2357
2358 info->done_count++;
2359 if (info->try_count == info->done_count) {
2360 if (ipmi_entity_pointer_cb(info->ent_id, sensor_detect_handler, info))
2361 detect_cleanup(info, NULL, ipmi_sensor_get_domain(sensor));
2362 } else
2363 ipmi_unlock(info->lock);
2364 }
2365
2366 static void
sensor_detect_send(ipmi_entity_t * ent,ipmi_sensor_t * sensor,void * cb_data)2367 sensor_detect_send(ipmi_entity_t *ent,
2368 ipmi_sensor_t *sensor,
2369 void *cb_data)
2370 {
2371 ent_active_detect_t *info = cb_data;
2372 int rv;
2373
2374 if (ipmi_sensor_get_ignore_for_presence(sensor))
2375 /* Sensor should be ignored for presence. */
2376 return;
2377
2378 info->try_count++;
2379 ipmi_unlock(info->lock);
2380
2381 rv = ipmi_sensor_get_reading(sensor, detect_reading_read, info);
2382 if (rv)
2383 rv = ipmi_sensor_get_states(sensor, detect_states_read, info);
2384
2385 ipmi_lock(info->lock);
2386 if (rv)
2387 info->try_count--;
2388 }
2389
2390 static int
try_presence_sensors(ipmi_entity_t * ent,ent_active_detect_t * info)2391 try_presence_sensors(ipmi_entity_t *ent, ent_active_detect_t *info)
2392 {
2393 if (locked_list_num_entries(ent->sensors) == 0)
2394 return ENOSYS;
2395
2396 /* Start the try count at 1 so the presence does not complete until
2397 after we are done here. */
2398 info->try_count = 1;
2399 info->done_count = 0;
2400
2401 ipmi_entity_iterate_sensors(ent, sensor_detect_send, info);
2402
2403 /* I couldn't message any sensors, go on. */
2404 if (info->try_count == 1)
2405 return ENOSYS;
2406
2407 info->done_count++;
2408 if (info->try_count == info->done_count)
2409 sensor_detect_handler(ent, info);
2410 else
2411 ipmi_unlock(info->lock);
2412 return 0;
2413 }
2414
2415 static void
detect_no_presence_sensor_presence(ipmi_entity_t * ent)2416 detect_no_presence_sensor_presence(ipmi_entity_t *ent)
2417 {
2418 ent_active_detect_t *detect;
2419 int rv;
2420
2421 detect = ipmi_mem_alloc(sizeof(*detect));
2422 if (!detect) {
2423 presence_finalize(ent, "detect_no_presence_sensor_presence");
2424 return;
2425 }
2426 rv = ipmi_create_lock(ent->domain, &detect->lock);
2427 if (rv) {
2428 presence_finalize(ent, "detect_no_presence_sensor_presence(2)");
2429 ipmi_mem_free(detect);
2430 return;
2431 }
2432
2433 detect->start_presence_event_count = ent->presence_event_count;
2434 detect->ent_id = ipmi_entity_convert_to_id(ent);
2435 detect->present = 0;
2436 ipmi_lock(detect->lock);
2437
2438 /* The successful one below will unlock the lock and free detect. */
2439 if (! try_presence_sensors(ent, detect)) {
2440 /* Success with sensors, nothing to do */
2441 } else if (! try_presence_controls(ent, detect)) {
2442 /* Note that controls are not technically part of the spec,
2443 but since we have them we use them for presence
2444 detection. */
2445 /* Success with controls, nothing to do */
2446 } else if (! try_presence_children(ent, detect)) {
2447 /* Success with children, nothing to do */
2448 } else {
2449 try_presence_frudev(ent, detect);
2450 }
2451 }
2452
2453 static void
states_read(ipmi_sensor_t * sensor,int err,ipmi_states_t * states,void * cb_data)2454 states_read(ipmi_sensor_t *sensor,
2455 int err,
2456 ipmi_states_t *states,
2457 void *cb_data)
2458 {
2459 int present;
2460 ipmi_entity_t *ent = cb_data;
2461 int val;
2462 int rv;
2463
2464 if (err) {
2465 i_ipmi_domain_entity_lock(ent->domain);
2466 i_ipmi_entity_get(ent);
2467 i_ipmi_domain_entity_unlock(ent->domain);
2468 detect_no_presence_sensor_presence(ent);
2469 i_ipmi_entity_put(ent);
2470 return;
2471 }
2472
2473 if (ipmi_is_initial_update_in_progress(states))
2474 /* Sensor did not return valid values, the entity is probably
2475 not present. */
2476 present = 0;
2477 else {
2478 rv = ipmi_sensor_discrete_event_readable(sensor,
2479 ent->presence_bit_offset,
2480 &val);
2481 if (rv || !val)
2482 /* The present bit is not supported, so use the absent bit. */
2483 present = !ipmi_is_state_set(states, !ent->presence_bit_offset);
2484 else
2485 /* The present bit is supported. */
2486 present = ipmi_is_state_set(states, ent->presence_bit_offset);
2487 }
2488
2489 presence_changed(ent, present);
2490 presence_finalize(ent, "states_read");
2491 }
2492
2493 static void
states_bit_read(ipmi_sensor_t * sensor,int err,ipmi_states_t * states,void * cb_data)2494 states_bit_read(ipmi_sensor_t *sensor,
2495 int err,
2496 ipmi_states_t *states,
2497 void *cb_data)
2498 {
2499 int present;
2500 ipmi_entity_t *ent = cb_data;
2501
2502 if (err) {
2503 i_ipmi_domain_entity_lock(ent->domain);
2504 i_ipmi_entity_get(ent);
2505 i_ipmi_domain_entity_unlock(ent->domain);
2506 detect_no_presence_sensor_presence(ent);
2507 i_ipmi_entity_put(ent);
2508 return;
2509 }
2510
2511 if (ipmi_is_initial_update_in_progress(states))
2512 /* Sensor did not return valid values, the entity is probably
2513 not present. */
2514 present = 0;
2515 else
2516 present = ipmi_is_state_set(states, ent->presence_bit_offset);
2517
2518 presence_changed(ent, present);
2519 presence_finalize(ent, "states_bit_read");
2520 }
2521
2522 void
ipmi_entity_set_presence_detector(ipmi_entity_t * entity,ipmi_entity_presence_detect_cb handler,void * handler_data)2523 ipmi_entity_set_presence_detector(ipmi_entity_t *entity,
2524 ipmi_entity_presence_detect_cb handler,
2525 void *handler_data)
2526 {
2527 entity->detect_presence = handler;
2528 entity->detect_presence_data = handler_data;
2529 entity->presence_possibly_changed = 1;
2530 }
2531
2532 void
ipmi_entity_detector_done(ipmi_entity_t * entity,int present)2533 ipmi_entity_detector_done(ipmi_entity_t *entity,
2534 int present)
2535 {
2536 presence_changed(entity, present);
2537 presence_finalize(entity, "entity_detector_done");
2538 }
2539
2540 static void
ent_detect_presence_nolock(ipmi_entity_t * ent,void * cb_data)2541 ent_detect_presence_nolock(ipmi_entity_t *ent, void *cb_data)
2542 {
2543 ent_detect_info_t *info = cb_data;
2544 int rv;
2545
2546 if (ent->in_presence_check
2547 || ((!info->force) && (! ent->presence_possibly_changed)))
2548 return;
2549 ent->presence_possibly_changed = 0;
2550 ent->in_presence_check = 1;
2551
2552 if (ent->hot_swappable) {
2553 ent_unlock(ent);
2554 ipmi_entity_check_hot_swap_state(ent);
2555 ent_lock(ent);
2556 }
2557
2558 i_ipmi_get_domain_fully_up(ent->domain, "ent_detect_presence");
2559 if (ent->detect_presence) {
2560 ent_unlock(ent);
2561 rv = ent->detect_presence(ent, ent->detect_presence_data);
2562 if (rv)
2563 presence_finalize(ent, "ent_detect_presence(4)");
2564 ent_lock(ent);
2565 } else if (ent->presence_sensor) {
2566 /* Presence sensor overrides everything. */
2567 ipmi_sensor_id_t psi = ent->presence_sensor_id;
2568 ent_unlock(ent);
2569 rv = ipmi_sensor_id_get_states(psi, states_read, ent);
2570 if (rv)
2571 presence_finalize(ent, "ent_detect_presence(2)");
2572 ent_lock(ent);
2573 } else if (ent->presence_bit_sensor) {
2574 /* Presence bit sensor overrides everything but a presence sensor. */
2575 ipmi_sensor_id_t psi = ent->presence_bit_sensor_id;
2576 ent_unlock(ent);
2577 rv = ipmi_sensor_id_get_states(psi, states_bit_read, ent);
2578 if (rv)
2579 presence_finalize(ent, "ent_detect_presence(3)");
2580 ent_lock(ent);
2581 } else {
2582 ent_unlock(ent);
2583 detect_no_presence_sensor_presence(ent);
2584 ent_lock(ent);
2585 }
2586 }
2587
2588 static void
ent_detect_presence(ipmi_entity_t * ent,void * cb_data)2589 ent_detect_presence(ipmi_entity_t *ent, void *cb_data)
2590 {
2591 ent_lock(ent);
2592 ent_detect_presence_nolock(ent, cb_data);
2593 ent_unlock(ent);
2594 }
2595
2596 int
ipmi_detect_ents_presence_changes(ipmi_entity_info_t * ents,int force)2597 ipmi_detect_ents_presence_changes(ipmi_entity_info_t *ents, int force)
2598 {
2599 ent_detect_info_t info;
2600
2601 info.force = force;
2602 ipmi_entities_iterate_entities(ents, ent_detect_presence, &info);
2603 return 0;
2604 }
2605
2606 int
ipmi_detect_entity_presence_change(ipmi_entity_t * ent,int force)2607 ipmi_detect_entity_presence_change(ipmi_entity_t *ent, int force)
2608 {
2609 ent_detect_info_t info;
2610
2611 info.force = force;
2612 ent_detect_presence(ent, &info);
2613 return 0;
2614 }
2615
2616 static void
entity_mc_active(ipmi_mc_t * mc,int active,void * cb_data)2617 entity_mc_active(ipmi_mc_t *mc, int active, void *cb_data)
2618 {
2619 ipmi_entity_t *ent = cb_data;
2620 int rv;
2621
2622 i_ipmi_domain_entity_lock(ent->domain);
2623 rv = i_ipmi_entity_get(ent);
2624 if (rv) {
2625 i_ipmi_domain_entity_unlock(ent->domain);
2626 return;
2627 }
2628
2629 ent_lock(ent);
2630 ent->frudev_active_reported = 1;
2631 if (ent->frudev_active != active) {
2632 ent->frudev_active = active;
2633 /* Only detect with frudev if there are no other
2634 presence-detecting things there. */
2635 if (ent_use_frudev_for_presence(ent)) {
2636 ent_detect_info_t info;
2637
2638 ent_unlock(ent);
2639 i_ipmi_domain_entity_unlock(ent->domain);
2640 info.force = 1;
2641 ent_detect_presence(ent, &info);
2642 goto do_put;
2643 }
2644 }
2645 ent_unlock(ent);
2646 i_ipmi_domain_entity_unlock(ent->domain);
2647 do_put:
2648 i_ipmi_entity_put(ent);
2649 }
2650
2651 /* Must be called with the entity lock held. May release and reclaim it. */
2652 static void
handle_new_presence_sensor(ipmi_entity_t * ent,ipmi_sensor_t * sensor)2653 handle_new_presence_sensor(ipmi_entity_t *ent, ipmi_sensor_t *sensor)
2654 {
2655 ipmi_event_state_t events;
2656 int event_support;
2657 int rv;
2658 int val;
2659
2660 ent->presence_sensor_id = ipmi_sensor_convert_to_id(sensor);
2661 ent->presence_sensor = sensor;
2662
2663 /* If we have a presence sensor, remove the presence bit sensor. */
2664 if (ent->presence_bit_sensor) {
2665 ent->presence_bit_sensor = NULL;
2666 ipmi_sensor_remove_discrete_event_handler(ent->presence_bit_sensor,
2667 presence_sensor_changed,
2668 ent);
2669 }
2670
2671 /*
2672 * Unfortunately, the present/absent bits in the sensor-specific
2673 * verses the generic device presence types are backwards.
2674 */
2675 if (ipmi_sensor_get_event_reading_type(sensor) ==
2676 IPMI_EVENT_READING_TYPE_DISCRETE_DEVICE_PRESENCE)
2677 ent->presence_bit_offset = 1;
2678 else
2679 ent->presence_bit_offset = 0;
2680
2681 event_support = ipmi_sensor_get_event_support(sensor);
2682
2683 /* Add our own event handler. */
2684 ipmi_sensor_add_discrete_event_handler(sensor,
2685 presence_sensor_changed,
2686 ent);
2687
2688 /* Nothing to do, it will just be on. */
2689 if (event_support == IPMI_EVENT_SUPPORT_GLOBAL_ENABLE)
2690 goto out;
2691
2692 /* Turn events and scanning on. */
2693 ipmi_event_state_init(&events);
2694 ipmi_event_state_set_events_enabled(&events, 1);
2695 ipmi_event_state_set_scanning_enabled(&events, 1);
2696
2697 if (event_support == IPMI_EVENT_SUPPORT_PER_STATE) {
2698 /* Turn on all the event enables that we can. */
2699 rv = ipmi_sensor_discrete_event_supported(sensor, 0, IPMI_ASSERTION,
2700 &val);
2701 if ((!rv) && (val))
2702 ipmi_discrete_event_set(&events, 0, IPMI_ASSERTION);
2703 rv = ipmi_sensor_discrete_event_supported(sensor, 0, IPMI_DEASSERTION,
2704 &val);
2705 if ((!rv) && (val))
2706 ipmi_discrete_event_set(&events, 0, IPMI_DEASSERTION);
2707 rv = ipmi_sensor_discrete_event_supported(sensor, 1, IPMI_ASSERTION,
2708 &val);
2709 if ((!rv) && (val))
2710 ipmi_discrete_event_set(&events, 1, IPMI_ASSERTION);
2711 rv = ipmi_sensor_discrete_event_supported(sensor, 1, IPMI_DEASSERTION,
2712 &val);
2713 if ((!rv) && (val))
2714 ipmi_discrete_event_set(&events, 1, IPMI_DEASSERTION);
2715 }
2716
2717 ent_unlock(ent);
2718 ipmi_sensor_set_event_enables(sensor, &events, NULL, NULL);
2719 ent_lock(ent);
2720
2721 out:
2722 ent->presence_possibly_changed = 1;
2723
2724 if (ent->hs_cb.get_hot_swap_state == NULL) {
2725 /* Set the entity hot-swap capable and use our internal state
2726 machine. */
2727 ipmi_entity_set_hot_swappable(ent, 1);
2728 ent->hs_cb = internal_hs_cb;
2729 }
2730 }
2731
2732 /* Must be called with the entity lock held. May release and reclaim it. */
2733 static void
handle_new_presence_bit_sensor(ipmi_entity_t * ent,ipmi_sensor_t * sensor,int bit)2734 handle_new_presence_bit_sensor(ipmi_entity_t *ent, ipmi_sensor_t *sensor,
2735 int bit)
2736 {
2737 ipmi_event_state_t events;
2738 int event_support;
2739
2740 ent->presence_bit_sensor = sensor;
2741 ent->presence_bit_offset = bit;
2742 ent->presence_bit_sensor_id = ipmi_sensor_convert_to_id(sensor);
2743
2744 event_support = ipmi_sensor_get_event_support(sensor);
2745
2746 /* Add our own event handler. */
2747 ipmi_sensor_add_discrete_event_handler(sensor,
2748 presence_bit_sensor_changed,
2749 ent);
2750
2751 /* Nothing to do, it will just be on. */
2752 if (event_support == IPMI_EVENT_SUPPORT_GLOBAL_ENABLE)
2753 goto out;
2754
2755 /* Turn events and scanning on. */
2756 ipmi_event_state_init(&events);
2757 ipmi_event_state_set_events_enabled(&events, 1);
2758 ipmi_event_state_set_scanning_enabled(&events, 1);
2759
2760 if (event_support == IPMI_EVENT_SUPPORT_PER_STATE) {
2761 int val;
2762 int rv;
2763 /* Turn on the event enables. */
2764 rv = ipmi_sensor_discrete_event_supported
2765 (sensor, ent->presence_bit_offset, IPMI_ASSERTION, &val);
2766 if (!rv && val)
2767 ipmi_discrete_event_set(&events, ent->presence_bit_offset,
2768 IPMI_ASSERTION);
2769 rv = ipmi_sensor_discrete_event_supported
2770 (sensor, ent->presence_bit_offset, IPMI_DEASSERTION, &val);
2771 if (!rv && val)
2772 ipmi_discrete_event_set(&events, ent->presence_bit_offset,
2773 IPMI_DEASSERTION);
2774 }
2775
2776 ent_unlock(ent);
2777 ipmi_sensor_enable_events(sensor, &events, NULL, NULL);
2778 ent_lock(ent);
2779
2780 out:
2781 ent->presence_possibly_changed = 1;
2782
2783 if (ent->hs_cb.get_hot_swap_state == NULL) {
2784 /* Set the entity hot-swap capable and use our internal state
2785 machine. */
2786 ipmi_entity_set_hot_swappable(ent, 1);
2787 ent->hs_cb = internal_hs_cb;
2788 }
2789 }
2790
2791 int
ipmi_entity_add_fully_up_handler(ipmi_entity_t * ent,ipmi_entity_ptr_cb handler,void * cb_data)2792 ipmi_entity_add_fully_up_handler(ipmi_entity_t *ent,
2793 ipmi_entity_ptr_cb handler,
2794 void *cb_data)
2795 {
2796 CHECK_ENTITY_LOCK(ent);
2797 if (locked_list_add(ent->fully_up_handlers, handler, cb_data))
2798 return 0;
2799 else
2800 return ENOMEM;
2801 }
2802
2803 int
ipmi_entity_remove_fully_up_handler(ipmi_entity_t * ent,ipmi_entity_ptr_cb handler,void * cb_data)2804 ipmi_entity_remove_fully_up_handler(ipmi_entity_t *ent,
2805 ipmi_entity_ptr_cb handler,
2806 void *cb_data)
2807 {
2808 CHECK_ENTITY_LOCK(ent);
2809 if (locked_list_remove(ent->fully_up_handlers, handler, cb_data))
2810 return 0;
2811 else
2812 return EINVAL;
2813 }
2814
2815 int
ipmi_entity_add_fully_up_handler_cl(ipmi_entity_t * ent,ipmi_entity_fully_up_cl_cb handler,void * cb_data)2816 ipmi_entity_add_fully_up_handler_cl(ipmi_entity_t *ent,
2817 ipmi_entity_fully_up_cl_cb handler,
2818 void *cb_data)
2819 {
2820 CHECK_ENTITY_LOCK(ent);
2821 if (locked_list_add(ent->fully_up_handlers_cl, handler, cb_data))
2822 return 0;
2823 else
2824 return ENOMEM;
2825 }
2826
2827 int
ipmi_entity_remove_fully_up_handler_cl(ipmi_entity_t * ent,ipmi_entity_fully_up_cl_cb handler,void * cb_data)2828 ipmi_entity_remove_fully_up_handler_cl(ipmi_entity_t *ent,
2829 ipmi_entity_fully_up_cl_cb handler,
2830 void *cb_data)
2831 {
2832 CHECK_ENTITY_LOCK(ent);
2833 if (locked_list_remove(ent->fully_up_handlers_cl, handler, cb_data))
2834 return 0;
2835 else
2836 return EINVAL;
2837 }
2838
2839 static int
call_fully_up_handler(void * cb_data,void * item1,void * item2)2840 call_fully_up_handler(void *cb_data, void *item1, void *item2)
2841 {
2842 ipmi_entity_t *ent = cb_data;
2843 ipmi_entity_ptr_cb handler = item1;
2844
2845 handler(ent, item2);
2846 return LOCKED_LIST_ITER_CONTINUE;
2847 }
2848
2849 static void
call_fully_up_handlers(ipmi_entity_t * ent)2850 call_fully_up_handlers(ipmi_entity_t *ent)
2851 {
2852 locked_list_iterate(ent->fully_up_handlers, call_fully_up_handler, ent);
2853 }
2854
2855 static void
report_sdrs_read_check(ipmi_entity_t * ent,void * cb_data)2856 report_sdrs_read_check(ipmi_entity_t *ent, void *cb_data)
2857 {
2858 ent_lock(ent);
2859 ent->sdr_add_done = 1;
2860 ent_unlock(ent);
2861 }
2862
2863 void
i_ipmi_entities_report_sdrs_read(ipmi_entity_info_t * ents)2864 i_ipmi_entities_report_sdrs_read(ipmi_entity_info_t *ents)
2865 {
2866 ipmi_entities_iterate_entities(ents, report_sdrs_read_check, NULL);
2867 }
2868
2869 static void
report_mcs_scanned_check(ipmi_entity_t * ent,void * cb_data)2870 report_mcs_scanned_check(ipmi_entity_t *ent, void *cb_data)
2871 {
2872 ent_lock(ent);
2873 ent->frudev_active_reported = 1;
2874 ent_unlock(ent);
2875 }
2876
2877 void
i_ipmi_entities_report_mcs_scanned(ipmi_entity_info_t * ents)2878 i_ipmi_entities_report_mcs_scanned(ipmi_entity_info_t *ents)
2879 {
2880 ipmi_entities_iterate_entities(ents, report_mcs_scanned_check, NULL);
2881 }
2882
2883 /***********************************************************************
2884 *
2885 * Handling of sensor and control addition and removal.
2886 *
2887 **********************************************************************/
2888
2889 int
ipmi_entity_add_sensor_update_handler(ipmi_entity_t * ent,ipmi_entity_sensor_cb handler,void * cb_data)2890 ipmi_entity_add_sensor_update_handler(ipmi_entity_t *ent,
2891 ipmi_entity_sensor_cb handler,
2892 void *cb_data)
2893 {
2894 CHECK_ENTITY_LOCK(ent);
2895 if (locked_list_add(ent->sensor_handlers, handler, cb_data))
2896 return 0;
2897 else
2898 return ENOMEM;
2899 }
2900
2901 int
ipmi_entity_remove_sensor_update_handler(ipmi_entity_t * ent,ipmi_entity_sensor_cb handler,void * cb_data)2902 ipmi_entity_remove_sensor_update_handler(ipmi_entity_t *ent,
2903 ipmi_entity_sensor_cb handler,
2904 void *cb_data)
2905 {
2906 CHECK_ENTITY_LOCK(ent);
2907 if (locked_list_remove(ent->sensor_handlers, handler, cb_data))
2908 return 0;
2909 else
2910 return EINVAL;
2911 }
2912
2913 int
ipmi_entity_add_sensor_update_handler_cl(ipmi_entity_t * ent,ipmi_entity_sensor_cl_cb handler,void * cb_data)2914 ipmi_entity_add_sensor_update_handler_cl(ipmi_entity_t *ent,
2915 ipmi_entity_sensor_cl_cb handler,
2916 void *cb_data)
2917 {
2918 CHECK_ENTITY_LOCK(ent);
2919 if (locked_list_add(ent->sensor_handlers_cl, handler, cb_data))
2920 return 0;
2921 else
2922 return ENOMEM;
2923 }
2924
2925 int
ipmi_entity_remove_sensor_update_handler_cl(ipmi_entity_t * ent,ipmi_entity_sensor_cl_cb handler,void * cb_data)2926 ipmi_entity_remove_sensor_update_handler_cl(ipmi_entity_t *ent,
2927 ipmi_entity_sensor_cl_cb handler,
2928 void *cb_data)
2929 {
2930 CHECK_ENTITY_LOCK(ent);
2931 if (locked_list_remove(ent->sensor_handlers_cl, handler, cb_data))
2932 return 0;
2933 else
2934 return EINVAL;
2935 }
2936
2937 typedef struct sensor_handler_s
2938 {
2939 enum ipmi_update_e op;
2940 ipmi_sensor_t *sensor;
2941 ipmi_entity_t *entity;
2942 } sensor_handler_t;
2943
2944 static int
call_sensor_handler(void * cb_data,void * item1,void * item2)2945 call_sensor_handler(void *cb_data, void *item1, void *item2)
2946 {
2947 sensor_handler_t *info = cb_data;
2948 ipmi_entity_sensor_cb handler = item1;
2949
2950 handler(info->op, info->entity, info->sensor, item2);
2951 return LOCKED_LIST_ITER_CONTINUE;
2952 }
2953
2954 void
i_ipmi_entity_call_sensor_handlers(ipmi_entity_t * ent,ipmi_sensor_t * sensor,enum ipmi_update_e op)2955 i_ipmi_entity_call_sensor_handlers(ipmi_entity_t *ent, ipmi_sensor_t *sensor,
2956 enum ipmi_update_e op)
2957 {
2958 sensor_handler_t info;
2959
2960 /* If we are reporting things, make sure the entity they are attached
2961 to is already reported. */
2962 i_ipmi_domain_entity_lock(ent->domain);
2963 if (ent->add_pending) {
2964 ent->add_pending = 0;
2965 i_ipmi_domain_entity_unlock(ent->domain);
2966 call_entity_update_handlers(ent, IPMI_ADDED);
2967 } else {
2968 i_ipmi_domain_entity_unlock(ent->domain);
2969 }
2970
2971 info.op = op;
2972 info.entity = ent;
2973 info.sensor = sensor;
2974 locked_list_iterate(ent->sensor_handlers, call_sensor_handler, &info);
2975 }
2976
2977 int
ipmi_entity_add_control_update_handler(ipmi_entity_t * ent,ipmi_entity_control_cb handler,void * cb_data)2978 ipmi_entity_add_control_update_handler(ipmi_entity_t *ent,
2979 ipmi_entity_control_cb handler,
2980 void *cb_data)
2981 {
2982 CHECK_ENTITY_LOCK(ent);
2983 if (locked_list_add(ent->control_handlers, handler, cb_data))
2984 return 0;
2985 else
2986 return ENOMEM;
2987 }
2988
2989 int
ipmi_entity_remove_control_update_handler(ipmi_entity_t * ent,ipmi_entity_control_cb handler,void * cb_data)2990 ipmi_entity_remove_control_update_handler(ipmi_entity_t *ent,
2991 ipmi_entity_control_cb handler,
2992 void *cb_data)
2993 {
2994 CHECK_ENTITY_LOCK(ent);
2995 if (locked_list_remove(ent->control_handlers, handler, cb_data))
2996 return 0;
2997 else
2998 return EINVAL;
2999 }
3000
3001 int
ipmi_entity_add_control_update_handler_cl(ipmi_entity_t * ent,ipmi_entity_control_cl_cb handler,void * cb_data)3002 ipmi_entity_add_control_update_handler_cl(ipmi_entity_t *ent,
3003 ipmi_entity_control_cl_cb handler,
3004 void *cb_data)
3005 {
3006 CHECK_ENTITY_LOCK(ent);
3007 if (locked_list_add(ent->control_handlers_cl, handler, cb_data))
3008 return 0;
3009 else
3010 return ENOMEM;
3011 }
3012
3013 int
ipmi_entity_remove_control_update_handler_cl(ipmi_entity_t * ent,ipmi_entity_control_cl_cb handler,void * cb_data)3014 ipmi_entity_remove_control_update_handler_cl(ipmi_entity_t *ent,
3015 ipmi_entity_control_cl_cb handler,
3016 void *cb_data)
3017 {
3018 CHECK_ENTITY_LOCK(ent);
3019 if (locked_list_remove(ent->control_handlers, handler, cb_data))
3020 return 0;
3021 else
3022 return EINVAL;
3023 }
3024
3025 typedef struct control_handler_s
3026 {
3027 enum ipmi_update_e op;
3028 ipmi_entity_t *entity;
3029 ipmi_control_t *control;
3030 } control_handler_t;
3031
3032 static int
call_control_handler(void * cb_data,void * item1,void * item2)3033 call_control_handler(void *cb_data, void *item1, void *item2)
3034 {
3035 control_handler_t *info = cb_data;
3036 ipmi_entity_control_cb handler = item1;
3037
3038 handler(info->op, info->entity, info->control, item2);
3039 return LOCKED_LIST_ITER_CONTINUE;
3040 }
3041
3042 void
i_ipmi_entity_call_control_handlers(ipmi_entity_t * ent,ipmi_control_t * control,enum ipmi_update_e op)3043 i_ipmi_entity_call_control_handlers(ipmi_entity_t *ent,
3044 ipmi_control_t *control,
3045 enum ipmi_update_e op)
3046 {
3047 control_handler_t info;
3048
3049
3050 /* If we are reporting things, make sure the entity they are attached
3051 to is already reported. */
3052 i_ipmi_domain_entity_lock(ent->domain);
3053 if (ent->add_pending) {
3054 ent->add_pending = 0;
3055 i_ipmi_domain_entity_unlock(ent->domain);
3056 call_entity_update_handlers(ent, IPMI_ADDED);
3057 } else {
3058 i_ipmi_domain_entity_unlock(ent->domain);
3059 }
3060
3061 info.op = op;
3062 info.entity = ent;
3063 info.control = control;
3064 locked_list_iterate(ent->control_handlers, call_control_handler, &info);
3065 }
3066
3067 static void handle_new_hot_swap_requester(ipmi_entity_t *ent,
3068 ipmi_sensor_t *sensor);
3069
3070 static int
is_hot_swap_requester(ipmi_sensor_t * sensor)3071 is_hot_swap_requester(ipmi_sensor_t *sensor)
3072 {
3073 if (ipmi_sensor_get_event_reading_type(sensor)
3074 == IPMI_EVENT_READING_TYPE_THRESHOLD)
3075 return 0;
3076
3077 return ipmi_sensor_is_hot_swap_requester(sensor, NULL, NULL);
3078 }
3079
3080 static void handle_new_hot_swap_power(ipmi_entity_t *ent,
3081 ipmi_control_t *control);
3082
3083 static int
is_hot_swap_power(ipmi_control_t * control)3084 is_hot_swap_power(ipmi_control_t *control)
3085 {
3086 if (ipmi_control_get_type(control) != IPMI_CONTROL_POWER)
3087 return 0;
3088
3089 if (ipmi_control_get_num_vals(control) != 1)
3090 return 0;
3091
3092 return ipmi_control_is_hot_swap_power(control);
3093 }
3094
3095 static void handle_new_hot_swap_indicator(ipmi_entity_t *ent,
3096 ipmi_control_t *control);
3097 static int
is_hot_swap_indicator(ipmi_control_t * control)3098 is_hot_swap_indicator(ipmi_control_t *control)
3099 {
3100 if (ipmi_control_get_type(control) != IPMI_CONTROL_LIGHT)
3101 return 0;
3102
3103 if (ipmi_control_get_num_vals(control) != 1)
3104 return 0;
3105
3106 return ipmi_control_is_hot_swap_indicator(control, NULL, NULL, NULL, NULL);
3107 }
3108
3109 static int
is_presence_sensor(ipmi_sensor_t * sensor)3110 is_presence_sensor(ipmi_sensor_t *sensor)
3111 {
3112 int val, rv;
3113 int supports_bit0 = 0;
3114 int supports_bit1 = 0;
3115 int reading_type;
3116
3117 /* Is it the right type (a presence sensor)? */
3118 if (ipmi_sensor_get_sensor_type(sensor) != 0x25)
3119 return 0;
3120
3121 reading_type = ipmi_sensor_get_event_reading_type(sensor);
3122 if (reading_type != IPMI_EVENT_READING_TYPE_SENSOR_SPECIFIC &&
3123 reading_type != IPMI_EVENT_READING_TYPE_DISCRETE_DEVICE_PRESENCE)
3124 /* Don't know how to interpret an other reading type codes. */
3125 return 0;
3126
3127 /* Presence sensors that don't generate events are kind of useless. */
3128 if (ipmi_sensor_get_event_support(sensor) == IPMI_EVENT_SUPPORT_NONE)
3129 return 0;
3130
3131 /* Check present bit */
3132 rv = ipmi_sensor_discrete_event_readable(sensor, 0, &val);
3133 if ((!rv) && (val))
3134 supports_bit0 = 1;
3135 /* Check absent bit. */
3136 rv = ipmi_sensor_discrete_event_readable(sensor, 1, &val);
3137 if ((!rv) && (val))
3138 supports_bit1 = 1;
3139
3140 /* What good is this? No support for the proper bits, I need to
3141 be able to read them. */
3142 if ((!supports_bit0) && (!supports_bit1))
3143 return 0;
3144
3145 return 1;
3146 }
3147
3148 static int
is_presence_bit_sensor(ipmi_sensor_t * sensor,int * bit_offset)3149 is_presence_bit_sensor(ipmi_sensor_t *sensor, int *bit_offset)
3150 {
3151 int val, rv;
3152 int bit;
3153 int sensor_type = ipmi_sensor_get_sensor_type(sensor);
3154 int reading_type = ipmi_sensor_get_event_reading_type(sensor);
3155
3156 if (reading_type != IPMI_EVENT_READING_TYPE_SENSOR_SPECIFIC)
3157 /* All presence bits are in sensor-specific bits, not generic ones */
3158 return 0;
3159
3160 /* Is it a sensor with a presence bit? */
3161 switch (sensor_type)
3162 {
3163 case IPMI_SENSOR_TYPE_POWER_SUPPLY: bit = 0; break;
3164 case IPMI_SENSOR_TYPE_BATTERY: bit = 2; break;
3165 case IPMI_SENSOR_TYPE_SLOT_CONNECTOR: bit = 2; break;
3166 case IPMI_SENSOR_TYPE_PROCESSOR: bit = 7; break;
3167 case IPMI_SENSOR_TYPE_DRIVE_SLOT: bit = 0; break;
3168 case IPMI_SENSOR_TYPE_MEMORY: bit = 6; break;
3169 default:
3170 return 0;
3171 }
3172
3173 /* Presence sensors that don't generate events are kind of useless. */
3174 if (ipmi_sensor_get_event_support(sensor) == IPMI_EVENT_SUPPORT_NONE)
3175 return 0;
3176
3177 /* Check if the bit is available */
3178 rv = ipmi_sensor_discrete_event_readable(sensor, bit, &val);
3179 if (rv || !val)
3180 return 0;
3181
3182 *bit_offset = bit;
3183
3184 return 1;
3185 }
3186
3187 void
ipmi_entity_add_sensor(ipmi_entity_t * ent,ipmi_sensor_t * sensor,void * link)3188 ipmi_entity_add_sensor(ipmi_entity_t *ent,
3189 ipmi_sensor_t *sensor,
3190 void *link)
3191 {
3192 int bit;
3193
3194 CHECK_ENTITY_LOCK(ent);
3195
3196 ent_lock(ent);
3197 if (is_presence_sensor(sensor) && (ent->presence_sensor == NULL)
3198 && (ent->presence_bit_sensor == NULL))
3199 {
3200 /* It's the presence sensor and we don't already have one. We
3201 keep this special. */
3202 handle_new_presence_sensor(ent, sensor);
3203 } else if ((ent->presence_sensor == NULL)
3204 && (ent->presence_bit_sensor == NULL)
3205 && is_presence_bit_sensor(sensor, &bit))
3206 {
3207 /* If it's a sensor with a presence bit, we use it. */
3208 handle_new_presence_bit_sensor(ent, sensor, bit);
3209 }
3210
3211 if (is_hot_swap_requester(sensor) && (ent->hot_swap_requester == NULL)) {
3212 handle_new_hot_swap_requester(ent, sensor);
3213 }
3214 ent_unlock(ent);
3215
3216 locked_list_add_entry(ent->sensors, sensor, NULL, link);
3217
3218 ent->presence_possibly_changed = 1;
3219 }
3220
3221 typedef struct sens_find_presence_s
3222 {
3223 int is_presence;
3224 int bit;
3225 ipmi_sensor_t *sensor;
3226 ipmi_sensor_t *ignore_sensor;
3227 } sens_cmp_info_t;
3228
3229 static void
sens_cmp_if_presence(ipmi_entity_t * ent,ipmi_sensor_t * sensor,void * cb_data)3230 sens_cmp_if_presence(ipmi_entity_t *ent, ipmi_sensor_t *sensor,
3231 void *cb_data)
3232 {
3233 sens_cmp_info_t *info = cb_data;
3234
3235 if (sensor == info->ignore_sensor)
3236 return;
3237
3238 if (info->is_presence)
3239 return;
3240
3241 info->is_presence = is_presence_sensor(sensor);
3242 if (info->is_presence) {
3243 info->sensor = sensor;
3244 handle_new_presence_sensor(ent, sensor);
3245 }
3246 }
3247
3248 static void
sens_cmp_if_presence_bit(ipmi_entity_t * ent,ipmi_sensor_t * sensor,void * cb_data)3249 sens_cmp_if_presence_bit(ipmi_entity_t *ent, ipmi_sensor_t *sensor,
3250 void *cb_data)
3251 {
3252 sens_cmp_info_t *info = cb_data;
3253
3254 if (sensor == info->ignore_sensor)
3255 return;
3256
3257 if (info->is_presence)
3258 return;
3259
3260 info->is_presence = is_presence_bit_sensor(sensor, &info->bit);
3261 if (info->is_presence) {
3262 info->sensor = sensor;
3263 handle_new_presence_bit_sensor(ent, sensor, info->bit);
3264 }
3265 }
3266
3267 /* Must be called with the entity lock held. May release and reclaim it. */
3268 static void
check_for_another_presence_sensor(ipmi_entity_t * ent,ipmi_sensor_t * old)3269 check_for_another_presence_sensor(ipmi_entity_t *ent, ipmi_sensor_t *old)
3270 {
3271 sens_cmp_info_t info;
3272
3273 info.sensor = NULL;
3274 info.ignore_sensor = old;
3275 info.is_presence = 0;
3276
3277 /* See if there is another presence sensor. */
3278 ipmi_entity_iterate_sensors(ent, sens_cmp_if_presence, &info);
3279
3280 if (! info.sensor) {
3281 /* See if there is a presence bit sensor. */
3282 ent->presence_sensor = NULL;
3283 info.ignore_sensor = NULL;
3284 info.is_presence = 0;
3285 ipmi_entity_iterate_sensors(ent, sens_cmp_if_presence_bit, &info);
3286 }
3287 }
3288
3289 void
ipmi_entity_remove_sensor(ipmi_entity_t * ent,ipmi_sensor_t * sensor)3290 ipmi_entity_remove_sensor(ipmi_entity_t *ent,
3291 ipmi_sensor_t *sensor)
3292 {
3293 /* Note that you *CANNOT* call ipmi_sensor_convert_to_id() (or any
3294 other thing like that) because the MC that the sensor belongs
3295 to may have disappeared already. So be careful. */
3296
3297 CHECK_ENTITY_LOCK(ent);
3298
3299 ent_lock(ent);
3300 if (sensor == ent->presence_sensor) {
3301 ent->presence_sensor = NULL;
3302 ent->presence_possibly_changed = 1;
3303 check_for_another_presence_sensor(ent, sensor);
3304 } else if (sensor == ent->presence_bit_sensor) {
3305 ent->presence_bit_sensor = NULL;
3306 ent->presence_possibly_changed = 1;
3307 check_for_another_presence_sensor(ent, sensor);
3308 }
3309 if (sensor == ent->hot_swap_requester) {
3310 ent->hot_swap_requester = NULL;
3311 }
3312 ent_unlock(ent);
3313
3314 if (! locked_list_remove(ent->sensors, sensor, NULL)) {
3315 ipmi_log(IPMI_LOG_WARNING,
3316 "%sentity.c(ipmi_entity_remove_sensor):"
3317 " Removal of a sensor from an entity was requested,"
3318 " but the sensor was not there",
3319 SENSOR_NAME(sensor));
3320 return;
3321 }
3322 }
3323
3324 void
ipmi_entity_add_control(ipmi_entity_t * ent,ipmi_control_t * control,void * link)3325 ipmi_entity_add_control(ipmi_entity_t *ent,
3326 ipmi_control_t *control,
3327 void *link)
3328 {
3329 CHECK_ENTITY_LOCK(ent);
3330
3331 ent_lock(ent);
3332 if (is_hot_swap_power(control))
3333 handle_new_hot_swap_power(ent, control);
3334 if (is_hot_swap_indicator(control))
3335 handle_new_hot_swap_indicator(ent, control);
3336 ent_unlock(ent);
3337
3338 locked_list_add_entry(ent->controls, control, NULL, link);
3339 ent->presence_possibly_changed = 1;
3340 }
3341
3342 void
ipmi_entity_remove_control(ipmi_entity_t * ent,ipmi_control_t * control)3343 ipmi_entity_remove_control(ipmi_entity_t *ent,
3344 ipmi_control_t *control)
3345 {
3346 /* Note that you *CANNOT* call ipmi_control_convert_to_id() (or any
3347 other thing like that) because the MC that the sensor belongs
3348 to may have disappeared already. So be careful. */
3349
3350 CHECK_ENTITY_LOCK(ent);
3351
3352 ent_lock(ent);
3353 if (control == ent->hot_swap_power) {
3354 /* If don't have power control, we can't manage hot-swap. */
3355 ipmi_entity_set_supports_managed_hot_swap(ent, 0);
3356
3357 ent->hot_swap_power = NULL;
3358 }
3359 if (control == ent->hot_swap_indicator)
3360 ent->hot_swap_indicator = NULL;
3361 ent_unlock(ent);
3362
3363 if (! locked_list_remove(ent->controls, control, NULL)) {
3364 ipmi_log(IPMI_LOG_WARNING,
3365 "%sentity.c(ipmi_entity_remove_control):"
3366 " Removal of a control from an entity was requested,"
3367 " but the control was not there",
3368 CONTROL_NAME(control));
3369 return;
3370 }
3371 ent->presence_possibly_changed = 1;
3372 }
3373
3374 typedef struct iterate_sensor_info_s
3375 {
3376 ipmi_entity_t *ent;
3377 ipmi_entity_iterate_sensor_cb handler;
3378 void *cb_data;
3379 int got_failed;
3380 } iterate_sensor_info_t;
3381
3382 static int
iterate_sensor_prefunc(void * cb_data,void * item1,void * item2)3383 iterate_sensor_prefunc(void *cb_data, void *item1, void *item2)
3384 {
3385 iterate_sensor_info_t *info = cb_data;
3386 ipmi_sensor_t *sensor = item1;
3387 int rv;
3388 ipmi_mc_t *mc = ipmi_sensor_get_mc(sensor);
3389 ipmi_domain_t *domain;
3390
3391 if (!mc)
3392 goto out_err;
3393 domain = ipmi_mc_get_domain(mc);
3394 i_ipmi_domain_mc_lock(domain);
3395 rv = i_ipmi_mc_get(mc);
3396 i_ipmi_domain_mc_unlock(domain);
3397 if (rv)
3398 goto out_err;
3399 rv = i_ipmi_sensor_get(sensor);
3400 if (rv) {
3401 i_ipmi_mc_put(mc);
3402 goto out_err;
3403 }
3404 info->got_failed = 0;
3405 return LOCKED_LIST_ITER_CONTINUE;
3406
3407 out_err:
3408 info->got_failed = 1;
3409 return LOCKED_LIST_ITER_CONTINUE;
3410 }
3411
3412 static int
iterate_sensor_handler(void * cb_data,void * item1,void * item2)3413 iterate_sensor_handler(void *cb_data, void *item1, void *item2)
3414 {
3415 iterate_sensor_info_t *info = cb_data;
3416 ipmi_sensor_t *sensor = item1;
3417 ipmi_mc_t *mc = ipmi_sensor_get_mc(sensor);
3418
3419 if (info->got_failed)
3420 goto out;
3421 info->handler(info->ent, item1, info->cb_data);
3422 i_ipmi_sensor_put(sensor);
3423 i_ipmi_mc_put(mc);
3424 out:
3425 return LOCKED_LIST_ITER_CONTINUE;
3426 }
3427
3428 void
ipmi_entity_iterate_sensors(ipmi_entity_t * ent,ipmi_entity_iterate_sensor_cb handler,void * cb_data)3429 ipmi_entity_iterate_sensors(ipmi_entity_t *ent,
3430 ipmi_entity_iterate_sensor_cb handler,
3431 void *cb_data)
3432 {
3433 iterate_sensor_info_t info = { ent, handler, cb_data };
3434
3435 CHECK_ENTITY_LOCK(ent);
3436
3437 locked_list_iterate_prefunc(ent->sensors, iterate_sensor_prefunc,
3438 iterate_sensor_handler, &info);
3439 }
3440
3441
3442 typedef struct iterate_control_info_s
3443 {
3444 ipmi_entity_t *ent;
3445 ipmi_entity_iterate_control_cb handler;
3446 void *cb_data;
3447 int got_failed;
3448 } iterate_control_info_t;
3449
3450 static int
iterate_control_prefunc(void * cb_data,void * item1,void * item2)3451 iterate_control_prefunc(void *cb_data, void *item1, void *item2)
3452 {
3453 iterate_control_info_t *info = cb_data;
3454 ipmi_control_t *control = item1;
3455 int rv;
3456 ipmi_mc_t *mc = ipmi_control_get_mc(control);
3457 ipmi_domain_t *domain = ipmi_mc_get_domain(mc);
3458
3459 if (!mc)
3460 goto out_err;
3461 i_ipmi_domain_mc_lock(domain);
3462 rv = i_ipmi_mc_get(mc);
3463 i_ipmi_domain_mc_unlock(domain);
3464 if (rv)
3465 goto out_err;
3466 rv = i_ipmi_control_get(control);
3467 if (rv) {
3468 i_ipmi_mc_put(mc);
3469 goto out_err;
3470 }
3471 info->got_failed = 0;
3472 return LOCKED_LIST_ITER_CONTINUE;
3473
3474 out_err:
3475 info->got_failed = 1;
3476 return LOCKED_LIST_ITER_CONTINUE;
3477 }
3478
3479 static int
iterate_control_handler(void * cb_data,void * item1,void * item2)3480 iterate_control_handler(void *cb_data, void *item1, void *item2)
3481 {
3482 iterate_control_info_t *info = cb_data;
3483 ipmi_control_t *control = item1;
3484 ipmi_mc_t *mc = ipmi_control_get_mc(control);
3485
3486 if (info->got_failed)
3487 goto out;
3488 info->handler(info->ent, item1, info->cb_data);
3489 i_ipmi_control_put(control);
3490 i_ipmi_mc_put(mc);
3491 out:
3492 return LOCKED_LIST_ITER_CONTINUE;
3493 }
3494
3495 void
ipmi_entity_iterate_controls(ipmi_entity_t * ent,ipmi_entity_iterate_control_cb handler,void * cb_data)3496 ipmi_entity_iterate_controls(ipmi_entity_t *ent,
3497 ipmi_entity_iterate_control_cb handler,
3498 void *cb_data)
3499 {
3500 iterate_control_info_t info = { ent, handler, cb_data };
3501
3502 CHECK_ENTITY_LOCK(ent);
3503
3504 locked_list_iterate_prefunc(ent->controls, iterate_control_prefunc,
3505 iterate_control_handler, &info);
3506 }
3507
3508 /***********************************************************************
3509 *
3510 * Handling of sensor data records for entities.
3511 *
3512 **********************************************************************/
3513
3514 static int
decode_ear(ipmi_sdr_t * sdr,dlr_info_t * info,ipmi_mc_t * mc)3515 decode_ear(ipmi_sdr_t *sdr, dlr_info_t *info, ipmi_mc_t *mc)
3516 {
3517 int i;
3518 int pos;
3519
3520 info->type = IPMI_ENTITY_EAR;
3521 info->output_handler = NULL;
3522
3523 info->device_num.channel = 0;
3524 info->device_num.address = 0;
3525
3526 info->entity_id = sdr->data[0];
3527 info->entity_instance = sdr->data[1];
3528
3529 info->linked_ear_exists = (sdr->data[2] & 0x40) == 0x40;
3530 info->presence_sensor_always_there = (sdr->data[2] & 0x20) == 0x20;
3531 info->is_ranges = (sdr->data[2] & 0x80) == 0x80;
3532
3533 for (i=0,pos=3; pos<11; pos+=2,i++) {
3534 info->contained_entities[i].entity_id = sdr->data[pos];
3535 info->contained_entities[i].entity_instance = sdr->data[pos+1];
3536 }
3537
3538 return 0;
3539 }
3540
3541 static int
decode_drear(ipmi_sdr_t * sdr,dlr_info_t * info,ipmi_mc_t * mc)3542 decode_drear(ipmi_sdr_t *sdr, dlr_info_t *info, ipmi_mc_t *mc)
3543 {
3544 int i;
3545 int pos;
3546
3547 info->type = IPMI_ENTITY_DREAR;
3548 info->output_handler = NULL;
3549
3550 info->entity_id = sdr->data[0];
3551 info->entity_instance = sdr->data[1];
3552
3553 if (sdr->data[1] >= 0x60) {
3554 info->device_num.channel = sdr->data[3] >> 4;
3555 info->device_num.address = sdr->data[2];
3556 }
3557
3558 info->linked_ear_exists = (sdr->data[4] & 0x40) == 0x40;
3559 info->presence_sensor_always_there = (sdr->data[4] & 0x20) == 0x20;
3560 info->is_ranges = (sdr->data[4] & 0x80) == 0x80;
3561
3562 for (i=0,pos=5; pos<21; pos+=4,i++) {
3563 if (sdr->data[pos+3] >= 0x60) {
3564 info->contained_entities[i].device_num.address = sdr->data[pos];
3565 info->contained_entities[i].device_num.channel = sdr->data[pos+1];
3566 }
3567 info->contained_entities[i].entity_id = sdr->data[pos+2];
3568 info->contained_entities[i].entity_instance = sdr->data[pos+3];
3569 }
3570
3571 return 0;
3572 }
3573
3574 static int
gdlr_output(ipmi_entity_t * ent,ipmi_sdr_info_t * sdrs,void * cb_data)3575 gdlr_output(ipmi_entity_t *ent, ipmi_sdr_info_t *sdrs, void *cb_data)
3576 {
3577 ipmi_sdr_t sdr;
3578 unsigned int len;
3579 dlr_info_t *info = &ent->info;
3580
3581 memset(&sdr, 0, sizeof(sdr));
3582
3583 sdr.major_version = IPMI_MAJOR_NUM_SDR;
3584 sdr.minor_version = IPMI_MINOR_NUM_SDR;
3585 sdr.type = IPMI_SDR_GENERIC_DEVICE_LOCATOR_RECORD;
3586 sdr.length = 10; /* We'll fix it later. */
3587 sdr.data[0] = info->access_address;
3588 sdr.data[1] = (info->slave_address
3589 | (info->channel >> 3));
3590 sdr.data[2] = ((info->channel << 5)
3591 | (info->lun << 3)
3592 | info->private_bus_id);
3593 sdr.data[3] = info->address_span & 0x7;
3594 sdr.data[4] = 0;
3595 sdr.data[5] = info->device_type;
3596 sdr.data[6] = info->device_type_modifier;
3597 sdr.data[7] = info->entity_id;
3598 sdr.data[8] = info->entity_instance;
3599 sdr.data[9] = info->oem;
3600 len = 16;
3601 ipmi_set_device_string(info->id,
3602 info->id_type,
3603 info->id_len,
3604 sdr.data+10, 0, &len);
3605 sdr.length += len;
3606
3607 return ipmi_sdr_add(sdrs, &sdr);
3608 }
3609
3610 static int
decode_gdlr(ipmi_sdr_t * sdr,dlr_info_t * info,ipmi_mc_t * mc)3611 decode_gdlr(ipmi_sdr_t *sdr, dlr_info_t *info, ipmi_mc_t *mc)
3612 {
3613 unsigned char *str;
3614 int rv;
3615
3616 info->type = IPMI_ENTITY_GENERIC;
3617 info->output_handler = gdlr_output;
3618
3619 if (sdr->data[8] >= 0x60) {
3620 info->device_num.channel = (sdr->data[2] >> 5) | ((sdr->data[1] << 3)
3621 & 0x08);
3622 info->device_num.address = sdr->data[0];
3623 } else {
3624 info->device_num.channel = 0;
3625 info->device_num.address = 0;
3626 }
3627
3628 info->access_address = sdr->data[0];
3629 info->slave_address = sdr->data[1];
3630 info->channel = ((sdr->data[2] >> 5)
3631 | ((sdr->data[1] << 3) & 0x08));
3632 info->lun = (sdr->data[2] >> 3) & 0x3;
3633 info->private_bus_id = sdr->data[2] & 0x7;
3634 info->address_span = sdr->data[3] & 0x7;
3635 info->device_type = sdr->data[5];
3636 info->device_type_modifier = sdr->data[6];
3637 info->entity_id = sdr->data[7];
3638 info->entity_instance = sdr->data[8];
3639 info->oem = sdr->data[9];
3640 str = sdr->data + 10;
3641 rv = ipmi_get_device_string(&str, sdr->length-10,
3642 info->id, IPMI_STR_SDR_SEMANTICS, 0,
3643 &info->id_type, ENTITY_ID_LEN, &info->id_len);
3644 if (rv) {
3645 ipmi_log(IPMI_LOG_WARNING,
3646 "%sentity.c(decode_gdlr):"
3647 " Error getting device ID string from SDR record %d: %d,"
3648 " this entity will be named **INVALID**",
3649 MC_NAME(mc), sdr->record_id, rv);
3650 strncpy(info->id, "**INVALID**", sizeof(info->id));
3651 info->id_len = strlen(info->id);
3652 info->id_type = IPMI_ASCII_STR;
3653 rv = 0;
3654 }
3655
3656 return rv;
3657 }
3658
3659 static int
frudlr_output(ipmi_entity_t * ent,ipmi_sdr_info_t * sdrs,void * cb_data)3660 frudlr_output(ipmi_entity_t *ent, ipmi_sdr_info_t *sdrs, void *cb_data)
3661 {
3662 ipmi_sdr_t sdr;
3663 unsigned int len;
3664 dlr_info_t *info = &ent->info;
3665
3666 memset(&sdr, 0, sizeof(sdr));
3667
3668 sdr.major_version = IPMI_MAJOR_NUM_SDR;
3669 sdr.minor_version = IPMI_MINOR_NUM_SDR;
3670 sdr.type = IPMI_SDR_FRU_DEVICE_LOCATOR_RECORD;
3671 sdr.length = 10; /* We'll fix it later. */
3672 sdr.data[0] = info->access_address;
3673 sdr.data[1] = info->fru_device_id;
3674 sdr.data[2] = ((info->is_logical_fru << 7)
3675 | (info->lun << 3)
3676 | info->private_bus_id);
3677 sdr.data[3] = info->channel << 4;
3678 sdr.data[4] = 0;
3679 sdr.data[5] = info->device_type;
3680 sdr.data[6] = info->device_type_modifier;
3681 sdr.data[7] = info->entity_id;
3682 sdr.data[8] = info->entity_instance;
3683 sdr.data[9] = info->oem;
3684 len = 16;
3685 ipmi_set_device_string(info->id,
3686 info->id_type,
3687 info->id_len,
3688 sdr.data+10, 0, &len);
3689 sdr.length += len;
3690
3691 return ipmi_sdr_add(sdrs, &sdr);
3692 }
3693
3694 static int
decode_frudlr(ipmi_sdr_t * sdr,dlr_info_t * info,ipmi_mc_t * mc)3695 decode_frudlr(ipmi_sdr_t *sdr, dlr_info_t *info, ipmi_mc_t *mc)
3696 {
3697 unsigned char *str;
3698 int rv;
3699
3700 info->type = IPMI_ENTITY_FRU;
3701 info->output_handler = frudlr_output;
3702
3703 if (sdr->data[8] >= 0x60) {
3704 info->device_num.channel = sdr->data[3] >> 4;
3705 info->device_num.address = sdr->data[0];
3706 } else {
3707 info->device_num.channel = 0;
3708 info->device_num.address = 0;
3709 }
3710
3711 info->access_address = sdr->data[0];
3712 info->fru_device_id = sdr->data[1];
3713 info->channel = sdr->data[3] >> 4;
3714 info->is_logical_fru = ((sdr->data[2] & 0x80) == 0x80);
3715 info->lun = (sdr->data[2] >> 3) & 0x3;
3716 info->private_bus_id = sdr->data[2] & 0x7;
3717 info->device_type = sdr->data[5];
3718 info->device_type_modifier = sdr->data[6];
3719 info->oem = sdr->data[9];
3720 info->entity_id = sdr->data[7];
3721 info->entity_instance = sdr->data[8];
3722 str = sdr->data + 10;
3723 rv = ipmi_get_device_string(&str,
3724 sdr->length-10,
3725 info->id, IPMI_STR_SDR_SEMANTICS, 0,
3726 &info->id_type, ENTITY_ID_LEN, &info->id_len);
3727 if (rv) {
3728 ipmi_log(IPMI_LOG_WARNING,
3729 "%sentity.c(decode_frudlr):"
3730 " Error getting device ID string from SDR record %d: %d,"
3731 " this entity will be named **INVALID**",
3732 MC_NAME(mc), sdr->record_id, rv);
3733 strncpy(info->id, "**INVALID**", sizeof(info->id));
3734 info->id_len = strlen(info->id);
3735 info->id_type = IPMI_ASCII_STR;
3736 rv = 0;
3737 }
3738
3739 return rv;
3740 }
3741
3742 static int
mcdlr_output(ipmi_entity_t * ent,ipmi_sdr_info_t * sdrs,void * cb_data)3743 mcdlr_output(ipmi_entity_t *ent, ipmi_sdr_info_t *sdrs, void *cb_data)
3744 {
3745 ipmi_sdr_t sdr;
3746 unsigned int len;
3747 dlr_info_t *info = &ent->info;
3748
3749 memset(&sdr, 0, sizeof(sdr));
3750
3751 sdr.major_version = IPMI_MAJOR_NUM_SDR;
3752 sdr.minor_version = IPMI_MINOR_NUM_SDR;
3753 sdr.type = IPMI_SDR_MC_DEVICE_LOCATOR_RECORD;
3754 sdr.length = 10; /* We'll fix it later. */
3755 sdr.data[0] = info->slave_address;
3756 sdr.data[1] = info->channel & 0xf;
3757 sdr.data[2] = ((info->ACPI_system_power_notify_required << 7)
3758 | (info->ACPI_device_power_notify_required << 6)
3759 | (info->controller_logs_init_agent_errors << 3)
3760 | (info->log_init_agent_errors_accessing << 2)
3761 | (info->global_init));
3762 sdr.data[3] = ((info->chassis_device << 7)
3763 | (info->bridge << 6)
3764 | (info->IPMB_event_generator << 5)
3765 | (info->IPMB_event_receiver << 4)
3766 | (info->FRU_inventory_device << 3)
3767 | (info->SEL_device << 2)
3768 | (info->SDR_repository_device << 1)
3769 | info->sensor_device);
3770 sdr.data[4] = 0;
3771 sdr.data[5] = 0;
3772 sdr.data[6] = 0;
3773 sdr.data[7] = ent->key.entity_id;
3774 sdr.data[8] = ent->key.entity_instance;
3775 sdr.data[9] = info->oem;
3776 len = 16;
3777 ipmi_set_device_string(info->id,
3778 info->id_type,
3779 info->id_len,
3780 sdr.data+10, 0, &len);
3781 sdr.length += len;
3782
3783 return ipmi_sdr_add(sdrs, &sdr);
3784 }
3785
3786 static int
decode_mcdlr(ipmi_sdr_t * sdr,dlr_info_t * info,ipmi_mc_t * mc)3787 decode_mcdlr(ipmi_sdr_t *sdr, dlr_info_t *info, ipmi_mc_t *mc)
3788 {
3789 unsigned char *data;
3790 unsigned char *str;
3791 int rv;
3792
3793
3794 info->type = IPMI_ENTITY_MC;
3795 info->output_handler = mcdlr_output;
3796
3797 if (sdr->data[8] >= 0x60) {
3798 info->device_num.channel = sdr->data[1] & 0xf;
3799 info->device_num.address = sdr->data[0];
3800 } else {
3801 info->device_num.channel = 0;
3802 info->device_num.address = 0;
3803 }
3804
3805 data = sdr->data;
3806 info->slave_address = *data;
3807 data++;
3808 if (sdr->major_version == 1 && sdr->minor_version == 0) {
3809 /* IPMI 1.0 SDR type 12 record, doesn't have the channel
3810 field, so we have to have special handling. */
3811 info->channel = 0;
3812 } else {
3813 info->channel = *data & 0xf;
3814 data++;
3815 }
3816
3817 info->ACPI_system_power_notify_required = (data[0] >> 7) & 1;
3818 info->ACPI_device_power_notify_required = (data[0] >> 6) & 1;
3819 info->controller_logs_init_agent_errors = (data[0] >> 3) & 1;
3820 info->log_init_agent_errors_accessing = (data[0] >> 2) & 1;
3821 info->global_init = (data[0] >> 0) & 3;
3822
3823 info->chassis_device = (data[1] >> 7) & 1;
3824 info->bridge = (data[1] >> 6) & 1;
3825 info->IPMB_event_generator = (data[1] >> 5) & 1;
3826 info->IPMB_event_receiver = (data[1] >> 4) & 1;
3827 info->FRU_inventory_device = (data[1] >> 3) & 1;
3828 info->SEL_device = (data[1] >> 2) & 1;
3829 info->SDR_repository_device = (data[1] >> 1) & 1;
3830 info->sensor_device = (data[1] >> 0) & 1;
3831
3832 /* We switch back to referring to sdr->data here, because the rest
3833 of the offsets are the same in 1.0 and 1.5. Only the power
3834 state and device capabilities change between the two
3835 version. */
3836 info->entity_id = sdr->data[7];
3837 info->entity_instance = sdr->data[8];
3838
3839 info->oem = sdr->data[9];
3840 str = sdr->data + 10;
3841 rv = ipmi_get_device_string(&str,
3842 sdr->length-10,
3843 info->id, IPMI_STR_SDR_SEMANTICS, 0,
3844 &info->id_type, ENTITY_ID_LEN, &info->id_len);
3845 if (rv) {
3846 ipmi_log(IPMI_LOG_WARNING,
3847 "%sentity.c(decode_mcdlr):"
3848 " Error getting device ID string from SDR record %d: %d,"
3849 " this entity will be named **INVALID**",
3850 MC_NAME(mc), sdr->record_id, rv);
3851 strncpy(info->id, "**INVALID**", sizeof(info->id));
3852 info->id_len = strlen(info->id);
3853 info->id_type = IPMI_ASCII_STR;
3854 rv = 0;
3855 }
3856
3857 /* Make sure the FRU fetch stuff works. */
3858 info->access_address = info->slave_address;
3859 info->fru_device_id = 0;
3860 info->is_logical_fru = 1;
3861 info->private_bus_id = 0;
3862
3863 return rv;
3864 }
3865
3866 typedef struct entity_found_s
3867 {
3868 int found;
3869 ipmi_entity_t *ent;
3870 ipmi_entity_t **cent;
3871 unsigned int cent_next;
3872 unsigned int cent_len;
3873 } entity_found_t;
3874
3875 typedef struct entity_sdr_info_s
3876 {
3877 ipmi_entity_info_t *ents;
3878 unsigned int len; /* array size */
3879 unsigned int next; /* next member to use. */
3880 entity_found_t *found; /* bools and info used for comparing. */
3881 dlr_info_t **dlrs;
3882 } entity_sdr_info_t;
3883
3884 static int
add_sdr_info(entity_sdr_info_t * infos,dlr_info_t * dlr)3885 add_sdr_info(entity_sdr_info_t *infos, dlr_info_t *dlr)
3886 {
3887 dlr_info_t *new_dlr;
3888
3889 if (infos->len == infos->next) {
3890 /* Need to expand the array. */
3891 unsigned int new_length = infos->len + 5;
3892 dlr_info_t **new_dlrs;
3893 entity_found_t *new_found;
3894
3895 new_dlrs = ipmi_mem_alloc(sizeof(dlr_info_t *) * new_length);
3896 if (!new_dlrs)
3897 return ENOMEM;
3898 new_found = ipmi_mem_alloc(sizeof(entity_found_t) * new_length);
3899 if (!new_found) {
3900 ipmi_mem_free(new_dlrs);
3901 return ENOMEM;
3902 }
3903 if (infos->dlrs) {
3904 memcpy(new_dlrs, infos->dlrs, sizeof(dlr_info_t *) * infos->len);
3905 memcpy(new_found, infos->found,
3906 sizeof(entity_found_t) * infos->len);
3907 ipmi_mem_free(infos->dlrs);
3908 ipmi_mem_free(infos->found);
3909 }
3910 memset(new_found + infos->len,
3911 0,
3912 sizeof(entity_found_t) * (new_length - infos->len));
3913 infos->dlrs = new_dlrs;
3914 infos->found = new_found;
3915 infos->len = new_length;
3916 }
3917
3918 new_dlr = ipmi_mem_alloc(sizeof(*new_dlr));
3919 if (!new_dlr)
3920 return ENOMEM;
3921
3922 memcpy(new_dlr, dlr, sizeof(*new_dlr));
3923 infos->dlrs[infos->next] = new_dlr;
3924 infos->next++;
3925
3926 return 0;
3927 }
3928
3929 static void
destroy_sdr_info(entity_sdr_info_t * infos)3930 destroy_sdr_info(entity_sdr_info_t *infos)
3931 {
3932 unsigned int i;
3933
3934 if (infos->dlrs) {
3935 for (i=0; i<infos->next; i++) {
3936 if (infos->found[i].cent)
3937 ipmi_mem_free(infos->found[i].cent);
3938 }
3939 for (i=0; i<infos->next; i++)
3940 ipmi_mem_free(infos->dlrs[i]);
3941 ipmi_mem_free(infos->dlrs);
3942 ipmi_mem_free(infos->found);
3943 }
3944 }
3945
3946 static void
cleanup_sdr_info(entity_sdr_info_t * infos)3947 cleanup_sdr_info(entity_sdr_info_t *infos)
3948 {
3949 unsigned int i;
3950
3951 if (infos->dlrs) {
3952 for (i=0; i<infos->next; i++) {
3953 if (infos->found[i].cent)
3954 ipmi_mem_free(infos->found[i].cent);
3955 infos->found[i].cent = NULL;
3956 infos->found[i].cent_len = 0;
3957 infos->found[i].cent_next = 0;
3958 }
3959 }
3960 }
3961
3962 static int
add_child_ent_to_found(entity_found_t * found,ipmi_entity_t * ent)3963 add_child_ent_to_found(entity_found_t *found,
3964 ipmi_entity_t *ent)
3965 {
3966 if (found->cent_next == found->cent_len) {
3967 int new_len = found->cent_len + 4;
3968 ipmi_entity_t **new_cent;
3969
3970 new_cent = ipmi_mem_alloc(sizeof(ipmi_entity_t *) * new_len);
3971 if (!new_cent)
3972 return ENOMEM;
3973 if (found->cent) {
3974 memcpy(new_cent, found->cent,
3975 sizeof(ipmi_entity_t *) * found->cent_len);
3976 ipmi_mem_free(found->cent);
3977 }
3978 found->cent = new_cent;
3979 found->cent_len = new_len;
3980 }
3981
3982 found->cent[found->cent_next] = ent;
3983 found->cent_next++;
3984
3985 return 0;
3986 }
3987
3988 /* Find all the entities for unfound dlrs and make sure there is room
3989 in the proper child and parent lists for the new
3990 parents/children. */
3991 static int
fill_in_entities(ipmi_entity_info_t * ents,entity_sdr_info_t * infos)3992 fill_in_entities(ipmi_entity_info_t *ents,
3993 entity_sdr_info_t *infos)
3994 {
3995 entity_found_t *found;
3996 unsigned int i, j;
3997 int rv;
3998 ipmi_entity_t *child;
3999 ipmi_entity_t *ent;
4000
4001 for (i=0; i<infos->next; i++) {
4002 found = infos->found+i;
4003
4004 if (found->found)
4005 continue;
4006
4007 if (infos->dlrs[i]->entity_id) {
4008 i_ipmi_domain_entity_lock(ents->domain);
4009 rv = entity_add(ents, infos->dlrs[i]->device_num,
4010 infos->dlrs[i]->entity_id,
4011 infos->dlrs[i]->entity_instance,
4012 infos->dlrs[i]->output_handler, NULL,
4013 &found->ent);
4014 if (rv)
4015 goto out_err;
4016 } else {
4017 /* If entity id is null, it should be ignored. */
4018 found->ent = NULL;
4019 continue;
4020 }
4021
4022 if ((infos->dlrs[i]->type != IPMI_ENTITY_EAR)
4023 && (infos->dlrs[i]->type != IPMI_ENTITY_DREAR))
4024 continue;
4025
4026 /* Find the first previous unfound entry that has the same
4027 entity as me to add the contained entities to. This means
4028 that every unfound entity will only have one set of
4029 contained entities in the cent array even if it has
4030 multiple DLRs. It will always be in the first entry. */
4031 if (i > 0) {
4032 j = i - 1;
4033 ent = found->ent;
4034 for (; ent == (infos->found+j)->ent; j--) {
4035 if ((infos->found+j)->found)
4036 goto next_ent;
4037 if ((infos->dlrs[j]->type != IPMI_ENTITY_EAR)
4038 && (infos->dlrs[j]->type != IPMI_ENTITY_DREAR))
4039 goto next_ent;
4040 found = infos->found+j;
4041
4042 /* Since this is an EAR and we are putting it's entries in
4043 another place, ignore this one. */
4044 (infos->found+i)->found = 1;
4045 next_ent:
4046 if (j == 0)
4047 break;
4048 }
4049 }
4050
4051 if (infos->dlrs[i]->is_ranges) {
4052 for (j=0; j<4; j+=2) {
4053 dlr_ref_t *cent1 = infos->dlrs[i]->contained_entities+j;
4054 dlr_ref_t *cent2 = infos->dlrs[i]->contained_entities+j+1;
4055 int k;
4056 if (cent1->entity_id == 0)
4057 continue;
4058 for (k=cent1->entity_instance; k<=cent2->entity_instance; k++){
4059 i_ipmi_domain_entity_lock(ents->domain);
4060 rv = entity_add(ents, cent1->device_num,
4061 cent1->entity_id, k,
4062 NULL, NULL, &child);
4063 if (rv)
4064 goto out_err;
4065 rv = add_child_ent_to_found(found, child);
4066 if (rv) {
4067 i_ipmi_entity_put(child);
4068 goto out_err;
4069 }
4070 }
4071 }
4072 } else {
4073 for (j=0; j<4; j++) {
4074 dlr_ref_t *cent = infos->dlrs[i]->contained_entities+j;
4075 if (cent->entity_id == 0)
4076 continue;
4077 i_ipmi_domain_entity_lock(ents->domain);
4078 rv = entity_add(ents, cent->device_num,
4079 cent->entity_id, cent->entity_instance,
4080 NULL, NULL, &child);
4081 if (rv)
4082 return rv;
4083 rv = add_child_ent_to_found(found, child);
4084 if (rv) {
4085 i_ipmi_entity_put(child);
4086 goto out_err;
4087 }
4088 }
4089 }
4090 }
4091
4092 return 0;
4093
4094 out_err:
4095 return rv;
4096 }
4097
4098 static void
put_entities(entity_sdr_info_t * infos)4099 put_entities(entity_sdr_info_t *infos)
4100 {
4101 entity_found_t *found;
4102 unsigned int i, j;
4103
4104 for (i=0; i<infos->next; i++) {
4105 found = infos->found+i;
4106
4107 if (found->ent)
4108 i_ipmi_entity_put(found->ent);
4109
4110 /* Still put the entity even if found, as it was refcounted by
4111 looking it up. */
4112 if (found->found)
4113 continue;
4114
4115 for (j=0; j<found->cent_next; j++)
4116 i_ipmi_entity_put(found->cent[j]);
4117 }
4118 }
4119
4120 static int
cmp_dlr(const dlr_info_t * d1,const dlr_info_t * d2)4121 cmp_dlr(const dlr_info_t *d1, const dlr_info_t *d2)
4122 {
4123
4124 if (d1->entity_id < d2->entity_id)
4125 return -1;
4126 if (d1->entity_id > d2->entity_id)
4127 return 1;
4128 if (d1->entity_instance < d2->entity_instance)
4129 return -1;
4130 if (d1->entity_instance > d2->entity_instance)
4131 return 1;
4132 return memcmp(d1, d2, sizeof(dlr_info_t));
4133 }
4134
4135 static int
cmp_dlr_qsort(const void * a,const void * b)4136 cmp_dlr_qsort(const void *a, const void *b)
4137 {
4138 const dlr_info_t *d1 = *((dlr_info_t **) a);
4139 const dlr_info_t *d2 = *((dlr_info_t **) b);
4140
4141 return cmp_dlr(d1, d2);
4142 }
4143
4144 struct locked_list_entry_s
4145 {
4146 locked_list_entry_t *next;
4147 };
4148
4149 int
ipmi_entity_scan_sdrs(ipmi_domain_t * domain,ipmi_mc_t * mc,ipmi_entity_info_t * ents,ipmi_sdr_info_t * sdrs)4150 ipmi_entity_scan_sdrs(ipmi_domain_t *domain,
4151 ipmi_mc_t *mc,
4152 ipmi_entity_info_t *ents,
4153 ipmi_sdr_info_t *sdrs)
4154 {
4155 unsigned int count;
4156 unsigned int i, j;
4157 int rv;
4158 entity_sdr_info_t infos;
4159 entity_sdr_info_t *old_infos;
4160 entity_found_t *found;
4161 locked_list_entry_t *entries = NULL, *entry;
4162
4163 memset(&infos, 0, sizeof(infos));
4164
4165 rv = ipmi_get_sdr_count(sdrs, &count);
4166 if (rv)
4167 return rv;
4168
4169 for (i=0; i<count; i++) {
4170 ipmi_sdr_t sdr;
4171 dlr_info_t dlr;
4172
4173 rv = ipmi_get_sdr_by_index(sdrs, i, &sdr);
4174 if (rv)
4175 goto out_err;
4176
4177 memset(&dlr, 0, sizeof(dlr));
4178
4179 switch (sdr.type) {
4180 case IPMI_SDR_ENTITY_ASSOCIATION_RECORD:
4181 rv = decode_ear(&sdr, &dlr, mc);
4182 if (!rv)
4183 rv = add_sdr_info(&infos, &dlr);
4184 break;
4185
4186 case IPMI_SDR_DR_ENTITY_ASSOCIATION_RECORD:
4187 rv = decode_drear(&sdr, &dlr, mc);
4188 if (!rv)
4189 rv = add_sdr_info(&infos, &dlr);
4190 break;
4191
4192 case IPMI_SDR_GENERIC_DEVICE_LOCATOR_RECORD:
4193 rv = decode_gdlr(&sdr, &dlr, mc);
4194 if (!rv)
4195 rv = add_sdr_info(&infos, &dlr);
4196 break;
4197
4198 case IPMI_SDR_FRU_DEVICE_LOCATOR_RECORD:
4199 rv = decode_frudlr(&sdr, &dlr, mc);
4200 if (!rv)
4201 rv = add_sdr_info(&infos, &dlr);
4202 break;
4203
4204 case IPMI_SDR_MC_DEVICE_LOCATOR_RECORD:
4205 rv = decode_mcdlr(&sdr, &dlr, mc);
4206 if (!rv)
4207 rv = add_sdr_info(&infos, &dlr);
4208 break;
4209 }
4210 if (rv)
4211 goto out_err;
4212 }
4213
4214 /* The domain and mc should be used, and there should only be one
4215 thread performing this operation (at least per MC), so it is
4216 safe to do this without locks. Note that we do *NOT* want
4217 locks while we are filling in the entities, as they may add
4218 entities and cause added callbacks. */
4219
4220 old_infos = i_ipmi_get_sdr_entities(domain, mc);
4221 if (!old_infos) {
4222 old_infos = ipmi_mem_alloc(sizeof(*old_infos));
4223 if (!old_infos) {
4224 rv = ENOMEM;
4225 goto out_err_unlock_nocleaninfos;
4226 }
4227 memset(old_infos, 0, sizeof(*old_infos));
4228 old_infos->ents = ents;
4229 i_ipmi_set_sdr_entities(domain, mc, old_infos);
4230 }
4231
4232 /* Clear out all the temporary found information we use for
4233 scanning. */
4234 if (old_infos->next > 0)
4235 memset(old_infos->found, 0, sizeof(entity_found_t) * old_infos->next);
4236 if (infos.next > 0)
4237 memset(infos.found, 0, sizeof(entity_found_t) * infos.next);
4238
4239 /* Sort the DLRs by parent entity id/entity instance/rest of data.
4240 This makes the rest of the operations here O(n) instead of
4241 O(n^2). */
4242 qsort(infos.dlrs, infos.next, sizeof(dlr_info_t *), cmp_dlr_qsort);
4243
4244 /* For every item in the new array, try to find it in the old
4245 array. Both arrays are sorted by entity id/entity
4246 instance/rest of data, so this is O(n). */
4247 i=0;
4248 j=0;
4249 while ((i < infos.next) && (j < old_infos->next)) {
4250 int c = cmp_dlr(infos.dlrs[i], old_infos->dlrs[j]);
4251 if (c == 0) {
4252 infos.found[i].found = 1;
4253 old_infos->found[j].found = 1;
4254 i++;
4255 j++;
4256 } else if (c < 0)
4257 i++;
4258 else
4259 j++;
4260 }
4261
4262 /* For every item in the array that is not found, make sure
4263 the entities exists and we have them. */
4264 rv = fill_in_entities(ents, &infos);
4265 if (rv)
4266 goto out_err_unlock;
4267 rv = fill_in_entities(ents, old_infos);
4268 if (rv)
4269 goto out_err_unlock;
4270
4271 /* Now ensure space is in each parent for all the children and
4272 each child's parent entry. */
4273 for (i=0; i<infos.next; i++) {
4274 if (infos.found[i].found)
4275 continue;
4276
4277 /* Allocate space for all the children and parents. */
4278 for (j=0; j<(infos.found[i].cent_next*2); j++) {
4279 entry = locked_list_alloc_entry();
4280 if (!entry) {
4281 rv = ENOMEM;
4282 goto out_err_unlock;
4283 }
4284 entry->next = entries;
4285 entries = entry;
4286 }
4287 }
4288
4289 /* After this, the operation cannot fail, since we have gotten all
4290 the objects we need and we have allocated enough entries for
4291 the parent and child lists. */
4292
4293 i_ipmi_domain_entity_lock(domain);
4294 rv = 0;
4295
4296 /* Destroy all the old information that was not in the new version
4297 of the SDRs. */
4298 for (i=0; i<old_infos->next; i++) {
4299 found = old_infos->found + i;
4300 if (found->found)
4301 continue;
4302 if (!found->ent)
4303 continue;
4304
4305 if ((old_infos->dlrs[i]->type != IPMI_ENTITY_EAR)
4306 && (old_infos->dlrs[i]->type != IPMI_ENTITY_DREAR))
4307 {
4308 /* A real DLR, decrement the refcount, and destroy the info. */
4309 found->ent->ref_count--;
4310 memset(&found->ent->info, 0, sizeof(dlr_info_t));
4311 } else {
4312 /* It's an EAR, so handling removing the children. */
4313 for (j=0; j<found->cent_next; j++)
4314 ipmi_entity_remove_child_internal(found->ent, found->cent[j]);
4315 }
4316 }
4317
4318 /* Add all the new information that was in the new SDRs. */
4319 for (i=0; i<infos.next; i++) {
4320 found = infos.found + i;
4321 if (found->found)
4322 continue;
4323 if (!found->ent)
4324 continue;
4325
4326 if ((infos.dlrs[i]->type != IPMI_ENTITY_EAR)
4327 && (infos.dlrs[i]->type != IPMI_ENTITY_DREAR))
4328 {
4329 uint8_t ipmb = 0xff;
4330 int channel = -1;
4331
4332 found->ent->changed = 1;
4333
4334 /* A real DLR, increment the refcount, and copy the info. */
4335 found->ent->ref_count++;
4336
4337 /* Don't fetch FRU information until present. */
4338
4339 /* Set up the MC information for the device. */
4340 if (infos.dlrs[i]->type == IPMI_ENTITY_FRU) {
4341 channel = infos.dlrs[i]->channel;
4342 ipmb = infos.dlrs[i]->access_address;
4343 memcpy(&found->ent->pending_info, infos.dlrs[i],
4344 sizeof(dlr_info_t));
4345 found->ent->pending_info_ready = 1;
4346 }
4347 else if (infos.dlrs[i]->type == IPMI_ENTITY_MC)
4348 {
4349 if (infos.dlrs[i]->FRU_inventory_device) {
4350 channel = infos.dlrs[i]->channel;
4351 ipmb = infos.dlrs[i]->access_address;
4352 memcpy(&found->ent->pending_info, infos.dlrs[i],
4353 sizeof(dlr_info_t));
4354 found->ent->pending_info_ready = 1;
4355 } else {
4356 if ((!found->ent->info.FRU_inventory_device)
4357 && (!found->ent->pending_info.FRU_inventory_device))
4358 {
4359 /* We prefer to only keep the information from the
4360 FRU inventory device MCDLR. */
4361 memcpy(&found->ent->pending_info, infos.dlrs[i],
4362 sizeof(dlr_info_t));
4363 found->ent->pending_info_ready = 1;
4364 }
4365
4366 /* Go ahead and scan the MC if we don't do
4367 anything else with this data. */
4368 ipmi_start_ipmb_mc_scan(domain, infos.dlrs[i]->channel,
4369 infos.dlrs[i]->access_address,
4370 infos.dlrs[i]->access_address,
4371 NULL, NULL);
4372 }
4373 } else {
4374 memcpy(&found->ent->pending_info, infos.dlrs[i],
4375 sizeof(dlr_info_t));
4376 found->ent->pending_info_ready = 1;
4377 }
4378
4379 /* If we can use the FRU device presence to detect whether
4380 the entity is present, we register the monitor with the
4381 appropriate management controller to see if it is
4382 active and base presence off of that, if no other
4383 presence detection capability is there. */
4384 if (ipmb == 0) {
4385 /* Not a valid IPMB, just ignore it. */
4386 } else if ((channel != -1) && (infos.dlrs[i]->entity_id)) {
4387 ipmi_mc_t *mc;
4388 /* Attempt to create the MC. */
4389 rv = i_ipmi_find_or_create_mc_by_slave_addr
4390 (domain, channel, ipmb, &mc);
4391 if (rv) {
4392 ipmi_log(IPMI_LOG_SEVERE,
4393 "%sentity.c(ipmi_entity_scan_sdrs):"
4394 " Could not add MC for MCDLR or FRUDLR,"
4395 " error %x", ENTITY_NAME(found->ent), rv);
4396 } else if (found->ent->frudev_present) {
4397 if (found->ent->frudev_mc != mc) {
4398 ipmi_log(IPMI_LOG_WARNING,
4399 "%sentity.c(ipmi_entity_scan_sdrs):"
4400 " Entity has two different MCs in"
4401 " different SDRs, only using the first"
4402 " for presence. MCs are %s and %s",
4403 ENTITY_NAME(found->ent),
4404 MC_NAME(found->ent->frudev_mc),
4405 MC_NAME(mc));
4406 }
4407 i_ipmi_mc_put(mc);
4408 } else {
4409 rv = ipmi_mc_add_active_handler(mc,
4410 entity_mc_active,
4411 found->ent);
4412 if (rv) {
4413 ipmi_log(IPMI_LOG_SEVERE,
4414 "%sentity.c(ipmi_entity_scan_sdrs):"
4415 " Could not add an MC active handler for"
4416 " MCDLR or FRUDLR,"
4417 " error %x", ENTITY_NAME(found->ent), rv);
4418 } else {
4419 i_ipmi_mc_use(mc);
4420 found->ent->frudev_present = 1;
4421 found->ent->frudev_active = ipmi_mc_is_active(mc);
4422 found->ent->frudev_mc = mc;
4423 found->ent->presence_possibly_changed = 1;
4424 }
4425 i_ipmi_mc_put(mc);
4426 }
4427 }
4428 } else {
4429 /* It's an EAR, so handling adding the children. */
4430 for (j=0; j<found->cent_next; j++) {
4431 entry = entries;
4432 entries = entry->next->next;
4433 add_child(found->ent, found->cent[j], entry, entry->next);
4434 found->ent->changed = 1;
4435 found->cent[j]->changed = 1;
4436 }
4437 }
4438 }
4439
4440 infos.ents = ents;
4441
4442 i_ipmi_domain_entity_unlock(domain);
4443
4444 put_entities(&infos);
4445 put_entities(old_infos);
4446
4447 destroy_sdr_info(old_infos);
4448 cleanup_sdr_info(&infos);
4449 memcpy(old_infos, &infos, sizeof(infos));
4450
4451 out:
4452 while (entries) {
4453 entry = entries;
4454 entries = entry->next;
4455 locked_list_free_entry(entry);
4456 }
4457 return rv;
4458
4459 out_err_unlock:
4460 put_entities(&infos);
4461 put_entities(old_infos);
4462
4463 out_err_unlock_nocleaninfos:
4464 i_ipmi_domain_entity_unlock(domain);
4465
4466 out_err:
4467 destroy_sdr_info(&infos);
4468 goto out;
4469 }
4470
4471 int
ipmi_sdr_entity_destroy(void * info)4472 ipmi_sdr_entity_destroy(void *info)
4473 {
4474 entity_sdr_info_t *infos = info;
4475 unsigned int i, j;
4476 int rv;
4477 ipmi_entity_t *ent, *child;
4478
4479 for (i=0; i<infos->next; i++) {
4480 i_ipmi_domain_entity_lock(infos->ents->domain);
4481 rv = entity_find(infos->ents, infos->dlrs[i]->device_num,
4482 infos->dlrs[i]->entity_id,
4483 infos->dlrs[i]->entity_instance,
4484 &ent);
4485 i_ipmi_domain_entity_unlock(infos->ents->domain);
4486 if (rv)
4487 continue;
4488
4489 if ((infos->dlrs[i]->type != IPMI_ENTITY_EAR)
4490 && (infos->dlrs[i]->type != IPMI_ENTITY_DREAR))
4491 {
4492 if (ent->frudev_present) {
4493 ipmi_mc_t *mc = ent->frudev_mc;
4494 i_ipmi_domain_mc_lock(infos->ents->domain);
4495 i_ipmi_mc_get(mc);
4496 i_ipmi_domain_mc_unlock(infos->ents->domain);
4497 ipmi_mc_remove_active_handler(ent->frudev_mc,
4498 entity_mc_active, ent);
4499 i_ipmi_mc_release(ent->frudev_mc);
4500 i_ipmi_mc_put(mc);
4501 ent->frudev_mc = NULL;
4502 ent->frudev_present = 0;
4503 }
4504
4505 ent->ref_count--;
4506 } else {
4507 if (infos->dlrs[i]->is_ranges) {
4508 for (j=0; j<4; j+=2) {
4509 dlr_ref_t *cent1 = infos->dlrs[i]->contained_entities+j;
4510 dlr_ref_t *cent2 = infos->dlrs[i]->contained_entities+j+1;
4511 int k;
4512 if (cent1->entity_id == 0)
4513 continue;
4514 for (k=cent1->entity_instance;
4515 k<=cent2->entity_instance;
4516 k++)
4517 {
4518 i_ipmi_domain_entity_lock(infos->ents->domain);
4519 rv = entity_find(infos->ents, cent1->device_num,
4520 cent1->entity_id, k,
4521 &child);
4522 i_ipmi_domain_entity_unlock(infos->ents->domain);
4523 if (rv)
4524 continue;
4525
4526 ipmi_entity_remove_child(ent, child);
4527 i_ipmi_entity_put(child);
4528 }
4529 }
4530 } else {
4531 for (j=0; j<4; j++) {
4532 dlr_ref_t *cent = infos->dlrs[i]->contained_entities+j;
4533 if (cent->entity_id == 0)
4534 continue;
4535 i_ipmi_domain_entity_lock(infos->ents->domain);
4536 rv = entity_find(infos->ents, cent->device_num,
4537 cent->entity_id, cent->entity_instance,
4538 &child);
4539 i_ipmi_domain_entity_unlock(infos->ents->domain);
4540 if (rv)
4541 continue;
4542 ipmi_entity_remove_child(ent, child);
4543 i_ipmi_entity_put(child);
4544 }
4545 }
4546 ipmi_detect_entity_presence_change(ent, 0);
4547 }
4548 i_ipmi_entity_put(ent);
4549 }
4550
4551 destroy_sdr_info(info);
4552 ipmi_mem_free(info);
4553
4554 return 0;
4555 }
4556
4557 /***********************************************************************
4558 *
4559 * SDR output code.
4560 *
4561 **********************************************************************/
4562
4563 #if SAVE_SDR_CODE_ENABLE
4564 typedef struct sdr_append_info_s
4565 {
4566 int err;
4567 ipmi_entity_info_t *ents;
4568 ipmi_sdr_info_t *sdrs;
4569 } sdr_append_info_t;
4570
4571 /* For sorting by entity ID/entity instance. */
4572 static int
cmp_entities(void * item1,void * item2)4573 cmp_entities(void *item1, void *item2)
4574 {
4575 ipmi_entity_t *ent1 = item1;
4576 ipmi_entity_t *ent2 = item2;
4577
4578 if (ent1->info.entity_id < ent2->info.entity_id)
4579 return -1;
4580 if (ent1->info.entity_id > ent2->info.entity_id)
4581 return 1;
4582 if (ent1->info.entity_instance < ent2->info.entity_instance)
4583 return -1;
4584 if (ent1->info.entity_instance > ent2->info.entity_instance)
4585 return 1;
4586 return 0;
4587 }
4588
4589 static int
do_ear_output(ipmi_sdr_info_t * sdrs,ipmi_sdr_t * sdr,ipmi_entity_t * (ents[]),int is_range,int other_entries,int len)4590 do_ear_output(ipmi_sdr_info_t *sdrs,
4591 ipmi_sdr_t *sdr,
4592 ipmi_entity_t *(ents[]),
4593 int is_range,
4594 int other_entries,
4595 int len)
4596 {
4597 int pos;
4598 int rv;
4599 int old_flags;
4600 int old_flags_pos;
4601 int i;
4602
4603 if (sdr->type == IPMI_SDR_ENTITY_ASSOCIATION_RECORD) {
4604 /* not device-relative */
4605 memset(sdr->data+3, 0, 8);
4606 old_flags = sdr->data[2];
4607 old_flags_pos = 2;
4608 if (is_range)
4609 sdr->data[2] |= 1 << 7;
4610 if (other_entries)
4611 sdr->data[2] |= 1 << 6;
4612 pos = 3;
4613 for (i=0; i<len; i++) {
4614 sdr->data[pos] = ents[i]->info.entity_id;
4615 pos++;
4616 sdr->data[pos] = ents[i]->info.entity_instance;
4617 pos++;
4618 }
4619 } else {
4620 /* device-relative */
4621 memset(sdr->data+5, 0, 16);
4622 old_flags = sdr->data[4];
4623 old_flags_pos = 4;
4624 if (is_range)
4625 sdr->data[4] |= 1 << 7;
4626 if (other_entries)
4627 sdr->data[4] |= 1 << 6;
4628 pos = 5;
4629 for (i=0; i<len; i++) {
4630 sdr->data[pos] = ents[i]->info.device_num.address;
4631 pos++;
4632 sdr->data[pos] = ents[i]->info.device_num.channel;
4633 pos++;
4634 sdr->data[pos] = ents[i]->info.entity_id;
4635 pos++;
4636 sdr->data[pos] = ents[i]->info.entity_instance;
4637 pos++;
4638 }
4639 }
4640
4641 rv = ipmi_sdr_add(sdrs, sdr);
4642
4643 /* Restore the original value of the flags field. */
4644 sdr->data[old_flags_pos] = old_flags;
4645
4646 return rv;
4647 }
4648
4649 static int
output_child_ears(ipmi_entity_t * ent,ipmi_sdr_info_t * sdrs)4650 output_child_ears(ipmi_entity_t *ent, ipmi_sdr_info_t *sdrs)
4651 {
4652 ipmi_sdr_t sdr;
4653 int prev_inst;
4654 ipmi_entity_t *curr, *next, *last;
4655 int curr_dlr_entry = 0;
4656 int is_range = 0;
4657 ipmi_entity_t *(ents[4]);
4658 ilist_iter_t iter;
4659 int rv;
4660
4661 if (ilist_empty(ent->child_entities))
4662 return 0;
4663
4664 memset(&sdr, 0, sizeof(sdr));
4665
4666 sdr.major_version = IPMI_MAJOR_NUM_SDR;
4667 sdr.minor_version = IPMI_MINOR_NUM_SDR;
4668 sdr.data[0] = ent->info.entity_id;
4669 sdr.data[1] = ent->info.entity_instance;
4670
4671 if ((sdr.major_version == 1) && (sdr.minor_version < 5)) {
4672 /* IPMI 1.0, we can olny use normal entity association
4673 records */
4674 sdr.type = IPMI_SDR_ENTITY_ASSOCIATION_RECORD;
4675 sdr.length = 11;
4676 sdr.data[2] = (ent->info.presence_sensor_always_there << 5);
4677 } else {
4678 /* IPMI 1.5, we only use the device-relative EARs. */
4679 sdr.type = IPMI_SDR_DR_ENTITY_ASSOCIATION_RECORD;
4680 sdr.length = 27;
4681 sdr.data[2] = ent->info.slave_address;
4682 sdr.data[3] = ent->info.channel;
4683 sdr.data[4] = (ent->info.presence_sensor_always_there << 5);
4684 }
4685
4686 ilist_sort(ent->child_entities, cmp_entities);
4687
4688 ilist_init_iter(&iter, ent->child_entities);
4689 last = NULL;
4690 if (ilist_first(&iter))
4691 next = ilist_get(&iter);
4692 else
4693 next = NULL;
4694 while (next) {
4695 curr = next;
4696 prev_inst = curr->info.entity_instance;
4697 if (ilist_next(&iter))
4698 next = ilist_get(&iter);
4699 else
4700 next = NULL;
4701 while (next
4702 && (next->info.entity_id == curr->info.entity_id)
4703 && (next->info.entity_instance == prev_inst+1))
4704 {
4705 last = next;
4706 if (ilist_next(&iter))
4707 next = ilist_get(&iter);
4708 else
4709 next = NULL;
4710 prev_inst++;
4711 }
4712 if (prev_inst > curr->info.entity_instance) {
4713 /* We have a range. */
4714 if ((curr_dlr_entry > 0) && (!is_range)) {
4715 rv = do_ear_output(sdrs, &sdr, ents,
4716 is_range, 1, curr_dlr_entry);
4717 if (rv)
4718 return rv;
4719 }
4720 is_range = 1;
4721 ents[curr_dlr_entry] = curr;
4722 ents[curr_dlr_entry+1] = last;
4723 curr_dlr_entry += 2;
4724 } else {
4725 /* Not a range. */
4726 if ((curr_dlr_entry > 0) && (is_range)) {
4727 rv = do_ear_output(sdrs, &sdr, ents,
4728 is_range, 1, curr_dlr_entry);
4729 if (rv)
4730 return rv;
4731 }
4732 is_range = 0;
4733 ents[curr_dlr_entry] = curr;
4734 curr_dlr_entry++;
4735 }
4736 if (curr_dlr_entry >= 4) {
4737 rv = do_ear_output(sdrs, &sdr, ents,
4738 is_range, next != NULL, curr_dlr_entry);
4739 if (rv)
4740 return rv;
4741 curr_dlr_entry = 0;
4742 }
4743 }
4744
4745 return 0;
4746 }
4747
4748 static void
ent_sdr_append_handler(ipmi_entity_t * ent,void * cb_data)4749 ent_sdr_append_handler(ipmi_entity_t *ent, void *cb_data)
4750 {
4751 sdr_append_info_t *info = cb_data;
4752
4753 if (info->err)
4754 return;
4755
4756 if (ent->sdr_gen_output)
4757 info->err = ent->sdr_gen_output(ent, info->sdrs, ent->sdr_gen_cb_data);
4758 if (!info->err)
4759 info->err = output_child_ears(ent, info->sdrs);
4760 }
4761
4762 int
ipmi_entity_append_to_sdrs(ipmi_entity_info_t * ents,ipmi_sdr_info_t * sdrs)4763 ipmi_entity_append_to_sdrs(ipmi_entity_info_t *ents,
4764 ipmi_sdr_info_t *sdrs)
4765 {
4766 sdr_append_info_t info = { 0, ents, sdrs };
4767
4768 ipmi_entities_iterate_entities(ents, ent_sdr_append_handler, &info);
4769 return info.err;
4770 }
4771 #endif
4772
4773 /***********************************************************************
4774 *
4775 * Get/set all the various entity values.
4776 *
4777 **********************************************************************/
4778
4779 ipmi_domain_t *
ipmi_entity_get_domain(ipmi_entity_t * ent)4780 ipmi_entity_get_domain(ipmi_entity_t *ent)
4781 {
4782 CHECK_ENTITY_LOCK(ent);
4783
4784 return ent->domain;
4785 }
4786
4787 int
ipmi_entity_get_access_address(ipmi_entity_t * ent)4788 ipmi_entity_get_access_address(ipmi_entity_t *ent)
4789 {
4790 CHECK_ENTITY_LOCK(ent);
4791
4792 return ent->info.access_address;
4793 }
4794
4795 void
ipmi_entity_set_access_address(ipmi_entity_t * ent,int access_address)4796 ipmi_entity_set_access_address(ipmi_entity_t *ent, int access_address)
4797 {
4798 CHECK_ENTITY_LOCK(ent);
4799
4800 ent->info.access_address = access_address;
4801 }
4802
4803 void
ipmi_entity_set_physical_slot_num(ipmi_entity_t * ent,int present,unsigned int val)4804 ipmi_entity_set_physical_slot_num(ipmi_entity_t *ent,
4805 int present,
4806 unsigned int val)
4807 {
4808 CHECK_ENTITY_LOCK(ent);
4809
4810 ent->slot_num = val;
4811 ent->slot_num_present = present;
4812 }
4813
4814 int
ipmi_entity_get_physical_slot_num(ipmi_entity_t * ent,unsigned int * slot_num)4815 ipmi_entity_get_physical_slot_num(ipmi_entity_t *ent, unsigned int *slot_num)
4816 {
4817 CHECK_ENTITY_LOCK(ent);
4818
4819 if (ent->slot_num_present) {
4820 *slot_num = ent->slot_num;
4821 return 0;
4822 }
4823 else
4824 return ENOSYS;
4825 }
4826
4827 int
ipmi_entity_get_slave_address(ipmi_entity_t * ent)4828 ipmi_entity_get_slave_address(ipmi_entity_t *ent)
4829 {
4830 CHECK_ENTITY_LOCK(ent);
4831
4832 return ent->info.slave_address;
4833 }
4834
4835 void
ipmi_entity_set_slave_address(ipmi_entity_t * ent,int slave_address)4836 ipmi_entity_set_slave_address(ipmi_entity_t *ent, int slave_address)
4837 {
4838 CHECK_ENTITY_LOCK(ent);
4839
4840 ent->info.slave_address = slave_address;
4841 }
4842
4843 int
ipmi_entity_get_channel(ipmi_entity_t * ent)4844 ipmi_entity_get_channel(ipmi_entity_t *ent)
4845 {
4846 CHECK_ENTITY_LOCK(ent);
4847
4848 return ent->info.channel;
4849 }
4850
4851 void
ipmi_entity_set_channel(ipmi_entity_t * ent,int channel)4852 ipmi_entity_set_channel(ipmi_entity_t *ent, int channel)
4853 {
4854 CHECK_ENTITY_LOCK(ent);
4855
4856 ent->info.channel = channel;
4857 }
4858
4859 int
ipmi_entity_get_mc_id(ipmi_entity_t * ent,ipmi_mcid_t * mc_id)4860 ipmi_entity_get_mc_id(ipmi_entity_t *ent, ipmi_mcid_t *mc_id)
4861 {
4862 ipmi_ipmb_addr_t sa;
4863 ipmi_mc_t *mc;
4864
4865 if ((ent->info.type != IPMI_ENTITY_MC)
4866 && (ent->info.type != IPMI_ENTITY_GENERIC))
4867 {
4868 return ENOSYS;
4869 }
4870
4871 sa.addr_type = IPMI_IPMB_ADDR_TYPE;
4872 sa.channel = ent->info.channel;
4873 sa.slave_addr = ent->info.slave_address;
4874 sa.lun = ent->info.lun;
4875
4876 mc = i_ipmi_find_mc_by_addr(ent->domain, (ipmi_addr_t *) &sa, sizeof(sa));
4877 if (!mc)
4878 return ENODEV;
4879
4880 *mc_id = ipmi_mc_convert_to_id(mc);
4881 i_ipmi_mc_put(mc);
4882
4883 return 0;
4884 }
4885
4886 int
ipmi_entity_get_lun(ipmi_entity_t * ent)4887 ipmi_entity_get_lun(ipmi_entity_t *ent)
4888 {
4889 CHECK_ENTITY_LOCK(ent);
4890
4891 return ent->info.lun;
4892 }
4893
4894 void
ipmi_entity_set_lun(ipmi_entity_t * ent,int lun)4895 ipmi_entity_set_lun(ipmi_entity_t *ent, int lun)
4896 {
4897 CHECK_ENTITY_LOCK(ent);
4898
4899 ent->info.lun = lun;
4900 }
4901
4902 int
ipmi_entity_get_private_bus_id(ipmi_entity_t * ent)4903 ipmi_entity_get_private_bus_id(ipmi_entity_t *ent)
4904 {
4905 CHECK_ENTITY_LOCK(ent);
4906
4907 return ent->info.private_bus_id;
4908 }
4909
4910 void
ipmi_entity_set_private_bus_id(ipmi_entity_t * ent,int private_bus_id)4911 ipmi_entity_set_private_bus_id(ipmi_entity_t *ent, int private_bus_id)
4912 {
4913 CHECK_ENTITY_LOCK(ent);
4914
4915 ent->info.private_bus_id = private_bus_id;
4916 }
4917
4918 int
ipmi_entity_get_is_logical_fru(ipmi_entity_t * ent)4919 ipmi_entity_get_is_logical_fru(ipmi_entity_t *ent)
4920 {
4921 CHECK_ENTITY_LOCK(ent);
4922
4923 return ent->info.is_logical_fru;
4924 }
4925
4926 void
ipmi_entity_set_is_logical_fru(ipmi_entity_t * ent,int is_logical_fru)4927 ipmi_entity_set_is_logical_fru(ipmi_entity_t *ent, int is_logical_fru)
4928 {
4929 CHECK_ENTITY_LOCK(ent);
4930
4931 ent->info.is_logical_fru = is_logical_fru;
4932 }
4933
4934 int
ipmi_entity_get_fru_device_id(ipmi_entity_t * ent)4935 ipmi_entity_get_fru_device_id(ipmi_entity_t *ent)
4936 {
4937 CHECK_ENTITY_LOCK(ent);
4938
4939 return ent->info.fru_device_id;
4940 }
4941
4942 void
ipmi_entity_set_fru_device_id(ipmi_entity_t * ent,int fru_device_id)4943 ipmi_entity_set_fru_device_id(ipmi_entity_t *ent, int fru_device_id)
4944 {
4945 CHECK_ENTITY_LOCK(ent);
4946
4947 ent->info.fru_device_id = fru_device_id;
4948 }
4949
4950 int
ipmi_entity_get_is_fru(ipmi_entity_t * ent)4951 ipmi_entity_get_is_fru(ipmi_entity_t *ent)
4952 {
4953 int rv = 0;
4954 CHECK_ENTITY_LOCK(ent);
4955
4956 ent_lock(ent);
4957 if (ent->info.type == IPMI_ENTITY_FRU)
4958 rv = 1;
4959 if ((ent->info.type == IPMI_ENTITY_MC) && (ent->info.FRU_inventory_device))
4960 rv = 1;
4961 ent_unlock(ent);
4962 return rv;
4963 }
4964
4965 int
ipmi_entity_get_is_mc(ipmi_entity_t * ent)4966 ipmi_entity_get_is_mc(ipmi_entity_t *ent)
4967 {
4968 CHECK_ENTITY_LOCK(ent);
4969
4970 return ent->info.type == IPMI_ENTITY_MC;
4971 }
4972
4973 enum ipmi_dlr_type_e
ipmi_entity_get_type(ipmi_entity_t * ent)4974 ipmi_entity_get_type(ipmi_entity_t *ent)
4975 {
4976 CHECK_ENTITY_LOCK(ent);
4977
4978 return ent->info.type;
4979 }
4980
4981 void
ipmi_entity_set_type(ipmi_entity_t * ent,enum ipmi_dlr_type_e type)4982 ipmi_entity_set_type(ipmi_entity_t *ent, enum ipmi_dlr_type_e type)
4983 {
4984 CHECK_ENTITY_LOCK(ent);
4985
4986 ent->info.type = type;
4987 }
4988
4989 int
ipmi_entity_get_entity_id(ipmi_entity_t * ent)4990 ipmi_entity_get_entity_id(ipmi_entity_t *ent)
4991 {
4992 CHECK_ENTITY_LOCK(ent);
4993
4994 return ent->key.entity_id;
4995 }
4996
4997 int
ipmi_entity_get_entity_instance(ipmi_entity_t * ent)4998 ipmi_entity_get_entity_instance(ipmi_entity_t *ent)
4999 {
5000 CHECK_ENTITY_LOCK(ent);
5001
5002 return ent->key.entity_instance;
5003 }
5004
5005 int
ipmi_entity_get_device_channel(ipmi_entity_t * ent)5006 ipmi_entity_get_device_channel(ipmi_entity_t *ent)
5007 {
5008 CHECK_ENTITY_LOCK(ent);
5009
5010 return ent->key.device_num.channel;
5011 }
5012
5013 int
ipmi_entity_get_device_address(ipmi_entity_t * ent)5014 ipmi_entity_get_device_address(ipmi_entity_t *ent)
5015 {
5016 CHECK_ENTITY_LOCK(ent);
5017
5018 return ent->key.device_num.address;
5019 }
5020
5021 int
ipmi_entity_get_device_type(ipmi_entity_t * ent)5022 ipmi_entity_get_device_type(ipmi_entity_t *ent)
5023 {
5024 CHECK_ENTITY_LOCK(ent);
5025
5026 return ent->info.device_type;
5027 }
5028
5029 void
ipmi_entity_set_device_type(ipmi_entity_t * ent,int device_type)5030 ipmi_entity_set_device_type(ipmi_entity_t *ent, int device_type)
5031 {
5032 CHECK_ENTITY_LOCK(ent);
5033
5034 ent->info.device_type = device_type;
5035 }
5036
5037 int
ipmi_entity_get_device_modifier(ipmi_entity_t * ent)5038 ipmi_entity_get_device_modifier(ipmi_entity_t *ent)
5039 {
5040 CHECK_ENTITY_LOCK(ent);
5041
5042 return ent->info.device_type_modifier;
5043 }
5044
5045 void
ipmi_entity_set_device_modifier(ipmi_entity_t * ent,int device_modifier)5046 ipmi_entity_set_device_modifier(ipmi_entity_t *ent, int device_modifier)
5047 {
5048 CHECK_ENTITY_LOCK(ent);
5049
5050 ent->info.device_type_modifier = device_modifier;
5051 }
5052
5053 int
ipmi_entity_get_oem(ipmi_entity_t * ent)5054 ipmi_entity_get_oem(ipmi_entity_t *ent)
5055 {
5056 CHECK_ENTITY_LOCK(ent);
5057
5058 return ent->info.oem;
5059 }
5060
5061 void
ipmi_entity_set_oem(ipmi_entity_t * ent,int oem)5062 ipmi_entity_set_oem(ipmi_entity_t *ent, int oem)
5063 {
5064 CHECK_ENTITY_LOCK(ent);
5065
5066 ent->info.oem = oem;
5067 }
5068
5069 int
ipmi_entity_get_address_span(ipmi_entity_t * ent)5070 ipmi_entity_get_address_span(ipmi_entity_t *ent)
5071 {
5072 CHECK_ENTITY_LOCK(ent);
5073
5074 return ent->info.address_span;
5075 }
5076
5077 void
ipmi_entity_set_address_span(ipmi_entity_t * ent,int address_span)5078 ipmi_entity_set_address_span(ipmi_entity_t *ent, int address_span)
5079 {
5080 CHECK_ENTITY_LOCK(ent);
5081
5082 ent->info.address_span = address_span;
5083 }
5084
5085 int
ipmi_entity_get_id_length(ipmi_entity_t * ent)5086 ipmi_entity_get_id_length(ipmi_entity_t *ent)
5087 {
5088 CHECK_ENTITY_LOCK(ent);
5089
5090 if (ent->info.id_type == IPMI_ASCII_STR)
5091 return ent->info.id_len+1;
5092 else
5093 return ent->info.id_len;
5094 }
5095
5096 enum ipmi_str_type_e
ipmi_entity_get_id_type(ipmi_entity_t * ent)5097 ipmi_entity_get_id_type(ipmi_entity_t *ent)
5098 {
5099 CHECK_ENTITY_LOCK(ent);
5100
5101 return ent->info.id_type;
5102 }
5103
5104 int
ipmi_entity_get_id(ipmi_entity_t * ent,char * id,int length)5105 ipmi_entity_get_id(ipmi_entity_t *ent, char *id, int length)
5106 {
5107 int clen;
5108
5109 CHECK_ENTITY_LOCK(ent);
5110
5111 ent_lock(ent);
5112 if ((int)ent->info.id_len > length)
5113 clen = length;
5114 else
5115 clen = ent->info.id_len;
5116 memcpy(id, ent->info.id, clen);
5117
5118 if (ent->info.id_type == IPMI_ASCII_STR) {
5119 /* NIL terminate the ASCII string. */
5120 if (clen == length)
5121 clen--;
5122
5123 id[clen] = '\0';
5124 }
5125 ent_unlock(ent);
5126
5127 return clen;
5128 }
5129
5130 void
ipmi_entity_set_id(ipmi_entity_t * ent,char * id,enum ipmi_str_type_e type,int length)5131 ipmi_entity_set_id(ipmi_entity_t *ent, char *id,
5132 enum ipmi_str_type_e type, int length)
5133 {
5134 CHECK_ENTITY_LOCK(ent);
5135
5136 if (length > ENTITY_ID_LEN)
5137 length = ENTITY_ID_LEN;
5138
5139 ent_lock(ent);
5140 memcpy(ent->info.id, id, length);
5141 ent->info.id_type = type;
5142 ent->info.id_len = length;
5143 ent_unlock(ent);
5144 entity_set_name(ent);
5145 }
5146
5147 int
ipmi_entity_get_presence_sensor_always_there(ipmi_entity_t * ent)5148 ipmi_entity_get_presence_sensor_always_there(ipmi_entity_t *ent)
5149 {
5150 CHECK_ENTITY_LOCK(ent);
5151
5152 return ent->info.presence_sensor_always_there;
5153 }
5154
5155 void
ipmi_entity_set_presence_sensor_always_there(ipmi_entity_t * ent,int val)5156 ipmi_entity_set_presence_sensor_always_there(ipmi_entity_t *ent, int val)
5157 {
5158 CHECK_ENTITY_LOCK(ent);
5159
5160 ent->info.presence_sensor_always_there = val;
5161 }
5162
5163 int
ipmi_entity_get_ACPI_system_power_notify_required(ipmi_entity_t * ent)5164 ipmi_entity_get_ACPI_system_power_notify_required(ipmi_entity_t *ent)
5165 {
5166 CHECK_ENTITY_LOCK(ent);
5167
5168 return ent->info.ACPI_system_power_notify_required;
5169 }
5170
5171 void
ipmi_entity_set_ACPI_system_power_notify_required(ipmi_entity_t * ent,int val)5172 ipmi_entity_set_ACPI_system_power_notify_required(ipmi_entity_t *ent,
5173 int val)
5174 {
5175 CHECK_ENTITY_LOCK(ent);
5176
5177 ent->info.ACPI_system_power_notify_required = val;
5178 }
5179
5180 int
ipmi_entity_get_ACPI_device_power_notify_required(ipmi_entity_t * ent)5181 ipmi_entity_get_ACPI_device_power_notify_required(ipmi_entity_t *ent)
5182 {
5183 CHECK_ENTITY_LOCK(ent);
5184
5185 return ent->info.ACPI_device_power_notify_required;
5186 }
5187
5188 void
ipmi_entity_set_ACPI_device_power_notify_required(ipmi_entity_t * ent,int val)5189 ipmi_entity_set_ACPI_device_power_notify_required(ipmi_entity_t *ent,
5190 int val)
5191 {
5192 CHECK_ENTITY_LOCK(ent);
5193
5194 ent->info.ACPI_device_power_notify_required = val;
5195 }
5196
5197 int
ipmi_entity_get_controller_logs_init_agent_errors(ipmi_entity_t * ent)5198 ipmi_entity_get_controller_logs_init_agent_errors(ipmi_entity_t *ent)
5199 {
5200 CHECK_ENTITY_LOCK(ent);
5201
5202 return ent->info.controller_logs_init_agent_errors;
5203 }
5204
5205 void
ipmi_entity_set_controller_logs_init_agent_errors(ipmi_entity_t * ent,int val)5206 ipmi_entity_set_controller_logs_init_agent_errors(ipmi_entity_t *ent,
5207 int val)
5208 {
5209 CHECK_ENTITY_LOCK(ent);
5210
5211 ent->info.controller_logs_init_agent_errors = val;
5212 }
5213
5214 int
ipmi_entity_get_log_init_agent_errors_accessing(ipmi_entity_t * ent)5215 ipmi_entity_get_log_init_agent_errors_accessing(ipmi_entity_t *ent)
5216 {
5217 CHECK_ENTITY_LOCK(ent);
5218
5219 return ent->info.log_init_agent_errors_accessing;
5220 }
5221
5222 void
ipmi_entity_set_log_init_agent_errors_accessing(ipmi_entity_t * ent,int val)5223 ipmi_entity_set_log_init_agent_errors_accessing(ipmi_entity_t *ent,
5224 int val)
5225 {
5226 CHECK_ENTITY_LOCK(ent);
5227
5228 ent->info.log_init_agent_errors_accessing = val;
5229 }
5230
5231 int
ipmi_entity_get_global_init(ipmi_entity_t * ent)5232 ipmi_entity_get_global_init(ipmi_entity_t *ent)
5233 {
5234 CHECK_ENTITY_LOCK(ent);
5235
5236 return ent->info.global_init;
5237 }
5238
5239 void
ipmi_entity_set_global_init(ipmi_entity_t * ent,int val)5240 ipmi_entity_set_global_init(ipmi_entity_t *ent,
5241 int val)
5242 {
5243 CHECK_ENTITY_LOCK(ent);
5244
5245 ent->info.global_init = val;
5246 }
5247
5248 int
ipmi_entity_get_chassis_device(ipmi_entity_t * ent)5249 ipmi_entity_get_chassis_device(ipmi_entity_t *ent)
5250 {
5251 CHECK_ENTITY_LOCK(ent);
5252
5253 return ent->info.chassis_device;
5254 }
5255
5256 void
ipmi_entity_set_chassis_device(ipmi_entity_t * ent,int val)5257 ipmi_entity_set_chassis_device(ipmi_entity_t *ent,
5258 int val)
5259 {
5260 CHECK_ENTITY_LOCK(ent);
5261
5262 ent->info.chassis_device = val;
5263 }
5264
5265 int
ipmi_entity_get_bridge(ipmi_entity_t * ent)5266 ipmi_entity_get_bridge(ipmi_entity_t *ent)
5267 {
5268 CHECK_ENTITY_LOCK(ent);
5269
5270 return ent->info.bridge;
5271 }
5272
5273 void
ipmi_entity_set_bridge(ipmi_entity_t * ent,int val)5274 ipmi_entity_set_bridge(ipmi_entity_t *ent,
5275 int val)
5276 {
5277 CHECK_ENTITY_LOCK(ent);
5278
5279 ent->info.bridge = val;
5280 }
5281
5282 int
ipmi_entity_get_IPMB_event_generator(ipmi_entity_t * ent)5283 ipmi_entity_get_IPMB_event_generator(ipmi_entity_t *ent)
5284 {
5285 CHECK_ENTITY_LOCK(ent);
5286
5287 return ent->info.IPMB_event_generator;
5288 }
5289
5290 void
ipmi_entity_set_IPMB_event_generator(ipmi_entity_t * ent,int val)5291 ipmi_entity_set_IPMB_event_generator(ipmi_entity_t *ent,
5292 int val)
5293 {
5294 CHECK_ENTITY_LOCK(ent);
5295
5296 ent->info.IPMB_event_generator = val;
5297 }
5298
5299 int
ipmi_entity_get_IPMB_event_receiver(ipmi_entity_t * ent)5300 ipmi_entity_get_IPMB_event_receiver(ipmi_entity_t *ent)
5301 {
5302 CHECK_ENTITY_LOCK(ent);
5303
5304 return ent->info.IPMB_event_receiver;
5305 }
5306
5307 void
ipmi_entity_set_IPMB_event_receiver(ipmi_entity_t * ent,int val)5308 ipmi_entity_set_IPMB_event_receiver(ipmi_entity_t *ent,
5309 int val)
5310 {
5311 CHECK_ENTITY_LOCK(ent);
5312
5313 ent->info.IPMB_event_receiver = val;
5314 }
5315
5316 int
ipmi_entity_get_FRU_inventory_device(ipmi_entity_t * ent)5317 ipmi_entity_get_FRU_inventory_device(ipmi_entity_t *ent)
5318 {
5319 CHECK_ENTITY_LOCK(ent);
5320
5321 return ent->info.FRU_inventory_device;
5322 }
5323
5324 void
ipmi_entity_set_FRU_inventory_device(ipmi_entity_t * ent,int val)5325 ipmi_entity_set_FRU_inventory_device(ipmi_entity_t *ent,
5326 int val)
5327 {
5328 CHECK_ENTITY_LOCK(ent);
5329
5330 ent->info.FRU_inventory_device = val;
5331 }
5332
5333 int
ipmi_entity_get_SEL_device(ipmi_entity_t * ent)5334 ipmi_entity_get_SEL_device(ipmi_entity_t *ent)
5335 {
5336 CHECK_ENTITY_LOCK(ent);
5337
5338 return ent->info.SEL_device;
5339 }
5340
5341 void
ipmi_entity_set_SEL_device(ipmi_entity_t * ent,int val)5342 ipmi_entity_set_SEL_device(ipmi_entity_t *ent,
5343 int val)
5344 {
5345 CHECK_ENTITY_LOCK(ent);
5346
5347 ent->info.SEL_device = val;
5348 }
5349
5350 int
ipmi_entity_get_SDR_repository_device(ipmi_entity_t * ent)5351 ipmi_entity_get_SDR_repository_device(ipmi_entity_t *ent)
5352 {
5353 CHECK_ENTITY_LOCK(ent);
5354
5355 return ent->info.SDR_repository_device;
5356 }
5357
5358 void
ipmi_entity_set_SDR_repository_device(ipmi_entity_t * ent,int val)5359 ipmi_entity_set_SDR_repository_device(ipmi_entity_t *ent,
5360 int val)
5361 {
5362 CHECK_ENTITY_LOCK(ent);
5363
5364 ent->info.SDR_repository_device = val;
5365 }
5366
5367 int
ipmi_entity_get_sensor_device(ipmi_entity_t * ent)5368 ipmi_entity_get_sensor_device(ipmi_entity_t *ent)
5369 {
5370 CHECK_ENTITY_LOCK(ent);
5371
5372 return ent->info.sensor_device;
5373 }
5374
5375 void
ipmi_entity_set_sensor_device(ipmi_entity_t * ent,int val)5376 ipmi_entity_set_sensor_device(ipmi_entity_t *ent,
5377 int val)
5378 {
5379 CHECK_ENTITY_LOCK(ent);
5380
5381 ent->info.sensor_device = val;
5382 }
5383
5384
5385 int
ipmi_entity_get_is_child(ipmi_entity_t * ent)5386 ipmi_entity_get_is_child(ipmi_entity_t *ent)
5387 {
5388 CHECK_ENTITY_LOCK(ent);
5389
5390 return locked_list_num_entries(ent->parent_entities) != 0;
5391 }
5392
5393 int
ipmi_entity_get_is_parent(ipmi_entity_t * ent)5394 ipmi_entity_get_is_parent(ipmi_entity_t *ent)
5395 {
5396 CHECK_ENTITY_LOCK(ent);
5397
5398 return locked_list_num_entries(ent->child_entities) != 0;
5399 }
5400
5401 int
ipmi_entity_is_present(ipmi_entity_t * ent)5402 ipmi_entity_is_present(ipmi_entity_t *ent)
5403 {
5404 CHECK_ENTITY_LOCK(ent);
5405
5406 return ent->present;
5407 }
5408
5409 static void
entity_id_is_present_cb(ipmi_entity_t * ent,void * cb_data)5410 entity_id_is_present_cb(ipmi_entity_t *ent, void *cb_data)
5411 {
5412 *((int *) cb_data) = ipmi_entity_is_present(ent);
5413 }
5414
5415 int
ipmi_entity_id_is_present(ipmi_entity_id_t id,int * present)5416 ipmi_entity_id_is_present(ipmi_entity_id_t id, int *present)
5417 {
5418 return ipmi_entity_pointer_cb(id, entity_id_is_present_cb, present);
5419 }
5420
5421 const char *
ipmi_entity_get_entity_id_string(ipmi_entity_t * ent)5422 ipmi_entity_get_entity_id_string(ipmi_entity_t *ent)
5423 {
5424 CHECK_ENTITY_LOCK(ent);
5425
5426 return ent->entity_id_string;
5427 }
5428
5429 void
ipmi_entity_set_entity_id_string(ipmi_entity_t * ent,char * str)5430 ipmi_entity_set_entity_id_string(ipmi_entity_t *ent, char *str)
5431 {
5432 CHECK_ENTITY_LOCK(ent);
5433
5434 ent->entity_id_string = str;
5435 }
5436
5437 /***********************************************************************
5438 *
5439 * Handle conversions between entity_ids and pointers.
5440 *
5441 **********************************************************************/
5442
5443 typedef struct iterate_entity_info_s
5444 {
5445 ipmi_entity_info_t *ents;
5446 ipmi_entities_iterate_entity_cb handler;
5447 void *cb_data;
5448 } iterate_entity_info_t;
5449
5450 static int
iterate_entity_handler(void * cb_data,void * item1,void * item2)5451 iterate_entity_handler(void *cb_data, void *item1, void *item2)
5452 {
5453 iterate_entity_info_t *info = cb_data;
5454 ipmi_entity_t *ent = item1;
5455
5456 info->handler(ent, info->cb_data);
5457 i_ipmi_entity_put(ent);
5458 return LOCKED_LIST_ITER_CONTINUE;
5459 }
5460
5461 void
ipmi_entities_iterate_entities(ipmi_entity_info_t * ents,ipmi_entities_iterate_entity_cb handler,void * cb_data)5462 ipmi_entities_iterate_entities(ipmi_entity_info_t *ents,
5463 ipmi_entities_iterate_entity_cb handler,
5464 void *cb_data)
5465 {
5466 iterate_entity_info_t info = { ents, handler, cb_data };
5467 locked_list_iterate_prefunc(ents->entities, iterate_entity_prefunc,
5468 iterate_entity_handler, &info);
5469 }
5470
5471 ipmi_entity_id_t
ipmi_entity_convert_to_id(ipmi_entity_t * ent)5472 ipmi_entity_convert_to_id(ipmi_entity_t *ent)
5473 {
5474 ipmi_entity_id_t val;
5475
5476 CHECK_ENTITY_LOCK(ent);
5477
5478 val.domain_id = ent->domain_id;
5479 val.entity_id = ent->key.entity_id;
5480 val.entity_instance = ent->key.entity_instance;
5481 val.channel = ent->key.device_num.channel;
5482 val.address = ent->key.device_num.address;
5483 val.seq = ent->seq;
5484
5485 return val;
5486 }
5487
5488 typedef struct mc_cb_info_s
5489 {
5490 ipmi_entity_ptr_cb handler;
5491 void *cb_data;
5492 ipmi_entity_id_t id;
5493 int err;
5494 int ignore_seq;
5495 } mc_cb_info_t;
5496
5497 static void
domain_cb(ipmi_domain_t * domain,void * cb_data)5498 domain_cb(ipmi_domain_t *domain, void *cb_data)
5499 {
5500 ipmi_device_num_t device_num;
5501 ipmi_entity_t *ent;
5502 mc_cb_info_t *info = cb_data;
5503
5504 device_num.channel = info->id.channel;
5505 device_num.address = info->id.address;
5506 i_ipmi_domain_entity_lock(domain);
5507 info->err = entity_find(ipmi_domain_get_entities(domain),
5508 device_num,
5509 info->id.entity_id,
5510 info->id.entity_instance,
5511 &ent);
5512 i_ipmi_domain_entity_unlock(domain);
5513
5514 if (!info->ignore_seq && !info->err) {
5515 if (ent->seq != info->id.seq) {
5516 info->err = EINVAL;
5517 i_ipmi_entity_put(ent);
5518 }
5519 }
5520 if (!info->err) {
5521 info->handler(ent, info->cb_data);
5522 i_ipmi_entity_put(ent);
5523 }
5524 }
5525
5526 int
ipmi_entity_pointer_cb(ipmi_entity_id_t id,ipmi_entity_ptr_cb handler,void * cb_data)5527 ipmi_entity_pointer_cb(ipmi_entity_id_t id,
5528 ipmi_entity_ptr_cb handler,
5529 void *cb_data)
5530 {
5531 int rv;
5532 mc_cb_info_t info;
5533
5534 info.handler = handler;
5535 info.cb_data = cb_data;
5536 info.id = id;
5537 info.err = 0;
5538 info.ignore_seq = 0;
5539
5540 rv = ipmi_domain_pointer_cb(id.domain_id, domain_cb, &info);
5541 if (!rv)
5542 rv = info.err;
5543
5544 return rv;
5545 }
5546
5547 static int
ipmi_entity_pointer_cb_noseq(ipmi_entity_id_t id,ipmi_entity_ptr_cb handler,void * cb_data)5548 ipmi_entity_pointer_cb_noseq(ipmi_entity_id_t id,
5549 ipmi_entity_ptr_cb handler,
5550 void *cb_data)
5551 {
5552 int rv;
5553 mc_cb_info_t info;
5554
5555 info.handler = handler;
5556 info.cb_data = cb_data;
5557 info.id = id;
5558 info.err = 0;
5559 info.ignore_seq = 1;
5560
5561 rv = ipmi_domain_pointer_cb(id.domain_id, domain_cb, &info);
5562 if (!rv)
5563 rv = info.err;
5564
5565 return rv;
5566 }
5567
5568 static void
get_seq(ipmi_entity_t * entity,void * cb_data)5569 get_seq(ipmi_entity_t *entity, void *cb_data)
5570 {
5571 ipmi_entity_id_t *id = cb_data;
5572
5573 *id = ipmi_entity_convert_to_id(entity);
5574 }
5575
5576 int
ipmi_entity_find_id(ipmi_domain_id_t domain_id,int entity_id,int entity_instance,int channel,int slave_address,ipmi_entity_id_t * id)5577 ipmi_entity_find_id(ipmi_domain_id_t domain_id,
5578 int entity_id, int entity_instance,
5579 int channel, int slave_address,
5580 ipmi_entity_id_t *id)
5581 {
5582 int rv;
5583
5584 id->domain_id = domain_id;
5585 id->entity_id = entity_id;
5586 id->entity_instance = entity_instance;
5587 id->channel = channel;
5588 id->address = slave_address;
5589
5590 rv = ipmi_entity_pointer_cb_noseq(*id, get_seq, id);
5591 return rv;
5592 }
5593
5594 int
ipmi_cmp_entity_id(ipmi_entity_id_t id1,ipmi_entity_id_t id2)5595 ipmi_cmp_entity_id(ipmi_entity_id_t id1, ipmi_entity_id_t id2)
5596 {
5597 int cmp;
5598
5599 cmp = ipmi_cmp_domain_id(id1.domain_id, id2.domain_id);
5600 if (cmp)
5601 return cmp;
5602
5603 if (id1.entity_id < id2.entity_id)
5604 return -1;
5605 if (id1.entity_id > id2.entity_id)
5606 return 1;
5607
5608 if (id1.entity_instance < id2.entity_instance)
5609 return -1;
5610 if (id1.entity_instance > id2.entity_instance)
5611 return 1;
5612
5613 if (id1.channel < id2.channel)
5614 return -1;
5615 if (id1.channel > id2.channel)
5616 return 1;
5617
5618 if (id1.address < id2.address)
5619 return -1;
5620 if (id1.address > id2.address)
5621 return 1;
5622
5623 if (id1.seq < id2.seq)
5624 return -1;
5625 if (id1.seq > id2.seq)
5626 return 1;
5627
5628 return 0;
5629 }
5630
5631 void
ipmi_entity_id_set_invalid(ipmi_entity_id_t * id)5632 ipmi_entity_id_set_invalid(ipmi_entity_id_t *id)
5633 {
5634 ipmi_domain_id_set_invalid(&id->domain_id);
5635 }
5636
5637 int
ipmi_entity_id_is_invalid(const ipmi_entity_id_t * id)5638 ipmi_entity_id_is_invalid(const ipmi_entity_id_t *id)
5639 {
5640 return (id->domain_id.domain == NULL);
5641 }
5642
5643
5644 #ifdef IPMI_CHECK_LOCKS
5645 void
i__ipmi_check_entity_lock(const ipmi_entity_t * entity)5646 i__ipmi_check_entity_lock(const ipmi_entity_t *entity)
5647 {
5648 if (!entity)
5649 return;
5650
5651 if (!DEBUG_LOCKS)
5652 return;
5653
5654 if (entity->usecount == 0)
5655 ipmi_report_lock_error(entity->os_hnd,
5656 "entity not locked when it should have been");
5657 }
5658 #endif
5659
5660 /***********************************************************************
5661 *
5662 * Entity FRU data handling.
5663 *
5664 **********************************************************************/
5665
5666 int
ipmi_entity_add_fru_update_handler(ipmi_entity_t * ent,ipmi_entity_fru_cb handler,void * cb_data)5667 ipmi_entity_add_fru_update_handler(ipmi_entity_t *ent,
5668 ipmi_entity_fru_cb handler,
5669 void *cb_data)
5670 {
5671 CHECK_ENTITY_LOCK(ent);
5672 if (locked_list_add(ent->fru_handlers, handler, cb_data))
5673 return 0;
5674 else
5675 return ENOMEM;
5676 }
5677
5678 int
ipmi_entity_remove_fru_update_handler(ipmi_entity_t * ent,ipmi_entity_fru_cb handler,void * cb_data)5679 ipmi_entity_remove_fru_update_handler(ipmi_entity_t *ent,
5680 ipmi_entity_fru_cb handler,
5681 void *cb_data)
5682 {
5683 CHECK_ENTITY_LOCK(ent);
5684 if (locked_list_remove(ent->fru_handlers, handler, cb_data))
5685 return 0;
5686 else
5687 return EINVAL;
5688 }
5689
5690 int
ipmi_entity_add_fru_update_handler_cl(ipmi_entity_t * ent,ipmi_entity_fru_cl_cb handler,void * cb_data)5691 ipmi_entity_add_fru_update_handler_cl(ipmi_entity_t *ent,
5692 ipmi_entity_fru_cl_cb handler,
5693 void *cb_data)
5694 {
5695 CHECK_ENTITY_LOCK(ent);
5696 if (locked_list_add(ent->fru_handlers_cl, handler, cb_data))
5697 return 0;
5698 else
5699 return ENOMEM;
5700 }
5701
5702 int
ipmi_entity_remove_fru_update_handler_cl(ipmi_entity_t * ent,ipmi_entity_fru_cl_cb handler,void * cb_data)5703 ipmi_entity_remove_fru_update_handler_cl(ipmi_entity_t *ent,
5704 ipmi_entity_fru_cl_cb handler,
5705 void *cb_data)
5706 {
5707 CHECK_ENTITY_LOCK(ent);
5708 if (locked_list_remove(ent->fru_handlers_cl, handler, cb_data))
5709 return 0;
5710 else
5711 return EINVAL;
5712 }
5713
5714 int
ipmi_entity_add_fru_update_werr_handler(ipmi_entity_t * ent,ipmi_entity_fru_werr_cb handler,void * cb_data)5715 ipmi_entity_add_fru_update_werr_handler(ipmi_entity_t *ent,
5716 ipmi_entity_fru_werr_cb handler,
5717 void *cb_data)
5718 {
5719 CHECK_ENTITY_LOCK(ent);
5720 if (locked_list_add(ent->fru_handlers_werr, handler, cb_data))
5721 return 0;
5722 else
5723 return ENOMEM;
5724 }
5725
5726 int
ipmi_entity_remove_fru_update_werr_handler(ipmi_entity_t * ent,ipmi_entity_fru_werr_cb handler,void * cb_data)5727 ipmi_entity_remove_fru_update_werr_handler(ipmi_entity_t *ent,
5728 ipmi_entity_fru_werr_cb handler,
5729 void *cb_data)
5730 {
5731 CHECK_ENTITY_LOCK(ent);
5732 if (locked_list_remove(ent->fru_handlers_werr, handler, cb_data))
5733 return 0;
5734 else
5735 return EINVAL;
5736 }
5737
5738 int
ipmi_entity_add_fru_update_werr_handler_cl(ipmi_entity_t * ent,ipmi_entity_fru_werr_cl_cb handler,void * cb_data)5739 ipmi_entity_add_fru_update_werr_handler_cl(ipmi_entity_t *ent,
5740 ipmi_entity_fru_werr_cl_cb handler,
5741 void *cb_data)
5742 {
5743 CHECK_ENTITY_LOCK(ent);
5744 if (locked_list_add(ent->fru_handlers_werr_cl, handler, cb_data))
5745 return 0;
5746 else
5747 return ENOMEM;
5748 }
5749
5750 int
ipmi_entity_remove_fru_update_werr_handler_cl(ipmi_entity_t * ent,ipmi_entity_fru_werr_cl_cb handler,void * cb_data)5751 ipmi_entity_remove_fru_update_werr_handler_cl(ipmi_entity_t *ent,
5752 ipmi_entity_fru_werr_cl_cb handler,
5753 void *cb_data)
5754 {
5755 CHECK_ENTITY_LOCK(ent);
5756 if (locked_list_remove(ent->fru_handlers_werr_cl, handler, cb_data))
5757 return 0;
5758 else
5759 return EINVAL;
5760 }
5761
5762 typedef struct fru_handler_s
5763 {
5764 enum ipmi_update_werr_e op;
5765 int err;
5766 ipmi_entity_t *entity;
5767 } fru_handler_t;
5768
5769 static int
call_fru_handler(void * cb_data,void * item1,void * item2)5770 call_fru_handler(void *cb_data, void *item1, void *item2)
5771 {
5772 fru_handler_t *info = cb_data;
5773 ipmi_entity_fru_cb handler = item1;
5774
5775 handler(info->op, info->entity, item2);
5776 return LOCKED_LIST_ITER_CONTINUE;
5777 }
5778
5779 static int
call_fru_handler_werr(void * cb_data,void * item1,void * item2)5780 call_fru_handler_werr(void *cb_data, void *item1, void *item2)
5781 {
5782 fru_handler_t *info = cb_data;
5783 ipmi_entity_fru_werr_cb handler = item1;
5784
5785 handler(info->op, info->err, info->entity, item2);
5786 return LOCKED_LIST_ITER_CONTINUE;
5787 }
5788
5789 void
i_ipmi_entity_call_fru_handlers(ipmi_entity_t * ent,enum ipmi_update_werr_e op,int err)5790 i_ipmi_entity_call_fru_handlers(ipmi_entity_t *ent, enum ipmi_update_werr_e op,
5791 int err)
5792 {
5793 fru_handler_t info;
5794
5795 info.op = op;
5796 info.err = err;
5797 info.entity = ent;
5798 locked_list_iterate(ent->fru_handlers_werr, call_fru_handler_werr, &info);
5799 if (op == IPMIE_ERROR) /* Old handler doesn't handle error value. */
5800 info.op = IPMI_CHANGED;
5801 locked_list_iterate(ent->fru_handlers, call_fru_handler, &info);
5802 }
5803
5804 typedef struct fru_ent_info_s
5805 {
5806 ipmi_entity_id_t ent_id;
5807 ipmi_entity_ptr_cb done;
5808 void *cb_data;
5809 ipmi_fru_t *fru;
5810 int err;
5811 } fru_ent_info_t;
5812
5813 static void
fru_fetched_ent_cb(ipmi_entity_t * ent,void * cb_data)5814 fru_fetched_ent_cb(ipmi_entity_t *ent, void *cb_data)
5815 {
5816 fru_ent_info_t *info = cb_data;
5817
5818 if (!info->err) {
5819 enum ipmi_update_werr_e op;
5820 ipmi_fru_t *ofru = ent->fru;
5821
5822 ent->fru = info->fru;
5823 if (ofru) {
5824 op = IPMIE_CHANGED;
5825 ipmi_fru_destroy_internal(ofru, NULL, NULL);
5826 } else {
5827 op = IPMIE_ADDED;
5828 }
5829
5830 i_ipmi_entity_call_fru_handlers(ent, op, 0);
5831 } else {
5832 ipmi_log(IPMI_LOG_WARNING,
5833 "%sentity.c(fru_fetched_ent_cb):"
5834 "Error fetching entity %d.%d FRU: %x",
5835 ENTITY_NAME(ent),
5836 ent->key.entity_id, ent->key.entity_instance, info->err);
5837 if ((ent->fru) && (info->fru))
5838 /* Keep the old FRU on errors. */
5839 ipmi_fru_destroy_internal(info->fru, NULL, NULL);
5840 else
5841 /* Keep it if we got it, it might have some useful
5842 information. */
5843 ent->fru = info->fru;
5844 i_ipmi_entity_call_fru_handlers(ent, IPMIE_ERROR, info->err);
5845 }
5846
5847 if (info->done)
5848 info->done(ent, info->cb_data);
5849 }
5850
5851 static void
fru_fetched_handler(ipmi_domain_t * domain,ipmi_fru_t * fru,int err,void * cb_data)5852 fru_fetched_handler(ipmi_domain_t *domain, ipmi_fru_t *fru,
5853 int err, void *cb_data)
5854 {
5855 fru_ent_info_t *info = cb_data;
5856 int rv;
5857
5858 info->fru = fru;
5859 info->err = err;
5860
5861 rv = ipmi_entity_pointer_cb(info->ent_id, fru_fetched_ent_cb, info);
5862 if (rv) {
5863 /* If we can't put the fru someplace, just destroy it. */
5864 ipmi_fru_destroy_internal(fru, NULL, NULL);
5865 if (info->done)
5866 info->done(NULL, info->cb_data);
5867 }
5868
5869 ipmi_mem_free(info);
5870 if (domain)
5871 i_ipmi_put_domain_fully_up(domain, "fru_fetched_handler");
5872 }
5873
5874 int
ipmi_entity_fetch_frus_cb(ipmi_entity_t * ent,ipmi_entity_ptr_cb done,void * cb_data)5875 ipmi_entity_fetch_frus_cb(ipmi_entity_t *ent,
5876 ipmi_entity_ptr_cb done,
5877 void *cb_data)
5878 {
5879 fru_ent_info_t *info;
5880 int rv;
5881
5882 if (! ipmi_option_FRUs(ent->domain))
5883 return ENOSYS;
5884
5885 info = ipmi_mem_alloc(sizeof(*info));
5886 if (!info)
5887 return ENOMEM;
5888
5889 info->ent_id = ipmi_entity_convert_to_id(ent);
5890 info->done = done;
5891 info->cb_data = cb_data;
5892
5893 /* fetch the FRU information. */
5894 i_ipmi_get_domain_fully_up(ent->domain, "ipmi_entity_fetch_frus_cb");
5895 rv = ipmi_fru_alloc_notrack(ent->domain,
5896 ent->info.is_logical_fru,
5897 ent->info.access_address,
5898 ent->info.fru_device_id,
5899 ent->info.lun,
5900 ent->info.private_bus_id,
5901 ent->info.channel,
5902 IPMI_FRU_ALL_AREA_MASK,
5903 fru_fetched_handler,
5904 info,
5905 NULL);
5906 if (rv) {
5907 ipmi_mem_free(info);
5908 ipmi_log(IPMI_LOG_WARNING,
5909 "%sentity.c(ipmi_entity_fetch_frus_cb):"
5910 " Unable to allocate the FRU: %x",
5911 ENTITY_NAME(ent), rv);
5912 i_ipmi_put_domain_fully_up(ent->domain, "ipmi_entity_fetch_frus_cb");
5913 }
5914
5915 return rv;
5916 }
5917
5918 int
ipmi_entity_fetch_frus(ipmi_entity_t * ent)5919 ipmi_entity_fetch_frus(ipmi_entity_t *ent)
5920 {
5921 return ipmi_entity_fetch_frus_cb(ent, NULL, NULL);
5922 }
5923
5924 ipmi_fru_t *
ipmi_entity_get_fru(ipmi_entity_t * ent)5925 ipmi_entity_get_fru(ipmi_entity_t *ent)
5926 {
5927 CHECK_ENTITY_LOCK(ent);
5928
5929 return ent->fru;
5930 }
5931
5932 void
i_ipmi_entity_set_fru(ipmi_entity_t * ent,ipmi_fru_t * fru)5933 i_ipmi_entity_set_fru(ipmi_entity_t *ent, ipmi_fru_t *fru)
5934 {
5935 CHECK_ENTITY_LOCK(ent);
5936
5937 if (ent->fru)
5938 ipmi_fru_destroy_internal(ent->fru, NULL, NULL);
5939 ent->fru = fru;
5940 }
5941
5942 /***************************************************************************
5943 *
5944 * Hot swap
5945 *
5946 ***************************************************************************/
5947
5948 int
ipmi_entity_set_hot_swappable(ipmi_entity_t * ent,int val)5949 ipmi_entity_set_hot_swappable(ipmi_entity_t *ent, int val)
5950 {
5951 ent->hot_swappable = val;
5952
5953 /* Make sure the user knows of the change. */
5954 ent->changed = 1;
5955
5956 return 0;
5957 }
5958
5959 int
ipmi_entity_hot_swappable(ipmi_entity_t * ent)5960 ipmi_entity_hot_swappable(ipmi_entity_t *ent)
5961 {
5962 return ent->hot_swappable;
5963 }
5964
5965 int
ipmi_entity_set_supports_managed_hot_swap(ipmi_entity_t * ent,int val)5966 ipmi_entity_set_supports_managed_hot_swap(ipmi_entity_t *ent, int val)
5967 {
5968 ent->supports_managed_hot_swap = val;
5969
5970 /* Make sure the user knows of the change. */
5971 ent->changed = 1;
5972
5973 return 0;
5974 }
5975
5976 int
ipmi_entity_supports_managed_hot_swap(ipmi_entity_t * ent)5977 ipmi_entity_supports_managed_hot_swap(ipmi_entity_t *ent)
5978 {
5979 return ent->supports_managed_hot_swap;
5980 }
5981
5982 int
ipmi_entity_add_hot_swap_handler(ipmi_entity_t * ent,ipmi_entity_hot_swap_cb handler,void * cb_data)5983 ipmi_entity_add_hot_swap_handler(ipmi_entity_t *ent,
5984 ipmi_entity_hot_swap_cb handler,
5985 void *cb_data)
5986 {
5987 CHECK_ENTITY_LOCK(ent);
5988 if (locked_list_add(ent->hot_swap_handlers, handler, cb_data))
5989 return 0;
5990 else
5991 return ENOMEM;
5992 }
5993
5994 int
ipmi_entity_remove_hot_swap_handler(ipmi_entity_t * ent,ipmi_entity_hot_swap_cb handler,void * cb_data)5995 ipmi_entity_remove_hot_swap_handler(ipmi_entity_t *ent,
5996 ipmi_entity_hot_swap_cb handler,
5997 void *cb_data)
5998 {
5999 CHECK_ENTITY_LOCK(ent);
6000 if (locked_list_remove(ent->hot_swap_handlers, handler, cb_data))
6001 return 0;
6002 else
6003 return EINVAL;
6004 }
6005
6006 int
ipmi_entity_add_hot_swap_handler_cl(ipmi_entity_t * ent,ipmi_entity_hot_swap_cl_cb handler,void * cb_data)6007 ipmi_entity_add_hot_swap_handler_cl(ipmi_entity_t *ent,
6008 ipmi_entity_hot_swap_cl_cb handler,
6009 void *cb_data)
6010 {
6011 CHECK_ENTITY_LOCK(ent);
6012 if (locked_list_add(ent->hot_swap_handlers_cl, handler, cb_data))
6013 return 0;
6014 else
6015 return ENOMEM;
6016 }
6017
6018 int
ipmi_entity_remove_hot_swap_handler_cl(ipmi_entity_t * ent,ipmi_entity_hot_swap_cl_cb handler,void * cb_data)6019 ipmi_entity_remove_hot_swap_handler_cl(ipmi_entity_t *ent,
6020 ipmi_entity_hot_swap_cl_cb handler,
6021 void *cb_data)
6022 {
6023 CHECK_ENTITY_LOCK(ent);
6024 if (locked_list_remove(ent->hot_swap_handlers_cl, handler, cb_data))
6025 return 0;
6026 else
6027 return EINVAL;
6028 }
6029
6030 void
ipmi_entity_set_hot_swap_control(ipmi_entity_t * ent,ipmi_entity_hot_swap_t * cbs)6031 ipmi_entity_set_hot_swap_control(ipmi_entity_t *ent,
6032 ipmi_entity_hot_swap_t *cbs)
6033 {
6034 CHECK_ENTITY_LOCK(ent);
6035
6036 ent->hs_cb = *cbs;
6037 }
6038
6039
6040
6041 typedef struct hot_swap_handler_info_s
6042 {
6043 ipmi_entity_t *ent;
6044 enum ipmi_hot_swap_states last_state;
6045 enum ipmi_hot_swap_states curr_state;
6046 ipmi_event_t **event;
6047 int handled;
6048 } hot_swap_handler_info_t;
6049
6050 static int
call_hot_swap_handler(void * cb_data,void * item1,void * item2)6051 call_hot_swap_handler(void *cb_data, void *item1, void *item2)
6052 {
6053 hot_swap_handler_info_t *info = cb_data;
6054 ipmi_entity_hot_swap_cb handler = item1;
6055 int handled;
6056
6057 handled = handler(info->ent, info->last_state, info->curr_state,
6058 item2, *(info->event));
6059 if (handled != IPMI_EVENT_NOT_HANDLED) {
6060 if (info->handled != IPMI_EVENT_HANDLED)
6061 /* Allow handled to override handled_pass, but not the
6062 other way. */
6063 info->handled = handled;
6064 if (handled == IPMI_EVENT_HANDLED)
6065 *(info->event) = NULL;
6066 }
6067 return LOCKED_LIST_ITER_CONTINUE;
6068 }
6069
6070 void
ipmi_entity_call_hot_swap_handlers(ipmi_entity_t * ent,enum ipmi_hot_swap_states last_state,enum ipmi_hot_swap_states curr_state,ipmi_event_t ** event,int * handled)6071 ipmi_entity_call_hot_swap_handlers(ipmi_entity_t *ent,
6072 enum ipmi_hot_swap_states last_state,
6073 enum ipmi_hot_swap_states curr_state,
6074 ipmi_event_t **event,
6075 int *handled)
6076 {
6077 hot_swap_handler_info_t info;
6078
6079 info.ent = ent;
6080 info.last_state = last_state;
6081 info.curr_state = curr_state;
6082 info.event = event;
6083 if (handled)
6084 info.handled = *handled;
6085 else
6086 info.handled = IPMI_EVENT_NOT_HANDLED;
6087 locked_list_iterate(ent->hot_swap_handlers, call_hot_swap_handler, &info);
6088 if (handled)
6089 *handled = info.handled;
6090 }
6091
6092 int
ipmi_entity_get_hot_swap_state(ipmi_entity_t * ent,ipmi_entity_hot_swap_state_cb handler,void * cb_data)6093 ipmi_entity_get_hot_swap_state(ipmi_entity_t *ent,
6094 ipmi_entity_hot_swap_state_cb handler,
6095 void *cb_data)
6096 {
6097 if (!ent->hot_swappable)
6098 return ENOSYS;
6099 if (!ent->hs_cb.get_hot_swap_state)
6100 return ENOSYS;
6101 return ent->hs_cb.get_hot_swap_state(ent, handler, cb_data);
6102 }
6103
6104 int
ipmi_entity_supports_auto_activate_time(ipmi_entity_t * ent)6105 ipmi_entity_supports_auto_activate_time(ipmi_entity_t *ent)
6106 {
6107 return (ent->hot_swappable && ent->hs_cb.get_auto_activate);
6108 }
6109
6110 int
ipmi_entity_set_auto_activate_time(ipmi_entity_t * ent,ipmi_timeout_t auto_act,ipmi_entity_cb done,void * cb_data)6111 ipmi_entity_set_auto_activate_time(ipmi_entity_t *ent,
6112 ipmi_timeout_t auto_act,
6113 ipmi_entity_cb done,
6114 void *cb_data)
6115 {
6116 if (!ent->hot_swappable)
6117 return ENOSYS;
6118 if (!ent->hs_cb.set_auto_activate)
6119 return ENOSYS;
6120 return ent->hs_cb.set_auto_activate(ent, auto_act, done, cb_data);
6121 }
6122
6123 int
ipmi_entity_get_auto_activate_time(ipmi_entity_t * ent,ipmi_entity_time_cb handler,void * cb_data)6124 ipmi_entity_get_auto_activate_time(ipmi_entity_t *ent,
6125 ipmi_entity_time_cb handler,
6126 void *cb_data)
6127 {
6128 if (!ent->hot_swappable)
6129 return ENOSYS;
6130 if (!ent->hs_cb.get_auto_activate)
6131 return ENOSYS;
6132 return ent->hs_cb.get_auto_activate(ent, handler, cb_data);
6133 }
6134
6135 int
ipmi_entity_supports_auto_deactivate_time(ipmi_entity_t * ent)6136 ipmi_entity_supports_auto_deactivate_time(ipmi_entity_t *ent)
6137 {
6138 return (ent->hot_swappable && ent->hs_cb.get_auto_activate);
6139 }
6140
6141 int
ipmi_entity_set_auto_deactivate_time(ipmi_entity_t * ent,ipmi_timeout_t auto_deact,ipmi_entity_cb done,void * cb_data)6142 ipmi_entity_set_auto_deactivate_time(ipmi_entity_t *ent,
6143 ipmi_timeout_t auto_deact,
6144 ipmi_entity_cb done,
6145 void *cb_data)
6146 {
6147 if (!ent->hot_swappable)
6148 return ENOSYS;
6149 if (!ent->hs_cb.set_auto_deactivate)
6150 return ENOSYS;
6151 return ent->hs_cb.set_auto_deactivate(ent, auto_deact, done, cb_data);
6152 }
6153
6154 int
ipmi_entity_get_auto_deactivate_time(ipmi_entity_t * ent,ipmi_entity_time_cb handler,void * cb_data)6155 ipmi_entity_get_auto_deactivate_time(ipmi_entity_t *ent,
6156 ipmi_entity_time_cb handler,
6157 void *cb_data)
6158 {
6159 if (!ent->hot_swappable)
6160 return ENOSYS;
6161 if (!ent->hs_cb.get_auto_deactivate)
6162 return ENOSYS;
6163 return ent->hs_cb.get_auto_deactivate(ent, handler, cb_data);
6164 }
6165
6166 int
ipmi_entity_set_activation_requested(ipmi_entity_t * ent,ipmi_entity_cb done,void * cb_data)6167 ipmi_entity_set_activation_requested(ipmi_entity_t *ent,
6168 ipmi_entity_cb done,
6169 void *cb_data)
6170 {
6171 if (!ent->hot_swappable)
6172 return ENOSYS;
6173 if (!ent->hs_cb.activate)
6174 return ENOSYS;
6175 return ent->hs_cb.set_activation_requested(ent, done, cb_data);
6176 }
6177
6178 int
ipmi_entity_activate(ipmi_entity_t * ent,ipmi_entity_cb done,void * cb_data)6179 ipmi_entity_activate(ipmi_entity_t *ent,
6180 ipmi_entity_cb done,
6181 void *cb_data)
6182 {
6183 if (!ent->hot_swappable)
6184 return ENOSYS;
6185 if (!ent->hs_cb.activate)
6186 return ENOSYS;
6187 return ent->hs_cb.activate(ent, done, cb_data);
6188 }
6189
6190 int
ipmi_entity_deactivate(ipmi_entity_t * ent,ipmi_entity_cb done,void * cb_data)6191 ipmi_entity_deactivate(ipmi_entity_t *ent,
6192 ipmi_entity_cb done,
6193 void *cb_data)
6194 {
6195 if (!ent->hot_swappable)
6196 return ENOSYS;
6197 if (!ent->hs_cb.deactivate)
6198 return ENOSYS;
6199 return ent->hs_cb.deactivate(ent, done, cb_data);
6200 }
6201
6202 int
ipmi_entity_check_hot_swap_state(ipmi_entity_t * ent)6203 ipmi_entity_check_hot_swap_state(ipmi_entity_t *ent)
6204 {
6205 if (!ent->hot_swappable)
6206 return ENOSYS;
6207 if (!ent->hs_cb.check_hot_swap_state)
6208 return ENOSYS;
6209 return ent->hs_cb.check_hot_swap_state(ent);
6210 }
6211
6212 /***********************************************************************
6213 *
6214 * Entity ID versions of the hot-swap calls.
6215 *
6216 **********************************************************************/
6217
6218 typedef struct entity_hot_swap_cb_info_s
6219 {
6220 int rv;
6221 ipmi_entity_hot_swap_state_cb handler;
6222 void *cb_data;
6223 } entity_hot_swap_cb_info_t;
6224
6225 typedef struct entity_cb_info_s
6226 {
6227 int rv;
6228 ipmi_timeout_t time;
6229 int val;
6230 ipmi_entity_cb handler;
6231 void *cb_data;
6232 } entity_cb_info_t;
6233
6234 typedef struct entity_val_cb_info_s
6235 {
6236 int rv;
6237 ipmi_entity_val_cb handler;
6238 void *cb_data;
6239 } entity_val_cb_info_t;
6240
6241 typedef struct entity_time_cb_info_s
6242 {
6243 int rv;
6244 ipmi_entity_time_cb handler;
6245 void *cb_data;
6246 } entity_time_cb_info_t;
6247
6248 static void
entity_id_get_hot_swap_state_cb(ipmi_entity_t * entity,void * cb_data)6249 entity_id_get_hot_swap_state_cb(ipmi_entity_t *entity, void *cb_data)
6250 {
6251 entity_hot_swap_cb_info_t *info = cb_data;
6252
6253 info->rv = ipmi_entity_get_hot_swap_state(entity, info->handler,
6254 info->cb_data);
6255 }
6256
6257 int
ipmi_entity_id_get_hot_swap_state(ipmi_entity_id_t id,ipmi_entity_hot_swap_state_cb handler,void * cb_data)6258 ipmi_entity_id_get_hot_swap_state(ipmi_entity_id_t id,
6259 ipmi_entity_hot_swap_state_cb handler,
6260 void *cb_data)
6261 {
6262 int rv;
6263 entity_hot_swap_cb_info_t info;
6264
6265 info.rv = 0;
6266 info.handler = handler;
6267 info.cb_data = cb_data;
6268
6269 rv = ipmi_entity_pointer_cb(id, entity_id_get_hot_swap_state_cb, &info);
6270 if (!rv)
6271 rv = info.rv;
6272 return rv;
6273 }
6274
6275 static void
entity_get_auto_activate_time_cb(ipmi_entity_t * ent,void * cb_data)6276 entity_get_auto_activate_time_cb(ipmi_entity_t *ent, void *cb_data)
6277 {
6278 entity_time_cb_info_t *info = cb_data;
6279
6280 info->rv = ipmi_entity_get_auto_activate_time(ent, info->handler,
6281 info->cb_data);
6282 }
6283
6284 int
ipmi_entity_id_get_auto_activate_time(ipmi_entity_id_t id,ipmi_entity_time_cb handler,void * cb_data)6285 ipmi_entity_id_get_auto_activate_time(ipmi_entity_id_t id,
6286 ipmi_entity_time_cb handler,
6287 void *cb_data)
6288 {
6289 entity_time_cb_info_t info;
6290 int rv;
6291
6292 info.rv = 0;
6293 info.handler = handler;
6294 info.cb_data = cb_data;
6295 rv = ipmi_entity_pointer_cb(id, entity_get_auto_activate_time_cb, &info);
6296 if (!rv)
6297 rv = info.rv;
6298 return rv;
6299 }
6300
6301 static void
entity_set_auto_activate_time_cb(ipmi_entity_t * ent,void * cb_data)6302 entity_set_auto_activate_time_cb(ipmi_entity_t *ent, void *cb_data)
6303 {
6304 entity_cb_info_t *info = cb_data;
6305
6306 info->rv = ipmi_entity_set_auto_activate_time(ent, info->time,
6307 info->handler,
6308 info->cb_data);
6309 }
6310
6311 int
ipmi_entity_id_set_auto_activate_time(ipmi_entity_id_t id,ipmi_timeout_t auto_act,ipmi_entity_cb done,void * cb_data)6312 ipmi_entity_id_set_auto_activate_time(ipmi_entity_id_t id,
6313 ipmi_timeout_t auto_act,
6314 ipmi_entity_cb done,
6315 void *cb_data)
6316 {
6317 entity_cb_info_t info;
6318 int rv;
6319
6320 info.rv = 0;
6321 info.time = auto_act;
6322 info.handler = done;
6323 info.cb_data = cb_data;
6324 rv = ipmi_entity_pointer_cb(id, entity_set_auto_activate_time_cb, &info);
6325 if (!rv)
6326 rv = info.rv;
6327 return rv;
6328 }
6329
6330 static void
entity_get_auto_deactivate_time_cb(ipmi_entity_t * ent,void * cb_data)6331 entity_get_auto_deactivate_time_cb(ipmi_entity_t *ent, void *cb_data)
6332 {
6333 entity_time_cb_info_t *info = cb_data;
6334
6335 info->rv = ipmi_entity_get_auto_deactivate_time(ent, info->handler,
6336 info->cb_data);
6337 }
6338
6339 int
ipmi_entity_id_get_auto_deactivate_time(ipmi_entity_id_t id,ipmi_entity_time_cb handler,void * cb_data)6340 ipmi_entity_id_get_auto_deactivate_time(ipmi_entity_id_t id,
6341 ipmi_entity_time_cb handler,
6342 void *cb_data)
6343 {
6344 entity_time_cb_info_t info;
6345 int rv;
6346
6347 info.rv = 0;
6348 info.handler = handler;
6349 info.cb_data = cb_data;
6350 rv = ipmi_entity_pointer_cb(id, entity_get_auto_deactivate_time_cb, &info);
6351 if (!rv)
6352 rv = info.rv;
6353 return rv;
6354 }
6355
6356 static void
entity_set_auto_deactivate_time_cb(ipmi_entity_t * ent,void * cb_data)6357 entity_set_auto_deactivate_time_cb(ipmi_entity_t *ent, void *cb_data)
6358 {
6359 entity_cb_info_t *info = cb_data;
6360
6361 info->rv = ipmi_entity_set_auto_deactivate_time(ent, info->time,
6362 info->handler,
6363 info->cb_data);
6364 }
6365
6366 int
ipmi_entity_id_set_auto_deactivate_time(ipmi_entity_id_t id,ipmi_timeout_t auto_deact,ipmi_entity_cb done,void * cb_data)6367 ipmi_entity_id_set_auto_deactivate_time(ipmi_entity_id_t id,
6368 ipmi_timeout_t auto_deact,
6369 ipmi_entity_cb done,
6370 void *cb_data)
6371 {
6372 entity_cb_info_t info;
6373 int rv;
6374
6375 info.rv = 0;
6376 info.time = auto_deact;
6377 info.handler = done;
6378 info.cb_data = cb_data;
6379 rv = ipmi_entity_pointer_cb(id, entity_set_auto_deactivate_time_cb, &info);
6380 if (!rv)
6381 rv = info.rv;
6382 return rv;
6383 }
6384
6385 static void
entity_activate_cb(ipmi_entity_t * ent,void * cb_data)6386 entity_activate_cb(ipmi_entity_t *ent, void *cb_data)
6387 {
6388 entity_cb_info_t *info = cb_data;
6389
6390 info->rv = ipmi_entity_activate(ent, info->handler,
6391 info->cb_data);
6392 }
6393
6394 int
ipmi_entity_id_activate(ipmi_entity_id_t id,ipmi_entity_cb done,void * cb_data)6395 ipmi_entity_id_activate(ipmi_entity_id_t id,
6396 ipmi_entity_cb done,
6397 void *cb_data)
6398 {
6399 entity_cb_info_t info;
6400 int rv;
6401
6402 info.rv = 0;
6403 info.handler = done;
6404 info.cb_data = cb_data;
6405 rv = ipmi_entity_pointer_cb(id, entity_activate_cb, &info);
6406 if (!rv)
6407 rv = info.rv;
6408 return rv;
6409 }
6410
6411 static void
entity_deactivate_cb(ipmi_entity_t * ent,void * cb_data)6412 entity_deactivate_cb(ipmi_entity_t *ent, void *cb_data)
6413 {
6414 entity_cb_info_t *info = cb_data;
6415
6416 info->rv = ipmi_entity_deactivate(ent, info->handler,
6417 info->cb_data);
6418 }
6419
6420 int
ipmi_entity_id_deactivate(ipmi_entity_id_t id,ipmi_entity_cb done,void * cb_data)6421 ipmi_entity_id_deactivate(ipmi_entity_id_t id,
6422 ipmi_entity_cb done,
6423 void *cb_data)
6424 {
6425 entity_cb_info_t info;
6426 int rv;
6427
6428 info.rv = 0;
6429 info.handler = done;
6430 info.cb_data = cb_data;
6431 rv = ipmi_entity_pointer_cb(id, entity_deactivate_cb, &info);
6432 if (!rv)
6433 rv = info.rv;
6434 return rv;
6435 }
6436
6437 static void
entity_check_hot_swap_state_cb(ipmi_entity_t * ent,void * cb_data)6438 entity_check_hot_swap_state_cb(ipmi_entity_t *ent, void *cb_data)
6439 {
6440 entity_val_cb_info_t *info = cb_data;
6441
6442 info->rv = ipmi_entity_check_hot_swap_state(ent);
6443 }
6444
6445 int
ipmi_entity_id_check_hot_swap_state(ipmi_entity_id_t id)6446 ipmi_entity_id_check_hot_swap_state(ipmi_entity_id_t id)
6447 {
6448 entity_val_cb_info_t info;
6449 int rv;
6450
6451 info.rv = 0;
6452 rv = ipmi_entity_pointer_cb(id, entity_check_hot_swap_state_cb, &info);
6453 if (!rv)
6454 rv = info.rv;
6455 return rv;
6456 }
6457
6458
6459 /***********************************************************************
6460 *
6461 * The internal hot-swap state machine.
6462 *
6463 **********************************************************************/
6464
6465 static int set_hot_swap_state(ipmi_entity_t *ent,
6466 enum ipmi_hot_swap_states state,
6467 ipmi_event_t *event);
6468
6469 static void
hot_swap_power_on(ipmi_control_t * control,int err,void * cb_data)6470 hot_swap_power_on(ipmi_control_t *control, int err, void *cb_data)
6471 {
6472 ipmi_entity_t *ent = cb_data;
6473
6474 if (err) {
6475 ipmi_log(IPMI_LOG_WARNING,
6476 "%sentity.c(hot_swap_power_on):"
6477 " Unable to set the hot swap power: %x",
6478 CONTROL_NAME(control), err);
6479 } else {
6480 ent_lock(ent);
6481 set_hot_swap_state(ent, IPMI_HOT_SWAP_ACTIVE, NULL);
6482 ent_unlock(ent);
6483 }
6484 }
6485
6486 static void
hot_swap_power_off(ipmi_control_t * control,int err,void * cb_data)6487 hot_swap_power_off(ipmi_control_t *control, int err, void *cb_data)
6488 {
6489 ipmi_entity_t *ent = cb_data;
6490
6491 if (err) {
6492 ipmi_log(IPMI_LOG_WARNING,
6493 "%sentity.c(hot_swap_power_off):"
6494 " Unable to set the hot swap power: %x",
6495 CONTROL_NAME(control), err);
6496 } else {
6497 ent_lock(ent);
6498 set_hot_swap_state(ent, IPMI_HOT_SWAP_INACTIVE, NULL);
6499 ent_unlock(ent);
6500 }
6501 }
6502
6503 typedef struct power_cb_info_s
6504 {
6505 ipmi_entity_t *ent;
6506 ipmi_entity_cb handler;
6507 void *cb_data;
6508 } power_cb_info_t;
6509
6510 static void
hot_swap_power_on_cb(ipmi_control_t * control,int err,void * cb_data)6511 hot_swap_power_on_cb(ipmi_control_t *control, int err, void *cb_data)
6512 {
6513 power_cb_info_t *info = cb_data;
6514 ipmi_entity_t *ent = info->ent;
6515
6516 if (err) {
6517 ipmi_log(IPMI_LOG_WARNING,
6518 "%sentity.c(hot_swap_power_on_cb):"
6519 " Unable to set the hot swap power: %x",
6520 CONTROL_NAME(control), err);
6521 } else {
6522 ent_lock(ent);
6523 set_hot_swap_state(ent, IPMI_HOT_SWAP_ACTIVE, NULL);
6524 ent_unlock(ent);
6525 }
6526
6527 if (info->handler)
6528 info->handler(info->ent, err, info->cb_data);
6529 ipmi_mem_free(info);
6530 }
6531
6532 static void
hot_swap_power_off_cb(ipmi_control_t * control,int err,void * cb_data)6533 hot_swap_power_off_cb(ipmi_control_t *control, int err, void *cb_data)
6534 {
6535 power_cb_info_t *info = cb_data;
6536 ipmi_entity_t *ent = info->ent;
6537
6538 if (err) {
6539 ipmi_log(IPMI_LOG_WARNING,
6540 "%sentity.c(hot_swap_power_off_cb):"
6541 " Unable to set the hot swap power: %x",
6542 CONTROL_NAME(control), err);
6543 } else {
6544 ent_lock(ent);
6545 set_hot_swap_state(ent, IPMI_HOT_SWAP_INACTIVE, NULL);
6546 ent_unlock(ent);
6547 }
6548
6549 if (info->handler)
6550 info->handler(info->ent, err, info->cb_data);
6551 ipmi_mem_free(info);
6552 }
6553
6554 static void
indicator_change(ipmi_control_t * control,int err,void * cb_data)6555 indicator_change(ipmi_control_t *control, int err, void *cb_data)
6556 {
6557 if (err)
6558 ipmi_log(IPMI_LOG_WARNING,
6559 "%sentity.c(indicator_change):"
6560 " Unable to set the hot swap indicator: %x",
6561 CONTROL_NAME(control), err);
6562 }
6563
6564 static int
hot_swap_act(ipmi_entity_t * ent,ipmi_entity_cb handler,void * cb_data)6565 hot_swap_act(ipmi_entity_t *ent, ipmi_entity_cb handler, void *cb_data)
6566 {
6567 int val;
6568 int rv = ENOSYS;
6569 ipmi_control_op_cb cb;
6570 power_cb_info_t *info = NULL;
6571
6572 ent_lock(ent);
6573 if (ent->hot_swap_state == IPMI_HOT_SWAP_ACTIVATION_REQUESTED) {
6574 if (ent->hot_swap_power) {
6575 if (handler == NULL) {
6576 cb = hot_swap_power_on;
6577 cb_data = ent;
6578 } else {
6579 info = ipmi_mem_alloc(sizeof(*info));
6580 if (!info) {
6581 rv = ENOMEM;
6582 goto out;
6583 }
6584 cb = hot_swap_power_on_cb;
6585 info->ent = ent;
6586 info->handler = handler;
6587 info->cb_data = cb_data;
6588 cb_data = info;
6589 }
6590
6591 val = 1;
6592 ent_unlock(ent);
6593 rv = ipmi_control_id_set_val(ent->hot_swap_power_id,
6594 &val,
6595 cb,
6596 cb_data);
6597 ent_lock(ent);
6598 if (!rv)
6599 set_hot_swap_state(ent, IPMI_HOT_SWAP_ACTIVATION_IN_PROGRESS,
6600 NULL);
6601 else if (info)
6602 ipmi_mem_free(info);
6603 }
6604 } else {
6605 rv = EAGAIN;
6606 }
6607 out:
6608 ent_unlock(ent);
6609
6610 return rv;
6611 }
6612
6613 static void
hot_swap_act_cb(ipmi_entity_t * ent,void * cb_data)6614 hot_swap_act_cb(ipmi_entity_t *ent, void *cb_data)
6615 {
6616 int rv;
6617
6618 rv = hot_swap_act(ent, NULL, NULL);
6619 if (rv && (rv != EAGAIN))
6620 ipmi_log(IPMI_LOG_WARNING,
6621 "%sentity.c(hot_swap_act_cb):"
6622 " Unable to set the hot swap power: %x",
6623 ENTITY_NAME(ent), rv);
6624 }
6625
6626 static void
hot_swap_act_timeout(void * cb_data,os_hnd_timer_id_t * timer)6627 hot_swap_act_timeout(void *cb_data, os_hnd_timer_id_t *timer)
6628 {
6629 ent_timer_info_t *info = cb_data;
6630 ipmi_entity_id_t entity_id;
6631
6632 ipmi_lock(info->lock);
6633 if (info->destroyed) {
6634 ipmi_unlock(info->lock);
6635 info->os_hnd->free_timer(info->os_hnd, info->timer);
6636 ipmi_mem_free(info);
6637 return;
6638 }
6639 info->running = 0;
6640 entity_id = ipmi_entity_convert_to_id(info->entity);
6641 ipmi_unlock(info->lock);
6642
6643 ipmi_entity_pointer_cb(entity_id, hot_swap_act_cb, NULL);
6644 }
6645
6646 static int
hot_swap_deact(ipmi_entity_t * ent,ipmi_entity_cb handler,void * cb_data)6647 hot_swap_deact(ipmi_entity_t *ent, ipmi_entity_cb handler, void *cb_data)
6648 {
6649 int val;
6650 int rv = ENOSYS;
6651 ipmi_control_op_cb cb;
6652 power_cb_info_t *info;
6653
6654 ent_lock(ent);
6655 if (ent->hot_swap_state == IPMI_HOT_SWAP_DEACTIVATION_REQUESTED) {
6656 if (ent->hot_swap_power) {
6657 if (handler == NULL) {
6658 cb = hot_swap_power_off;
6659 cb_data = ent;
6660 } else {
6661 info = ipmi_mem_alloc(sizeof(*info));
6662 if (!info) {
6663 rv = ENOMEM;
6664 goto out;
6665 }
6666 cb = hot_swap_power_off_cb;
6667 info->ent = ent;
6668 info->handler = handler;
6669 info->cb_data = cb_data;
6670 cb_data = info;
6671 }
6672
6673 val = 0;
6674 ent_unlock(ent);
6675 rv = ipmi_control_id_set_val(ent->hot_swap_power_id,
6676 &val,
6677 cb,
6678 cb_data);
6679 ent_lock(ent);
6680 if (!rv)
6681 set_hot_swap_state(ent, IPMI_HOT_SWAP_DEACTIVATION_IN_PROGRESS,
6682 NULL);
6683 }
6684 } else {
6685 rv = EAGAIN;
6686 }
6687 out:
6688 ent_unlock(ent);
6689
6690 return rv;
6691 }
6692
6693 static void
hot_swap_deact_cb(ipmi_entity_t * ent,void * cb_data)6694 hot_swap_deact_cb(ipmi_entity_t *ent, void *cb_data)
6695 {
6696 int rv;
6697
6698 rv = hot_swap_deact(ent, NULL, NULL);
6699 if (rv && (rv != EAGAIN))
6700 ipmi_log(IPMI_LOG_WARNING,
6701 "%sentity.c(hot_swap_deact_cb):"
6702 " Unable to set the hot swap power: %x",
6703 ENTITY_NAME(ent), rv);
6704 }
6705
6706 static void
hot_swap_deact_timeout(void * cb_data,os_hnd_timer_id_t * timer)6707 hot_swap_deact_timeout(void *cb_data, os_hnd_timer_id_t *timer)
6708 {
6709 ent_timer_info_t *info = cb_data;
6710 ipmi_entity_id_t entity_id;
6711
6712 ipmi_lock(info->lock);
6713 if (info->destroyed) {
6714 ipmi_unlock(info->lock);
6715 info->os_hnd->free_timer(info->os_hnd, info->timer);
6716 ipmi_mem_free(info);
6717 return;
6718 }
6719 info->running = 0;
6720 entity_id = ipmi_entity_convert_to_id(info->entity);
6721 ipmi_unlock(info->lock);
6722
6723 ipmi_entity_pointer_cb(entity_id, hot_swap_deact_cb, NULL);
6724 }
6725
6726 /* Must be called with the entity locked. Note that it may release
6727 and reclaim the lock as part of its operation. */
6728 static int
set_hot_swap_state(ipmi_entity_t * ent,enum ipmi_hot_swap_states state,ipmi_event_t * event)6729 set_hot_swap_state(ipmi_entity_t *ent,
6730 enum ipmi_hot_swap_states state,
6731 ipmi_event_t *event)
6732 {
6733 int val;
6734 int set = 1;
6735 enum ipmi_hot_swap_states old_state;
6736 int handled = IPMI_EVENT_NOT_HANDLED;
6737
6738 old_state = ent->hot_swap_state;
6739
6740 switch (state)
6741 {
6742 case IPMI_HOT_SWAP_INACTIVE:
6743 val = ent->hot_swap_ind_inact;
6744 break;
6745
6746 case IPMI_HOT_SWAP_ACTIVATION_REQUESTED:
6747 val = ent->hot_swap_ind_req_act;
6748 entity_start_timer(ent->hot_swap_act_info,
6749 ent->hot_swap_act_timeout,
6750 hot_swap_act_timeout);
6751 break;
6752
6753 case IPMI_HOT_SWAP_ACTIVE:
6754 val = ent->hot_swap_ind_act;
6755 break;
6756
6757 case IPMI_HOT_SWAP_DEACTIVATION_REQUESTED:
6758 val = ent->hot_swap_ind_req_deact;
6759 entity_start_timer(ent->hot_swap_deact_info,
6760 ent->hot_swap_deact_timeout,
6761 hot_swap_deact_timeout);
6762 break;
6763
6764 case IPMI_HOT_SWAP_DEACTIVATION_IN_PROGRESS:
6765 case IPMI_HOT_SWAP_NOT_PRESENT:
6766 case IPMI_HOT_SWAP_OUT_OF_CON:
6767 default:
6768 set = 0;
6769 break;
6770 }
6771
6772 if (set && ent->hot_swap_indicator) {
6773 int rv;
6774
6775 rv = ipmi_control_id_set_val(ent->hot_swap_indicator_id, &val,
6776 indicator_change, NULL);
6777 if (rv)
6778 ipmi_log(IPMI_LOG_SEVERE,
6779 "%sentity.c(set_hot_swap_state): Unable to"
6780 " set control value to %d, error %x",
6781 CONTROL_NAME(ent->hot_swap_indicator),
6782 val, rv);
6783 }
6784
6785 if (old_state != state) {
6786 ent->hot_swap_state = state;
6787 ent_unlock(ent);
6788 ipmi_entity_call_hot_swap_handlers(ent, old_state, state, &event,
6789 &handled);
6790 ent_lock(ent);
6791 }
6792
6793 return handled;
6794 }
6795
6796 static int
hot_swap_requester_changed(ipmi_sensor_t * sensor,enum ipmi_event_dir_e dir,int offset,int severity,int prev_severity,void * cb_data,ipmi_event_t * event)6797 hot_swap_requester_changed(ipmi_sensor_t *sensor,
6798 enum ipmi_event_dir_e dir,
6799 int offset,
6800 int severity,
6801 int prev_severity,
6802 void *cb_data,
6803 ipmi_event_t *event)
6804 {
6805 ipmi_entity_t *ent = cb_data;
6806 int handled = IPMI_EVENT_NOT_HANDLED;
6807
6808 ent_lock(ent);
6809 if (offset != ent->hot_swap_offset)
6810 goto out;
6811
6812 if (ent->hot_swap_requesting_val && (dir == IPMI_ASSERTION)) {
6813 /* A hot-swap is being requested */
6814 switch (ent->hot_swap_state)
6815 {
6816 case IPMI_HOT_SWAP_ACTIVE:
6817 handled = set_hot_swap_state
6818 (ent, IPMI_HOT_SWAP_DEACTIVATION_REQUESTED, event);
6819 break;
6820
6821 case IPMI_HOT_SWAP_ACTIVATION_REQUESTED:
6822 handled = set_hot_swap_state
6823 (ent, IPMI_HOT_SWAP_INACTIVE, event);
6824 break;
6825
6826 case IPMI_HOT_SWAP_ACTIVATION_IN_PROGRESS:
6827 handled = set_hot_swap_state
6828 (ent, IPMI_HOT_SWAP_DEACTIVATION_IN_PROGRESS, event);
6829 break;
6830
6831 case IPMI_HOT_SWAP_DEACTIVATION_REQUESTED:
6832 case IPMI_HOT_SWAP_DEACTIVATION_IN_PROGRESS:
6833 case IPMI_HOT_SWAP_OUT_OF_CON:
6834 case IPMI_HOT_SWAP_INACTIVE:
6835 case IPMI_HOT_SWAP_NOT_PRESENT:
6836 default:
6837 break;
6838 }
6839 } else {
6840 /* A hot-swap is being derequested */
6841 switch (ent->hot_swap_state)
6842 {
6843 case IPMI_HOT_SWAP_DEACTIVATION_REQUESTED:
6844 handled = set_hot_swap_state
6845 (ent, IPMI_HOT_SWAP_ACTIVE, event);
6846 break;
6847
6848 case IPMI_HOT_SWAP_INACTIVE:
6849 handled = set_hot_swap_state
6850 (ent, IPMI_HOT_SWAP_ACTIVATION_REQUESTED, event);
6851 break;
6852
6853 case IPMI_HOT_SWAP_ACTIVATION_REQUESTED:
6854 case IPMI_HOT_SWAP_ACTIVATION_IN_PROGRESS:
6855 case IPMI_HOT_SWAP_ACTIVE:
6856 case IPMI_HOT_SWAP_DEACTIVATION_IN_PROGRESS:
6857 case IPMI_HOT_SWAP_OUT_OF_CON:
6858 case IPMI_HOT_SWAP_NOT_PRESENT:
6859 default:
6860 break;
6861 }
6862 }
6863
6864 out:
6865 ent_unlock(ent);
6866 return handled;
6867 }
6868
6869 static void power_checked(ipmi_control_t *control,
6870 int err,
6871 int *val,
6872 void *cb_data);
6873
6874 static int
hot_swap_power_changed(ipmi_control_t * control,int * valid_vals,int * vals,void * cb_data,ipmi_event_t * event)6875 hot_swap_power_changed(ipmi_control_t *control,
6876 int *valid_vals,
6877 int *vals,
6878 void *cb_data,
6879 ipmi_event_t *event)
6880 {
6881 ipmi_entity_t *ent = cb_data;
6882
6883 if (!valid_vals[0])
6884 return IPMI_EVENT_NOT_HANDLED;
6885
6886 if (ent->present)
6887 power_checked(control, 0, vals, ent);
6888
6889 return IPMI_EVENT_NOT_HANDLED;
6890 }
6891
6892 static void
handle_new_hot_swap_indicator(ipmi_entity_t * ent,ipmi_control_t * control)6893 handle_new_hot_swap_indicator(ipmi_entity_t *ent, ipmi_control_t *control)
6894 {
6895 int val = 0;
6896 int rv;
6897
6898 ipmi_control_is_hot_swap_indicator(control,
6899 &ent->hot_swap_ind_req_act,
6900 &ent->hot_swap_ind_act,
6901 &ent->hot_swap_ind_req_deact,
6902 &ent->hot_swap_ind_inact);
6903
6904 ent->hot_swap_indicator_id = ipmi_control_convert_to_id(control);
6905 ent->hot_swap_indicator = control;
6906 switch (ent->hot_swap_state)
6907 {
6908 case IPMI_HOT_SWAP_INACTIVE:
6909 val = ent->hot_swap_ind_inact;
6910 break;
6911
6912 case IPMI_HOT_SWAP_ACTIVATION_REQUESTED:
6913 val = ent->hot_swap_ind_req_act;
6914 break;
6915
6916 case IPMI_HOT_SWAP_ACTIVATION_IN_PROGRESS:
6917 case IPMI_HOT_SWAP_ACTIVE:
6918 val = ent->hot_swap_ind_act;
6919 break;
6920
6921 case IPMI_HOT_SWAP_DEACTIVATION_REQUESTED:
6922 case IPMI_HOT_SWAP_DEACTIVATION_IN_PROGRESS:
6923 val = ent->hot_swap_ind_req_deact;
6924 break;
6925
6926 default:
6927 val = ent->hot_swap_ind_inact;
6928 break;
6929 }
6930
6931 ent_unlock(ent);
6932 rv = ipmi_control_set_val(control, &val, NULL, NULL);
6933 ent_lock(ent);
6934 if (rv)
6935 ipmi_log(IPMI_LOG_SEVERE,
6936 "%sentity.c(handle_new_hot_swap_indicator): Unable to"
6937 " set control value, error %x",
6938 CONTROL_NAME(control), rv);
6939 }
6940
6941 static void
requester_checked(ipmi_sensor_t * sensor,int err,ipmi_states_t * states,void * cb_data)6942 requester_checked(ipmi_sensor_t *sensor,
6943 int err,
6944 ipmi_states_t *states,
6945 void *cb_data)
6946 {
6947 ipmi_entity_t *ent = cb_data;
6948
6949 if (err) {
6950 ipmi_log(IPMI_LOG_SEVERE,
6951 "%sentity.c(requester_chedked): Unable to"
6952 " get requester value, error %x",
6953 SENSOR_NAME(sensor), err);
6954 return;
6955 }
6956
6957 ent_lock(ent);
6958 if (ipmi_is_state_set(states, ent->hot_swap_offset)
6959 == ent->hot_swap_requesting_val)
6960 {
6961 /* requester is requesting, change the state. */
6962 if (ent->hot_swap_state == IPMI_HOT_SWAP_ACTIVE)
6963 set_hot_swap_state(ent, IPMI_HOT_SWAP_DEACTIVATION_REQUESTED,
6964 NULL);
6965 } else {
6966 if (ent->hot_swap_state == IPMI_HOT_SWAP_INACTIVE)
6967 set_hot_swap_state(ent, IPMI_HOT_SWAP_ACTIVATION_REQUESTED,
6968 NULL);
6969 }
6970 ent_unlock(ent);
6971 }
6972
6973 static void
power_checked(ipmi_control_t * control,int err,int * val,void * cb_data)6974 power_checked(ipmi_control_t *control,
6975 int err,
6976 int *val,
6977 void *cb_data)
6978 {
6979 int rv;
6980 ipmi_entity_t *ent = cb_data;
6981
6982 if (err) {
6983 ipmi_log(IPMI_LOG_SEVERE,
6984 "%sentity.c(power_checked): Unable to"
6985 " get power value, error %x",
6986 CONTROL_NAME(control), err);
6987 return;
6988 }
6989
6990 ent_lock(ent);
6991 if (val[0])
6992 set_hot_swap_state(ent, IPMI_HOT_SWAP_ACTIVE, NULL);
6993 else
6994 set_hot_swap_state(ent, IPMI_HOT_SWAP_INACTIVE, NULL);
6995
6996 if (ent->hot_swap_requester) {
6997 ipmi_sensor_id_t hsr = ent->hot_swap_requester_id;
6998 ent_unlock(ent);
6999 rv = ipmi_sensor_id_get_states(hsr, requester_checked, ent);
7000 if (rv) {
7001 ipmi_log(IPMI_LOG_SEVERE,
7002 "%sentity.c(power_checked): Unable to"
7003 " request requester status, error %x",
7004 SENSOR_NAME(ent->hot_swap_requester), rv);
7005 }
7006 } else
7007 ent_unlock(ent);
7008 }
7009
7010 static void
handle_new_hot_swap_power(ipmi_entity_t * ent,ipmi_control_t * control)7011 handle_new_hot_swap_power(ipmi_entity_t *ent, ipmi_control_t *control)
7012 {
7013 int rv;
7014
7015 /* Add our own event handler. */
7016 rv = ipmi_control_add_val_event_handler(control,
7017 hot_swap_power_changed,
7018 ent);
7019 if (rv) {
7020 ipmi_log(IPMI_LOG_SEVERE,
7021 "%sentity.c(handle_new_hot_swap_power): Unable to"
7022 " add an event handler, error %x",
7023 CONTROL_NAME(control), rv);
7024 goto out;
7025 }
7026
7027 ent->hot_swap_power_id = ipmi_control_convert_to_id(control);
7028 ent->hot_swap_power = control;
7029
7030 /* If we have power control, we can manage hot-swap. */
7031 ipmi_entity_set_supports_managed_hot_swap(ent, 1);
7032
7033 if (ent->hot_swappable) {
7034 ent_unlock(ent);
7035 rv = ipmi_control_get_val(control, power_checked, ent);
7036 ent_lock(ent);
7037 if (rv) {
7038 ipmi_log(IPMI_LOG_SEVERE,
7039 "%sentity.c(handle_new_hot_swap_power): Unable to"
7040 " request power status, error %x",
7041 CONTROL_NAME(ent->hot_swap_power), rv);
7042 }
7043 }
7044 out:
7045 return;
7046 }
7047
7048 /* Must be called with the entity lock held. May release and reclaim it. */
7049 static void
handle_new_hot_swap_requester(ipmi_entity_t * ent,ipmi_sensor_t * sensor)7050 handle_new_hot_swap_requester(ipmi_entity_t *ent, ipmi_sensor_t *sensor)
7051 {
7052 ipmi_event_state_t events;
7053 int event_support;
7054 int rv;
7055 int val;
7056
7057 ent->hot_swap_requester_id = ipmi_sensor_convert_to_id(sensor);
7058
7059 ipmi_sensor_is_hot_swap_requester(sensor,
7060 &ent->hot_swap_offset,
7061 &ent->hot_swap_requesting_val);
7062
7063 event_support = ipmi_sensor_get_event_support(sensor);
7064
7065 /* Add our own event handler. */
7066 rv = ipmi_sensor_add_discrete_event_handler(sensor,
7067 hot_swap_requester_changed,
7068 ent);
7069 if (rv) {
7070 ipmi_log(IPMI_LOG_SEVERE,
7071 "%sentity.c(handle_new_hot_swap_requester): Unable to"
7072 " add an event handler, error %x",
7073 SENSOR_NAME(sensor), rv);
7074 goto out;
7075 }
7076
7077 ent->hot_swap_requester = sensor;
7078
7079 /* Nothing to do, events will just be on. */
7080 if (event_support == IPMI_EVENT_SUPPORT_GLOBAL_ENABLE)
7081 goto out;
7082
7083 /* Turn events and scanning on. */
7084 ipmi_event_state_init(&events);
7085 ipmi_event_state_set_events_enabled(&events, 1);
7086 ipmi_event_state_set_scanning_enabled(&events, 1);
7087
7088 if (event_support == IPMI_EVENT_SUPPORT_PER_STATE) {
7089 /* Turn on all the event enables that we can. */
7090 rv = ipmi_sensor_discrete_event_supported
7091 (sensor,
7092 ent->hot_swap_offset,
7093 IPMI_ASSERTION,
7094 &val);
7095 if ((!rv) && (val))
7096 ipmi_discrete_event_set(&events, ent->hot_swap_offset,
7097 IPMI_ASSERTION);
7098 rv = ipmi_sensor_discrete_event_supported
7099 (sensor,
7100 ent->hot_swap_offset,
7101 IPMI_DEASSERTION,
7102 &val);
7103 if ((!rv) && (val))
7104 ipmi_discrete_event_set(&events, ent->hot_swap_offset,
7105 IPMI_DEASSERTION);
7106 }
7107
7108 ent_unlock(ent);
7109 ipmi_sensor_set_event_enables(sensor, &events, NULL, NULL);
7110 ent_lock(ent);
7111
7112 if (ent->hot_swappable) {
7113 ipmi_sensor_id_t hsr = ent->hot_swap_requester_id;
7114 ent_unlock(ent);
7115 rv = ipmi_sensor_id_get_states(hsr, requester_checked, ent);
7116 ent_lock(ent);
7117 if (rv) {
7118 ipmi_log(IPMI_LOG_SEVERE,
7119 "%sentity.c(handle_new_hot_swap_requester): Unable to"
7120 " request requester status, error %x",
7121 SENSOR_NAME(ent->hot_swap_requester), rv);
7122 }
7123 }
7124
7125 out:
7126 return;
7127 }
7128
7129 static int
handle_hot_swap_presence(ipmi_entity_t * ent,int present,ipmi_event_t * event)7130 handle_hot_swap_presence(ipmi_entity_t *ent,
7131 int present,
7132 ipmi_event_t *event)
7133 {
7134 int handled = IPMI_EVENT_NOT_HANDLED;
7135 int rv;
7136
7137 ent_lock(ent);
7138 if (present) {
7139 if ((!ent->hot_swap_power)
7140 || (ent->hot_swap_act_timeout == IPMI_TIMEOUT_NOW))
7141 {
7142 /* No power control or immediate timeout, it goes straight
7143 to active. */
7144 handled = set_hot_swap_state(ent, IPMI_HOT_SWAP_ACTIVE, event);
7145 ent_unlock(ent);
7146 } else {
7147 ipmi_control_id_t hsp = ent->hot_swap_power_id;
7148 ent_unlock(ent);
7149 rv = ipmi_control_id_get_val(hsp, power_checked, ent);
7150 if (rv) {
7151 ipmi_log(IPMI_LOG_SEVERE,
7152 "%sentity.c(handle_hot_swap_presence): Unable to"
7153 " request power status, error %x",
7154 CONTROL_NAME(ent->hot_swap_power), rv);
7155 }
7156 }
7157 } else {
7158 handled = set_hot_swap_state(ent, IPMI_HOT_SWAP_NOT_PRESENT, event);
7159 ent_unlock(ent);
7160 }
7161
7162 return handled;
7163 }
7164
7165 static int
e_get_hot_swap_state(ipmi_entity_t * ent,ipmi_entity_hot_swap_state_cb handler,void * cb_data)7166 e_get_hot_swap_state(ipmi_entity_t *ent,
7167 ipmi_entity_hot_swap_state_cb handler,
7168 void *cb_data)
7169 {
7170 if (handler)
7171 handler(ent, 0, ent->hot_swap_state, cb_data);
7172 return 0;
7173 }
7174
7175 static int
e_set_auto_activate(ipmi_entity_t * ent,ipmi_timeout_t auto_act,ipmi_entity_cb done,void * cb_data)7176 e_set_auto_activate(ipmi_entity_t *ent,
7177 ipmi_timeout_t auto_act,
7178 ipmi_entity_cb done,
7179 void *cb_data)
7180 {
7181 int rv = 0;
7182
7183 ent_lock(ent);
7184 if (!ent->hot_swap_power)
7185 rv = ENOSYS;
7186 else
7187 ent->hot_swap_act_timeout = auto_act;
7188 ent_unlock(ent);
7189
7190 if ((!rv) && (done))
7191 done(ent, 0, cb_data);
7192
7193 return rv;
7194 }
7195
7196 static int
e_get_auto_activate(ipmi_entity_t * ent,ipmi_entity_time_cb handler,void * cb_data)7197 e_get_auto_activate(ipmi_entity_t *ent,
7198 ipmi_entity_time_cb handler,
7199 void *cb_data)
7200 {
7201 int rv = 0;
7202 ipmi_timeout_t time = 0;
7203
7204 ent_lock(ent);
7205 if (!ent->hot_swap_power)
7206 rv = ENOSYS;
7207 else
7208 time = ent->hot_swap_act_timeout;
7209 ent_unlock(ent);
7210
7211 if ((!rv) && (handler))
7212 handler(ent, 0, time, cb_data);
7213
7214 return rv;
7215 }
7216
7217 static int
e_set_auto_deactivate(ipmi_entity_t * ent,ipmi_timeout_t auto_act,ipmi_entity_cb done,void * cb_data)7218 e_set_auto_deactivate(ipmi_entity_t *ent,
7219 ipmi_timeout_t auto_act,
7220 ipmi_entity_cb done,
7221 void *cb_data)
7222 {
7223 int rv = 0;
7224
7225 ent_lock(ent);
7226 if (!ent->hot_swap_power)
7227 rv = ENOSYS;
7228 else
7229 ent->hot_swap_deact_timeout = auto_act;
7230 ent_unlock(ent);
7231
7232 if ((!rv) && (done))
7233 done(ent, 0, cb_data);
7234
7235 return rv;
7236 }
7237
7238 static int
e_get_auto_deactivate(ipmi_entity_t * ent,ipmi_entity_time_cb handler,void * cb_data)7239 e_get_auto_deactivate(ipmi_entity_t *ent,
7240 ipmi_entity_time_cb handler,
7241 void *cb_data)
7242 {
7243 int rv = 0;
7244 ipmi_timeout_t time = 0;
7245
7246 ent_lock(ent);
7247 if (!ent->hot_swap_power)
7248 rv = ENOSYS;
7249 else
7250 time = ent->hot_swap_deact_timeout;
7251 ent_unlock(ent);
7252
7253 if ((!rv) && (handler))
7254 handler(ent, 0, time, cb_data);
7255
7256 return 0;
7257 }
7258
7259 static int
e_activate(ipmi_entity_t * ent,ipmi_entity_cb done,void * cb_data)7260 e_activate(ipmi_entity_t *ent,
7261 ipmi_entity_cb done,
7262 void *cb_data)
7263 {
7264 return hot_swap_act(ent, done, cb_data);
7265 }
7266
7267 static int
e_deactivate(ipmi_entity_t * ent,ipmi_entity_cb done,void * cb_data)7268 e_deactivate(ipmi_entity_t *ent,
7269 ipmi_entity_cb done,
7270 void *cb_data)
7271 {
7272 return hot_swap_deact(ent, done, cb_data);
7273 }
7274
7275 typedef struct get_hot_swap_info_s
7276 {
7277 ipmi_entity_t *ent;
7278 ipmi_entity_val_cb handler;
7279 void *cb_data;
7280 } get_hot_swap_info_t;
7281
got_hot_swap_ind(ipmi_control_t * control,int err,int * cbval,void * cb_data)7282 static void got_hot_swap_ind(ipmi_control_t *control,
7283 int err,
7284 int *cbval,
7285 void *cb_data)
7286 {
7287 get_hot_swap_info_t *info = cb_data;
7288 int val = 0;
7289
7290 if (!err)
7291 val = *cbval;
7292
7293 info->handler(info->ent, err, val, info->cb_data);
7294 ipmi_mem_free(info);
7295 }
7296
7297 static int
e_get_hot_swap_indicator(ipmi_entity_t * ent,ipmi_entity_val_cb handler,void * cb_data)7298 e_get_hot_swap_indicator(ipmi_entity_t *ent,
7299 ipmi_entity_val_cb handler,
7300 void *cb_data)
7301 {
7302 get_hot_swap_info_t *info;
7303 int rv;
7304 ipmi_control_id_t id;
7305
7306 ent_lock(ent);
7307 if (! ent->hot_swap_indicator) {
7308 ent_unlock(ent);
7309 return ENOSYS;
7310 }
7311 id = ent->hot_swap_indicator_id;
7312 ent_unlock(ent);
7313
7314 info = ipmi_mem_alloc(sizeof(*info));
7315 if (!info)
7316 return ENOMEM;
7317
7318 info->ent = ent;
7319 info->handler = handler;
7320 info->cb_data = cb_data;
7321 rv = ipmi_control_id_get_val(id, got_hot_swap_ind, &info);
7322 if (rv)
7323 ipmi_mem_free(info);
7324 return rv;
7325 }
7326
7327 typedef struct set_hot_swap_ind_info_s
7328 {
7329 ipmi_entity_t *ent;
7330 ipmi_entity_cb handler;
7331 void *cb_data;
7332 } set_hot_swap_ind_info_t;
7333
set_hot_swap_ind(ipmi_control_t * control,int err,void * cb_data)7334 static void set_hot_swap_ind(ipmi_control_t *control,
7335 int err,
7336 void *cb_data)
7337 {
7338 set_hot_swap_ind_info_t *info = cb_data;
7339
7340 info->handler(info->ent, err, info->cb_data);
7341 ipmi_mem_free(info);
7342 }
7343
7344 static int
e_set_hot_swap_indicator(ipmi_entity_t * ent,int val,ipmi_entity_cb done,void * cb_data)7345 e_set_hot_swap_indicator(ipmi_entity_t *ent,
7346 int val,
7347 ipmi_entity_cb done,
7348 void *cb_data)
7349 {
7350 set_hot_swap_ind_info_t *info;
7351 int rv;
7352 ipmi_control_id_t id;
7353
7354 ent_lock(ent);
7355 if (! ent->hot_swap_indicator) {
7356 ent_unlock(ent);
7357 return ENOSYS;
7358 }
7359 id = ent->hot_swap_indicator_id;
7360 ent_unlock(ent);
7361
7362 info = ipmi_mem_alloc(sizeof(*info));
7363 if (!info)
7364 return ENOMEM;
7365
7366 info->ent = ent;
7367 info->handler = done;
7368 info->cb_data = cb_data;
7369 rv = ipmi_control_id_set_val(id, &val, set_hot_swap_ind, &info);
7370 if (rv)
7371 ipmi_mem_free(info);
7372 return rv;
7373 }
7374
7375 static void
got_hot_swap_req(ipmi_sensor_t * sensor,int err,ipmi_states_t * states,void * cb_data)7376 got_hot_swap_req(ipmi_sensor_t *sensor,
7377 int err,
7378 ipmi_states_t *states,
7379 void *cb_data)
7380 {
7381 get_hot_swap_info_t *info = cb_data;
7382 int val = 0;
7383
7384 if (!err) {
7385 ent_lock(info->ent);
7386 if (ipmi_is_state_set(states, info->ent->hot_swap_offset)
7387 == info->ent->hot_swap_requesting_val)
7388 {
7389 val = 1;
7390 }
7391 ent_unlock(info->ent);
7392 }
7393 info->handler(info->ent, err, val, info->cb_data);
7394 ipmi_mem_free(info);
7395 }
7396
7397 static int
e_get_hot_swap_requester(ipmi_entity_t * ent,ipmi_entity_val_cb handler,void * cb_data)7398 e_get_hot_swap_requester(ipmi_entity_t *ent,
7399 ipmi_entity_val_cb handler,
7400 void *cb_data)
7401 {
7402 get_hot_swap_info_t *info;
7403 int rv;
7404 ipmi_sensor_id_t id;
7405
7406 ent_lock(ent);
7407 if (! ent->hot_swap_requester) {
7408 ent_unlock(ent);
7409 return ENOSYS;
7410 }
7411 id = ent->hot_swap_requester_id;
7412 ent_unlock(ent);
7413
7414 info = ipmi_mem_alloc(sizeof(*info));
7415 if (!info)
7416 return ENOMEM;
7417
7418 info->ent = ent;
7419 info->handler = handler;
7420 info->cb_data = cb_data;
7421 rv = ipmi_sensor_id_get_states(id, got_hot_swap_req, &info);
7422 if (rv)
7423 ipmi_mem_free(info);
7424 return rv;
7425 }
7426
7427 typedef struct hs_check_s
7428 {
7429 int power;
7430 ipmi_entity_t *entity;
7431 } hs_check_t;
7432
7433 static void
check_requester(ipmi_sensor_t * sensor,int err,ipmi_states_t * states,void * cb_data)7434 check_requester(ipmi_sensor_t *sensor,
7435 int err,
7436 ipmi_states_t *states,
7437 void *cb_data)
7438 {
7439 hs_check_t *info = cb_data;
7440 ipmi_entity_t *ent = info->entity;
7441
7442 if (err) {
7443 ipmi_log(IPMI_LOG_SEVERE,
7444 "%sentity.c(requester_checked): Unable to"
7445 " get requester value, error %x",
7446 SENSOR_NAME(sensor), err);
7447 goto out;
7448 }
7449
7450 ent_lock(ent);
7451 if (ipmi_is_state_set(states, ent->hot_swap_offset)
7452 == ent->hot_swap_requesting_val)
7453 {
7454 /* requester is requesting, change the state. */
7455 if (info->power)
7456 set_hot_swap_state(ent, IPMI_HOT_SWAP_DEACTIVATION_REQUESTED,
7457 NULL);
7458 else
7459 set_hot_swap_state(ent, IPMI_HOT_SWAP_INACTIVE, NULL);
7460 } else {
7461 if (info->power)
7462 set_hot_swap_state(ent, IPMI_HOT_SWAP_ACTIVE, NULL);
7463 else
7464 set_hot_swap_state(ent, IPMI_HOT_SWAP_ACTIVATION_REQUESTED,
7465 NULL);
7466 }
7467 ent_unlock(ent);
7468
7469 out:
7470 ipmi_mem_free(info);
7471 }
7472
7473 static void
check_power(ipmi_control_t * control,int err,int * val,void * cb_data)7474 check_power(ipmi_control_t *control,
7475 int err,
7476 int *val,
7477 void *cb_data)
7478 {
7479 int rv;
7480 hs_check_t *info = cb_data;
7481 ipmi_entity_t *ent = info->entity;
7482
7483 if (err) {
7484 ipmi_log(IPMI_LOG_SEVERE,
7485 "%sentity.c(check_power): Unable to"
7486 " get power value, error %x",
7487 CONTROL_NAME(control), err);
7488 ipmi_mem_free(info);
7489 return;
7490 }
7491
7492 info->power = val[0];
7493
7494 ent_lock(ent);
7495 if (ent->hot_swap_requester) {
7496 ipmi_sensor_id_t hsr = ent->hot_swap_requester_id;
7497 ent_unlock(ent);
7498 rv = ipmi_sensor_id_get_states(hsr, check_requester, info);
7499 if (rv) {
7500 ipmi_log(IPMI_LOG_SEVERE,
7501 "%sentity.c(check_power): Unable to"
7502 " request requester status, error %x",
7503 SENSOR_NAME(ent->hot_swap_requester), rv);
7504 ipmi_mem_free(info);
7505 }
7506 } else {
7507 if (info->power)
7508 set_hot_swap_state(ent, IPMI_HOT_SWAP_ACTIVE, NULL);
7509 else
7510 set_hot_swap_state(ent, IPMI_HOT_SWAP_INACTIVE, NULL);
7511 ent_unlock(ent);
7512 ipmi_mem_free(info);
7513 }
7514 }
7515
7516 static int
e_check_hot_swap_state(ipmi_entity_t * ent)7517 e_check_hot_swap_state(ipmi_entity_t *ent)
7518 {
7519 hs_check_t *info;
7520 int rv = 0;
7521
7522 info = ipmi_mem_alloc(sizeof(*info));
7523 if (!info)
7524 return ENOMEM;
7525
7526 info->entity = ent;
7527 info->power = 1; /* Assume power is on if no power control. */
7528
7529 ent_lock(ent);
7530 if (ent->hot_swap_power) {
7531 ipmi_control_id_t hsp = ent->hot_swap_power_id;
7532 ent_unlock(ent);
7533 rv = ipmi_control_id_get_val(hsp, check_power, info);
7534 } else if (ent->hot_swap_requester) {
7535 ipmi_sensor_id_t hsr = ent->hot_swap_requester_id;
7536 ent_unlock(ent);
7537 rv = ipmi_sensor_id_get_states(hsr, check_requester, info);
7538 } else {
7539 ent_unlock(ent);
7540 ipmi_mem_free(info);
7541 }
7542
7543 if (info && rv)
7544 ipmi_mem_free(info);
7545
7546 return rv;
7547 }
7548
7549
7550
7551 /***********************************************************************
7552 *
7553 * More hot-swap stuff. Don't use it. This is only here because HPI
7554 * requires it.
7555 *
7556 **********************************************************************/
7557
7558 int
ipmi_entity_get_hot_swap_indicator(ipmi_entity_t * ent,ipmi_entity_val_cb handler,void * cb_data)7559 ipmi_entity_get_hot_swap_indicator(ipmi_entity_t *ent,
7560 ipmi_entity_val_cb handler,
7561 void *cb_data)
7562 {
7563 if (!ent->hot_swappable)
7564 return ENOSYS;
7565 if (!ent->hs_cb.get_hot_swap_indicator)
7566 return ENOSYS;
7567 return ent->hs_cb.get_hot_swap_indicator(ent, handler, cb_data);
7568 }
7569
7570 int
ipmi_entity_set_hot_swap_indicator(ipmi_entity_t * ent,int val,ipmi_entity_cb done,void * cb_data)7571 ipmi_entity_set_hot_swap_indicator(ipmi_entity_t *ent,
7572 int val,
7573 ipmi_entity_cb done,
7574 void *cb_data)
7575 {
7576 if (!ent->hot_swappable)
7577 return ENOSYS;
7578 if (!ent->hs_cb.set_hot_swap_indicator)
7579 return ENOSYS;
7580 return ent->hs_cb.set_hot_swap_indicator(ent, val, done, cb_data);
7581 }
7582
7583 int
ipmi_entity_get_hot_swap_requester(ipmi_entity_t * ent,ipmi_entity_val_cb handler,void * cb_data)7584 ipmi_entity_get_hot_swap_requester(ipmi_entity_t *ent,
7585 ipmi_entity_val_cb handler,
7586 void *cb_data)
7587 {
7588 if (!ent->hot_swappable)
7589 return ENOSYS;
7590 if (!ent->hs_cb.get_hot_swap_requester)
7591 return ENOSYS;
7592 return ent->hs_cb.get_hot_swap_requester(ent, handler, cb_data);
7593 }
7594
7595 static void
entity_get_hot_swap_indicator_cb(ipmi_entity_t * ent,void * cb_data)7596 entity_get_hot_swap_indicator_cb(ipmi_entity_t *ent, void *cb_data)
7597 {
7598 entity_val_cb_info_t *info = cb_data;
7599
7600 if (!ent->hot_swappable)
7601 info->rv = ENOSYS;
7602 else if (!ent->hs_cb.get_hot_swap_indicator)
7603 info->rv = ENOSYS;
7604 else
7605 info->rv = ent->hs_cb.get_hot_swap_indicator(ent,
7606 info->handler,
7607 info->cb_data);
7608 }
7609
7610 int
ipmi_entity_id_get_hot_swap_indicator(ipmi_entity_id_t id,ipmi_entity_val_cb handler,void * cb_data)7611 ipmi_entity_id_get_hot_swap_indicator(ipmi_entity_id_t id,
7612 ipmi_entity_val_cb handler,
7613 void *cb_data)
7614 {
7615 entity_val_cb_info_t info;
7616 int rv;
7617
7618 info.rv = 0;
7619 info.handler = handler;
7620 info.cb_data = cb_data;
7621 rv = ipmi_entity_pointer_cb(id, entity_get_hot_swap_indicator_cb, &info);
7622 if (!rv)
7623 rv = info.rv;
7624 return rv;
7625 }
7626
7627 static void
entity_set_hot_swap_indicator_cb(ipmi_entity_t * ent,void * cb_data)7628 entity_set_hot_swap_indicator_cb(ipmi_entity_t *ent, void *cb_data)
7629 {
7630 entity_cb_info_t *info = cb_data;
7631
7632 if (!ent->hot_swappable)
7633 info->rv = ENOSYS;
7634 else if (!ent->hs_cb.set_hot_swap_indicator)
7635 info->rv = ENOSYS;
7636 else
7637 info->rv = ent->hs_cb.set_hot_swap_indicator(ent,
7638 info->val,
7639 info->handler,
7640 info->cb_data);
7641 }
7642
7643 int
ipmi_entity_id_set_hot_swap_indicator(ipmi_entity_id_t id,int val,ipmi_entity_cb done,void * cb_data)7644 ipmi_entity_id_set_hot_swap_indicator(ipmi_entity_id_t id,
7645 int val,
7646 ipmi_entity_cb done,
7647 void *cb_data)
7648 {
7649 entity_cb_info_t info;
7650 int rv;
7651
7652 info.rv = 0;
7653 info.val = val;
7654 info.handler = done;
7655 info.cb_data = cb_data;
7656 rv = ipmi_entity_pointer_cb(id, entity_set_hot_swap_indicator_cb, &info);
7657 if (!rv)
7658 rv = info.rv;
7659 return rv;
7660 }
7661
7662 static void
entity_get_hot_swap_requester_cb(ipmi_entity_t * ent,void * cb_data)7663 entity_get_hot_swap_requester_cb(ipmi_entity_t *ent, void *cb_data)
7664 {
7665 entity_val_cb_info_t *info = cb_data;
7666
7667 if (!ent->hot_swappable)
7668 info->rv = ENOSYS;
7669 else if (!ent->hs_cb.get_hot_swap_requester)
7670 info->rv = ENOSYS;
7671 else
7672 info->rv = ent->hs_cb.get_hot_swap_requester(ent,
7673 info->handler,
7674 info->cb_data);
7675 }
7676
7677 int
ipmi_entity_id_get_hot_swap_requester(ipmi_entity_id_t id,ipmi_entity_val_cb handler,void * cb_data)7678 ipmi_entity_id_get_hot_swap_requester(ipmi_entity_id_t id,
7679 ipmi_entity_val_cb handler,
7680 void *cb_data)
7681 {
7682 entity_val_cb_info_t info;
7683 int rv;
7684
7685 info.rv = 0;
7686 info.handler = handler;
7687 info.cb_data = cb_data;
7688 rv = ipmi_entity_pointer_cb(id, entity_get_hot_swap_requester_cb, &info);
7689 if (!rv)
7690 rv = info.rv;
7691 return rv;
7692 }
7693
7694 /***********************************************************************
7695 *
7696 * Entity message handling.
7697 *
7698 **********************************************************************/
7699
7700 static void
entity_opq_ready2(ipmi_entity_t * entity,void * cb_data)7701 entity_opq_ready2(ipmi_entity_t *entity, void *cb_data)
7702 {
7703 ipmi_entity_op_info_t *info = cb_data;
7704 if (info->__handler)
7705 info->__handler(entity, 0, info->__cb_data);
7706 }
7707
7708 static int
entity_opq_ready(void * cb_data,int shutdown)7709 entity_opq_ready(void *cb_data, int shutdown)
7710 {
7711 ipmi_entity_op_info_t *info = cb_data;
7712 int rv;
7713
7714 if (shutdown) {
7715 /* Technically this can't happen, but just in case... */
7716 ipmi_log(IPMI_LOG_SEVERE,
7717 "%sentity.c(entity_opq_ready): "
7718 "Entity was destroyed while an operation was in progress",
7719 ENTITY_NAME(info->__entity));
7720 if (info->__handler)
7721 info->__handler(info->__entity, ECANCELED, info->__cb_data);
7722 return OPQ_HANDLER_STARTED;
7723 }
7724
7725 rv = ipmi_entity_pointer_cb(info->__entity_id, entity_opq_ready2, info);
7726 if (rv) {
7727 /* Technically this can't happen, but just in case... */
7728 ipmi_log(IPMI_LOG_SEVERE,
7729 "%sentity.c(entity_opq_ready): "
7730 "Entity pointer callback failed",
7731 ENTITY_NAME(info->__entity));
7732 if (info->__handler)
7733 info->__handler(info->__entity, rv, info->__cb_data);
7734 }
7735
7736 return OPQ_HANDLER_STARTED;
7737 }
7738
7739 int
ipmi_entity_add_opq(ipmi_entity_t * entity,ipmi_entity_cb handler,ipmi_entity_op_info_t * info,void * cb_data)7740 ipmi_entity_add_opq(ipmi_entity_t *entity,
7741 ipmi_entity_cb handler,
7742 ipmi_entity_op_info_t *info,
7743 void *cb_data)
7744 {
7745 if (entity->destroyed)
7746 return EINVAL;
7747
7748 info->__entity = entity;
7749 info->__entity_id = ipmi_entity_convert_to_id(entity);
7750 info->__cb_data = cb_data;
7751 info->__handler = handler;
7752 if (!opq_new_op(entity->waitq, entity_opq_ready, info, 0))
7753 return ENOMEM;
7754 return 0;
7755 }
7756
7757 void
ipmi_entity_opq_done(ipmi_entity_t * entity)7758 ipmi_entity_opq_done(ipmi_entity_t *entity)
7759 {
7760 /* Protect myself from NULL entitys. This way, it doesn't have to
7761 be done in each call. */
7762 if (!entity)
7763 return;
7764
7765 /* No check for the lock. It will sometimes fail at destruction
7766 time. */
7767
7768 opq_op_done(entity->waitq);
7769 }
7770
7771 static void
entity_rsp_handler2(ipmi_entity_t * entity,void * cb_data)7772 entity_rsp_handler2(ipmi_entity_t *entity, void *cb_data)
7773 {
7774 ipmi_entity_op_info_t *info = cb_data;
7775
7776 if (info->__rsp_handler)
7777 info->__rsp_handler(entity, 0, info->__rsp, info->__cb_data);
7778 }
7779
7780 static void
entity_rsp_handler(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)7781 entity_rsp_handler(ipmi_mc_t *mc,
7782 ipmi_msg_t *rsp,
7783 void *rsp_data)
7784 {
7785 ipmi_entity_op_info_t *info = rsp_data;
7786 int rv;
7787
7788 /* Call the next stage with the lock held. */
7789 info->__rsp = rsp;
7790 rv = ipmi_entity_pointer_cb(info->__entity_id,
7791 entity_rsp_handler2,
7792 info);
7793 if (rv) {
7794 /* This really can't happen, there will be something in the
7795 opq, so the entity cannot go away. */
7796 ipmi_log(IPMI_LOG_ERR_INFO,
7797 "%sentity.c(entity_rsp_handler): "
7798 "Could not convert entity id to a pointer, entity was"
7799 " probably destroyed while operation was in progress",
7800 MC_NAME(mc));
7801 if (info->__rsp_handler) {
7802 i_ipmi_domain_entity_lock(info->__entity->domain);
7803 info->__entity->usecount++;
7804 i_ipmi_domain_entity_unlock(info->__entity->domain);
7805 info->__rsp_handler(info->__entity, rv, NULL, info->__cb_data);
7806 i_ipmi_entity_put(info->__entity);
7807 }
7808 }
7809 }
7810
7811 static void
send_command_mc_cb(ipmi_mc_t * mc,void * cb_data)7812 send_command_mc_cb(ipmi_mc_t *mc, void *cb_data)
7813 {
7814 ipmi_entity_op_info_t *info = cb_data;
7815
7816 info->__err = ipmi_mc_send_command(mc, info->__lun, info->__msg,
7817 entity_rsp_handler, info);
7818 }
7819
7820 int
ipmi_entity_send_command(ipmi_entity_t * entity,ipmi_mcid_t mcid,unsigned int lun,ipmi_msg_t * msg,ipmi_entity_rsp_cb handler,ipmi_entity_op_info_t * info,void * cb_data)7821 ipmi_entity_send_command(ipmi_entity_t *entity,
7822 ipmi_mcid_t mcid,
7823 unsigned int lun,
7824 ipmi_msg_t *msg,
7825 ipmi_entity_rsp_cb handler,
7826 ipmi_entity_op_info_t *info,
7827 void *cb_data)
7828 {
7829 int rv;
7830
7831 CHECK_ENTITY_LOCK(entity);
7832
7833 if (entity->destroyed)
7834 return EINVAL;
7835
7836 info->__entity = entity;
7837 info->__entity_id = ipmi_entity_convert_to_id(entity);
7838 info->__cb_data = cb_data;
7839 info->__rsp_handler = handler;
7840 info->__err = 0;
7841 info->__msg = msg;
7842 info->__lun = lun;
7843 rv = ipmi_mc_pointer_cb(mcid, send_command_mc_cb, info);
7844 if (!rv)
7845 rv = info->__err;
7846 return rv;
7847 }
7848
7849
7850 /***********************************************************************
7851 *
7852 * Cruft
7853 *
7854 **********************************************************************/
7855
7856 int
ipmi_entity_set_presence_handler(ipmi_entity_t * ent,ipmi_entity_presence_nd_cb handler,void * cb_data)7857 ipmi_entity_set_presence_handler(ipmi_entity_t *ent,
7858 ipmi_entity_presence_nd_cb handler,
7859 void *cb_data)
7860 {
7861 CHECK_ENTITY_LOCK(ent);
7862
7863 ent_lock(ent);
7864 ent->cruft_presence_handler = handler;
7865 ent->cruft_presence_cb_data = cb_data;
7866 ent_unlock(ent);
7867 return 0;
7868 }
7869
7870 int
ipmi_entity_set_sensor_update_handler(ipmi_entity_t * ent,ipmi_entity_sensor_cb handler,void * cb_data)7871 ipmi_entity_set_sensor_update_handler(ipmi_entity_t *ent,
7872 ipmi_entity_sensor_cb handler,
7873 void *cb_data)
7874 {
7875 int rv = 0;
7876
7877 CHECK_ENTITY_LOCK(ent);
7878
7879 ent_lock(ent);
7880 if (ent->cruft_sensor_handler)
7881 ipmi_entity_remove_sensor_update_handler
7882 (ent,
7883 ent->cruft_sensor_handler,
7884 ent->cruft_sensor_cb_data);
7885
7886 ent->cruft_sensor_handler = handler;
7887 ent->cruft_sensor_cb_data = cb_data;
7888 if (handler)
7889 rv = ipmi_entity_add_sensor_update_handler(ent, handler, cb_data);
7890 ent_unlock(ent);
7891 return rv;
7892 }
7893
7894 int
ipmi_entity_set_control_update_handler(ipmi_entity_t * ent,ipmi_entity_control_cb handler,void * cb_data)7895 ipmi_entity_set_control_update_handler(ipmi_entity_t *ent,
7896 ipmi_entity_control_cb handler,
7897 void *cb_data)
7898 {
7899 int rv = 0;
7900
7901 CHECK_ENTITY_LOCK(ent);
7902
7903 ent_lock(ent);
7904 if (ent->cruft_control_handler)
7905 ipmi_entity_remove_control_update_handler
7906 (ent,
7907 ent->cruft_control_handler,
7908 ent->cruft_control_cb_data);
7909
7910 ent->cruft_control_handler = handler;
7911 ent->cruft_control_cb_data = cb_data;
7912 if (handler)
7913 rv = ipmi_entity_add_control_update_handler(ent, handler, cb_data);
7914 ent_unlock(ent);
7915 return rv;
7916 }
7917
7918 int
ipmi_entity_set_fru_update_handler(ipmi_entity_t * ent,ipmi_entity_fru_cb handler,void * cb_data)7919 ipmi_entity_set_fru_update_handler(ipmi_entity_t *ent,
7920 ipmi_entity_fru_cb handler,
7921 void *cb_data)
7922 {
7923 int rv = 0;
7924
7925 CHECK_ENTITY_LOCK(ent);
7926
7927 ent_lock(ent);
7928 if (ent->cruft_fru_handler)
7929 ipmi_entity_remove_fru_update_handler
7930 (ent,
7931 ent->cruft_fru_handler,
7932 ent->cruft_fru_cb_data);
7933
7934 ent->cruft_fru_handler = handler;
7935 ent->cruft_fru_cb_data = cb_data;
7936 if (handler)
7937 rv = ipmi_entity_add_fru_update_handler(ent, handler, cb_data);
7938 ent_unlock(ent);
7939 return rv;
7940 }
7941
7942 /*
7943 * Getting the FRU values for an entity.
7944 */
7945
7946 #define FRU_VAL_GET(type, name) \
7947 int \
7948 ipmi_entity_get_ ## name(ipmi_entity_t *entity, \
7949 type *val) \
7950 { \
7951 CHECK_ENTITY_LOCK(entity); \
7952 if (!entity->fru) \
7953 return ENOSYS; \
7954 return ipmi_fru_get_ ## name(entity->fru, val); \
7955 }
7956
7957 #define FRU_STR_GET(name) \
7958 int \
7959 ipmi_entity_get_ ## name(ipmi_entity_t *entity, \
7960 char *str, \
7961 unsigned int *strlen) \
7962 { \
7963 CHECK_ENTITY_LOCK(entity); \
7964 if (!entity->fru) \
7965 return ENOSYS; \
7966 return ipmi_fru_get_ ## name(entity->fru, str, strlen); \
7967 }
7968
7969 #define FRU_CUSTOM_GET(name) \
7970 int \
7971 ipmi_entity_get_ ## name ## _custom_len(ipmi_entity_t *entity, \
7972 unsigned int num, \
7973 unsigned int *length) \
7974 { \
7975 CHECK_ENTITY_LOCK(entity); \
7976 if (!entity->fru) \
7977 return ENOSYS; \
7978 return ipmi_fru_get_ ## name ## _custom_len(entity->fru, num, length);\
7979 } \
7980 int \
7981 ipmi_entity_get_## name ## _custom_type(ipmi_entity_t *entity, \
7982 unsigned int num, \
7983 enum ipmi_str_type_e *type) \
7984 { \
7985 CHECK_ENTITY_LOCK(entity); \
7986 if (!entity->fru) \
7987 return ENOSYS; \
7988 return ipmi_fru_get_ ## name ## _custom_type(entity->fru, num, type);\
7989 } \
7990 int \
7991 ipmi_entity_get_## name ## _custom(ipmi_entity_t *entity, \
7992 unsigned int num, \
7993 char *str, \
7994 unsigned int *str_len) \
7995 { \
7996 CHECK_ENTITY_LOCK(entity); \
7997 if (!entity->fru) \
7998 return ENOSYS; \
7999 return ipmi_fru_get_ ## name ## _custom(entity->fru, num, str, str_len);\
8000 }
8001
FRU_VAL_GET(unsigned char,internal_use_version)8002 FRU_VAL_GET(unsigned char, internal_use_version)
8003 FRU_VAL_GET(unsigned int, internal_use_length)
8004
8005 int
8006 ipmi_entity_get_internal_use_data(ipmi_entity_t *entity,
8007 unsigned char *data,
8008 unsigned int *max_len)
8009 {
8010 CHECK_ENTITY_LOCK(entity);
8011 if (!entity->fru)
8012 return ENOSYS;
8013 return ipmi_fru_get_internal_use_data(entity->fru, data, max_len);
8014 }
8015
FRU_VAL_GET(unsigned char,chassis_info_version)8016 FRU_VAL_GET(unsigned char, chassis_info_version)
8017 FRU_VAL_GET(unsigned char, chassis_info_type)
8018
8019 FRU_VAL_GET(unsigned int, chassis_info_part_number_len)
8020 FRU_VAL_GET(enum ipmi_str_type_e, chassis_info_part_number_type)
8021 FRU_STR_GET(chassis_info_part_number)
8022 FRU_VAL_GET(unsigned int, chassis_info_serial_number_len)
8023 FRU_VAL_GET(enum ipmi_str_type_e, chassis_info_serial_number_type)
8024 FRU_STR_GET(chassis_info_serial_number)
8025 FRU_CUSTOM_GET(chassis_info)
8026
8027 FRU_VAL_GET(unsigned char, board_info_version)
8028 FRU_VAL_GET(unsigned char, board_info_lang_code)
8029 int ipmi_entity_get_board_info_mfg_time(ipmi_entity_t *entity,
8030 time_t *time)
8031 {
8032 CHECK_ENTITY_LOCK(entity);
8033 if (!entity->fru)
8034 return ENOSYS;
8035 return ipmi_fru_get_board_info_mfg_time(entity->fru, time);
8036 }
FRU_VAL_GET(unsigned int,board_info_board_manufacturer_len)8037 FRU_VAL_GET(unsigned int, board_info_board_manufacturer_len)
8038 FRU_VAL_GET(enum ipmi_str_type_e, board_info_board_manufacturer_type)
8039 FRU_STR_GET(board_info_board_manufacturer)
8040 FRU_VAL_GET(unsigned int, board_info_board_product_name_len)
8041 FRU_VAL_GET(enum ipmi_str_type_e, board_info_board_product_name_type)
8042 FRU_STR_GET(board_info_board_product_name)
8043 FRU_VAL_GET(unsigned int, board_info_board_serial_number_len)
8044 FRU_VAL_GET(enum ipmi_str_type_e, board_info_board_serial_number_type)
8045 FRU_STR_GET(board_info_board_serial_number)
8046 FRU_VAL_GET(unsigned int, board_info_board_part_number_len)
8047 FRU_VAL_GET(enum ipmi_str_type_e, board_info_board_part_number_type)
8048 FRU_STR_GET(board_info_board_part_number)
8049 FRU_VAL_GET(unsigned int, board_info_fru_file_id_len)
8050 FRU_VAL_GET(enum ipmi_str_type_e, board_info_fru_file_id_type)
8051 FRU_STR_GET(board_info_fru_file_id)
8052 FRU_CUSTOM_GET(board_info)
8053
8054 FRU_VAL_GET(unsigned char, product_info_version)
8055 FRU_VAL_GET(unsigned char, product_info_lang_code)
8056 FRU_VAL_GET(unsigned int, product_info_manufacturer_name_len)
8057 FRU_VAL_GET(enum ipmi_str_type_e, product_info_manufacturer_name_type)
8058 FRU_STR_GET(product_info_manufacturer_name)
8059 FRU_VAL_GET(unsigned int, product_info_product_name_len)
8060 FRU_VAL_GET(enum ipmi_str_type_e, product_info_product_name_type)
8061 FRU_STR_GET(product_info_product_name)
8062 FRU_VAL_GET(unsigned int, product_info_product_part_model_number_len)
8063 FRU_VAL_GET(enum ipmi_str_type_e, product_info_product_part_model_number_type)
8064 FRU_STR_GET(product_info_product_part_model_number)
8065 FRU_VAL_GET(unsigned int, product_info_product_version_len)
8066 FRU_VAL_GET(enum ipmi_str_type_e, product_info_product_version_type)
8067 FRU_STR_GET(product_info_product_version)
8068 FRU_VAL_GET(unsigned int, product_info_product_serial_number_len)
8069 FRU_VAL_GET(enum ipmi_str_type_e, product_info_product_serial_number_type)
8070 FRU_STR_GET(product_info_product_serial_number)
8071 FRU_VAL_GET(unsigned int, product_info_asset_tag_len)
8072 FRU_VAL_GET(enum ipmi_str_type_e, product_info_asset_tag_type)
8073 FRU_STR_GET(product_info_asset_tag)
8074 FRU_VAL_GET(unsigned int, product_info_fru_file_id_len)
8075 FRU_VAL_GET(enum ipmi_str_type_e, product_info_fru_file_id_type)
8076 FRU_STR_GET(product_info_fru_file_id)
8077 FRU_CUSTOM_GET(product_info)
8078
8079 unsigned int
8080 ipmi_entity_get_num_multi_records(ipmi_entity_t *entity)
8081 {
8082 CHECK_ENTITY_LOCK(entity);
8083 if (!entity->fru)
8084 return 0;
8085 return ipmi_fru_get_num_multi_records(entity->fru);
8086 }
8087
8088 int
ipmi_entity_get_multi_record_type(ipmi_entity_t * entity,unsigned int num,unsigned char * type)8089 ipmi_entity_get_multi_record_type(ipmi_entity_t *entity,
8090 unsigned int num,
8091 unsigned char *type)
8092 {
8093 CHECK_ENTITY_LOCK(entity);
8094 if (!entity->fru)
8095 return ENOSYS;
8096 return ipmi_fru_get_multi_record_type(entity->fru, num, type);
8097 }
8098
8099 int
ipmi_entity_get_multi_record_format_version(ipmi_entity_t * entity,unsigned int num,unsigned char * ver)8100 ipmi_entity_get_multi_record_format_version(ipmi_entity_t *entity,
8101 unsigned int num,
8102 unsigned char *ver)
8103 {
8104 CHECK_ENTITY_LOCK(entity);
8105 if (!entity->fru)
8106 return ENOSYS;
8107 return ipmi_fru_get_multi_record_format_version(entity->fru, num, ver);
8108 }
8109
8110 int
ipmi_entity_get_multi_record_data_len(ipmi_entity_t * entity,unsigned int num,unsigned int * len)8111 ipmi_entity_get_multi_record_data_len(ipmi_entity_t *entity,
8112 unsigned int num,
8113 unsigned int *len)
8114 {
8115 CHECK_ENTITY_LOCK(entity);
8116 if (!entity->fru)
8117 return ENOSYS;
8118 return ipmi_fru_get_multi_record_data_len(entity->fru, num, len);
8119 }
8120
8121 int
ipmi_entity_get_multi_record_data(ipmi_entity_t * entity,unsigned int num,unsigned char * data,unsigned int * length)8122 ipmi_entity_get_multi_record_data(ipmi_entity_t *entity,
8123 unsigned int num,
8124 unsigned char *data,
8125 unsigned int *length)
8126 {
8127 CHECK_ENTITY_LOCK(entity);
8128 if (!entity->fru)
8129 return ENOSYS;
8130 return ipmi_fru_get_multi_record_data(entity->fru, num, data, length);
8131 }
8132