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