1 /*
2  * domain.c
3  *
4  * MontaVista IPMI code for handling IPMI domains
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/ipmi_conn.h>
39 #include <OpenIPMI/ipmiif.h>
40 #include <OpenIPMI/ipmi_sdr.h>
41 #include <OpenIPMI/ipmi_msgbits.h>
42 #include <OpenIPMI/ipmi_err.h>
43 #include <OpenIPMI/ipmi_auth.h>
44 
45 #include <OpenIPMI/internal/locked_list.h>
46 #include <OpenIPMI/internal/ilist.h>
47 #include <OpenIPMI/internal/ipmi_event.h>
48 #include <OpenIPMI/internal/ipmi_int.h>
49 #include <OpenIPMI/internal/ipmi_oem.h>
50 #include <OpenIPMI/internal/ipmi_utils.h>
51 #include <OpenIPMI/internal/ipmi_domain.h>
52 #include <OpenIPMI/internal/ipmi_entity.h>
53 #include <OpenIPMI/internal/ipmi_mc.h>
54 
55 #ifdef DEBUG_EVENTS
56 static void
dump_hex(const unsigned char * data,int len)57 dump_hex(const unsigned char *data, int len)
58 {
59     int i;
60     for (i=0; i<len; i++) {
61 	if ((i != 0) && ((i % 16) == 0)) {
62 	    ipmi_log(IPMI_LOG_DEBUG_CONT, "\n  ");
63 	}
64 	ipmi_log(IPMI_LOG_DEBUG_CONT, " %2.2x", data[i]);
65     }
66 }
67 #endif
68 
69 /* Rescan the bus for MCs every 10 minutes by default. */
70 #define IPMI_AUDIT_DOMAIN_INTERVAL 600
71 
72 /* Re-query the SEL every 10 seconds by default. */
73 #define IPMI_SEL_QUERY_INTERVAL 10
74 
75 /* Timer structure for rescanning the bus. */
76 typedef struct audit_domain_info_s
77 {
78     int           cancelled;
79     os_handler_t  *os_hnd;
80     ipmi_lock_t   *lock;
81     ipmi_domain_t *domain;
82 } audit_domain_info_t;
83 
84 /* Used to keep a record of a bus scan. */
85 typedef struct mc_ipmb_scan_info_s mc_ipmb_scan_info_t;
86 struct mc_ipmb_scan_info_s
87 {
88     ipmi_addr_t         addr;
89     unsigned int        addr_len;
90     ipmi_domain_t       *domain;
91     ipmi_msg_t          msg;
92     unsigned int        end_addr;
93     ipmi_domain_cb      done_handler;
94     void                *cb_data;
95     mc_ipmb_scan_info_t *next;
96     unsigned int        missed_responses;
97     int                 cancelled;
98     int                 timer_running;
99     os_handler_t        *os_hnd;
100     os_hnd_timer_id_t   *timer;
101     ipmi_lock_t         *lock;
102 };
103 
104 /* This structure tracks messages sent to the domain, it is primarily
105    here so messages can be rerouted to other connections when a
106    connection fails. */
107 typedef struct ll_msg_s
108 {
109     ipmi_domain_t                *domain;
110     int                          con;
111 
112     ipmi_msg_t                   msg;
113     unsigned char                msg_data[IPMI_MAX_MSG_LENGTH];
114 
115     ipmi_addr_response_handler_t rsp_handler;
116     ipmi_msgi_t                  *rsp_item;
117 
118     long                         seq;
119 
120     int                          side_effects;
121 
122     ilist_item_t link;
123 } ll_msg_t;
124 
125 typedef struct activate_timer_info_s
126 {
127     int           cancelled;
128     ipmi_domain_t *domain;
129     os_handler_t  *os_hnd;
130     ipmi_lock_t   *lock;
131     volatile int  running;
132 } activate_timer_info_t;
133 
134 typedef struct domain_check_oem_s domain_check_oem_t;
135 
136 typedef struct mc_table_s
137 {
138     unsigned short size;
139     unsigned short curr;
140     ipmi_mc_t      **mcs;
141 } mc_table_t;
142 
143 struct ipmi_domain_s
144 {
145     /* Used for error reporting. We add an extra space at the end, thus
146        the +1. */
147     char name[IPMI_DOMAIN_NAME_LEN+1];
148 
149     /* Used to handle shutdown race conditions. */
150     int             valid;
151     int             in_shutdown;
152 
153     /* Is anyone using this domain? */
154     unsigned int    usecount;
155 
156     /* Used to handle startup race conditions. */
157     int             in_startup;
158 
159     /* OS handler to use for domain operations. */
160     os_handler_t *os_hnd;
161 
162     /* A lock for handling miscellaneous data changes. */
163     ipmi_lock_t *domain_lock;
164 
165     /* The main set of SDRs on a BMC. */
166     ipmi_sdr_info_t *main_sdrs;
167 
168     /* The sensors that came from the main SDR. */
169     ipmi_sensor_t **sensors_in_main_sdr;
170     unsigned int  sensors_in_main_sdr_count;
171 
172     /* The entities that came from the device SDR on this MC are
173        somehow stored in this data structure. */
174     void *entities_in_main_sdr;
175 
176     /* OEM data for OEM code. */
177     void                            *oem_data;
178     ipmi_domain_destroy_oem_data_cb oem_data_destroyer;
179 
180     /* The type of domain, defaults to unknown */
181     enum ipmi_domain_type domain_type;
182 
183     /* Major and minor versions of the connection. */
184     unsigned int major_version : 4;
185     unsigned int minor_version : 4;
186     unsigned int SDR_repository_support : 1;
187 
188     /* A special MC used to represent the system interface. */
189     ipmi_mc_t *si_mc;
190 
191     /* Used for generating unique numbers for a domain. */
192     unsigned int uniq_num;
193 
194 #define IPMB_HASH 32
195     mc_table_t ipmb_mcs[IPMB_HASH];
196 #define MAX_CONS 2
197     ipmi_mc_t *sys_intf_mcs[MAX_CONS];
198     ipmi_lock_t *mc_lock;
199 
200     /* A list of outstanding messages.  We use this so we can reroute
201        messages to another connection in case a connection fails. */
202     ilist_t     *cmds;
203     ipmi_lock_t *cmds_lock;
204     long        cmds_seq; /* Sequence number for messages to avoid
205 			     reuse problems. */
206     long        conn_seq[MAX_CONS]; /* Sequence number for connection
207 				       switchovers to avoid handling
208 				       old messages. */
209 
210     locked_list_t            *event_handlers;
211     locked_list_t            *event_handlers_cl;
212     ipmi_oem_event_handler_cb oem_event_handler;
213     void                      *oem_event_cb_data;
214 
215     locked_list_t            *new_sensor_handlers; /* callbacks for
216                                              OEM-specific sensors*/
217 
218     ipmi_domain_shutdown_cb shutdown_handler;
219 
220     /* Are we in the middle of an MC bus scan? */
221     int scanning_bus_count;
222 
223     ipmi_entity_info_t    *entities;
224     ipmi_lock_t           *entities_lock;
225 
226     ipmi_lock_t   *con_lock;
227     int           working_conn;
228     ipmi_con_t    *conn[MAX_CONS];
229     int           con_active[MAX_CONS];
230     unsigned char con_ipmb_addr[MAX_CONS][MAX_IPMI_USED_CHANNELS];
231 
232     int           con_up[MAX_CONS];
233 
234     /* A list of connection fail handler, separate from the main one. */
235     locked_list_t *con_change_handlers;
236     locked_list_t *con_change_cl_handlers;
237 
238     /* Are any low-level connections up? */
239     int connection_up;
240 
241     /* If we got some type of invalid return from the BMC, we mark
242        this and retry at audit intervals. */
243     int got_invalid_dev_id;
244 
245     /* Are we in the process of connecting? */
246     int connecting;
247 
248 #define MAX_PORTS_PER_CON 16
249     /* -1 if not valid, 0 if not up, 1 if up. */
250     int           port_up[MAX_PORTS_PER_CON][MAX_CONS];
251 
252     /* Should I do a full bus scan for devices on the bus? */
253     int           do_bus_scan;
254 
255     /* Timer for rescanning the bus periodically. */
256     unsigned int        audit_domain_interval; /* seconds between checks */
257     os_hnd_timer_id_t   *audit_domain_timer;
258     audit_domain_info_t *audit_domain_timer_info;
259 
260     /* This is a list of all the bus scans currently happening, so
261        they can be properly freed. */
262     mc_ipmb_scan_info_t *bus_scans_running;
263 
264     ipmi_chan_info_t chan[MAX_IPMI_USED_CHANNELS];
265     char             chan_set[MAX_IPMI_USED_CHANNELS];
266     unsigned char    msg_int_type;
267     unsigned char    event_msg_int_type;
268 
269     /* A list of handlers to call when an MC is added to the domain. */
270     locked_list_t *mc_upd_handlers;
271     locked_list_t *mc_upd_cl_handlers;
272 
273     /* A list of IPMB addresses to not scan. */
274     ilist_t     *ipmb_ignores;
275     ipmi_lock_t *ipmb_ignores_lock;
276 
277     /* This is a timer that waits a little while before activating a
278        connection if all connections are not active.  It avoids race
279        conditions with activiation. */
280     os_hnd_timer_id_t     *activate_timer;
281     activate_timer_info_t *activate_timer_info;
282 
283     unsigned int default_sel_rescan_time;
284 
285     /* Used to inform the user that the main SDR has been read. */
286     ipmi_domain_cb SDRs_read_handler;
287     void           *SDRs_read_handler_cb_data;
288 
289     /* Used to inform OEM code that the user has been informed that
290        the connection is up. */
291     ipmi_domain_ptr_cb con_up_handler;
292     void               *con_up_handler_cb_data;
293 
294     /* Fixups for SDRs. */
295     ipmi_domain_oem_fixup_sdrs_cb fixup_sdrs_handler;
296     void                          *fixup_sdrs_cb_data;
297 
298     unsigned int       fully_up_count;
299     ipmi_domain_ptr_cb domain_fully_up;
300     void               *domain_fully_up_cb_data;
301 
302     /* Used to inform the user that the bus scanning has been done */
303     ipmi_domain_cb bus_scan_handler;
304     void           *bus_scan_handler_cb_data;
305 
306     /* If we are running a domain OEM check, then this will be the
307        check that is running.  Otherwise it is NULL. */
308     domain_check_oem_t *check;
309 
310     int                       close_count;
311     ipmi_domain_close_done_cb close_done;
312     void                      *close_done_cb_data;
313 
314     i_ipmi_domain_fru_setup_cb fru_setup_cb;
315     void                      *fru_setup_cb_data;
316 
317     /* Anonymous attributes for the domain. */
318     locked_list_t *attr;
319 
320     /* Statistics for the domain. */
321     locked_list_t *stats;
322 
323     /* Keep a linked-list of these. */
324     ipmi_domain_t *next, *prev;
325 
326     /* Cruft... */
327     struct ipmi_domain_mc_upd_s     *mc_upd_cruft;
328     struct ipmi_event_handler_id_s  *event_cruft;
329     struct ipmi_domain_con_change_s *con_change_cruft;
330 
331     ipmi_domain_entity_cb cruft_entity_update_handler;
332     void                  *cruft_entity_update_cb_data;
333 
334     ipmi_ll_stat_info_t *con_stat_info;
335 
336     /* Option processing */
337     unsigned int option_all : 1;
338     unsigned int option_SDRs : 1;
339     unsigned int option_SEL : 1;
340     unsigned int option_FRUs : 1;
341     unsigned int option_IPMB_scan : 1;
342     unsigned int option_OEM_init : 1;
343     unsigned int option_set_event_rcvr : 1;
344     unsigned int option_set_sel_time : 1;
345     unsigned int option_activate_if_possible : 1;
346     unsigned int option_local_only : 1;
347     unsigned int option_local_only_set : 1;
348     unsigned int option_use_cache : 1;
349 };
350 
351 /* A list of all domains in the system. */
352 static locked_list_t *domains_list;
353 
354 static void domain_audit(void *cb_data, os_hnd_timer_id_t *id);
355 
356 static int domain_send_mc_id(ipmi_domain_t *domain);
357 
358 static void cancel_domain_oem_check(ipmi_domain_t *domain);
359 
360 static void real_close_connection(ipmi_domain_t *domain);
361 
362 static void free_domain_cruft(ipmi_domain_t *domain);
363 
364 static void ll_con_changed(ipmi_con_t   *ipmi,
365 			   int          err,
366 			   unsigned int port_num,
367 			   int          still_connected,
368 			   void         *cb_data);
369 
370 static void ll_addr_changed(ipmi_con_t    *ipmi,
371 			    int           err,
372 			    const unsigned char ipmb_addr[],
373 			    unsigned int  num_ipmb_addr,
374 			    int           active,
375 			    unsigned int  hacks,
376 			    void          *cb_data);
377 
378 /***********************************************************************
379  *
380  * Some general utilities
381  *
382  **********************************************************************/
383 
384 static int
first_working_con(ipmi_domain_t * domain)385 first_working_con(ipmi_domain_t *domain)
386 {
387     int i;
388 
389     for (i=0; i<MAX_CONS; i++)
390 	if (domain->con_up[i])
391 	    return i;
392     return -1;
393 }
394 
395 static int
first_active_con(ipmi_domain_t * domain)396 first_active_con(ipmi_domain_t *domain)
397 {
398     int i;
399 
400     for (i=0; i<MAX_CONS; i++)
401 	if (domain->con_up[i] && domain->con_active[i])
402 	    return i;
403     return -1;
404 }
405 
406 static int
get_con_num(ipmi_domain_t * domain,ipmi_con_t * ipmi)407 get_con_num(ipmi_domain_t *domain, ipmi_con_t *ipmi)
408 {
409     int u;
410 
411     for (u=0; u<MAX_CONS; u++) {
412 	if (ipmi == domain->conn[u])
413 	    break;
414     }
415 
416     if (u == MAX_CONS) {
417 	ipmi_log(IPMI_LOG_SEVERE,
418 		 "%sdomain.c(get_con_num): "
419 		 "Got a connection change from an invalid domain",
420 		 DOMAIN_NAME(domain));
421 	return -1;
422     }
423 
424     return u;
425 }
426 
427 static void
deliver_rsp(ipmi_domain_t * domain,ipmi_addr_response_handler_t rsp_handler,ipmi_msgi_t * rspi)428 deliver_rsp(ipmi_domain_t                *domain,
429 	    ipmi_addr_response_handler_t rsp_handler,
430 	    ipmi_msgi_t                  *rspi)
431 {
432     int used = IPMI_MSG_ITEM_NOT_USED;
433 
434     if (rsp_handler)
435 	used = rsp_handler(domain, rspi);
436 
437     if (!used)
438 	ipmi_free_msg_item(rspi);
439 }
440 
441 /***********************************************************************
442  *
443  * Used for handling detecting when the domain is fully up.
444  *
445  **********************************************************************/
446 void
i_ipmi_get_domain_fully_up(ipmi_domain_t * domain,const char * name)447 i_ipmi_get_domain_fully_up(ipmi_domain_t *domain, const char *name)
448 {
449     ipmi_lock(domain->domain_lock);
450     domain->fully_up_count++;
451     ipmi_unlock(domain->domain_lock);
452 }
453 
454 void
i_ipmi_put_domain_fully_up(ipmi_domain_t * domain,const char * name)455 i_ipmi_put_domain_fully_up(ipmi_domain_t *domain, const char *name)
456 {
457     ipmi_lock(domain->domain_lock);
458     domain->fully_up_count--;
459     if (domain->fully_up_count == 0) {
460 	ipmi_domain_ptr_cb domain_fully_up;
461 	void               *domain_fully_up_cb_data;
462 
463 	domain_fully_up = domain->domain_fully_up;
464 	domain_fully_up_cb_data = domain->domain_fully_up_cb_data;
465 	domain->domain_fully_up = NULL;
466 	ipmi_unlock(domain->domain_lock);
467 	i_ipmi_entities_report_mcs_scanned(domain->entities);
468 	if (domain_fully_up)
469 	    domain_fully_up(domain, domain_fully_up_cb_data);
470 	return;
471     }
472     ipmi_unlock(domain->domain_lock);
473 }
474 
475 int
ipmi_domain_is_fully_up(ipmi_domain_t * domain)476 ipmi_domain_is_fully_up(ipmi_domain_t *domain)
477 {
478     return domain->fully_up_count == 0;
479 }
480 
481 /***********************************************************************
482  *
483  * Domain data structure creation and destruction
484  *
485  **********************************************************************/
486 
487 static locked_list_t *domain_change_handlers;
488 
489 int
ipmi_domain_add_domain_change_handler(ipmi_domain_change_cb handler,void * cb_data)490 ipmi_domain_add_domain_change_handler(ipmi_domain_change_cb handler,
491 				      void                  *cb_data)
492 {
493     if (locked_list_add(domain_change_handlers, handler, cb_data))
494 	return 0;
495     else
496 	return ENOMEM;
497 }
498 
499 int
ipmi_domain_remove_domain_change_handler(ipmi_domain_change_cb handler,void * cb_data)500 ipmi_domain_remove_domain_change_handler(ipmi_domain_change_cb handler,
501 					 void                  *cb_data)
502 {
503     if (locked_list_remove(domain_change_handlers, handler, cb_data))
504 	return 0;
505     else
506 	return EINVAL;
507 }
508 
509 typedef struct domain_change_info_s
510 {
511     enum ipmi_update_e op;
512     ipmi_domain_t      *domain;
513 } domain_change_info_t;
514 
515 static int
iterate_domain_changes(void * cb_data,void * item1,void * item2)516 iterate_domain_changes(void *cb_data, void *item1, void *item2)
517 {
518     domain_change_info_t  *info = cb_data;
519     ipmi_domain_change_cb handler = item1;
520 
521     handler(info->domain, info->op, item2);
522     return LOCKED_LIST_ITER_CONTINUE;
523 }
524 
525 static void
call_domain_change(ipmi_domain_t * domain,enum ipmi_update_e op)526 call_domain_change(ipmi_domain_t      *domain,
527 		   enum ipmi_update_e op)
528 {
529     domain_change_info_t info = { op, domain };
530     locked_list_iterate(domain_change_handlers, iterate_domain_changes, &info);
531 }
532 
533 int
i_ipmi_domain_in_shutdown(ipmi_domain_t * domain)534 i_ipmi_domain_in_shutdown(ipmi_domain_t *domain)
535 {
536     return domain->in_shutdown;
537 }
538 
539 static void
iterate_cleanup_mc(ipmi_domain_t * domain,ipmi_mc_t * mc,void * cb_data)540 iterate_cleanup_mc(ipmi_domain_t *domain, ipmi_mc_t *mc, void *cb_data)
541 {
542     i_ipmi_cleanup_mc(mc);
543 }
544 
545 void
ipmi_domain_set_oem_shutdown_handler(ipmi_domain_t * domain,ipmi_domain_shutdown_cb handler)546 ipmi_domain_set_oem_shutdown_handler(ipmi_domain_t           *domain,
547 				     ipmi_domain_shutdown_cb handler)
548 {
549     domain->shutdown_handler = handler;
550 }
551 
552 static int destroy_attr(void *cb_data, void *item1, void *item2);
553 static int destroy_stat(void *cb_data, void *item1, void *item2);
554 static void call_mc_upd_cl_handlers(ipmi_domain_t         *domain,
555 				    ipmi_domain_mc_upd_cb handler,
556 				    void                  *handler_data);
557 static void call_con_change_cl_handlers(ipmi_domain_t      *domain,
558 					ipmi_domain_con_cb handler,
559 					void               *handler_data);
560 static void call_event_handler_cl_handlers(ipmi_domain_t         *domain,
561 					   ipmi_event_handler_cb handler,
562 					   void                 *handler_data);
563 
564 static int
mc_upds_cleanup(void * cb_data,void * item1,void * item2)565 mc_upds_cleanup(void *cb_data, void *item1, void *item2)
566 {
567     call_mc_upd_cl_handlers(cb_data, item1, item2);
568     return LOCKED_LIST_ITER_CONTINUE;
569 }
570 
571 static int
con_change_cleanup(void * cb_data,void * item1,void * item2)572 con_change_cleanup(void *cb_data, void *item1, void *item2)
573 {
574     call_con_change_cl_handlers(cb_data, item1, item2);
575     return LOCKED_LIST_ITER_CONTINUE;
576 }
577 
578 static int
event_handler_cleanup(void * cb_data,void * item1,void * item2)579 event_handler_cleanup(void *cb_data, void *item1, void *item2)
580 {
581     call_event_handler_cl_handlers(cb_data, item1, item2);
582     return LOCKED_LIST_ITER_CONTINUE;
583 }
584 
585 static void
cleanup_domain(ipmi_domain_t * domain)586 cleanup_domain(ipmi_domain_t *domain)
587 {
588     unsigned int i;
589     int          rv;
590 
591     /* This must be first, so that nuking the oustanding messages will
592        cause the right thing to happen. */
593     cancel_domain_oem_check(domain);
594 
595     if (domain->attr) {
596 	locked_list_iterate(domain->attr, destroy_attr, domain);
597 	locked_list_destroy(domain->attr);
598 	domain->attr = NULL;
599     }
600 
601     if (domain->stats) {
602 	locked_list_iterate(domain->stats, destroy_stat, domain);
603 	locked_list_destroy(domain->stats);
604 	domain->stats = NULL;
605     }
606 
607     /* Nuke all outstanding messages. */
608     if ((domain->cmds_lock) && (domain->cmds)) {
609 	ll_msg_t     *nmsg;
610 	int          ok;
611 	ilist_iter_t iter;
612 
613 	ipmi_lock(domain->cmds_lock);
614 
615 	ilist_init_iter(&iter, domain->cmds);
616 	ok = ilist_first(&iter);
617 	while (ok) {
618 	    ipmi_msgi_t *rspi;
619 
620 	    nmsg = ilist_get(&iter);
621 	    rspi = nmsg->rsp_item;
622 
623 	    rspi->msg.netfn = nmsg->msg.netfn | 1;
624 	    rspi->msg.cmd = nmsg->msg.cmd;
625 	    rspi->msg.data = rspi->data;
626 	    rspi->msg.data_len = 1;
627 	    rspi->msg.data[0] = IPMI_UNKNOWN_ERR_CC;
628 	    deliver_rsp(domain, nmsg->rsp_handler, rspi);
629 
630 	    ilist_delete(&iter);
631 	    ipmi_mem_free(nmsg);
632 	    ok = ilist_first(&iter);
633 	}
634 	ipmi_unlock(domain->cmds_lock);
635     }
636     if (domain->cmds_lock)
637 	ipmi_destroy_lock(domain->cmds_lock);
638     if (domain->cmds)
639 	free_ilist(domain->cmds);
640 
641     /* Shutdown code called here. */
642     if (domain->shutdown_handler)
643 	domain->shutdown_handler(domain);
644 
645     /* Delete the sensors from the main SDR repository. */
646     if (domain->sensors_in_main_sdr) {
647 	for (i=0; i<domain->sensors_in_main_sdr_count; i++) {
648 	    i_ipmi_domain_entity_lock(domain);
649 	    if (domain->sensors_in_main_sdr[i]) {
650 		ipmi_sensor_t *sensor = domain->sensors_in_main_sdr[i];
651 		ipmi_entity_t *entity = ipmi_sensor_get_entity(sensor);
652 		ipmi_mc_t     *mc = ipmi_sensor_get_mc(sensor);
653 		i_ipmi_entity_get(entity);
654 		i_ipmi_sensor_get(sensor);
655 		i_ipmi_domain_entity_unlock(domain);
656 		i_ipmi_domain_mc_lock(domain);
657 		i_ipmi_mc_get(mc);
658 		i_ipmi_domain_mc_unlock(domain);
659 		ipmi_sensor_destroy(domain->sensors_in_main_sdr[i]);
660 		i_ipmi_sensor_put(sensor);
661 		i_ipmi_mc_put(mc);
662 		i_ipmi_entity_put(entity);
663 	    } else
664 		i_ipmi_domain_entity_unlock(domain);
665 	}
666 	ipmi_mem_free(domain->sensors_in_main_sdr);
667     }
668 
669     if (domain->entities_in_main_sdr) {
670 	ipmi_sdr_entity_destroy(domain->entities_in_main_sdr);
671 	domain->entities_in_main_sdr = NULL;
672     }
673 
674     if (domain->activate_timer_info) {
675 	if (domain->activate_timer_info->lock) {
676 	    ipmi_lock(domain->activate_timer_info->lock);
677 	    if (domain->activate_timer) {
678 		int arv = 0;
679 		if (domain->activate_timer_info->running)
680 		    arv = domain->os_hnd->stop_timer(domain->os_hnd,
681 						     domain->activate_timer);
682 
683 		if (!arv) {
684 		    /* If we can stop the timer, free it and it's info.
685 		       If we can't stop the timer, that means that the
686 		       code is currently in the timer handler, so we let
687 		       the "cancelled" value do this for us. */
688 		    domain->os_hnd->free_timer(domain->os_hnd,
689 					       domain->activate_timer);
690 		    ipmi_unlock(domain->activate_timer_info->lock);
691 		    ipmi_destroy_lock(domain->activate_timer_info->lock);
692 		    ipmi_mem_free(domain->activate_timer_info);
693 		} else {
694 		    domain->activate_timer_info->cancelled = 1;
695 		    ipmi_unlock(domain->activate_timer_info->lock);
696 		}
697 	    } else {
698 		ipmi_unlock(domain->activate_timer_info->lock);
699 		ipmi_destroy_lock(domain->activate_timer_info->lock);
700 	    }
701 	} else {
702 	    ipmi_mem_free(domain->activate_timer_info);
703 	}
704     }
705 
706     /* We cleanup the MCs twice.  Some MCs may not be destroyed (but
707        only left inactive) in the first pass due to references form
708        other MCs SDR repositories.  The second pass will get them
709        all. */
710     ipmi_domain_iterate_mcs(domain, iterate_cleanup_mc, NULL);
711     ipmi_domain_iterate_mcs(domain, iterate_cleanup_mc, NULL);
712 
713     if (domain->si_mc) {
714 	i_ipmi_mc_get(domain->si_mc);
715 	i_ipmi_mc_release(domain->si_mc);
716 	i_ipmi_cleanup_mc(domain->si_mc);
717 	i_ipmi_mc_put(domain->si_mc);
718     }
719 
720     /* Destroy the main SDR repository, if it exists. */
721     if (domain->main_sdrs)
722 	ipmi_sdr_info_destroy(domain->main_sdrs, NULL, NULL);
723 
724     if (domain->audit_domain_timer_info) {
725 	domain->audit_domain_timer_info->cancelled = 1;
726 	ipmi_lock(domain->audit_domain_timer_info->lock);
727 	rv = domain->os_hnd->stop_timer(domain->os_hnd,
728 					domain->audit_domain_timer);
729 	ipmi_unlock(domain->audit_domain_timer_info->lock);
730 	if (!rv) {
731 	    /* If we can stop the timer or it wasn't running, free it
732 	       and it's info.  If we can't stop the timer, that means
733 	       that the code is currently in the timer handler, so we
734 	       let the "cancelled" value do this for us. */
735 	    if (domain->audit_domain_timer)
736 		domain->os_hnd->free_timer(domain->os_hnd,
737 					   domain->audit_domain_timer);
738 	    if (domain->audit_domain_timer_info->lock)
739 		ipmi_destroy_lock(domain->audit_domain_timer_info->lock);
740 	    ipmi_mem_free(domain->audit_domain_timer_info);
741 	}
742     }
743 
744     if (domain->event_handlers) {
745 	locked_list_iterate(domain->event_handlers, event_handler_cleanup,
746 			    domain);
747 	locked_list_destroy(domain->event_handlers);
748     }
749     if (domain->event_handlers_cl)
750 	locked_list_destroy(domain->event_handlers_cl);
751 
752     if (domain->con_change_handlers) {
753 	locked_list_iterate(domain->con_change_handlers, con_change_cleanup,
754 			    domain);
755 	locked_list_destroy(domain->con_change_handlers);
756     }
757     if (domain->con_change_cl_handlers)
758 	locked_list_destroy(domain->con_change_cl_handlers);
759 
760     if (domain->new_sensor_handlers)
761         locked_list_destroy(domain->new_sensor_handlers);
762 
763     if (domain->ipmb_ignores) {
764 	ilist_iter_t iter;
765 	ilist_init_iter(&iter, domain->ipmb_ignores);
766 	while (ilist_first(&iter)) {
767 	    ilist_delete(&iter);
768 	}
769 	free_ilist(domain->ipmb_ignores);
770     }
771     if (domain->bus_scans_running) {
772 	mc_ipmb_scan_info_t *item;
773 	while (domain->bus_scans_running) {
774 	    item = domain->bus_scans_running;
775 	    domain->bus_scans_running = item->next;
776 	    ipmi_lock(item->lock);
777 	    if (item->timer_running) {
778 		if (item->os_hnd->stop_timer(item->os_hnd, item->timer)) {
779 		    item->cancelled = 1;
780 		    ipmi_unlock(item->lock);
781 		    item = NULL;
782 		}
783 	    }
784 	    if (item) {
785 		ipmi_unlock(item->lock);
786 		item->os_hnd->free_timer(item->os_hnd, item->timer);
787 		ipmi_destroy_lock(item->lock);
788 		ipmi_mem_free(item);
789 	    }
790 	}
791     }
792 
793     /* Destroy the entities last, since sensors and controls may
794        refer to them. */
795     if (domain->entities)
796 	ipmi_entity_info_destroy(domain->entities);
797     if (domain->entities_lock)
798 	ipmi_destroy_lock(domain->entities_lock);
799 
800     call_domain_change(domain, IPMI_DELETED);
801 
802     /* The MC list should no longer have anything in it. */
803     if (domain->mc_upd_handlers) {
804 	locked_list_iterate(domain->mc_upd_handlers, mc_upds_cleanup, domain);
805 	locked_list_destroy(domain->mc_upd_handlers);
806     }
807     if (domain->mc_upd_cl_handlers)
808 	locked_list_destroy(domain->mc_upd_cl_handlers);
809 
810     for (i=0; i<IPMB_HASH; i++) {
811 	if (domain->ipmb_mcs[i].mcs)
812 	    ipmi_mem_free(domain->ipmb_mcs[i].mcs);
813     }
814 
815     /* We wait until here to call the OEM data destroyer, the process
816        of destroying information that has previously gone on can call
817        OEM callbacks, we want the OEM data to hang around until we
818        don't need it for sure. */
819     if (domain->oem_data && domain->oem_data_destroyer)
820 	domain->oem_data_destroyer(domain, domain->oem_data);
821 
822     if (domain->con_stat_info)
823 	ipmi_ll_con_free_stat_info(domain->con_stat_info);
824 
825     /* Locks must be last, because they can be used by many things. */
826     if (domain->ipmb_ignores_lock)
827 	ipmi_destroy_lock(domain->ipmb_ignores_lock);
828     if (domain->mc_lock)
829 	ipmi_destroy_lock(domain->mc_lock);
830     if (domain->con_lock)
831 	ipmi_destroy_lock(domain->con_lock);
832     if (domain->domain_lock)
833 	ipmi_destroy_lock(domain->domain_lock);
834 
835     /* Cruft */
836     free_domain_cruft(domain);
837 
838     ipmi_mem_free(domain);
839 }
840 
con_register_stat(ipmi_ll_stat_info_t * info,const char * name,const char * instance,void ** stat)841 static int con_register_stat(ipmi_ll_stat_info_t *info,
842 			     const char          *name,
843 			     const char          *instance,
844 			     void                **stat)
845 {
846     ipmi_domain_stat_t *rstat = NULL;
847     int                rv;
848     ipmi_domain_t      *domain = ipmi_ll_con_stat_get_user_data(info);
849 
850     rv = ipmi_domain_stat_register(domain, name, instance, &rstat);
851     if (!rv)
852 	*stat = rstat;
853     return rv;
854 }
855 
con_add_stat(ipmi_ll_stat_info_t * info,void * stat,int value)856 static void con_add_stat(ipmi_ll_stat_info_t *info,
857 			 void                *stat,
858 			 int                 value)
859 {
860     ipmi_domain_stat_add(stat, value);
861 }
862 
con_unregister_stat(ipmi_ll_stat_info_t * info,void * stat)863 static void con_unregister_stat(ipmi_ll_stat_info_t *info,
864 				void                *stat)
865 {
866     ipmi_domain_stat_put(stat);
867 }
868 
869 static int
process_options(ipmi_domain_t * domain,ipmi_open_option_t * options,unsigned int num_options)870 process_options(ipmi_domain_t      *domain,
871 		ipmi_open_option_t *options,
872 		unsigned int       num_options)
873 {
874     unsigned int i;
875 
876     /* Option processing. */
877     for (i=0; i<num_options; i++) {
878 	switch (options[i].option) {
879 	case IPMI_OPEN_OPTION_ALL:
880 	    domain->option_all = options[i].ival != 0;
881 	    break;
882 	case IPMI_OPEN_OPTION_SDRS:
883 	    domain->option_SDRs = options[i].ival != 0;
884 	    break;
885 	case IPMI_OPEN_OPTION_FRUS:
886 	    domain->option_FRUs = options[i].ival != 0;
887 	    break;
888 	case IPMI_OPEN_OPTION_SEL:
889 	    domain->option_SEL = options[i].ival != 0;
890 	    break;
891 	case IPMI_OPEN_OPTION_IPMB_SCAN:
892 	    domain->option_IPMB_scan = options[i].ival != 0;
893 	    break;
894 	case IPMI_OPEN_OPTION_OEM_INIT:
895 	    domain->option_OEM_init = options[i].ival != 0;
896 	    break;
897 	case IPMI_OPEN_OPTION_SET_EVENT_RCVR:
898 	    domain->option_set_event_rcvr = options[i].ival != 0;
899 	    break;
900 	case IPMI_OPEN_OPTION_SET_SEL_TIME:
901 	    domain->option_set_sel_time = options[i].ival != 0;
902 	    break;
903 	case IPMI_OPEN_OPTION_USE_CACHE:
904 	    domain->option_use_cache = options[i].ival != 0;
905 	    break;
906 	case IPMI_OPEN_OPTION_ACTIVATE_IF_POSSIBLE:
907 	    domain->option_activate_if_possible = options[i].ival != 0;
908 	    break;
909 	case IPMI_OPEN_OPTION_LOCAL_ONLY:
910 	    domain->option_local_only = options[i].ival != 0;
911 	    domain->option_local_only_set = 1;
912 	    break;
913 	default:
914 	    return EINVAL;
915 	}
916     }
917 
918     return 0;
919 }
920 
921 static int
setup_domain(const char * name,ipmi_con_t * ipmi[],int num_con,ipmi_open_option_t * options,unsigned int num_options,ipmi_domain_t ** new_domain)922 setup_domain(const char         *name,
923 	     ipmi_con_t         *ipmi[],
924 	     int                num_con,
925 	     ipmi_open_option_t *options,
926 	     unsigned int       num_options,
927 	     ipmi_domain_t      **new_domain)
928 {
929     struct timeval               timeout;
930     ipmi_domain_t                *domain;
931     int                          rv;
932     ipmi_system_interface_addr_t si;
933     int                          i, j;
934     unsigned int                 priv;
935 
936     /* Don't allow '(' in the domain name, as that messes up the
937        naming.  That is the only restriction. */
938     if (strchr(name, '('))
939 	return EINVAL;
940 
941     domain = ipmi_mem_alloc(sizeof(*domain));
942     if (!domain)
943 	return ENOMEM;
944     memset(domain, 0, sizeof(*domain));
945 
946     domain->in_startup = 1;
947     domain->option_all = 1;
948     domain->option_set_event_rcvr = 1;
949     domain->option_set_sel_time = 1;
950     domain->option_activate_if_possible = 1;
951     domain->option_local_only = 0;
952     domain->option_local_only_set = 0;
953     domain->option_use_cache = 1;
954 
955     priv = IPMI_PRIVILEGE_ADMIN;
956     for (i=0; i<num_con; i++) {
957 	/* Find the least-common demominator privilege for the
958 	   connections. */
959 	if ((ipmi[i]->priv_level != 0) && (ipmi[i]->priv_level < priv))
960 	    priv = ipmi[i]->priv_level;
961     }
962 
963     /* Enable setting the event receiver (by default) if the privilege
964        is admin or greater. */
965     domain->option_set_event_rcvr = (priv >= IPMI_PRIVILEGE_ADMIN);
966     domain->option_set_sel_time = (priv >= IPMI_PRIVILEGE_ADMIN);
967 
968     if (options)
969 	process_options(domain, options, num_options);
970 
971     strncpy(domain->name, name, sizeof(domain->name)-2);
972     i = strlen(domain->name);
973     if (i > 0) {
974 	domain->name[i] = ' ';
975 	domain->name[i+1] = '\0';
976     }
977 
978     domain->os_hnd = ipmi[0]->os_hnd;
979 
980     domain->valid = 1;
981     domain->in_shutdown = 0;
982     domain->usecount = 1;
983 
984     domain->stats = locked_list_alloc(domain->os_hnd);
985     if (!domain->stats) {
986 	ipmi_mem_free(domain);
987 	return ENOMEM;
988     }
989 
990     domain->con_stat_info = ipmi_ll_con_alloc_stat_info();
991     if (!domain->con_stat_info) {
992 	locked_list_destroy(domain->stats);
993 	ipmi_mem_free(domain);
994 	return ENOMEM;
995     }
996     ipmi_ll_con_stat_info_set_register(domain->con_stat_info,
997 				       con_register_stat);
998     ipmi_ll_con_stat_info_set_adder(domain->con_stat_info, con_add_stat);
999     ipmi_ll_con_stat_info_set_unregister(domain->con_stat_info,
1000 					 con_unregister_stat);
1001     ipmi_ll_con_stat_set_user_data(domain->con_stat_info, domain);
1002 
1003     for (i=0; i<num_con; i++) {
1004 	int len1 = strlen(domain->name);
1005 	domain->conn[i] = ipmi[i];
1006 	for (j=0; j<MAX_IPMI_USED_CHANNELS; j++)
1007 	    domain->con_ipmb_addr[i][j] = 0x20;
1008 	domain->con_active[i] = 1;
1009 	domain->con_up[i] = 0;
1010 	ipmi[i]->name = ipmi_mem_alloc(len1 + 11);
1011 	if (ipmi[i]->name)
1012 	    snprintf(ipmi[i]->name, len1 + 11, "%s%d ", domain->name, i);
1013 	ipmi[i]->user_data = domain;
1014 
1015 	for (j=0; j<MAX_PORTS_PER_CON; j++)
1016 	    domain->port_up[j][i] = -1;
1017 
1018 	if (ipmi[i]->register_stat_handler)
1019 	    ipmi[i]->register_stat_handler(ipmi[i], domain->con_stat_info);
1020     }
1021 
1022     domain->connection_up = 0;
1023 
1024     /* Create the locks before anything else. */
1025     domain->default_sel_rescan_time = IPMI_SEL_QUERY_INTERVAL;
1026 
1027     /* Set the default timer intervals. */
1028     domain->audit_domain_interval = IPMI_AUDIT_DOMAIN_INTERVAL;
1029 
1030     rv = ipmi_create_lock(domain, &domain->mc_lock);
1031     if (rv)
1032 	goto out_err;
1033 
1034     rv = ipmi_create_lock(domain, &domain->con_lock);
1035     if (rv)
1036 	goto out_err;
1037 
1038     rv = ipmi_create_lock(domain, &domain->domain_lock);
1039     if (rv)
1040 	goto out_err;
1041 
1042     rv = ipmi_create_lock(domain, &domain->entities_lock);
1043     if (rv)
1044 	goto out_err;
1045 
1046     domain->activate_timer_info = ipmi_mem_alloc(sizeof(activate_timer_info_t));
1047     if (!domain->activate_timer_info) {
1048 	rv = ENOMEM;
1049 	goto out_err;
1050     }
1051 
1052     domain->activate_timer_info->lock = NULL;
1053     domain->activate_timer_info->domain = domain;
1054     domain->activate_timer_info->cancelled = 0;
1055     domain->activate_timer_info->os_hnd = domain->os_hnd;
1056     domain->activate_timer_info->running = 0;
1057 
1058     rv = ipmi_create_lock(domain, &domain->activate_timer_info->lock);
1059     if (rv)
1060 	goto out_err;
1061 
1062     rv = domain->os_hnd->alloc_timer(domain->os_hnd,
1063 				     &(domain->activate_timer));
1064     if (rv)
1065 	goto out_err;
1066 
1067     domain->event_handlers_cl = locked_list_alloc(domain->os_hnd);
1068     if (!domain->event_handlers_cl) {
1069 	rv = ENOMEM;
1070 	goto out_err;
1071     }
1072 
1073     domain->event_handlers = locked_list_alloc(domain->os_hnd);
1074     if (!domain->event_handlers) {
1075 	rv = ENOMEM;
1076 	goto out_err;
1077     }
1078 
1079     domain->attr = locked_list_alloc(domain->os_hnd);
1080     if (!domain->attr) {
1081 	rv = ENOMEM;
1082 	goto out_err;
1083     }
1084 
1085     domain->do_bus_scan = 1;
1086 
1087     si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
1088     si.channel = IPMI_BMC_CHANNEL;
1089     si.lun = 0;
1090     rv = i_ipmi_create_mc(domain,
1091 			  (ipmi_addr_t *) &si, sizeof(si),
1092 			  &domain->si_mc);
1093     if (rv)
1094 	goto out_err;
1095     i_ipmi_mc_use(domain->si_mc);
1096 
1097     /* Force this one to always be active, so anything that uses it is
1098        always ready to go.  Since it represents the connection, it
1099        really can't ever go inactive. */
1100     i_ipmi_mc_force_active(domain->si_mc, 1);
1101 
1102     rv = ipmi_sdr_info_alloc(domain, domain->si_mc, 0, 0, &domain->main_sdrs);
1103     if (rv)
1104 	goto out_err;
1105 
1106     rv = ipmi_create_lock(domain, &domain->cmds_lock);
1107     if (rv)
1108 	goto out_err;
1109 
1110     domain->cmds = alloc_ilist();
1111     if (! domain->cmds) {
1112 	rv = ENOMEM;
1113 	goto out_err;
1114     }
1115 
1116     domain->con_change_cl_handlers = locked_list_alloc(domain->os_hnd);
1117     if (! domain->con_change_cl_handlers) {
1118 	rv = ENOMEM;
1119 	goto out_err;
1120     }
1121 
1122     domain->con_change_handlers = locked_list_alloc(domain->os_hnd);
1123     if (! domain->con_change_handlers) {
1124 	rv = ENOMEM;
1125 	goto out_err;
1126     }
1127 
1128     domain->mc_upd_cl_handlers = locked_list_alloc(domain->os_hnd);
1129     if (! domain->mc_upd_cl_handlers) {
1130 	rv = ENOMEM;
1131 	goto out_err;
1132     }
1133 
1134     domain->mc_upd_handlers = locked_list_alloc(domain->os_hnd);
1135     if (! domain->mc_upd_handlers) {
1136 	rv = ENOMEM;
1137 	goto out_err;
1138     }
1139 
1140     domain->new_sensor_handlers = locked_list_alloc(domain->os_hnd);
1141     if (! domain->new_sensor_handlers) {
1142         rv = ENOMEM;
1143         goto out_err;
1144     }
1145 
1146     rv = ipmi_create_lock(domain, &domain->ipmb_ignores_lock);
1147     if (rv)
1148 	goto out_err;
1149 
1150     domain->ipmb_ignores = alloc_ilist();
1151     if (! domain->ipmb_ignores) {
1152 	rv = ENOMEM;
1153 	goto out_err;
1154     }
1155 
1156     domain->bus_scans_running = NULL;
1157 
1158     domain->audit_domain_timer_info
1159 	= ipmi_mem_alloc(sizeof(audit_domain_info_t));
1160     if (!domain->audit_domain_timer_info) {
1161 	rv = ENOMEM;
1162 	goto out_err;
1163     }
1164     memset(domain->audit_domain_timer_info, 0, sizeof(audit_domain_info_t));
1165 
1166     domain->audit_domain_timer_info->domain = domain;
1167     domain->audit_domain_timer_info->os_hnd = domain->os_hnd;
1168     domain->audit_domain_timer_info->cancelled = 0;
1169     rv = ipmi_create_lock(domain, &domain->audit_domain_timer_info->lock);
1170     if (rv)
1171 	goto out_err;
1172     rv = domain->os_hnd->alloc_timer(domain->os_hnd,
1173 				     &(domain->audit_domain_timer));
1174     if (rv)
1175 	goto out_err;
1176 
1177     timeout.tv_sec = domain->audit_domain_interval;
1178     timeout.tv_usec = 0;
1179     domain->os_hnd->start_timer(domain->os_hnd,
1180 				domain->audit_domain_timer,
1181 				&timeout,
1182 				domain_audit,
1183 				domain->audit_domain_timer_info);
1184 
1185     rv = ipmi_entity_info_alloc(domain, &(domain->entities));
1186     if (rv)
1187 	goto out_err;
1188 
1189     memset(domain->chan, 0, sizeof(domain->chan));
1190 
1191  out_err:
1192     if (domain->si_mc)
1193 	i_ipmi_mc_put(domain->si_mc);
1194 
1195     if (rv) {
1196 	for (i=0; i<num_con; i++) {
1197 	    if (ipmi[i]->register_stat_handler)
1198 		ipmi[i]->unregister_stat_handler(ipmi[i],
1199 						 domain->con_stat_info);
1200 	}
1201 	cleanup_domain(domain);
1202     } else
1203 	*new_domain = domain;
1204 
1205     return rv;
1206 }
1207 
1208 /***********************************************************************
1209  *
1210  * Locking handling
1211  *
1212  **********************************************************************/
1213 
1214 #ifdef IPMI_CHECK_LOCKS
1215 void
i__ipmi_check_domain_lock(const ipmi_domain_t * domain)1216 i__ipmi_check_domain_lock(const ipmi_domain_t *domain)
1217 {
1218     if (!domain)
1219 	return;
1220 
1221     if (!DEBUG_LOCKS)
1222 	return;
1223 
1224     if (domain->usecount == 0)
1225 	ipmi_report_lock_error(domain->os_hnd,
1226 			       "domain not locked when it should have been");
1227 }
1228 #endif
1229 
1230 void
i_ipmi_domain_entity_lock(ipmi_domain_t * domain)1231 i_ipmi_domain_entity_lock(ipmi_domain_t *domain)
1232 {
1233 
1234     CHECK_DOMAIN_LOCK(domain);
1235     ipmi_lock(domain->entities_lock);
1236 }
1237 
1238 void
i_ipmi_domain_entity_unlock(ipmi_domain_t * domain)1239 i_ipmi_domain_entity_unlock(ipmi_domain_t *domain)
1240 {
1241     CHECK_DOMAIN_LOCK(domain);
1242     ipmi_unlock(domain->entities_lock);
1243 }
1244 
1245 void
i_ipmi_domain_mc_lock(ipmi_domain_t * domain)1246 i_ipmi_domain_mc_lock(ipmi_domain_t *domain)
1247 {
1248 
1249     CHECK_DOMAIN_LOCK(domain);
1250     ipmi_lock(domain->mc_lock);
1251 }
1252 
1253 void
i_ipmi_domain_mc_unlock(ipmi_domain_t * domain)1254 i_ipmi_domain_mc_unlock(ipmi_domain_t *domain)
1255 {
1256     CHECK_DOMAIN_LOCK(domain);
1257     ipmi_unlock(domain->mc_lock);
1258 }
1259 
1260 /***********************************************************************
1261  *
1262  * Domain validation
1263  *
1264  **********************************************************************/
1265 
1266 /* A open hash table of all the registered domains. */
1267 #define DOMAIN_HASH_SIZE 128
1268 static ipmi_domain_t *domains[DOMAIN_HASH_SIZE];
1269 static ipmi_lock_t *domains_lock;
1270 static int domains_initialized = 0;
1271 
1272 static void
add_known_domain(ipmi_domain_t * domain)1273 add_known_domain(ipmi_domain_t *domain)
1274 {
1275     unsigned int hash = ipmi_hash_pointer(domain) % DOMAIN_HASH_SIZE;
1276 
1277     ipmi_lock(domains_lock);
1278 
1279     domain->prev = NULL;
1280     domain->next = domains[hash];
1281     if (domains[hash])
1282 	domains[hash]->prev = domain;
1283     domains[hash] = domain;
1284 
1285     ipmi_unlock(domains_lock);
1286 }
1287 
1288 static void
remove_known_domain(ipmi_domain_t * domain)1289 remove_known_domain(ipmi_domain_t *domain)
1290 {
1291     ipmi_lock(domains_lock);
1292 
1293     if (domain->next)
1294 	domain->next->prev = domain->prev;
1295     if (domain->prev)
1296 	domain->prev->next = domain->next;
1297     else {
1298 	unsigned int hash = ipmi_hash_pointer(domain) % DOMAIN_HASH_SIZE;
1299 	domains[hash] = domain->next;
1300     }
1301 
1302     ipmi_unlock(domains_lock);
1303 }
1304 
1305 /* Validate that the domain and it's underlying connection is valid
1306    and increment its use count. */
1307 int
i_ipmi_domain_get(ipmi_domain_t * domain)1308 i_ipmi_domain_get(ipmi_domain_t *domain)
1309 {
1310     unsigned int  hash = ipmi_hash_pointer(domain) % DOMAIN_HASH_SIZE;
1311     ipmi_domain_t *c;
1312     int           rv = 0;
1313 
1314     if (!domains_initialized)
1315 	    return ECANCELED;
1316 
1317     ipmi_lock(domains_lock);
1318 
1319     c = domains[hash];
1320     while (c != NULL) {
1321 	if (c == domain)
1322 	    break;
1323 	c = c->next;
1324     }
1325     if (c == NULL) {
1326 	rv = EINVAL;
1327 	goto out;
1328     }
1329 
1330     /* We do this check after we find the domain in the list, because
1331        want to make sure the pointer is good before we do this. */
1332     if (!domain->valid) {
1333 	rv = EINVAL;
1334 	goto out;
1335     }
1336 
1337     domain->usecount++;
1338 
1339  out:
1340     ipmi_unlock(domains_lock);
1341 
1342     return rv;
1343 }
1344 
1345 void
i_ipmi_domain_put(ipmi_domain_t * domain)1346 i_ipmi_domain_put(ipmi_domain_t *domain)
1347 {
1348     ipmi_lock(domains_lock);
1349 
1350     if ((domain->usecount == 1) && (domain->in_shutdown)) {
1351 	ipmi_unlock(domains_lock);
1352 	/* The domain has been destroyed, finish the process. */
1353 	real_close_connection(domain);
1354 	return;
1355     }
1356 
1357     domain->usecount--;
1358 
1359     ipmi_unlock(domains_lock);
1360 }
1361 
1362 /***********************************************************************
1363  *
1364  * Handle global OEM callbacks new domains.
1365  *
1366  **********************************************************************/
1367 typedef struct oem_handlers_s {
1368     ipmi_domain_oem_check check;
1369     void                  *cb_data;
1370 } oem_handlers_t;
1371 
1372 /* FIXME - do we need a lock?  Probably, add it. */
1373 static ilist_t *oem_handlers;
1374 
1375 int
ipmi_register_domain_oem_check(ipmi_domain_oem_check check,void * cb_data)1376 ipmi_register_domain_oem_check(ipmi_domain_oem_check check,
1377 			       void                  *cb_data)
1378 {
1379     oem_handlers_t *new_item;
1380 
1381     new_item = ipmi_mem_alloc(sizeof(*new_item));
1382     if (!new_item)
1383 	return ENOMEM;
1384 
1385     new_item->check = check;
1386     new_item->cb_data = cb_data;
1387 
1388     if (! ilist_add_tail(oem_handlers, new_item, NULL)) {
1389 	ipmi_mem_free(new_item);
1390 	return ENOMEM;
1391     }
1392 
1393     return 0;
1394 }
1395 
1396 static int
oem_handler_cmp(void * item,void * cb_data)1397 oem_handler_cmp(void *item, void *cb_data)
1398 {
1399     oem_handlers_t *hndlr = item;
1400     oem_handlers_t *cmp = cb_data;
1401 
1402     return ((hndlr->check == cmp->check)
1403 	    && (hndlr->cb_data == cmp->cb_data));
1404 }
1405 
1406 int
ipmi_deregister_domain_oem_check(ipmi_domain_oem_check check,void * cb_data)1407 ipmi_deregister_domain_oem_check(ipmi_domain_oem_check check,
1408 				 void                  *cb_data)
1409 {
1410     oem_handlers_t *hndlr;
1411     oem_handlers_t tmp;
1412     ilist_iter_t   iter;
1413 
1414     tmp.check = check;
1415     tmp.cb_data = cb_data;
1416     ilist_init_iter(&iter, oem_handlers);
1417     ilist_unpositioned(&iter);
1418     hndlr = ilist_search_iter(&iter, oem_handler_cmp, &tmp);
1419     if (hndlr) {
1420 	ilist_delete(&iter);
1421 	ipmi_mem_free(hndlr);
1422 	return 0;
1423     }
1424     return ENOENT;
1425 }
1426 
1427 struct domain_check_oem_s
1428 {
1429     int                        cancelled;
1430     ipmi_domain_oem_check_done done;
1431     void                       *cb_data;
1432     oem_handlers_t             *curr_handler;
1433 };
1434 
1435 static void domain_oem_check_done(ipmi_domain_t *domain,
1436 				  int           err,
1437 				  void          *cb_data);
1438 
1439 static void
start_oem_domain_check(ipmi_domain_t * domain,domain_check_oem_t * check)1440 start_oem_domain_check(ipmi_domain_t      *domain,
1441 		       domain_check_oem_t *check)
1442 {
1443     ilist_iter_t     iter;
1444 
1445     ilist_init_iter(&iter, oem_handlers);
1446     if (!ilist_first(&iter)) {
1447 	/* Empty list, just go on */
1448 	check->done(domain, 0, check->cb_data);
1449 	ipmi_mem_free(check);
1450 	goto out;
1451     } else {
1452 	oem_handlers_t *h = ilist_get(&iter);
1453 	int            rv = ENOSYS;
1454 
1455 	while (rv) {
1456 	    check->curr_handler = h;
1457 	    rv = h->check(domain, domain_oem_check_done, check);
1458 	    if (!rv)
1459 		break;
1460 	    if (rv != ENOSYS)
1461 		break;
1462 	    if (!ilist_next(&iter)) {
1463 		/* End of list, just go on */
1464 		check->done(domain, 0, check->cb_data);
1465 		ipmi_mem_free(check);
1466 		goto out;
1467 	    }
1468 	    h = ilist_get(&iter);
1469 	}
1470 	if (rv) {
1471 	    if (rv == ENOSYS)
1472 		/* This just means that we didn't match anything. */
1473 		rv = 0;
1474 
1475 	    /* We didn't get a check to start, just give up. */
1476 	    check->done(domain, rv, check->cb_data);
1477 	    ipmi_mem_free(check);
1478 	}
1479     }
1480  out:
1481     return;
1482 }
1483 
1484 static int
oem_handler_cmp2(void * item,void * cb_data)1485 oem_handler_cmp2(void *item, void *cb_data)
1486 {
1487     oem_handlers_t *hndlr = item;
1488     oem_handlers_t *cmp = cb_data;
1489 
1490     return (hndlr == cmp);
1491 }
1492 
1493 static void
next_oem_domain_check(ipmi_domain_t * domain,domain_check_oem_t * check)1494 next_oem_domain_check(ipmi_domain_t      *domain,
1495 		      domain_check_oem_t *check)
1496 {
1497     oem_handlers_t *h;
1498     ilist_iter_t   iter;
1499 
1500     /* We can't keep an interater in the check, because the list may
1501        change during execution. */
1502     ilist_init_iter(&iter, oem_handlers);
1503     ilist_unpositioned(&iter);
1504     h = ilist_search_iter(&iter, oem_handler_cmp2, check->curr_handler);
1505     if (!h) {
1506 	/* The current handler we were working on went away, start over. */
1507 	start_oem_domain_check(domain, check);
1508     } else {
1509 	int rv = 1;
1510 
1511 	while (rv) {
1512 	    if (!ilist_next(&iter)) {
1513 		/* End of list, just go on */
1514 		check->done(domain, 0, check->cb_data);
1515 		ipmi_mem_free(check);
1516 		goto out;
1517 	    }
1518 	    h = ilist_get(&iter);
1519 	    check->curr_handler = h;
1520 	    rv = h->check(domain, domain_oem_check_done, check);
1521 	}
1522 	if (rv) {
1523 	    /* We didn't get a check to start, just give up. */
1524 	    check->done(domain, 0, check->cb_data);
1525 	    ipmi_mem_free(check);
1526 	}
1527     }
1528  out:
1529     return;
1530 }
1531 
1532 static void
domain_oem_check_done(ipmi_domain_t * domain,int err,void * cb_data)1533 domain_oem_check_done(ipmi_domain_t *domain,
1534 		      int           err,
1535 		      void          *cb_data)
1536 {
1537     domain_check_oem_t *check = cb_data;
1538 
1539     if (check->cancelled) {
1540 	check->done(NULL, ECANCELED, check->cb_data);
1541 	ipmi_mem_free(check);
1542 	return;
1543     }
1544 
1545     if (err != ENOSYS) {
1546 	/* Either we got a success or some error trying to install the
1547 	   OEM handlers. */
1548 	check->done(domain, err, check->cb_data);
1549 	ipmi_mem_free(check);
1550 	return;
1551     }
1552 
1553     next_oem_domain_check(domain, check);
1554 }
1555 
1556 static int
check_oem_handlers(ipmi_domain_t * domain,ipmi_domain_oem_check_done done,void * cb_data)1557 check_oem_handlers(ipmi_domain_t              *domain,
1558 		   ipmi_domain_oem_check_done done,
1559 		   void                       *cb_data)
1560 {
1561     domain_check_oem_t *check;
1562 
1563     check = ipmi_mem_alloc(sizeof(*check));
1564     if (!check)
1565 	return ENOMEM;
1566 
1567     check->done = done;
1568     check->cb_data = cb_data;
1569     check->cancelled = 0;
1570 
1571     start_oem_domain_check(domain, check);
1572 
1573     return 0;
1574 }
1575 
1576 static void
cancel_domain_oem_check(ipmi_domain_t * domain)1577 cancel_domain_oem_check(ipmi_domain_t *domain)
1578 {
1579     if (domain->check)
1580 	domain->check->cancelled = 1;
1581 }
1582 
1583 /***********************************************************************
1584  *
1585  * FRU data handling
1586  *
1587  **********************************************************************/
i_ipmi_domain_fru_set_special_setup(ipmi_domain_t * domain,i_ipmi_domain_fru_setup_cb setup,void * cb_data)1588 int i_ipmi_domain_fru_set_special_setup(ipmi_domain_t             *domain,
1589 					i_ipmi_domain_fru_setup_cb setup,
1590 					void                      *cb_data)
1591 {
1592     domain->fru_setup_cb = setup;
1593     domain->fru_setup_cb_data = cb_data;
1594     return 0;
1595 }
1596 
i_ipmi_domain_fru_call_special_setup(ipmi_domain_t * domain,unsigned char is_logical,unsigned char device_address,unsigned char device_id,unsigned char lun,unsigned char private_bus,unsigned char channel,ipmi_fru_t * fru)1597 int i_ipmi_domain_fru_call_special_setup(ipmi_domain_t *domain,
1598 					 unsigned char is_logical,
1599 					 unsigned char device_address,
1600 					 unsigned char device_id,
1601 					 unsigned char lun,
1602 					 unsigned char private_bus,
1603 					 unsigned char channel,
1604 					 ipmi_fru_t    *fru)
1605 {
1606     if (!domain->fru_setup_cb)
1607 	return 0;
1608     return domain->fru_setup_cb(domain, is_logical, device_address,
1609 				device_id, lun, private_bus, channel,
1610 				fru, domain->fru_setup_cb_data);
1611 }
1612 
1613 /***********************************************************************
1614  *
1615  * MC handling
1616  *
1617  **********************************************************************/
1618 
1619 #define HASH_SLAVE_ADDR(x) (((x) >> 1) & (IPMB_HASH-1))
1620 
1621 ipmi_mc_t *
i_ipmi_find_mc_by_addr(ipmi_domain_t * domain,const ipmi_addr_t * addr,unsigned int addr_len)1622 i_ipmi_find_mc_by_addr(ipmi_domain_t     *domain,
1623 		       const ipmi_addr_t *addr,
1624 		       unsigned int      addr_len)
1625 {
1626     ipmi_mc_t     *mc = NULL;
1627 
1628     if (addr_len > sizeof(ipmi_addr_t))
1629 	return NULL;
1630 
1631     ipmi_lock(domain->mc_lock);
1632     if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1633 	if (addr->channel == IPMI_BMC_CHANNEL)
1634 	    mc = domain->si_mc;
1635 	else if (addr->channel < MAX_CONS)
1636 	    mc = domain->sys_intf_mcs[addr->channel];
1637     } else if (addr->addr_type == IPMI_IPMB_ADDR_TYPE) {
1638 	const ipmi_ipmb_addr_t *ipmb = (ipmi_ipmb_addr_t *) addr;
1639 	int                    idx;
1640 	const mc_table_t       *tab;
1641 	ipmi_addr_t            addr2;
1642 	unsigned int           addr2_len;
1643 	int                    i;
1644 
1645 	if (addr_len >= sizeof(*ipmb)) {
1646 	    idx = HASH_SLAVE_ADDR(ipmb->slave_addr);
1647 	    tab = &(domain->ipmb_mcs[idx]);
1648 	    for (i=0; i<tab->size; i++) {
1649 		if (tab->mcs[i]) {
1650 		    ipmi_mc_get_ipmi_address(tab->mcs[i], &addr2, &addr2_len);
1651 
1652 		    if (ipmi_addr_equal_nolun(addr, addr_len,
1653 					      &addr2, addr2_len))
1654 		    {
1655 			mc = tab->mcs[i];
1656 			break;
1657 		    }
1658 		}
1659 	    }
1660 	}
1661     }
1662 
1663     /* If we cannot get the MC, it has been destroyed. */
1664     if (mc) {
1665 	if (i_ipmi_mc_get(mc))
1666 	    mc = NULL;
1667     }
1668     ipmi_unlock(domain->mc_lock);
1669 
1670     return mc;
1671 }
1672 
1673 static int
in_ipmb_ignores(ipmi_domain_t * domain,unsigned char channel,unsigned char ipmb_addr)1674 in_ipmb_ignores(ipmi_domain_t *domain,
1675 		unsigned char channel,
1676 		unsigned char ipmb_addr)
1677 {
1678     unsigned long addr;
1679     unsigned char first, last, ichan;
1680     ilist_iter_t iter;
1681     int          rv = 0;
1682 
1683     ipmi_lock(domain->ipmb_ignores_lock);
1684     ilist_init_iter(&iter, domain->ipmb_ignores);
1685     ilist_unpositioned(&iter);
1686     while (ilist_next(&iter)) {
1687 	addr = (unsigned long) ilist_get(&iter);
1688 	first = addr & 0xff;
1689 	last = (addr >> 8) & 0xff;
1690 	ichan = (addr >> 16) & 0xff;
1691 	if ((ichan == channel) && (ipmb_addr >= first) && (ipmb_addr <= last))
1692 	    rv = 1;
1693     }
1694     ipmi_unlock(domain->ipmb_ignores_lock);
1695 
1696     return rv;
1697 }
1698 
1699 int
ipmi_domain_add_ipmb_ignore(ipmi_domain_t * domain,unsigned char channel,unsigned char ipmb_addr)1700 ipmi_domain_add_ipmb_ignore(ipmi_domain_t *domain,
1701 			    unsigned char channel,
1702 			    unsigned char ipmb_addr)
1703 {
1704     unsigned long addr = ipmb_addr | (ipmb_addr << 8) | (channel << 16);
1705     int           rv = 0;
1706 
1707     ipmi_lock(domain->ipmb_ignores_lock);
1708     if (! ilist_add_tail(domain->ipmb_ignores, (void *) addr, NULL))
1709 	rv = ENOMEM;
1710     ipmi_unlock(domain->ipmb_ignores_lock);
1711 
1712     return rv;
1713 }
1714 
1715 int
ipmi_domain_add_ipmb_ignore_range(ipmi_domain_t * domain,unsigned char channel,unsigned char first_ipmb_addr,unsigned char last_ipmb_addr)1716 ipmi_domain_add_ipmb_ignore_range(ipmi_domain_t *domain,
1717 				  unsigned char channel,
1718 				  unsigned char first_ipmb_addr,
1719 				  unsigned char last_ipmb_addr)
1720 {
1721     unsigned long addr = (first_ipmb_addr | (last_ipmb_addr << 8)
1722 			  | (channel << 16));
1723     int           rv = 0;
1724 
1725     ipmi_lock(domain->ipmb_ignores_lock);
1726     if (! ilist_add_tail(domain->ipmb_ignores, (void *) addr, NULL))
1727 	return ENOMEM;
1728     ipmi_unlock(domain->ipmb_ignores_lock);
1729 
1730     return rv;
1731 }
1732 
1733 typedef struct mc_upd_info_s
1734 {
1735     enum ipmi_update_e op;
1736     ipmi_domain_t      *domain;
1737     ipmi_mc_t          *mc;
1738 } mc_upd_info_t;
1739 
1740 static int
iterate_mc_upds(void * cb_data,void * item1,void * item2)1741 iterate_mc_upds(void *cb_data, void *item1, void *item2)
1742 {
1743     mc_upd_info_t         *info = cb_data;
1744     ipmi_domain_mc_upd_cb handler = item1;
1745 
1746     handler(info->op, info->domain, info->mc, item2);
1747     return LOCKED_LIST_ITER_CONTINUE;
1748 }
1749 
1750 static int
add_mc_to_domain(ipmi_domain_t * domain,ipmi_mc_t * mc)1751 add_mc_to_domain(ipmi_domain_t *domain, ipmi_mc_t *mc)
1752 {
1753     char         addr_data[sizeof(ipmi_addr_t)];
1754     ipmi_addr_t  *addr = (ipmi_addr_t *) addr_data;
1755     unsigned int addr_len;
1756     int          rv = 0;
1757 
1758     CHECK_DOMAIN_LOCK(domain);
1759     CHECK_MC_LOCK(mc);
1760 
1761     ipmi_mc_get_ipmi_address(mc, addr, &addr_len);
1762 
1763     ipmi_lock(domain->mc_lock);
1764 
1765     if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1766 	if (addr->channel >= MAX_CONS)
1767 	    rv = EINVAL;
1768 	else
1769 	    domain->sys_intf_mcs[addr->channel] = mc;
1770     } else if (addr->addr_type == IPMI_IPMB_ADDR_TYPE) {
1771 	ipmi_ipmb_addr_t *ipmb = (ipmi_ipmb_addr_t *) addr;
1772 	int              idx;
1773 	mc_table_t       *tab;
1774 	int              i;
1775 
1776 	idx = HASH_SLAVE_ADDR(ipmb->slave_addr);
1777 	tab = &(domain->ipmb_mcs[idx]);
1778 	if (tab->size == tab->curr) {
1779 	    ipmi_mc_t **nmcs;
1780 
1781 	    nmcs = ipmi_mem_alloc(sizeof(ipmi_mc_t *) * (tab->size+5));
1782 	    if (!nmcs) {
1783 		rv = ENOMEM;
1784 		goto out_unlock;
1785 	    }
1786 	    if (tab->mcs) {
1787 		memcpy(nmcs, tab->mcs, sizeof(ipmi_mc_t *) * tab->size);
1788 		ipmi_mem_free(tab->mcs);
1789 	    }
1790 	    memset(nmcs+tab->size, 0, sizeof(ipmi_mc_t *) * 5);
1791 	    tab->size += 5;
1792 	    tab->mcs = nmcs;
1793 	}
1794 	for (i=0; i<tab->size; i++) {
1795 	    if (!tab->mcs[i]) {
1796 		tab->mcs[i] = mc;
1797 		tab->curr++;
1798 		break;
1799 	    }
1800 	}
1801     }
1802 
1803 out_unlock:
1804     ipmi_unlock(domain->mc_lock);
1805 
1806     return rv;
1807 }
1808 
1809 static void
call_mc_upd_handlers(ipmi_domain_t * domain,ipmi_mc_t * mc,enum ipmi_update_e op)1810 call_mc_upd_handlers(ipmi_domain_t      *domain,
1811 		     ipmi_mc_t          *mc,
1812 		     enum ipmi_update_e op)
1813 {
1814     mc_upd_info_t info;
1815 
1816     CHECK_DOMAIN_LOCK(domain);
1817     CHECK_MC_LOCK(mc);
1818 
1819     info.domain = domain;
1820     info.op = op;
1821     info.mc = mc;
1822     locked_list_iterate(domain->mc_upd_handlers, iterate_mc_upds, &info);
1823 }
1824 
1825 int
ipmi_domain_add_mc_updated_handler(ipmi_domain_t * domain,ipmi_domain_mc_upd_cb handler,void * cb_data)1826 ipmi_domain_add_mc_updated_handler(ipmi_domain_t         *domain,
1827 				   ipmi_domain_mc_upd_cb handler,
1828 				   void                  *cb_data)
1829 {
1830     if (locked_list_add(domain->mc_upd_handlers, handler, cb_data))
1831 	return 0;
1832     else
1833 	return ENOMEM;
1834 }
1835 
1836 typedef struct mc_upd_cl_info_s
1837 {
1838     ipmi_domain_mc_upd_cb handler;
1839     void                  *handler_data;
1840 } mc_upd_cl_info_t;
1841 
1842 
1843 static int
iterate_mc_upds_cl(void * cb_data,void * item1,void * item2)1844 iterate_mc_upds_cl(void *cb_data, void *item1, void *item2)
1845 {
1846     mc_upd_cl_info_t         *info = cb_data;
1847     ipmi_domain_mc_upd_cl_cb handler = item1;
1848 
1849     handler(info->handler, info->handler_data, item2);
1850     return LOCKED_LIST_ITER_CONTINUE;
1851 }
1852 
1853 static void
call_mc_upd_cl_handlers(ipmi_domain_t * domain,ipmi_domain_mc_upd_cb handler,void * handler_data)1854 call_mc_upd_cl_handlers(ipmi_domain_t         *domain,
1855 			ipmi_domain_mc_upd_cb handler,
1856 			void                  *handler_data)
1857 {
1858     mc_upd_cl_info_t info;
1859 
1860     info.handler = handler;
1861     info.handler_data = handler_data;
1862     locked_list_iterate(domain->mc_upd_cl_handlers, iterate_mc_upds_cl, &info);
1863 }
1864 
1865 int
ipmi_domain_remove_mc_updated_handler(ipmi_domain_t * domain,ipmi_domain_mc_upd_cb handler,void * cb_data)1866 ipmi_domain_remove_mc_updated_handler(ipmi_domain_t        *domain,
1867 				      ipmi_domain_mc_upd_cb handler,
1868 				      void                  *cb_data)
1869 {
1870     if (locked_list_remove(domain->mc_upd_handlers, handler, cb_data))
1871 	return 0;
1872     else
1873 	return EINVAL;
1874 }
1875 
1876 int
ipmi_domain_add_mc_updated_handler_cl(ipmi_domain_t * domain,ipmi_domain_mc_upd_cl_cb handler,void * cb_data)1877 ipmi_domain_add_mc_updated_handler_cl(ipmi_domain_t            *domain,
1878 				      ipmi_domain_mc_upd_cl_cb handler,
1879 				      void                     *cb_data)
1880 {
1881     if (locked_list_add(domain->mc_upd_cl_handlers, handler, cb_data))
1882 	return 0;
1883     else
1884 	return ENOMEM;
1885 }
1886 
1887 int
ipmi_domain_remove_mc_updated_handler_cl(ipmi_domain_t * domain,ipmi_domain_mc_upd_cl_cb handler,void * cb_data)1888 ipmi_domain_remove_mc_updated_handler_cl(ipmi_domain_t            *domain,
1889 					 ipmi_domain_mc_upd_cl_cb handler,
1890 					 void                     *cb_data)
1891 {
1892     if (locked_list_remove(domain->mc_upd_cl_handlers, handler, cb_data))
1893 	return 0;
1894     else
1895 	return EINVAL;
1896 }
1897 
1898 /* Must be called with the domain MC lock held.  It will be
1899    released. */
1900 int
i_ipmi_remove_mc_from_domain(ipmi_domain_t * domain,ipmi_mc_t * mc)1901 i_ipmi_remove_mc_from_domain(ipmi_domain_t *domain, ipmi_mc_t *mc)
1902 {
1903     char         addr_data[sizeof(ipmi_addr_t)];
1904     ipmi_addr_t  *addr = (ipmi_addr_t *) addr_data;
1905     unsigned int addr_len;
1906     int          found = 0;
1907 
1908     ipmi_mc_get_ipmi_address(mc, addr, &addr_len);
1909 
1910     if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
1911 	if ((addr->channel < MAX_CONS)
1912 	    && (mc == domain->sys_intf_mcs[addr->channel]))
1913 	{
1914 	    domain->sys_intf_mcs[addr->channel] = NULL;
1915 	    found = 1;
1916 	}
1917     } else if (addr->addr_type == IPMI_IPMB_ADDR_TYPE) {
1918 	ipmi_ipmb_addr_t *ipmb = (ipmi_ipmb_addr_t *) addr;
1919 	int              idx;
1920 	mc_table_t       *tab;
1921 	int              i;
1922 
1923 	idx = HASH_SLAVE_ADDR(ipmb->slave_addr);
1924 	tab = &(domain->ipmb_mcs[idx]);
1925 	for (i=0; i<tab->size; i++) {
1926 	    if (tab->mcs[i] == mc) {
1927 		tab->curr--;
1928 		tab->mcs[i] = NULL;
1929 		found = 1;
1930 	    }
1931 	}
1932     }
1933 
1934     ipmi_unlock(domain->mc_lock);
1935 
1936     if (found) {
1937 	call_mc_upd_handlers(domain, mc, IPMI_DELETED);
1938 	return 0;
1939     } else
1940 	return ENOENT;
1941 }
1942 
1943 int
i_ipmi_find_or_create_mc_by_slave_addr(ipmi_domain_t * domain,unsigned int channel,unsigned int slave_addr,ipmi_mc_t ** new_mc)1944 i_ipmi_find_or_create_mc_by_slave_addr(ipmi_domain_t *domain,
1945 				       unsigned int  channel,
1946 				       unsigned int  slave_addr,
1947 				       ipmi_mc_t     **new_mc)
1948 {
1949     ipmi_mc_t   *mc;
1950     char        addr_data[sizeof(ipmi_addr_t)];
1951     ipmi_addr_t *addr = (ipmi_addr_t *) addr_data;
1952     int         addr_size;
1953     int         rv;
1954 
1955     if (channel == IPMI_BMC_CHANNEL) {
1956 	ipmi_system_interface_addr_t *saddr = (void *) addr;
1957 	saddr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
1958 	saddr->channel = slave_addr;
1959 	saddr->lun = 0;
1960 	addr_size = sizeof(*saddr);
1961     } else {
1962 	ipmi_ipmb_addr_t *iaddr = (void *) addr;
1963 	iaddr->addr_type = IPMI_IPMB_ADDR_TYPE;
1964 	iaddr->channel = channel;
1965 	iaddr->lun = 0;
1966 	iaddr->slave_addr = slave_addr;
1967 	addr_size = sizeof(*iaddr);
1968     }
1969 
1970     mc = i_ipmi_find_mc_by_addr(domain, addr, addr_size);
1971     if (mc) {
1972 	if (new_mc)
1973 	    *new_mc = mc;
1974 	return 0;
1975     }
1976 
1977     rv = i_ipmi_create_mc(domain, addr, addr_size, &mc);
1978     if (rv)
1979 	return rv;
1980 
1981     /* If we find an MC in the SDRs that we don't know about yet,
1982        attempt to scan it. */
1983     if (ipmi_option_IPMB_scan(domain))
1984 	ipmi_start_ipmb_mc_scan(domain, channel, slave_addr, slave_addr,
1985 				NULL, NULL);
1986 
1987     rv = add_mc_to_domain(domain, mc);
1988     if (rv) {
1989 	i_ipmi_cleanup_mc(mc);
1990 	i_ipmi_mc_put(mc);
1991 	return rv;
1992     }
1993     call_mc_upd_handlers(domain, mc, IPMI_ADDED);
1994 
1995     if (new_mc)
1996 	*new_mc = mc;
1997     return 0;
1998 }
1999 
2000 /***********************************************************************
2001  *
2002  * Command/response handling
2003  *
2004  **********************************************************************/
2005 
cmp_nmsg(void * item,void * cb_data)2006 static int cmp_nmsg(void *item, void *cb_data)
2007 {
2008     ll_msg_t *nmsg1 = item;
2009     ll_msg_t *nmsg2 = cb_data;
2010 
2011     return ((nmsg1 == nmsg2)
2012 	    && (nmsg1->domain == nmsg2->domain));
2013 }
2014 
2015 /* Must be called with the cmds_lock held. */
2016 static int
find_and_remove_msg(ipmi_domain_t * domain,ll_msg_t * nmsg,long seq)2017 find_and_remove_msg(ipmi_domain_t *domain, ll_msg_t *nmsg, long seq)
2018 {
2019     ilist_iter_t iter;
2020     int          rv = 0;
2021 
2022     ilist_init_iter(&iter, domain->cmds);
2023     ilist_unpositioned(&iter);
2024     if ((ilist_search_iter(&iter, cmp_nmsg, nmsg) != NULL)
2025 	&& (nmsg->seq == seq))
2026     {
2027 	ilist_delete(&iter);
2028 	rv = 1;
2029     }
2030     return rv;
2031 }
2032 
2033 static int
ll_rsp_handler(ipmi_con_t * ipmi,ipmi_msgi_t * orspi)2034 ll_rsp_handler(ipmi_con_t   *ipmi,
2035 	       ipmi_msgi_t  *orspi)
2036 {
2037     ipmi_msgi_t   *rspi;
2038     ipmi_domain_t *domain = orspi->data1;
2039     ll_msg_t      *nmsg = orspi->data2;
2040     long          seq = (long) orspi->data3;
2041     long          conn_seq = (long) orspi->data4;
2042     int           rv;
2043 
2044     rv = i_ipmi_domain_get(domain);
2045     if (rv)
2046 	/* No need to report these to the upper layer, they have
2047 	   already been delivered in the cleanup code. */
2048 	return IPMI_MSG_ITEM_NOT_USED;
2049 
2050     ipmi_lock(domain->cmds_lock);
2051     if (conn_seq != domain->conn_seq[nmsg->con]) {
2052 	/* The message has been rerouted, just ignore this response. */
2053 	ipmi_unlock(domain->cmds_lock);
2054 	goto out_unlock;
2055     }
2056 
2057     if (!find_and_remove_msg(domain, nmsg, seq)) {
2058 	ipmi_unlock(domain->cmds_lock);
2059 	goto out_unlock;
2060     }
2061     ipmi_unlock(domain->cmds_lock);
2062 
2063     rspi = nmsg->rsp_item;
2064     if (nmsg->rsp_handler) {
2065 	ipmi_move_msg_item(rspi, orspi);
2066 	memcpy(&rspi->addr, &orspi->addr, orspi->addr_len);
2067 	rspi->addr_len = orspi->addr_len;
2068 	deliver_rsp(domain, nmsg->rsp_handler, rspi);
2069     } else
2070 	ipmi_free_msg_item(rspi);
2071     ipmi_mem_free(nmsg);
2072  out_unlock:
2073     i_ipmi_domain_put(domain);
2074     return IPMI_MSG_ITEM_NOT_USED;
2075 }
2076 
2077 static int
ll_si_rsp_handler(ipmi_con_t * ipmi,ipmi_msgi_t * orspi)2078 ll_si_rsp_handler(ipmi_con_t *ipmi, ipmi_msgi_t *orspi)
2079 {
2080     ipmi_msgi_t                  *rspi;
2081     ipmi_domain_t                *domain = orspi->data1;
2082     ll_msg_t                     *nmsg = orspi->data2;
2083     int                          rv;
2084 
2085     rspi = nmsg->rsp_item;
2086 
2087     rv = i_ipmi_domain_get(domain);
2088     if (rv) {
2089 	/* Note that since we don't track SI messages, we must report
2090 	   them to the upper layer through this interface when the
2091 	   domain goes away. */
2092 	deliver_rsp(NULL, nmsg->rsp_handler, rspi);
2093 	return IPMI_MSG_ITEM_NOT_USED;
2094     }
2095 
2096     if (nmsg->rsp_handler) {
2097 	ipmi_move_msg_item(rspi, orspi);
2098 	/* Set the LUN from the response message. */
2099 	ipmi_addr_set_lun(&rspi->addr, ipmi_addr_get_lun(&rspi->addr));
2100 	deliver_rsp(domain, nmsg->rsp_handler, rspi);
2101     } else
2102 	ipmi_free_msg_item(rspi);
2103     ipmi_mem_free(nmsg);
2104 
2105     i_ipmi_domain_put(domain);
2106     return IPMI_MSG_ITEM_NOT_USED;
2107 }
2108 
2109 static int
matching_domain_sysaddr(ipmi_domain_t * domain,const ipmi_addr_t * addr,ipmi_system_interface_addr_t * si)2110 matching_domain_sysaddr(ipmi_domain_t *domain, const ipmi_addr_t *addr,
2111 			ipmi_system_interface_addr_t *si)
2112 {
2113     if (addr->addr_type == IPMI_IPMB_ADDR_TYPE) {
2114 	ipmi_ipmb_addr_t *ipmb = (ipmi_ipmb_addr_t *) addr;
2115 	int              i;
2116 
2117 	if (ipmb->channel >= MAX_IPMI_USED_CHANNELS)
2118 	    return 0;
2119 
2120 	if (domain->chan[ipmb->channel].medium != IPMI_CHANNEL_MEDIUM_IPMB)
2121 	    return 0;
2122 
2123 	for (i=0; i<MAX_CONS; i++) {
2124 	    if (domain->con_active[i]
2125 		&& domain->con_up[i]
2126 		&& (domain->con_ipmb_addr[i][ipmb->channel]==ipmb->slave_addr)
2127 		&& domain->sys_intf_mcs[i])
2128 	    {
2129 		si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2130 		si->channel = i;
2131 		si->lun = ipmb->lun;
2132 		return 1;
2133 	    }
2134 	}
2135     }
2136 
2137     return 0;
2138 }
2139 
2140 static int
send_command_option(ipmi_domain_t * domain,int conn,const ipmi_addr_t * addr,unsigned int addr_len,const ipmi_msg_t * msg,const ipmi_con_option_t * options,ipmi_ll_rsp_handler_t handler,void * handler_data)2141 send_command_option(ipmi_domain_t           *domain,
2142 		    int                     conn,
2143 		    const ipmi_addr_t       *addr,
2144 		    unsigned int            addr_len,
2145 		    const ipmi_msg_t        *msg,
2146 		    const ipmi_con_option_t *options,
2147 		    ipmi_ll_rsp_handler_t   handler,
2148 		    void		    *handler_data)
2149 {
2150     if (domain->conn[conn]->send_command_option)
2151 	return domain->conn[conn]->send_command_option(domain->conn[conn],
2152 						       addr, addr_len,
2153 						       msg,
2154 						       options,
2155 						       handler,
2156 						       handler_data);
2157     else
2158 	return domain->conn[conn]->send_command(domain->conn[conn],
2159 						addr, addr_len,
2160 						msg,
2161 						handler,
2162 						handler_data);
2163 }
2164 
2165 static int
send_command_addr(ipmi_domain_t * domain,const ipmi_addr_t * addr,unsigned int addr_len,const ipmi_msg_t * msg,ipmi_addr_response_handler_t rsp_handler,void * rsp_data1,void * rsp_data2,int side_effects)2166 send_command_addr(ipmi_domain_t                *domain,
2167 		  const ipmi_addr_t            *addr,
2168 		  unsigned int                 addr_len,
2169 		  const ipmi_msg_t             *msg,
2170 		  ipmi_addr_response_handler_t rsp_handler,
2171 		  void                         *rsp_data1,
2172 		  void                         *rsp_data2,
2173 		  int			       side_effects)
2174 {
2175     int                          rv;
2176     int                          u;
2177     ll_msg_t                     *nmsg;
2178     ipmi_system_interface_addr_t si;
2179     ipmi_ll_rsp_handler_t        handler;
2180     void                         *data4 = NULL;
2181     int                          is_ipmb = 0;
2182     ipmi_msgi_t                  *rspi;
2183     ipmi_con_option_t            opt_data[2];
2184     ipmi_con_option_t		 *options = NULL;
2185 
2186     if (addr_len > sizeof(ipmi_addr_t))
2187 	return EINVAL;
2188 
2189     if (msg->data_len > IPMI_MAX_MSG_LENGTH)
2190 	return EINVAL;
2191 
2192     if (domain->in_shutdown)
2193 	return EINVAL;
2194 
2195     if (side_effects) {
2196 	options = opt_data;
2197 	options[0].option = IPMI_CON_MSG_OPTION_SIDE_EFFECTS;
2198 	options[0].ival = 1;
2199 	options[1].option = IPMI_CON_OPTION_LIST_END;
2200     }
2201 
2202     CHECK_DOMAIN_LOCK(domain);
2203 
2204     nmsg = ipmi_mem_alloc(sizeof(*nmsg));
2205     if (!nmsg)
2206 	return ENOMEM;
2207     nmsg->rsp_item = ipmi_alloc_msg_item();
2208     if (!nmsg->rsp_item) {
2209 	ipmi_mem_free(nmsg);
2210 	return ENOMEM;
2211     }
2212 
2213     /* Copy the address here because where we send it may change.  But
2214        we want the response address to match what we sent. */
2215     memcpy(&nmsg->rsp_item->addr, addr, addr_len);
2216     nmsg->rsp_item->addr_len = addr_len;
2217 
2218     if (matching_domain_sysaddr(domain, addr, &si)) {
2219 	/* We have a direct connection to this BMC and it is up and
2220 	   operational, so talk directly to it. */
2221 	u = si.channel;
2222 	si.channel = IPMI_BMC_CHANNEL;
2223 	addr = (ipmi_addr_t *) &si;
2224 	addr_len = sizeof(si);
2225 	handler = ll_si_rsp_handler;
2226     } else if ((addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2227 	&& (addr->channel != IPMI_BMC_CHANNEL))
2228     {
2229 	u = addr->channel;
2230 
2231 	/* Messages to system interface addresses use the channel to
2232            choose which system address to message. */
2233 	if ((u < 0) || (u >= MAX_CONS)) {
2234 	    rv = EINVAL;
2235 	    goto out;
2236 	}
2237 	if (!domain->conn[u]) {
2238 	    rv = EINVAL;
2239 	    goto out;
2240 	}
2241 
2242 	si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2243 	si.channel = IPMI_BMC_CHANNEL;
2244 	si.lun = ((ipmi_system_interface_addr_t *) addr)->lun;
2245 	addr = (ipmi_addr_t *) &si;
2246 	addr_len = sizeof(si);
2247 	handler = ll_si_rsp_handler;
2248     } else {
2249 	u = domain->working_conn;
2250 
2251 	/* If we don't have any working connection, just use connection
2252 	   zero. */
2253 	if (u == -1)
2254 	    u = 0;
2255 	handler = ll_rsp_handler;
2256 	is_ipmb = 1;
2257     }
2258 
2259     nmsg->domain = domain;
2260     nmsg->con = u;
2261 
2262     memcpy(&nmsg->msg, msg, sizeof(nmsg->msg));
2263     nmsg->msg.data = nmsg->msg_data;
2264     nmsg->msg.data_len = msg->data_len;
2265     memcpy(nmsg->msg.data, msg->data, msg->data_len);
2266 
2267     nmsg->rsp_handler = rsp_handler;
2268     nmsg->rsp_item->data1 = rsp_data1;
2269     nmsg->rsp_item->data2 = rsp_data2;
2270 
2271     nmsg->side_effects = side_effects;
2272 
2273     ipmi_lock(domain->cmds_lock);
2274     nmsg->seq = domain->cmds_seq;
2275     domain->cmds_seq++;
2276 
2277     /* Have to delay this to here so we are holding the lock. */
2278     if (is_ipmb)
2279 	data4 = (void *) (long) domain->conn_seq[u];
2280 
2281     rspi = ipmi_alloc_msg_item();
2282     if (!rspi) {
2283 	rv = ENOMEM;
2284 	goto out_unlock;
2285     }
2286 
2287     rspi->data1 = domain;
2288     rspi->data2 = nmsg;
2289     rspi->data3 = (void *) nmsg->seq;
2290     rspi->data4 = data4;
2291     rv = send_command_option(domain, u, addr, addr_len,
2292 			     msg, options, handler, rspi);
2293 
2294     if (rv) {
2295 	ipmi_free_msg_item(rspi);
2296 	goto out_unlock;
2297     } else if (is_ipmb) {
2298 	/* If it's a system interface we don't add it to the list of
2299 	   commands running, because it will never need to be
2300 	   rerouted. */
2301 	ilist_add_tail(domain->cmds, nmsg, &nmsg->link);
2302     }
2303  out_unlock:
2304     ipmi_unlock(domain->cmds_lock);
2305 
2306  out:
2307     if (rv) {
2308 	ipmi_free_msg_item(nmsg->rsp_item);
2309 	ipmi_mem_free(nmsg);
2310     }
2311     return rv;
2312 }
2313 
2314 int
ipmi_send_command_addr(ipmi_domain_t * domain,const ipmi_addr_t * addr,unsigned int addr_len,const ipmi_msg_t * msg,ipmi_addr_response_handler_t rsp_handler,void * rsp_data1,void * rsp_data2)2315 ipmi_send_command_addr(ipmi_domain_t                *domain,
2316 		       const ipmi_addr_t	    *addr,
2317 		       unsigned int                 addr_len,
2318 		       const ipmi_msg_t             *msg,
2319 		       ipmi_addr_response_handler_t rsp_handler,
2320 		       void                         *rsp_data1,
2321 		       void                         *rsp_data2)
2322 {
2323     return send_command_addr(domain, addr, addr_len, msg, rsp_handler,
2324 			     rsp_data1, rsp_data2, 0);
2325 }
2326 
2327 int
ipmi_send_command_addr_sideeff(ipmi_domain_t * domain,const ipmi_addr_t * addr,unsigned int addr_len,const ipmi_msg_t * msg,ipmi_addr_response_handler_t rsp_handler,void * rsp_data1,void * rsp_data2)2328 ipmi_send_command_addr_sideeff(ipmi_domain_t                *domain,
2329 			       const ipmi_addr_t	    *addr,
2330 			       unsigned int                 addr_len,
2331 			       const ipmi_msg_t             *msg,
2332 			       ipmi_addr_response_handler_t rsp_handler,
2333 			       void                         *rsp_data1,
2334 			       void                         *rsp_data2)
2335 {
2336     return send_command_addr(domain, addr, addr_len, msg, rsp_handler,
2337 			     rsp_data1, rsp_data2, 1);
2338 }
2339 
2340 /* Take all the commands for any inactive or down connection and
2341    resend them on another connection.  */
2342 static void
reroute_cmds(ipmi_domain_t * domain,int old_con,int new_con)2343 reroute_cmds(ipmi_domain_t *domain, int old_con, int new_con)
2344 {
2345     ilist_iter_t iter;
2346     int          rv;
2347     ll_msg_t     *nmsg;
2348 
2349     ipmi_lock(domain->cmds_lock);
2350     ilist_init_iter(&iter, domain->cmds);
2351     rv = ilist_first(&iter);
2352     (domain->conn_seq[old_con])++;
2353     while (rv) {
2354 	nmsg = ilist_get(&iter);
2355 	if (nmsg->con == old_con) {
2356 	    ipmi_msgi_t       *rspi;
2357 	    ipmi_con_option_t opt_data[2];
2358 	    ipmi_con_option_t *options = NULL;
2359 
2360 	    nmsg->seq = domain->cmds_seq;
2361 	    domain->cmds_seq++; /* Make the message unique so a
2362                                    response from the other connection
2363                                    will not match. */
2364 	    nmsg->con = new_con;
2365 
2366 	    rspi = ipmi_alloc_msg_item();
2367 	    if (!rspi)
2368 		goto send_err;
2369 
2370 	    if (nmsg->side_effects) {
2371 		options = opt_data;
2372 		options[0].option = IPMI_CON_MSG_OPTION_SIDE_EFFECTS;
2373 		options[0].ival = 1;
2374 		options[1].option = IPMI_CON_OPTION_LIST_END;
2375 	    }
2376 
2377 	    rspi->data1 = domain;
2378 	    rspi->data2 = nmsg;
2379 	    rspi->data3 = (void *) nmsg->seq;
2380 	    rspi->data4 = (void *) domain->conn_seq[new_con];
2381 	    rv = send_command_option(domain, new_con,
2382 				     &nmsg->rsp_item->addr,
2383 				     nmsg->rsp_item->addr_len,
2384 				     &nmsg->msg,
2385 				     options,
2386 				     ll_rsp_handler,
2387 				     rspi);
2388 	    if (rv) {
2389 		ipmi_free_msg_item(rspi);
2390 	    send_err:
2391 		/* Couldn't send the message, just fail it. */
2392 		if (nmsg->rsp_handler) {
2393 		    rspi = nmsg->rsp_item;
2394 		    rspi->msg.netfn = nmsg->msg.netfn | 1;
2395 		    rspi->msg.cmd = nmsg->msg.cmd;
2396 		    rspi->msg.data = rspi->data;
2397 		    rspi->msg.data_len = 1;
2398 		    rspi->data[0] = IPMI_UNKNOWN_ERR_CC;
2399 		    deliver_rsp(domain, nmsg->rsp_handler, rspi);
2400 		}
2401 		rv = ilist_delete(&iter);
2402 		ipmi_mem_free(nmsg);
2403 		continue;
2404 	    }
2405 	}
2406 	rv = ilist_next(&iter);
2407     }
2408     ipmi_unlock(domain->cmds_lock);
2409 }
2410 
2411 /***********************************************************************
2412  *
2413  * Bus scanning
2414  *
2415  **********************************************************************/
2416 
2417 /* This is the number of device ID queries that an MC must not respond
2418    to in a row to be considered dead. */
2419 #define MAX_MC_MISSED_RESPONSES 10
2420 
2421 void
ipmi_domain_set_ipmb_rescan_time(ipmi_domain_t * domain,unsigned int seconds)2422 ipmi_domain_set_ipmb_rescan_time(ipmi_domain_t *domain, unsigned int seconds)
2423 {
2424     int            rv;
2425     struct timeval timeout;
2426 
2427     CHECK_DOMAIN_LOCK(domain);
2428 
2429     ipmi_lock(domain->audit_domain_timer_info->lock);
2430     domain->audit_domain_interval = seconds;
2431     rv = domain->os_hnd->stop_timer(domain->os_hnd,
2432 				    domain->audit_domain_timer);
2433     if (rv) {
2434 	/* If we can't stop the timer, that's ok, the timer is in the
2435 	   wakeup and will handle the restart for us. */
2436 	ipmi_unlock(domain->audit_domain_timer_info->lock);
2437 	return;
2438     }
2439     timeout.tv_sec = domain->audit_domain_interval;
2440     timeout.tv_usec = 0;
2441     domain->os_hnd->start_timer(domain->os_hnd,
2442 				domain->audit_domain_timer,
2443 				&timeout,
2444 				domain_audit,
2445 				domain->audit_domain_timer_info);
2446     ipmi_unlock(domain->audit_domain_timer_info->lock);
2447 }
2448 
2449 unsigned int
ipmi_domain_get_ipmb_rescan_time(ipmi_domain_t * domain)2450 ipmi_domain_get_ipmb_rescan_time(ipmi_domain_t *domain)
2451 {
2452     CHECK_DOMAIN_LOCK(domain);
2453 
2454     return domain->audit_domain_interval;
2455 }
2456 
2457 int
ipmi_domain_set_full_bus_scan(ipmi_domain_t * domain,int val)2458 ipmi_domain_set_full_bus_scan(ipmi_domain_t *domain, int val)
2459 {
2460     CHECK_DOMAIN_LOCK(domain);
2461 
2462     domain->do_bus_scan = val;
2463     return 0;
2464 }
2465 
2466 static void
add_bus_scans_running(ipmi_domain_t * domain,mc_ipmb_scan_info_t * info)2467 add_bus_scans_running(ipmi_domain_t *domain, mc_ipmb_scan_info_t *info)
2468 {
2469     info->next = domain->bus_scans_running;
2470     domain->bus_scans_running = info;
2471 }
2472 
2473 static void
remove_bus_scans_running(ipmi_domain_t * domain,mc_ipmb_scan_info_t * info)2474 remove_bus_scans_running(ipmi_domain_t *domain, mc_ipmb_scan_info_t *info)
2475 {
2476     mc_ipmb_scan_info_t *i2;
2477 
2478     i2 = domain->bus_scans_running;
2479     if (i2 == info)
2480 	domain->bus_scans_running = info->next;
2481     else
2482 	while (i2->next != NULL) {
2483 	    if (i2->next == info) {
2484 		i2->next = info->next;
2485 		break;
2486 	    }
2487 	    i2 = i2->next;
2488 	}
2489 }
2490 
2491 static int devid_bc_rsp_handler(ipmi_domain_t *domain, ipmi_msgi_t *rspi);
2492 
2493 static void
rescan_timeout_handler(void * cb_data,os_hnd_timer_id_t * id)2494 rescan_timeout_handler(void *cb_data, os_hnd_timer_id_t *id)
2495 {
2496     mc_ipmb_scan_info_t *info = cb_data;
2497     int                 rv;
2498     ipmi_ipmb_addr_t    *ipmb;
2499     ipmi_domain_t       *domain;
2500 
2501     ipmi_lock(info->lock);
2502     if (info->cancelled) {
2503 	ipmi_unlock(info->lock);
2504 	info->os_hnd->free_timer(info->os_hnd, info->timer);
2505 	ipmi_destroy_lock(info->lock);
2506 	ipmi_mem_free(info);
2507 	return;
2508     }
2509     info->timer_running = 0;
2510     ipmi_unlock(info->lock);
2511 
2512     domain = info->domain;
2513     rv = i_ipmi_domain_get(domain);
2514     if (rv) {
2515 	ipmi_log(IPMI_LOG_INFO,
2516 		 "%sdomain.c(rescan_timeout_handler): "
2517 		 "BMC went away while scanning for MCs",
2518 		 DOMAIN_NAME(domain));
2519 	return;
2520     }
2521 
2522     goto retry_addr;
2523 
2524  next_addr_nolock:
2525     ipmb = (ipmi_ipmb_addr_t *) &info->addr;
2526     ipmb->slave_addr += 2;
2527     if ((info->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2528 	|| (ipmb->slave_addr > info->end_addr)) {
2529 	/* We've hit the end, we can quit now. */
2530 	if (info->done_handler)
2531 	    info->done_handler(domain, 0, info->cb_data);
2532 	remove_bus_scans_running(domain, info);
2533 	info->os_hnd->free_timer(info->os_hnd, info->timer);
2534 	ipmi_destroy_lock(info->lock);
2535 	ipmi_mem_free(info);
2536 	goto out;
2537     }
2538     info->missed_responses = 0;
2539     if (in_ipmb_ignores(domain, ipmb->channel, ipmb->slave_addr))
2540 	goto next_addr_nolock;
2541 
2542  retry_addr:
2543     rv = ipmi_send_command_addr(domain,
2544 				&(info->addr),
2545 				info->addr_len,
2546 				&(info->msg),
2547 				devid_bc_rsp_handler,
2548 				info, NULL);
2549     if (rv)
2550 	goto next_addr_nolock;
2551 
2552  out:
2553     i_ipmi_domain_put(domain);
2554 }
2555 
2556 static int
devid_bc_rsp_handler(ipmi_domain_t * domain,ipmi_msgi_t * rspi)2557 devid_bc_rsp_handler(ipmi_domain_t *domain, ipmi_msgi_t *rspi)
2558 {
2559     ipmi_msg_t          *msg = &rspi->msg;
2560     ipmi_addr_t         *addr = &rspi->addr;
2561     unsigned int        addr_len = rspi->addr_len;
2562     mc_ipmb_scan_info_t *info = rspi->data1;
2563     int                 rv;
2564     ipmi_mc_t           *mc = NULL;
2565     ipmi_ipmb_addr_t    *ipmb;
2566     int                 mc_added = 0;
2567     int                 mc_changed = 0;
2568 
2569 
2570     rv = i_ipmi_domain_get(domain);
2571     if (rv) {
2572 	ipmi_log(IPMI_LOG_INFO,
2573 		 "%sdomain.c(devid_bc_rsp_handler): "
2574 		 "BMC went away while scanning for MCs",
2575 		 DOMAIN_NAME(domain));
2576 	return IPMI_MSG_ITEM_NOT_USED;
2577     }
2578 
2579     mc = i_ipmi_find_mc_by_addr(domain, addr, addr_len);
2580     if (msg->data[0] == 0) {
2581 	if (mc && ipmi_mc_is_active(mc)
2582 	    && !i_ipmi_mc_device_data_compares(mc, msg))
2583 	{
2584 	    /* The MC was replaced with a new one, so clear the old
2585                one and add a new one. */
2586 	    i_ipmi_cleanup_mc(mc);
2587 	    i_ipmi_mc_put(mc);
2588 	    mc = i_ipmi_find_mc_by_addr(domain, addr, addr_len);
2589 	}
2590 	if (!mc || !ipmi_mc_is_active(mc)) {
2591 	    /* It doesn't already exist, or it's inactive, so add
2592                it. */
2593 	    if (!mc) {
2594 		/* If it's not there, then add it.  If it's just not
2595                    active, reuse the same data. */
2596 		rv = i_ipmi_create_mc(domain, addr, addr_len, &mc);
2597 		if (rv) {
2598 		    /* Out of memory, just give up for now. */
2599 		    if (info->done_handler)
2600 			info->done_handler(domain, 0, info->cb_data);
2601 		    remove_bus_scans_running(domain, info);
2602 		    info->os_hnd->free_timer(info->os_hnd, info->timer);
2603 		    ipmi_destroy_lock(info->lock);
2604 		    ipmi_mem_free(info);
2605 		    goto out;
2606 		}
2607 
2608 		rv = add_mc_to_domain(domain, mc);
2609 		if (rv) {
2610 		    i_ipmi_cleanup_mc(mc);
2611 		    goto next_addr;
2612 		}
2613 
2614 		rv = i_ipmi_mc_get_device_id_data_from_rsp(mc, msg);
2615 		if (rv) {
2616 		    /* If we couldn't handle the device data, just clean
2617 		       it up */
2618 		    i_ipmi_cleanup_mc(mc);
2619 		    goto out;
2620 		}
2621 
2622 		/* In this case, the use count is defined to be 1, so
2623 		   it will always be set up properly and the previous
2624 		   function will not return EAGAIN, no need to
2625 		   check. */
2626 
2627 		mc_added = 1;
2628 		i_ipmi_mc_handle_new(mc);
2629 	    } else {
2630 		/* It was inactive, activate it. */
2631 		rv = i_ipmi_mc_get_device_id_data_from_rsp(mc, msg);
2632 		if (rv == EAGAIN) {
2633 		    /* The MC is in use, so we cannot handle it right
2634 		       now.  We wait until the MC is released to do
2635 		       that and cue off the pending new MC field in
2636 		       the MC. */
2637 		} else if (rv) {
2638 		    /* If we couldn't handle the device data, just clean
2639 		       it up. */
2640 		    i_ipmi_cleanup_mc(mc);
2641 		} else {
2642 		    mc_changed = 1;
2643 		    i_ipmi_mc_handle_new(mc);
2644 		}
2645 	    }
2646 	} else {
2647 	    /* Periodically check the MCs. */
2648 	    i_ipmi_mc_check_mc(mc);
2649 	}
2650     } else if (mc && ipmi_mc_is_active(mc)) {
2651 	/* Didn't get a response.  Maybe the MC has gone away? */
2652 	info->missed_responses++;
2653 
2654 	/* We fail system interface addresses immediately, since they
2655            shouldn't be a timeout problem. */
2656 	if ((info->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2657 	    || (info->missed_responses >= MAX_MC_MISSED_RESPONSES))
2658 	{
2659 	    i_ipmi_cleanup_mc(mc);
2660 	    goto next_addr;
2661 	} else {
2662 	    /* Try again after a second. */
2663 	    struct timeval timeout;
2664 
2665 	    if (msg->data[0] == IPMI_TIMEOUT_CC)
2666 		/* If we timed out, then no need to time, since a
2667 		   second has gone by already. */
2668 		goto retry_addr;
2669 
2670 	    ipmi_lock(info->lock);
2671 	    timeout.tv_sec = 1;
2672 	    timeout.tv_usec = 0;
2673 	    info->timer_running = 1;
2674 	    info->os_hnd->start_timer(info->os_hnd,
2675 				      info->timer,
2676 				      &timeout,
2677 				      rescan_timeout_handler,
2678 				      info);
2679 	    ipmi_unlock(info->lock);
2680 	    goto out;
2681 	}
2682     }
2683 
2684  next_addr:
2685     if (mc_added)
2686 	call_mc_upd_handlers(domain, mc, IPMI_ADDED);
2687     else if (mc_changed)
2688 	call_mc_upd_handlers(domain, mc, IPMI_CHANGED);
2689 
2690  next_addr_nolock:
2691     ipmb = (ipmi_ipmb_addr_t *) &info->addr;
2692     ipmb->slave_addr += 2;
2693     if ((info->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
2694 	|| (ipmb->slave_addr > info->end_addr)) {
2695 	/* We've hit the end, we can quit now. */
2696 	if (info->done_handler)
2697 	    info->done_handler(domain, 0, info->cb_data);
2698 	remove_bus_scans_running(domain, info);
2699 	info->os_hnd->free_timer(info->os_hnd, info->timer);
2700 	ipmi_destroy_lock(info->lock);
2701 	ipmi_mem_free(info);
2702 	goto out;
2703     }
2704     info->missed_responses = 0;
2705     if (in_ipmb_ignores(domain, ipmb->channel, ipmb->slave_addr))
2706 	goto next_addr_nolock;
2707 
2708  retry_addr:
2709     rv = ipmi_send_command_addr(domain,
2710 				&(info->addr),
2711 				info->addr_len,
2712 				&(info->msg),
2713 				devid_bc_rsp_handler,
2714 				info, NULL);
2715     if (rv)
2716 	goto next_addr_nolock;
2717 
2718  out:
2719     if (mc)
2720 	i_ipmi_mc_put(mc);
2721     i_ipmi_domain_put(domain);
2722     return IPMI_MSG_ITEM_NOT_USED;
2723 }
2724 
2725 int
ipmi_start_ipmb_mc_scan(ipmi_domain_t * domain,int channel,unsigned int start_addr,unsigned int end_addr,ipmi_domain_cb done_handler,void * cb_data)2726 ipmi_start_ipmb_mc_scan(ipmi_domain_t  *domain,
2727 	       		int            channel,
2728 	       		unsigned int   start_addr,
2729 			unsigned int   end_addr,
2730 			ipmi_domain_cb done_handler,
2731 			void           *cb_data)
2732 {
2733     mc_ipmb_scan_info_t *info;
2734     int                 rv;
2735     ipmi_ipmb_addr_t    *ipmb;
2736 
2737     CHECK_DOMAIN_LOCK(domain);
2738 
2739     if (channel >= MAX_IPMI_USED_CHANNELS)
2740 	return EINVAL;
2741 
2742     if ((domain->chan[channel].medium != 1)
2743 	&& !(start_addr == 0x20 || end_addr == 0x20))
2744 	/* Make sure it is IPMB, or the BMC address. */
2745 	return ENOSYS;
2746 
2747     info = ipmi_mem_alloc(sizeof(*info));
2748     if (!info)
2749 	return ENOMEM;
2750     memset(info, 0, sizeof(*info));
2751 
2752     info->domain = domain;
2753     ipmb = (ipmi_ipmb_addr_t *) &info->addr;
2754     ipmb->addr_type = IPMI_IPMB_BROADCAST_ADDR_TYPE;
2755     ipmb->channel = channel;
2756     ipmb->slave_addr = start_addr;
2757     ipmb->lun = 0;
2758     info->addr_len = sizeof(*ipmb);
2759     info->msg.netfn = IPMI_APP_NETFN;
2760     info->msg.cmd = IPMI_GET_DEVICE_ID_CMD;
2761     info->msg.data = NULL;
2762     info->msg.data_len = 0;
2763     info->end_addr = end_addr;
2764     info->done_handler = done_handler;
2765     info->cb_data = cb_data;
2766     info->missed_responses = 0;
2767     info->os_hnd = domain->os_hnd;
2768     rv = info->os_hnd->alloc_timer(info->os_hnd, &info->timer);
2769     if (rv)
2770 	goto out_err;
2771 
2772     rv = ipmi_create_lock(domain, &info->lock);
2773     if (rv)
2774 	goto out_err;
2775 
2776     rv = ENOSYS; /* Return err if no scans done */
2777 
2778     /* Skip addresses we must ignore. */
2779     while (in_ipmb_ignores(domain, ipmb->channel, ipmb->slave_addr)) {
2780 	/* ipmb->slave_addr is 8 bits, so we can't do a <= comparison as it
2781 	   will overflow after 254. */
2782 	if (ipmb->slave_addr == end_addr)
2783 	    goto out_err;
2784 	ipmb->slave_addr += 2;
2785     }
2786     while (rv) {
2787 	rv = ipmi_send_command_addr(domain,
2788 				    &info->addr,
2789 				    info->addr_len,
2790 				    &(info->msg),
2791 				    devid_bc_rsp_handler,
2792 				    info, NULL);
2793 	if (rv) {
2794 	    if (ipmb->slave_addr == end_addr)
2795 		goto out_err;
2796 	    ipmb->slave_addr += 2;
2797 	}
2798     }
2799 
2800     if (rv)
2801 	goto out_err;
2802     else
2803 	add_bus_scans_running(domain, info);
2804     return 0;
2805 
2806  out_err:
2807     if (info->timer)
2808 	info->os_hnd->free_timer(info->os_hnd, info->timer);
2809     if (info->lock)
2810 	ipmi_destroy_lock(info->lock);
2811     ipmi_mem_free(info);
2812     return 0; /* Since the done handler is always called, always
2813 		 return true.  Bus scans always succeed. */
2814 }
2815 
2816 int
ipmi_start_si_scan(ipmi_domain_t * domain,int si_num,ipmi_domain_cb done_handler,void * cb_data)2817 ipmi_start_si_scan(ipmi_domain_t  *domain,
2818 		   int            si_num,
2819 		   ipmi_domain_cb done_handler,
2820 		   void           *cb_data)
2821 {
2822     mc_ipmb_scan_info_t          *info;
2823     ipmi_system_interface_addr_t *si;
2824     int                          rv;
2825 
2826     info = ipmi_mem_alloc(sizeof(mc_ipmb_scan_info_t));
2827     if (!info)
2828 	return ENOMEM;
2829     memset(info, 0, sizeof(*info));
2830 
2831     info->domain = domain;
2832     si = (void *) &info->addr;
2833     si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
2834     si->channel = si_num;
2835     si->lun = 0;
2836     info->addr_len = sizeof(*si);
2837     info->msg.netfn = IPMI_APP_NETFN;
2838     info->msg.cmd = IPMI_GET_DEVICE_ID_CMD;
2839     info->msg.data = NULL;
2840     info->msg.data_len = 0;
2841     info->done_handler = done_handler;
2842     info->cb_data = cb_data;
2843     info->missed_responses = 0;
2844     info->os_hnd = domain->os_hnd;
2845     rv = info->os_hnd->alloc_timer(info->os_hnd, &info->timer);
2846     if (rv)
2847 	goto out_err;
2848 
2849     rv = ipmi_create_lock(domain, &info->lock);
2850     if (rv)
2851 	goto out_err;
2852 
2853     rv = ipmi_send_command_addr(domain,
2854 				&info->addr,
2855 				info->addr_len,
2856 				&(info->msg),
2857 				devid_bc_rsp_handler,
2858 				info, NULL);
2859     if (rv)
2860 	goto out_err;
2861     else
2862 	add_bus_scans_running(domain, info);
2863     return 0;
2864 
2865  out_err:
2866     if (info->timer)
2867 	info->os_hnd->free_timer(info->os_hnd, info->timer);
2868     if (info->lock)
2869 	ipmi_destroy_lock(info->lock);
2870     ipmi_mem_free(info);
2871     return rv;
2872 }
2873 
2874 static void
mc_scan_done(ipmi_domain_t * domain,int err,void * cb_data)2875 mc_scan_done(ipmi_domain_t *domain, int err, void *cb_data)
2876 {
2877     ipmi_domain_cb bus_scan_handler;
2878     void           *bus_scan_handler_cb_data;
2879 
2880     ipmi_lock(domain->mc_lock);
2881     domain->scanning_bus_count--;
2882     if (domain->scanning_bus_count) {
2883 	i_ipmi_put_domain_fully_up(domain, "mc_scan_done");
2884 	ipmi_unlock(domain->mc_lock);
2885 	return;
2886     }
2887 
2888     bus_scan_handler = domain->bus_scan_handler;
2889     bus_scan_handler_cb_data = domain->bus_scan_handler_cb_data;
2890     ipmi_unlock(domain->mc_lock);
2891     if (bus_scan_handler)
2892 	bus_scan_handler(domain, 0,
2893 			 bus_scan_handler_cb_data);
2894     i_ipmi_put_domain_fully_up(domain, "mc_scan_done");
2895 }
2896 
2897 void
i_ipmi_start_mc_scan_one(ipmi_domain_t * domain,int chan,int first,int last)2898 i_ipmi_start_mc_scan_one(ipmi_domain_t *domain, int chan, int first, int last)
2899 {
2900     int rv;
2901 
2902     i_ipmi_get_domain_fully_up(domain, "i_ipmi_start_mc_scan_one");
2903     domain->scanning_bus_count++;
2904     rv = ipmi_start_ipmb_mc_scan(domain, chan, first, last,
2905 				 mc_scan_done, NULL);
2906     if (rv) {
2907 	domain->scanning_bus_count--;
2908 	i_ipmi_put_domain_fully_up(domain, "i_ipmi_start_mc_scan_one");
2909     }
2910 }
2911 
2912 static int
cmp_int(const void * v1,const void * v2)2913 cmp_int(const void *v1, const void *v2)
2914 {
2915     const int *i1 = v1;
2916     const int *i2 = v2;
2917     if (*i1 < *i2)
2918 	return -1;
2919     else if (*i1 > *i2)
2920 	return 1;
2921     else
2922 	return 0;
2923 }
2924 
2925 void
ipmi_domain_start_full_ipmb_scan(ipmi_domain_t * domain)2926 ipmi_domain_start_full_ipmb_scan(ipmi_domain_t *domain)
2927 {
2928     int i, j;
2929     int rv;
2930     int got_bmc = 0;
2931 
2932     if (domain->in_shutdown)
2933 	return;
2934 
2935     ipmi_lock(domain->mc_lock);
2936     if (!domain->do_bus_scan || (!ipmi_option_IPMB_scan(domain))) {
2937 	/* Always scan the local BMC(s). */
2938 	for (i=0; i<MAX_CONS; i++) {
2939 	    if (!domain->conn[i])
2940 		continue;
2941 	    for (j=0; j<MAX_IPMI_USED_CHANNELS; j++) {
2942 		if (domain->chan[j].medium != IPMI_CHANNEL_MEDIUM_IPMB)
2943 		    continue;
2944 		i_ipmi_start_mc_scan_one(domain, j,
2945 					 domain->con_ipmb_addr[i][j],
2946 					 domain->con_ipmb_addr[i][j]);
2947 		break;
2948 	    }
2949 	    if (j == MAX_IPMI_USED_CHANNELS) {
2950 		/* Didn't find a valid channel, just scan 0 to get one. */
2951 		i_ipmi_start_mc_scan_one(domain, 0,
2952 					 domain->con_ipmb_addr[i][0],
2953 					 domain->con_ipmb_addr[i][0]);
2954 	    }
2955 	}
2956 	ipmi_unlock(domain->mc_lock);
2957 	return;
2958     }
2959 
2960     if (domain->scanning_bus_count) {
2961 	ipmi_unlock(domain->mc_lock);
2962 	return;
2963     }
2964 
2965     /* If a connections supports sysaddress scanning, then scan the
2966        system address for that connection. */
2967     for (i=0; i<MAX_CONS; i++) {
2968 	if ((domain->con_up[i]) && domain->conn[i]->scan_sysaddr) {
2969 	    i_ipmi_get_domain_fully_up(domain,
2970 				       "ipmi_domain_start_full_ipmb_scan");
2971 	    domain->scanning_bus_count++;
2972 	    rv = ipmi_start_si_scan(domain, i, mc_scan_done, NULL);
2973 	    if (rv) {
2974 		domain->scanning_bus_count--;
2975 		i_ipmi_put_domain_fully_up(domain,
2976 					   "ipmi_domain_start_full_ipmb_scan");
2977 	    }
2978 	}
2979     }
2980 
2981     /* Now start the IPMB scans. */
2982     for (i=0; i<MAX_IPMI_USED_CHANNELS; i++) {
2983 	if (domain->chan[i].medium == IPMI_CHANNEL_MEDIUM_IPMB) {
2984 	    if (!got_bmc) {
2985 		got_bmc = 1;
2986 		/* Always scan the normal BMC first. */
2987 		i_ipmi_start_mc_scan_one(domain, i, 0x20, 0x20);
2988 		i_ipmi_start_mc_scan_one(domain, i, 0x10, 0xf0);
2989 	    } else {
2990 		/* This is unfortunately complicated.  We only want
2991 		   the BMC to show up in one place, so we only scan
2992 		   the BMC's address on the first one.  If we have a
2993 		   system with two connections (two BMCs), we want to
2994 		   make sure they don't show up on each others lists.
2995 		   So except for the first IPMB, we ignore all BMC
2996 		   IPMB addresses. */
2997 		int ignore_addr[MAX_CONS];
2998 		int num_ignore = 0;
2999 		int cstart = 0x10;
3000 		for (j=0; j<MAX_CONS; j++) {
3001 		    if (! domain->conn[j])
3002 			continue;
3003 		    ignore_addr[num_ignore] = domain->con_ipmb_addr[j][i];
3004 		    num_ignore++;
3005 		}
3006 		qsort(ignore_addr, num_ignore, sizeof(int), cmp_int);
3007 		for (j=0; j<num_ignore; j++) {
3008 		    i_ipmi_start_mc_scan_one(domain, i,
3009 					     cstart, ignore_addr[j]-1);
3010 		    cstart = ignore_addr[j]+1;
3011 		}
3012 		if (cstart <= 0xf0)
3013 		    i_ipmi_start_mc_scan_one(domain, i, cstart, 0xf0);
3014 	    }
3015 	}
3016     }
3017     ipmi_unlock(domain->mc_lock);
3018 }
3019 
3020 static void
refetch_sdr_handler(ipmi_sdr_info_t * sdrs,int err,int changed,unsigned int count,void * cb_data)3021 refetch_sdr_handler(ipmi_sdr_info_t *sdrs,
3022 		    int             err,
3023 		    int             changed,
3024 		    unsigned int    count,
3025 		    void            *cb_data)
3026 {
3027     ipmi_domain_t *domain = cb_data;
3028 
3029     if (changed) {
3030 	ipmi_entity_scan_sdrs(domain, NULL,
3031 			      domain->entities, domain->main_sdrs);
3032 	ipmi_sensor_handle_sdrs(domain, NULL, domain->main_sdrs);
3033 	ipmi_detect_ents_presence_changes(domain->entities, 1);
3034 	i_ipmi_entities_report_sdrs_read(domain->entities);
3035     }
3036 }
3037 
3038 static void
check_main_sdrs(ipmi_domain_t * domain)3039 check_main_sdrs(ipmi_domain_t *domain)
3040 {
3041     if (ipmi_option_SDRs(domain))
3042 	ipmi_sdr_fetch(domain->main_sdrs, refetch_sdr_handler, domain);
3043 }
3044 
3045 static void
domain_audit(void * cb_data,os_hnd_timer_id_t * id)3046 domain_audit(void *cb_data, os_hnd_timer_id_t *id)
3047 {
3048     struct timeval      timeout;
3049     audit_domain_info_t *info = cb_data;
3050     ipmi_domain_t       *domain = info->domain;
3051     int                 rv;
3052 
3053     ipmi_lock(info->lock);
3054     if (info->cancelled) {
3055 	ipmi_unlock(info->lock);
3056 	info->os_hnd->free_timer(info->os_hnd, id);
3057 	ipmi_destroy_lock(info->lock);
3058 	ipmi_mem_free(info);
3059 	return;
3060     }
3061 
3062     rv = i_ipmi_domain_get(domain);
3063     if (rv)
3064 	goto out;
3065 
3066     if (domain->got_invalid_dev_id) {
3067 	/* Failure getting device id, just try again. */
3068 	domain_send_mc_id(domain);
3069 	goto out_start_timer;
3070     }
3071 
3072     /* Only operate if we know a connection is up. */
3073     if (! domain->connection_up)
3074 	goto out_start_timer;
3075 
3076     /* Rescan all the presence sensors to make sure they are valid. */
3077     ipmi_detect_domain_presence_changes(domain, 1);
3078 
3079     ipmi_domain_start_full_ipmb_scan(domain);
3080 
3081     /* Also check to see if the SDRs have changed. */
3082     check_main_sdrs(domain);
3083 
3084  out_start_timer:
3085     timeout.tv_sec = domain->audit_domain_interval;
3086     timeout.tv_usec = 0;
3087     domain->os_hnd->start_timer(domain->os_hnd,
3088 				id,
3089 				&timeout,
3090 				domain_audit,
3091 				info);
3092     i_ipmi_domain_put(domain);
3093  out:
3094     ipmi_unlock(info->lock);
3095 }
3096 
3097 /***********************************************************************
3098  *
3099  * Incoming event handling.
3100  *
3101  **********************************************************************/
3102 
3103 typedef struct event_sensor_info_s
3104 {
3105     int          err;
3106     ipmi_event_t *event;
3107 } event_sensor_info_t;
3108 
3109 void
event_sensor_cb(ipmi_sensor_t * sensor,void * cb_data)3110 event_sensor_cb(ipmi_sensor_t *sensor, void *cb_data)
3111 {
3112     event_sensor_info_t *info = cb_data;
3113 
3114     /* It's an event for a specific sensor, and the sensor exists. */
3115     info->err = ipmi_sensor_event(sensor, info->event);
3116 }
3117 
3118 void
i_ipmi_domain_system_event_handler(ipmi_domain_t * domain,ipmi_mc_t * ev_mc,ipmi_event_t * event)3119 i_ipmi_domain_system_event_handler(ipmi_domain_t *domain,
3120 				   ipmi_mc_t     *ev_mc,
3121 				   ipmi_event_t  *event)
3122 {
3123     int          rv = 1;
3124     ipmi_time_t  timestamp = ipmi_event_get_timestamp(event);
3125     unsigned int type = ipmi_event_get_type(event);
3126 
3127     /* We do not need any locking to assure that events are delivered
3128        in order (from the same SEL).  Indeed, locking here wouldn't
3129        help.  But the event-fetching mechanisms are guaranteed to be
3130        single-threaded, so ordering is always preserved there. */
3131 
3132     if (DEBUG_EVENTS) {
3133 	ipmi_mcid_t         mcid = ipmi_event_get_mcid(event);
3134 	unsigned int        record_id = ipmi_event_get_record_id(event);
3135 	unsigned int        data_len = ipmi_event_get_data_len(event);
3136 	const unsigned char *data;
3137 
3138 	ipmi_log(IPMI_LOG_DEBUG_START,
3139 		 "Event recid mc (0x%x):%4.4x type:%2.2x timestamp %lld:",
3140 		 mcid.mc_num, record_id, type, (long long) timestamp);
3141 	if (data_len) {
3142 	    ipmi_log(IPMI_LOG_DEBUG_CONT, "\n  ");
3143 	    data = ipmi_event_get_data_ptr(event);
3144 	    dump_hex(data, data_len);
3145 	}
3146 	ipmi_log(IPMI_LOG_DEBUG_END, " ");
3147     }
3148 
3149     /* Let the OEM handler for the MC that the message came from have
3150        a go at it first.  Note that OEM handlers must look at the time
3151        themselves. */
3152     if (i_ipmi_mc_check_sel_oem_event_handler(ev_mc, event))
3153 	return;
3154 
3155     /* It's a system event record from an MC, and the timestamp is
3156        later than our startup timestamp. */
3157     if ((type == 0x02) && !ipmi_event_is_old(event)) {
3158 	/* It's a standard IPMI event. */
3159 	ipmi_mc_t           *mc;
3160 	ipmi_sensor_id_t    id;
3161 	event_sensor_info_t info;
3162 	const unsigned char *data;
3163 
3164 	mc = i_ipmi_event_get_generating_mc(domain, ev_mc, event);
3165 	if (!mc)
3166 	    goto out;
3167 
3168 	/* Let the OEM handler for the MC that sent the event try
3169 	   next. */
3170 	if (i_ipmi_mc_check_oem_event_handler(mc, event)) {
3171 	    i_ipmi_mc_put(mc);
3172 	    return;
3173 	}
3174 
3175 	/* The OEM code didn't handle it. */
3176 	data = ipmi_event_get_data_ptr(event);
3177 	id.mcid = ipmi_mc_convert_to_id(mc);
3178 	id.lun = data[5] & 0x3;
3179 	id.sensor_num = data[8];
3180 
3181 	info.event = event;
3182 
3183 	rv = ipmi_sensor_pointer_cb(id, event_sensor_cb, &info);
3184 	if (!rv)
3185 	    rv = info.err;
3186 
3187 	i_ipmi_mc_put(mc);
3188     }
3189 
3190  out:
3191     /* It's an event from system software, or the info couldn't be found. */
3192     if (rv)
3193 	ipmi_handle_unhandled_event(domain, event);
3194 }
3195 
3196 static void
ll_event_handler(ipmi_con_t * ipmi,const ipmi_addr_t * addr,unsigned int addr_len,ipmi_event_t * event,void * cb_data)3197 ll_event_handler(ipmi_con_t        *ipmi,
3198 		 const ipmi_addr_t *addr,
3199 		 unsigned int      addr_len,
3200 		 ipmi_event_t      *event,
3201 		 void              *cb_data)
3202 {
3203     ipmi_domain_t                *domain = cb_data;
3204     ipmi_mc_t                    *mc;
3205     int                          rv;
3206     ipmi_system_interface_addr_t si;
3207 
3208     rv = i_ipmi_domain_get(domain);
3209     if (rv)
3210 	return;
3211 
3212     /* Convert the address to the proper one if it comes from a
3213        specific connection. */
3214     if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
3215 	int i;
3216 
3217 	for (i=0; i<MAX_CONS; i++) {
3218 	    if (domain->conn[i] == ipmi)
3219 		break;
3220 	}
3221 	if (i == MAX_CONS)
3222 	    goto out;
3223 	addr = (ipmi_addr_t *) &si;
3224 	si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3225 	si.channel = i;
3226 	si.lun = 0;
3227 	addr_len = sizeof(si);
3228     }
3229 
3230     /* It came from an MC, so find the MC. */
3231     mc = i_ipmi_find_mc_by_addr(domain, addr, addr_len);
3232     if (!mc)
3233 	goto out;
3234     ipmi_event_set_mcid(event, ipmi_mc_convert_to_id(mc));
3235 
3236     if (event == NULL) {
3237 	/* The incoming event didn't carry the full event information.
3238 	   Just scan for events in the MC's SEL. */
3239 	ipmi_mc_reread_sel(mc, NULL, NULL);
3240     } else {
3241 	/* Add it to the mc's event log. */
3242 	rv = i_ipmi_mc_sel_event_add(mc, event);
3243 
3244 	if (rv != EEXIST)
3245 	    /* Call the handler on it if it wasn't already in there. */
3246 	    i_ipmi_domain_system_event_handler(domain, mc, event);
3247     }
3248     i_ipmi_mc_put(mc);
3249 
3250  out:
3251     i_ipmi_domain_put(domain);
3252 }
3253 
3254 typedef struct call_event_handler_s
3255 {
3256     ipmi_domain_t *domain;
3257     ipmi_event_t  *event;
3258 } call_event_handler_t;
3259 
3260 static int
call_event_handler(void * cb_data,void * item1,void * item2)3261 call_event_handler(void *cb_data, void *item1, void *item2)
3262 {
3263     call_event_handler_t  *info = cb_data;
3264     ipmi_event_handler_cb handler = item1;
3265 
3266     handler(info->domain, info->event, item2);
3267     return LOCKED_LIST_ITER_CONTINUE;
3268 }
3269 
3270 void
ipmi_handle_unhandled_event(ipmi_domain_t * domain,ipmi_event_t * event)3271 ipmi_handle_unhandled_event(ipmi_domain_t *domain, ipmi_event_t *event)
3272 {
3273     call_event_handler_t info;
3274 
3275     info.domain = domain;
3276     info.event = event;
3277     locked_list_iterate(domain->event_handlers, call_event_handler, &info);
3278 }
3279 
3280 int
ipmi_domain_add_event_handler(ipmi_domain_t * domain,ipmi_event_handler_cb handler,void * cb_data)3281 ipmi_domain_add_event_handler(ipmi_domain_t           *domain,
3282 			      ipmi_event_handler_cb   handler,
3283 			      void                    *cb_data)
3284 {
3285     CHECK_DOMAIN_LOCK(domain);
3286 
3287     if (locked_list_add(domain->event_handlers, handler, cb_data))
3288 	return 0;
3289     else
3290 	return ENOMEM;
3291 }
3292 
3293 int
ipmi_domain_remove_event_handler(ipmi_domain_t * domain,ipmi_event_handler_cb handler,void * cb_data)3294 ipmi_domain_remove_event_handler(ipmi_domain_t           *domain,
3295 				 ipmi_event_handler_cb   handler,
3296 				 void                    *cb_data)
3297 {
3298     CHECK_DOMAIN_LOCK(domain);
3299 
3300     if (locked_list_remove(domain->event_handlers, handler, cb_data))
3301 	return 0;
3302     else
3303 	return EINVAL;
3304 }
3305 
3306 typedef struct event_handler_cl_info_s
3307 {
3308     ipmi_event_handler_cb handler;
3309     void                  *handler_data;
3310 } event_handler_cl_info_t;
3311 
3312 
3313 static int
iterate_event_handler_cl(void * cb_data,void * item1,void * item2)3314 iterate_event_handler_cl(void *cb_data, void *item1, void *item2)
3315 {
3316     event_handler_cl_info_t  *info = cb_data;
3317     ipmi_event_handler_cl_cb handler = item1;
3318 
3319     handler(info->handler, info->handler_data, item2);
3320     return LOCKED_LIST_ITER_CONTINUE;
3321 }
3322 
3323 static void
call_event_handler_cl_handlers(ipmi_domain_t * domain,ipmi_event_handler_cb handler,void * handler_data)3324 call_event_handler_cl_handlers(ipmi_domain_t         *domain,
3325 			       ipmi_event_handler_cb handler,
3326 			       void                  *handler_data)
3327 {
3328     event_handler_cl_info_t info;
3329 
3330     info.handler = handler;
3331     info.handler_data = handler_data;
3332     locked_list_iterate(domain->event_handlers_cl, iterate_event_handler_cl,
3333 			&info);
3334 }
3335 
3336 int
ipmi_domain_add_event_handler_cl(ipmi_domain_t * domain,ipmi_event_handler_cl_cb handler,void * cb_data)3337 ipmi_domain_add_event_handler_cl(ipmi_domain_t            *domain,
3338 				 ipmi_event_handler_cl_cb handler,
3339 				 void                     *cb_data)
3340 {
3341     CHECK_DOMAIN_LOCK(domain);
3342 
3343     if (locked_list_add(domain->event_handlers_cl, handler, cb_data))
3344 	return 0;
3345     else
3346 	return ENOMEM;
3347 }
3348 
3349 int
ipmi_domain_remove_event_handler_cl(ipmi_domain_t * domain,ipmi_event_handler_cl_cb handler,void * cb_data)3350 ipmi_domain_remove_event_handler_cl(ipmi_domain_t            *domain,
3351 				    ipmi_event_handler_cl_cb handler,
3352 				    void                     *cb_data)
3353 {
3354     CHECK_DOMAIN_LOCK(domain);
3355 
3356     if (locked_list_remove(domain->event_handlers_cl, handler, cb_data))
3357 	return 0;
3358     else
3359 	return EINVAL;
3360 }
3361 
3362 int
ipmi_domain_disable_events(ipmi_domain_t * domain)3363 ipmi_domain_disable_events(ipmi_domain_t *domain)
3364 {
3365     int rv;
3366     int return_rv = 0;
3367     int i;
3368 
3369     CHECK_DOMAIN_LOCK(domain);
3370 
3371     for (i=0; i<MAX_CONS; i++) {
3372 	rv = domain->conn[i]->remove_event_handler(domain->conn[i],
3373 						   ll_event_handler,
3374 						   domain);
3375 	if (!return_rv)
3376 	    return_rv = rv;
3377     }
3378     return return_rv;
3379 }
3380 
3381 int
ipmi_domain_enable_events(ipmi_domain_t * domain)3382 ipmi_domain_enable_events(ipmi_domain_t *domain)
3383 {
3384     int return_rv = 0;
3385     int rv;
3386     int i;
3387 
3388     CHECK_DOMAIN_LOCK(domain);
3389 
3390     for (i=0; i<MAX_CONS; i++) {
3391 	if (! domain->conn[i])
3392 	    continue;
3393 
3394 	rv = domain->conn[i]->add_event_handler(domain->conn[i],
3395 						ll_event_handler,
3396 						domain);
3397 	if (!return_rv)
3398 	    return_rv = rv;
3399     }
3400     return return_rv;
3401 }
3402 
3403 /***********************************************************************
3404  *
3405  * SEL handling
3406  *
3407  **********************************************************************/
3408 
3409 int
ipmi_domain_del_event(ipmi_domain_t * domain,ipmi_event_t * event,ipmi_domain_cb done_handler,void * cb_data)3410 ipmi_domain_del_event(ipmi_domain_t  *domain,
3411 		      ipmi_event_t   *event,
3412 		      ipmi_domain_cb done_handler,
3413 		      void           *cb_data)
3414 {
3415     return ipmi_event_delete(event, done_handler, cb_data);
3416 }
3417 
3418 typedef struct next_event_handler_info_s
3419 {
3420     ipmi_event_t       *rv;
3421     const ipmi_event_t *event;
3422     ipmi_mcid_t        event_mcid;
3423     int                found_curr_mc;
3424     int                do_prev; /* If going backwards, this will be 1. */
3425 } next_event_handler_info_t;
3426 
3427 static void
next_event_handler(ipmi_domain_t * domain,ipmi_mc_t * mc,void * cb_data)3428 next_event_handler(ipmi_domain_t *domain, ipmi_mc_t *mc, void *cb_data)
3429 {
3430     next_event_handler_info_t *info = cb_data;
3431     ipmi_mcid_t               mcid = ipmi_mc_convert_to_id(mc);
3432 
3433     if (info->rv)
3434 	/* We've found an event already, just return. */
3435 	return;
3436 
3437     if (info->do_prev) {
3438 	if (info->found_curr_mc)
3439 	    /* We've found the MC that had the event, but it didn't have
3440 	       any more events.  Look for last events now. */
3441 	    info->rv = ipmi_mc_last_event(mc);
3442 	else if (ipmi_cmp_mc_id(info->event_mcid, mcid) == 0) {
3443 	    info->found_curr_mc = 1;
3444 	    info->rv = ipmi_mc_prev_event(mc, info->event);
3445 	}
3446     } else {
3447 	if (info->found_curr_mc)
3448 	    /* We've found the MC that had the event, but it didn't have
3449 	       any more events.  Look for first events now. */
3450 	    info->rv = ipmi_mc_first_event(mc);
3451 	else if (ipmi_cmp_mc_id(info->event_mcid, mcid) == 0) {
3452 	    info->found_curr_mc = 1;
3453 	    info->rv = ipmi_mc_next_event(mc, info->event);
3454 	}
3455     }
3456 }
3457 
3458 ipmi_event_t *
ipmi_domain_first_event(ipmi_domain_t * domain)3459 ipmi_domain_first_event(ipmi_domain_t *domain)
3460 {
3461     next_event_handler_info_t info;
3462 
3463     CHECK_DOMAIN_LOCK(domain);
3464 
3465     info.rv = NULL;
3466     info.event = NULL;
3467     info.found_curr_mc = 1;
3468     info.do_prev = 0;
3469     ipmi_domain_iterate_mcs(domain, next_event_handler, &info);
3470 
3471     return info.rv;
3472 }
3473 
3474 ipmi_event_t *
ipmi_domain_last_event(ipmi_domain_t * domain)3475 ipmi_domain_last_event(ipmi_domain_t *domain)
3476 {
3477     next_event_handler_info_t info;
3478 
3479     CHECK_DOMAIN_LOCK(domain);
3480 
3481     info.rv = NULL;
3482     info.event = NULL;
3483     info.found_curr_mc = 1;
3484     info.do_prev = 1;
3485     ipmi_domain_iterate_mcs_rev(domain, next_event_handler, &info);
3486 
3487     return info.rv;
3488 }
3489 
3490 ipmi_event_t *
ipmi_domain_next_event(ipmi_domain_t * domain,const ipmi_event_t * event)3491 ipmi_domain_next_event(ipmi_domain_t *domain, const ipmi_event_t *event)
3492 {
3493     next_event_handler_info_t info;
3494 
3495     CHECK_DOMAIN_LOCK(domain);
3496 
3497     info.rv = NULL;
3498     info.event = event;
3499     info.found_curr_mc = 0;
3500     info.do_prev = 0;
3501     info.event_mcid = ipmi_event_get_mcid(event);
3502     ipmi_domain_iterate_mcs(domain, next_event_handler, &info);
3503 
3504     return info.rv;
3505 }
3506 
3507 ipmi_event_t *
ipmi_domain_prev_event(ipmi_domain_t * domain,const ipmi_event_t * event)3508 ipmi_domain_prev_event(ipmi_domain_t *domain, const ipmi_event_t *event)
3509 {
3510     next_event_handler_info_t info;
3511 
3512     CHECK_DOMAIN_LOCK(domain);
3513 
3514     info.rv = NULL;
3515     info.event = event;
3516     info.found_curr_mc = 0;
3517     info.do_prev = 1;
3518     info.event_mcid = ipmi_event_get_mcid(event);
3519     ipmi_domain_iterate_mcs_rev(domain, next_event_handler, &info);
3520 
3521     return info.rv;
3522 }
3523 
3524 static void
sel_count_handler(ipmi_domain_t * domain,ipmi_mc_t * mc,void * cb_data)3525 sel_count_handler(ipmi_domain_t *domain, ipmi_mc_t *mc, void *cb_data)
3526 {
3527     int *count = cb_data;
3528 
3529     *count += ipmi_mc_sel_count(mc);
3530 }
3531 
3532 int
ipmi_domain_sel_count(ipmi_domain_t * domain,unsigned int * count)3533 ipmi_domain_sel_count(ipmi_domain_t *domain,
3534 		      unsigned int  *count)
3535 {
3536     CHECK_DOMAIN_LOCK(domain);
3537 
3538     *count = 0;
3539     ipmi_domain_iterate_mcs(domain, sel_count_handler, count);
3540     return 0;
3541 }
3542 
3543 static void
sel_entries_used_handler(ipmi_domain_t * domain,ipmi_mc_t * mc,void * cb_data)3544 sel_entries_used_handler(ipmi_domain_t *domain, ipmi_mc_t *mc, void *cb_data)
3545 {
3546     int *count = cb_data;
3547 
3548     *count += ipmi_mc_sel_entries_used(mc);
3549 }
3550 
ipmi_domain_sel_entries_used(ipmi_domain_t * domain,unsigned int * count)3551 int ipmi_domain_sel_entries_used(ipmi_domain_t *domain,
3552 				 unsigned int  *count)
3553 {
3554     CHECK_DOMAIN_LOCK(domain);
3555 
3556     *count = 0;
3557     ipmi_domain_iterate_mcs(domain, sel_entries_used_handler, count);
3558     return 0;
3559 }
3560 
3561 static void
set_sel_rescan_time(ipmi_domain_t * domain,ipmi_mc_t * mc,void * cb_data)3562 set_sel_rescan_time(ipmi_domain_t *domain, ipmi_mc_t *mc, void *cb_data)
3563 {
3564     ipmi_mc_set_sel_rescan_time(mc, domain->default_sel_rescan_time);
3565 }
3566 
3567 void
ipmi_domain_set_sel_rescan_time(ipmi_domain_t * domain,unsigned int seconds)3568 ipmi_domain_set_sel_rescan_time(ipmi_domain_t *domain,
3569 				unsigned int  seconds)
3570 {
3571     CHECK_DOMAIN_LOCK(domain);
3572 
3573     domain->default_sel_rescan_time = seconds;
3574     ipmi_domain_iterate_mcs(domain, set_sel_rescan_time, NULL);
3575 }
3576 
3577 unsigned int
ipmi_domain_get_sel_rescan_time(ipmi_domain_t * domain)3578 ipmi_domain_get_sel_rescan_time(ipmi_domain_t *domain)
3579 {
3580     CHECK_DOMAIN_LOCK(domain);
3581 
3582     return domain->default_sel_rescan_time;
3583 }
3584 
3585 /* Code to explicitly reread all the SELs in the domain. */
3586 typedef struct sels_reread_s
3587 {
3588     /* The number of pending requests. */
3589     int         count;
3590 
3591     /* The actual number of MCs we tried to request from .*/
3592     int         tried;
3593 
3594     /* This is the last error that occurred. */
3595     int         err;
3596 
3597     ipmi_domain_cb handler;
3598     void           *cb_data;
3599 
3600     /* We may have multiple threads going at the data from multiple
3601        SEL reads, so we need to protect the data. */
3602     ipmi_lock_t *lock;
3603 
3604     ipmi_domain_t *domain;
3605 } sels_reread_t;
3606 
3607 static void
reread_sel_handler(ipmi_mc_t * mc,int err,void * cb_data)3608 reread_sel_handler(ipmi_mc_t *mc, int err, void *cb_data)
3609 {
3610     sels_reread_t *info = cb_data;
3611     int           count;
3612     int           rv;
3613 
3614     ipmi_lock(info->lock);
3615     info->count--;
3616     count = info->count;
3617     if (err)
3618 	info->err = err;
3619     ipmi_unlock(info->lock);
3620     if (count == 0) {
3621 	/* We were the last one, call the main handler. */
3622 
3623 	/* First validate the domain. */
3624 	rv = i_ipmi_domain_get(info->domain);
3625 	if (rv)
3626 	    info->domain = NULL;
3627 
3628 	if (info->handler)
3629 	    info->handler(info->domain, info->err, info->cb_data);
3630 	ipmi_destroy_lock(info->lock);
3631 	if (info->domain)
3632 	    i_ipmi_domain_put(info->domain);
3633 	ipmi_mem_free(info);
3634     }
3635 }
3636 
3637 static void
reread_sels_handler(ipmi_domain_t * domain,ipmi_mc_t * mc,void * cb_data)3638 reread_sels_handler(ipmi_domain_t *domain,
3639 		    ipmi_mc_t     *mc,
3640 		    void          *cb_data)
3641 {
3642     sels_reread_t *info = cb_data;
3643     int           rv;
3644 
3645     if (ipmi_mc_sel_device_support(mc)) {
3646 	info->tried++;
3647 	rv = ipmi_mc_reread_sel(mc, reread_sel_handler, info);
3648 	if (rv)
3649 	    info->err = rv;
3650 	else
3651 	    info->count++;
3652     }
3653 }
3654 
3655 int
ipmi_domain_reread_sels(ipmi_domain_t * domain,ipmi_domain_cb handler,void * cb_data)3656 ipmi_domain_reread_sels(ipmi_domain_t  *domain,
3657 			ipmi_domain_cb handler,
3658 			void           *cb_data)
3659 {
3660     sels_reread_t *info;
3661     int           rv;
3662 
3663     info = ipmi_mem_alloc(sizeof(*info));
3664     if (!info)
3665 	return ENOMEM;
3666 
3667     rv = ipmi_create_lock(domain, &info->lock);
3668     if (rv) {
3669 	ipmi_mem_free(info);
3670 	return rv;
3671     }
3672     info->count = 0;
3673     info->tried = 0;
3674     info->err = 0;
3675     info->domain = domain;
3676     info->handler = handler;
3677     info->cb_data = cb_data;
3678     ipmi_lock(info->lock);
3679     rv = ipmi_domain_iterate_mcs(domain, reread_sels_handler, info);
3680     if (rv) {
3681 	ipmi_unlock(info->lock);
3682 	ipmi_destroy_lock(info->lock);
3683 	ipmi_mem_free(info);
3684 	return rv;
3685     }
3686     if ((info->tried > 0) && (info->count == 0)) {
3687 	/* We tried to do an SEL fetch, but failed to actually
3688 	   accomplish any.  Return an error. */
3689 	rv = info->err;
3690 	ipmi_unlock(info->lock);
3691 	ipmi_destroy_lock(info->lock);
3692 	ipmi_mem_free(info);
3693 	return rv;
3694     }
3695 
3696     if (info->count == 0) {
3697 	/* No requests, so return an error. */
3698 	ipmi_unlock(info->lock);
3699 	ipmi_destroy_lock(info->lock);
3700 	ipmi_mem_free(info);
3701 	return ENOSYS;
3702     }
3703     ipmi_unlock(info->lock);
3704 
3705     return 0;
3706 }
3707 
3708 /***********************************************************************
3709  *
3710  * Generic handling of entities and MCs.
3711  *
3712  **********************************************************************/
3713 
3714 int
ipmi_detect_domain_presence_changes(ipmi_domain_t * domain,int force)3715 ipmi_detect_domain_presence_changes(ipmi_domain_t *domain, int force)
3716 {
3717     int rv;
3718 
3719     CHECK_DOMAIN_LOCK(domain);
3720 
3721     rv = ipmi_detect_ents_presence_changes(domain->entities, force);
3722     return rv;
3723 }
3724 
3725 os_handler_t *
ipmi_domain_get_os_hnd(ipmi_domain_t * domain)3726 ipmi_domain_get_os_hnd(ipmi_domain_t *domain)
3727 {
3728     CHECK_DOMAIN_LOCK(domain);
3729     return domain->os_hnd;
3730 }
3731 
3732 ipmi_entity_info_t *
ipmi_domain_get_entities(ipmi_domain_t * domain)3733 ipmi_domain_get_entities(ipmi_domain_t *domain)
3734 {
3735     CHECK_DOMAIN_LOCK(domain);
3736     return domain->entities;
3737 }
3738 
3739 void
i_ipmi_get_sdr_sensors(ipmi_domain_t * domain,ipmi_mc_t * mc,ipmi_sensor_t *** sensors,unsigned int * count)3740 i_ipmi_get_sdr_sensors(ipmi_domain_t *domain,
3741 		       ipmi_mc_t     *mc,
3742 		       ipmi_sensor_t ***sensors,
3743 		       unsigned int  *count)
3744 {
3745     if (mc) {
3746 	i_ipmi_mc_get_sdr_sensors(mc, sensors, count);
3747     } else {
3748 	CHECK_DOMAIN_LOCK(domain);
3749 	*sensors = domain->sensors_in_main_sdr;
3750 	*count = domain->sensors_in_main_sdr_count;
3751     }
3752 }
3753 
3754 void
i_ipmi_set_sdr_sensors(ipmi_domain_t * domain,ipmi_mc_t * mc,ipmi_sensor_t ** sensors,unsigned int count)3755 i_ipmi_set_sdr_sensors(ipmi_domain_t *domain,
3756 		       ipmi_mc_t     *mc,
3757 		       ipmi_sensor_t **sensors,
3758 		       unsigned int  count)
3759 {
3760     if (mc) {
3761 	i_ipmi_mc_set_sdr_sensors(mc, sensors, count);
3762     } else {
3763 	CHECK_DOMAIN_LOCK(domain);
3764 	domain->sensors_in_main_sdr = sensors;
3765 	domain->sensors_in_main_sdr_count = count;
3766     }
3767 }
3768 
3769 void *
i_ipmi_get_sdr_entities(ipmi_domain_t * domain,ipmi_mc_t * mc)3770 i_ipmi_get_sdr_entities(ipmi_domain_t *domain,
3771 			ipmi_mc_t     *mc)
3772 {
3773     if (mc) {
3774 	return i_ipmi_mc_get_sdr_entities(mc);
3775     } else {
3776 	CHECK_DOMAIN_LOCK(domain);
3777 	return domain->entities_in_main_sdr;
3778     }
3779 }
3780 
3781 void
i_ipmi_set_sdr_entities(ipmi_domain_t * domain,ipmi_mc_t * mc,void * entities)3782 i_ipmi_set_sdr_entities(ipmi_domain_t *domain,
3783 			ipmi_mc_t     *mc,
3784 			void          *entities)
3785 {
3786     if (mc) {
3787 	i_ipmi_mc_set_sdr_entities(mc, entities);
3788     } else {
3789 	CHECK_DOMAIN_LOCK(domain);
3790 	domain->entities_in_main_sdr = entities;
3791     }
3792 }
3793 
3794 int
ipmi_domain_add_entity_update_handler(ipmi_domain_t * domain,ipmi_domain_entity_cb handler,void * cb_data)3795 ipmi_domain_add_entity_update_handler(ipmi_domain_t         *domain,
3796 				      ipmi_domain_entity_cb handler,
3797 				      void                  *cb_data)
3798 {
3799     CHECK_DOMAIN_LOCK(domain);
3800 
3801     return ipmi_entity_info_add_update_handler(domain->entities,
3802 					       handler,
3803 					       cb_data);
3804 }
3805 
3806 int
ipmi_domain_remove_entity_update_handler(ipmi_domain_t * domain,ipmi_domain_entity_cb handler,void * cb_data)3807 ipmi_domain_remove_entity_update_handler(ipmi_domain_t         *domain,
3808 					 ipmi_domain_entity_cb handler,
3809 					 void                  *cb_data)
3810 {
3811     CHECK_DOMAIN_LOCK(domain);
3812 
3813     return ipmi_entity_info_remove_update_handler(domain->entities,
3814 						  handler,
3815 						  cb_data);
3816 }
3817 
3818 int
ipmi_domain_add_entity_update_handler_cl(ipmi_domain_t * domain,ipmi_domain_entity_cl_cb handler,void * cb_data)3819 ipmi_domain_add_entity_update_handler_cl(ipmi_domain_t            *domain,
3820 					 ipmi_domain_entity_cl_cb handler,
3821 					 void                     *cb_data)
3822 {
3823     CHECK_DOMAIN_LOCK(domain);
3824 
3825     return ipmi_entity_info_add_update_handler_cl(domain->entities,
3826 						  handler,
3827 						  cb_data);
3828 }
3829 
3830 int
ipmi_domain_remove_entity_update_handler_cl(ipmi_domain_t * domain,ipmi_domain_entity_cl_cb handler,void * cb_data)3831 ipmi_domain_remove_entity_update_handler_cl(ipmi_domain_t            *domain,
3832 					    ipmi_domain_entity_cl_cb handler,
3833 					    void                     *cb_data)
3834 {
3835     CHECK_DOMAIN_LOCK(domain);
3836 
3837     return ipmi_entity_info_remove_update_handler_cl(domain->entities,
3838 						     handler,
3839 						     cb_data);
3840 }
3841 
3842 int
ipmi_domain_iterate_entities(ipmi_domain_t * domain,ipmi_entity_ptr_cb handler,void * cb_data)3843 ipmi_domain_iterate_entities(ipmi_domain_t      *domain,
3844 			     ipmi_entity_ptr_cb handler,
3845 			     void               *cb_data)
3846 {
3847     CHECK_DOMAIN_LOCK(domain);
3848 
3849     ipmi_entities_iterate_entities(domain->entities, handler, cb_data);
3850     return 0;
3851 }
3852 
3853 int
ipmi_domain_iterate_mcs(ipmi_domain_t * domain,ipmi_domain_iterate_mcs_cb handler,void * cb_data)3854 ipmi_domain_iterate_mcs(ipmi_domain_t              *domain,
3855 			ipmi_domain_iterate_mcs_cb handler,
3856 			void                       *cb_data)
3857 {
3858     int i, j;
3859 
3860     CHECK_DOMAIN_LOCK(domain);
3861 
3862     ipmi_lock(domain->mc_lock);
3863     for (i=0; i<MAX_CONS; i++) {
3864 	ipmi_mc_t *mc = domain->sys_intf_mcs[i];
3865 	if (mc && !i_ipmi_mc_get(mc)) {
3866 	    ipmi_unlock(domain->mc_lock);
3867 	    handler(domain, mc, cb_data);
3868 	    i_ipmi_mc_put(mc);
3869 	    ipmi_lock(domain->mc_lock);
3870 	}
3871     }
3872     for (i=0; i<IPMB_HASH; i++) {
3873 	mc_table_t *tab = &(domain->ipmb_mcs[i]);
3874 
3875 	for (j=0; j<tab->size; j++) {
3876 	    ipmi_mc_t *mc = tab->mcs[j];
3877 	    if (mc && !i_ipmi_mc_get(mc)) {
3878 		ipmi_unlock(domain->mc_lock);
3879 		handler(domain, mc, cb_data);
3880 		i_ipmi_mc_put(mc);
3881 		ipmi_lock(domain->mc_lock);
3882 	    }
3883 	}
3884     }
3885     ipmi_unlock(domain->mc_lock);
3886     return 0;
3887 }
3888 
3889 int
ipmi_domain_iterate_mcs_rev(ipmi_domain_t * domain,ipmi_domain_iterate_mcs_cb handler,void * cb_data)3890 ipmi_domain_iterate_mcs_rev(ipmi_domain_t              *domain,
3891 			    ipmi_domain_iterate_mcs_cb handler,
3892 			    void                       *cb_data)
3893 {
3894     int i, j;
3895 
3896     CHECK_DOMAIN_LOCK(domain);
3897 
3898     ipmi_lock(domain->mc_lock);
3899     for (i=IPMB_HASH-1; i>=0; i--) {
3900 	mc_table_t *tab = &(domain->ipmb_mcs[i]);
3901 
3902 	for (j=tab->size-1; j>=0; j--) {
3903 	    ipmi_mc_t *mc = tab->mcs[j];
3904 	    if (mc && !i_ipmi_mc_get(mc)) {
3905 		ipmi_unlock(domain->mc_lock);
3906 		handler(domain, mc, cb_data);
3907 		i_ipmi_mc_put(mc);
3908 		ipmi_lock(domain->mc_lock);
3909 	    }
3910 	}
3911     }
3912     for (i=MAX_CONS-1; i>=0; i--) {
3913 	ipmi_mc_t *mc = domain->sys_intf_mcs[i];
3914 	if (mc && !i_ipmi_mc_get(mc)) {
3915 	    ipmi_unlock(domain->mc_lock);
3916 	    handler(domain, mc, cb_data);
3917 	    i_ipmi_mc_put(mc);
3918 	    ipmi_lock(domain->mc_lock);
3919 	}
3920     }
3921     ipmi_unlock(domain->mc_lock);
3922     return 0;
3923 }
3924 
3925 #if SAVE_SDR_CODE_ENABLE
3926 typedef struct sdrs_saved_info_s
3927 {
3928     ipmi_domain_t  *domain;
3929     ipmi_domain_cb done;
3930     void           *cb_data;
3931 } sdrs_saved_info_t;
3932 
3933 static void
sdrs_saved(ipmi_sdr_info_t * sdrs,int err,void * cb_data)3934 sdrs_saved(ipmi_sdr_info_t *sdrs, int err, void *cb_data)
3935 {
3936     sdrs_saved_info_t *info = cb_data;
3937 
3938     info->done(info->domain, err, info->cb_data);
3939     ipmi_mem_free(info);
3940 }
3941 
3942 int
ipmi_domain_store_entities(ipmi_domain_t * domain,ipmi_domain_cb done,void * cb_data)3943 ipmi_domain_store_entities(ipmi_domain_t  *domain,
3944 			   ipmi_domain_cb done,
3945 			   void           *cb_data)
3946 {
3947     int               rv;
3948     ipmi_sdr_info_t   *stored_sdrs;
3949     sdrs_saved_info_t *info;
3950 
3951     /* FIXME - this is certainly broken. */
3952 
3953     CHECK_DOMAIN_LOCK(domain);
3954 
3955     info = ipmi_mem_alloc(sizeof(*info));
3956     if (!info)
3957 	return ENOMEM;
3958 
3959     /* Create an SDR repository to store. */
3960     rv = ipmi_sdr_info_alloc(domain, NULL, 0, 0, &stored_sdrs);
3961     if (rv) {
3962 	ipmi_mem_free(info);
3963 	return rv;
3964     }
3965 
3966     /* Now store a channel SDR in case we are less than 1.5. */
3967     {
3968 	ipmi_sdr_t sdr;
3969 	int        i;
3970 
3971 	sdr.major_version = 1;
3972 	sdr.minor_version = 0;
3973 	sdr.type = 0x14; /*  */
3974 	sdr.length = 11;
3975 	for (i=0; i<8; i++) {
3976 	    /* FIXME - what about the LUN and transmit support? */
3977 	    if (domain->chan[i].protocol) {
3978 		sdr.data[i] = (domain->chan[i].protocol
3979 			       | (domain->chan[i].xmit_support << 7)
3980 			       | (domain->chan[i].recv_lun << 4));
3981 	    } else {
3982 		sdr.data[i] = 0;
3983 	    }
3984 	}
3985 	sdr.data[8] = domain->msg_int_type;
3986 	sdr.data[9] = domain->event_msg_int_type;
3987 	sdr.data[10] = 0;
3988 
3989 	rv = ipmi_sdr_add(stored_sdrs, &sdr);
3990 	if (rv)
3991 	    goto out_err;
3992     }
3993 
3994     rv = ipmi_entity_append_to_sdrs(domain->entities, stored_sdrs);
3995     if (rv)
3996 	goto out_err;
3997 
3998     info->domain = domain;
3999     info->done = done;
4000     info->cb_data = cb_data;
4001     rv = ipmi_sdr_save(stored_sdrs, sdrs_saved, info);
4002 
4003  out_err:
4004     if (rv)
4005 	ipmi_mem_free(info);
4006     ipmi_sdr_info_destroy(stored_sdrs, NULL, NULL);
4007     return rv;
4008 }
4009 #endif
4010 
4011 /***********************************************************************
4012  *
4013  * ID handling
4014  *
4015  **********************************************************************/
4016 
4017 ipmi_domain_id_t
ipmi_domain_convert_to_id(ipmi_domain_t * domain)4018 ipmi_domain_convert_to_id(ipmi_domain_t *domain)
4019 {
4020     ipmi_domain_id_t val;
4021 
4022     CHECK_DOMAIN_LOCK(domain);
4023 
4024     val.domain = domain;
4025     return val;
4026 }
4027 
4028 int
ipmi_domain_pointer_cb(ipmi_domain_id_t id,ipmi_domain_ptr_cb handler,void * cb_data)4029 ipmi_domain_pointer_cb(ipmi_domain_id_t   id,
4030 		       ipmi_domain_ptr_cb handler,
4031 		       void               *cb_data)
4032 {
4033     int           rv;
4034     ipmi_domain_t *domain;
4035 
4036     domain = id.domain;
4037 
4038     rv = i_ipmi_domain_get(domain);
4039     if (!rv) {
4040 	handler(domain, cb_data);
4041 	i_ipmi_domain_put(domain);
4042     }
4043 
4044     return rv;
4045 }
4046 
4047 int
ipmi_cmp_domain_id(ipmi_domain_id_t id1,ipmi_domain_id_t id2)4048 ipmi_cmp_domain_id(ipmi_domain_id_t id1, ipmi_domain_id_t id2)
4049 {
4050     if (id1.domain > id2.domain)
4051 	return 1;
4052     if (id1.domain < id2.domain)
4053 	return -1;
4054     return 0;
4055 }
4056 
4057 void
ipmi_domain_id_set_invalid(ipmi_domain_id_t * id)4058 ipmi_domain_id_set_invalid(ipmi_domain_id_t *id)
4059 {
4060     id->domain = NULL;
4061 }
4062 
4063 int
ipmi_domain_id_is_invalid(const ipmi_domain_id_t * id)4064 ipmi_domain_id_is_invalid(const ipmi_domain_id_t *id)
4065 {
4066     return (id->domain == NULL);
4067 }
4068 
4069 /***********************************************************************
4070  *
4071  * Handle global OEM callbacks for new domain MCs.
4072  *
4073  **********************************************************************/
4074 
4075 typedef struct mc_oem_handlers_s {
4076     unsigned int                 manufacturer_id;
4077     unsigned int                 first_product_id;
4078     unsigned int                 last_product_id;
4079     ipmi_oem_domain_match_handler_cb handler;
4080     ipmi_oem_domain_shutdown_handler_cb shutdown;
4081     void                         *cb_data;
4082 } mc_oem_handlers_t;
4083 
4084 static locked_list_t *mc_oem_handlers;
4085 
4086 int
ipmi_domain_register_oem_handler(unsigned int manufacturer_id,unsigned int product_id,ipmi_oem_domain_match_handler_cb handler,ipmi_oem_domain_shutdown_handler_cb shutdown,void * cb_data)4087 ipmi_domain_register_oem_handler(unsigned int                 manufacturer_id,
4088 				 unsigned int                 product_id,
4089 				 ipmi_oem_domain_match_handler_cb handler,
4090 				 ipmi_oem_domain_shutdown_handler_cb shutdown,
4091 				 void                         *cb_data)
4092 {
4093     mc_oem_handlers_t *new_item;
4094     int               rv;
4095 
4096     /* This might be called before initialization, so be 100% sure. */
4097     rv = i_ipmi_domain_init();
4098     if (rv)
4099 	return rv;
4100 
4101     new_item = ipmi_mem_alloc(sizeof(*new_item));
4102     if (!new_item)
4103 	return ENOMEM;
4104 
4105     new_item->manufacturer_id = manufacturer_id;
4106     new_item->first_product_id = product_id;
4107     new_item->last_product_id = product_id;
4108     new_item->handler = handler;
4109     new_item->shutdown = shutdown;
4110     new_item->cb_data = cb_data;
4111 
4112     if (! locked_list_add(mc_oem_handlers, new_item, NULL)) {
4113 	ipmi_mem_free(new_item);
4114 	return ENOMEM;
4115     }
4116 
4117     return 0;
4118 }
4119 
4120 int
ipmi_domain_register_oem_handler_range(unsigned int manufacturer_id,unsigned int first_product_id,unsigned int last_product_id,ipmi_oem_domain_match_handler_cb handler,ipmi_oem_domain_shutdown_handler_cb shutdown,void * cb_data)4121 ipmi_domain_register_oem_handler_range(unsigned int           manufacturer_id,
4122 				       unsigned int           first_product_id,
4123 				       unsigned int           last_product_id,
4124 				       ipmi_oem_domain_match_handler_cb handler,
4125 				       ipmi_oem_domain_shutdown_handler_cb shutdown,
4126 				       void                         *cb_data)
4127 {
4128     mc_oem_handlers_t *new_item;
4129     int               rv;
4130 
4131     /* This might be called before initialization, so be 100% sure. */
4132     rv = i_ipmi_mc_init();
4133     if (rv)
4134 	return rv;
4135 
4136     new_item = ipmi_mem_alloc(sizeof(*new_item));
4137     if (!new_item)
4138 	return ENOMEM;
4139 
4140     new_item->manufacturer_id = manufacturer_id;
4141     new_item->first_product_id = first_product_id;
4142     new_item->last_product_id = last_product_id;
4143     new_item->handler = handler;
4144     new_item->shutdown = shutdown;
4145     new_item->cb_data = cb_data;
4146 
4147     if (! locked_list_add(mc_oem_handlers, new_item, NULL)) {
4148 	ipmi_mem_free(new_item);
4149 	return ENOMEM;
4150     }
4151 
4152     return 0;
4153 }
4154 
4155 typedef struct handler_cmp_s
4156 {
4157     int           rv;
4158     unsigned int  manufacturer_id;
4159     unsigned int  first_product_id;
4160     unsigned int  last_product_id;
4161     ipmi_domain_t *domain;
4162 } handler_cmp_t;
4163 
4164 static int
mc_oem_handler_cmp_dereg(void * cb_data,void * item1,void * item2)4165 mc_oem_handler_cmp_dereg(void *cb_data, void *item1, void *item2)
4166 {
4167     mc_oem_handlers_t *hndlr = item1;
4168     handler_cmp_t     *cmp = cb_data;
4169 
4170     if ((hndlr->manufacturer_id == cmp->manufacturer_id)
4171 	&& (hndlr->first_product_id <= cmp->first_product_id)
4172 	&& (hndlr->last_product_id >= cmp->last_product_id))
4173     {
4174 	cmp->rv = 0;
4175 	locked_list_remove(mc_oem_handlers, item1, item2);
4176 	ipmi_mem_free(hndlr);
4177 	return LOCKED_LIST_ITER_STOP;
4178     }
4179     return LOCKED_LIST_ITER_CONTINUE;
4180 }
4181 
4182 int
ipmi_domain_deregister_oem_handler(unsigned int manufacturer_id,unsigned int product_id)4183 ipmi_domain_deregister_oem_handler(unsigned int manufacturer_id,
4184 				   unsigned int product_id)
4185 {
4186     handler_cmp_t  tmp;
4187 
4188     tmp.rv = ENOENT;
4189     tmp.manufacturer_id = manufacturer_id;
4190     tmp.first_product_id = product_id;
4191     tmp.last_product_id = product_id;
4192     locked_list_iterate(mc_oem_handlers, mc_oem_handler_cmp_dereg, &tmp);
4193     return tmp.rv;
4194 }
4195 
4196 int
ipmi_domain_deregister_oem_handler_range(unsigned int manufacturer_id,unsigned int first_product_id,unsigned int last_product_id)4197 ipmi_domain_deregister_oem_handler_range(unsigned int manufacturer_id,
4198 					 unsigned int first_product_id,
4199 					 unsigned int last_product_id)
4200 {
4201     handler_cmp_t  tmp;
4202 
4203     tmp.rv = ENOENT;
4204     tmp.manufacturer_id = manufacturer_id;
4205     tmp.first_product_id = first_product_id;
4206     tmp.last_product_id = last_product_id;
4207     locked_list_iterate(mc_oem_handlers, mc_oem_handler_cmp_dereg, &tmp);
4208     return tmp.rv;
4209 }
4210 
4211 static int
mc_oem_handler_call(void * cb_data,void * item1,void * item2)4212 mc_oem_handler_call(void *cb_data, void *item1, void *item2)
4213 {
4214     mc_oem_handlers_t *hndlr = item1;
4215     handler_cmp_t     *cmp = cb_data;
4216 
4217     if ((hndlr->manufacturer_id == cmp->manufacturer_id)
4218 	&& (hndlr->first_product_id <= cmp->first_product_id)
4219 	&& (hndlr->last_product_id >= cmp->last_product_id))
4220     {
4221 	cmp->rv = hndlr->handler(cmp->domain, hndlr->cb_data);
4222 	return LOCKED_LIST_ITER_STOP;
4223     }
4224     return LOCKED_LIST_ITER_CONTINUE;
4225 }
4226 
4227 static int
check_mc_oem_handlers(ipmi_domain_t * domain)4228 check_mc_oem_handlers(ipmi_domain_t *domain)
4229 {
4230     handler_cmp_t  tmp;
4231 
4232     tmp.rv = 0;
4233     tmp.manufacturer_id = ipmi_mc_manufacturer_id(domain->si_mc);
4234     tmp.first_product_id = ipmi_mc_product_id(domain->si_mc);
4235     tmp.last_product_id = tmp.first_product_id;
4236     tmp.domain = domain;
4237     locked_list_iterate(mc_oem_handlers, mc_oem_handler_call, &tmp);
4238     return tmp.rv;
4239 }
4240 
4241 int
ipmi_domain_set_sdrs_fixup_handler(ipmi_domain_t * domain,ipmi_domain_oem_fixup_sdrs_cb handler,void * cb_data)4242 ipmi_domain_set_sdrs_fixup_handler(ipmi_domain_t                 *domain,
4243 				   ipmi_domain_oem_fixup_sdrs_cb handler,
4244 				   void                          *cb_data)
4245 {
4246     CHECK_DOMAIN_LOCK(domain);
4247     domain->fixup_sdrs_handler = handler;
4248     domain->fixup_sdrs_cb_data = cb_data;
4249     return 0;
4250 }
4251 
4252 
4253 /***********************************************************************
4254  *
4255  * Connection setup and handling
4256  *
4257  **********************************************************************/
4258 
4259 int
ipmi_domain_set_main_SDRs_read_handler(ipmi_domain_t * domain,ipmi_domain_cb handler,void * cb_data)4260 ipmi_domain_set_main_SDRs_read_handler(ipmi_domain_t  *domain,
4261 				       ipmi_domain_cb handler,
4262 				       void           *cb_data)
4263 {
4264     CHECK_DOMAIN_LOCK(domain);
4265 
4266     ipmi_lock(domain->domain_lock);
4267     domain->SDRs_read_handler = handler;
4268     domain->SDRs_read_handler_cb_data = cb_data;
4269     ipmi_unlock(domain->domain_lock);
4270     return 0;
4271 }
4272 
4273 int
ipmi_domain_set_con_up_handler(ipmi_domain_t * domain,ipmi_domain_ptr_cb handler,void * cb_data)4274 ipmi_domain_set_con_up_handler(ipmi_domain_t      *domain,
4275 			       ipmi_domain_ptr_cb handler,
4276 			       void               *cb_data)
4277 {
4278     CHECK_DOMAIN_LOCK(domain);
4279 
4280     ipmi_lock(domain->domain_lock);
4281     domain->con_up_handler = handler;
4282     domain->con_up_handler_cb_data = cb_data;
4283     ipmi_unlock(domain->domain_lock);
4284     return 0;
4285 }
4286 
4287 int
ipmi_domain_set_bus_scan_handler(ipmi_domain_t * domain,ipmi_domain_cb handler,void * cb_data)4288 ipmi_domain_set_bus_scan_handler(ipmi_domain_t  *domain,
4289 				 ipmi_domain_cb handler,
4290 				 void           *cb_data)
4291 {
4292     CHECK_DOMAIN_LOCK(domain);
4293 
4294     ipmi_lock(domain->mc_lock);
4295     domain->bus_scan_handler = handler;
4296     domain->bus_scan_handler_cb_data = cb_data;
4297     ipmi_unlock(domain->mc_lock);
4298     return 0;
4299 }
4300 
4301 static void
conn_close(ipmi_con_t * ipmi,void * cb_data)4302 conn_close(ipmi_con_t *ipmi, void *cb_data)
4303 {
4304     ipmi_domain_close_done_cb close_done;
4305     void                      *my_cb_data;
4306     ipmi_domain_t             *domain = cb_data;
4307     int                       done = 0;
4308 
4309     ipmi_lock(domain->domain_lock);
4310     domain->close_count--;
4311     done = domain->close_count <= 0;
4312     ipmi_unlock(domain->domain_lock);
4313 
4314     if (!done)
4315 	return;
4316 
4317     remove_known_domain(domain);
4318 
4319     close_done = domain->close_done;
4320     my_cb_data = domain->close_done_cb_data;
4321 
4322     cleanup_domain(domain);
4323 
4324     if (close_done)
4325 	close_done(my_cb_data);
4326 }
4327 
4328 static void
real_close_connection(ipmi_domain_t * domain)4329 real_close_connection(ipmi_domain_t *domain)
4330 {
4331     ipmi_con_t                *ipmi[MAX_CONS];
4332     int                       i;
4333 
4334     for (i=0; i<MAX_CONS; i++) {
4335 	ipmi[i] = domain->conn[i];
4336 
4337 	if (!ipmi[i])
4338 	    continue;
4339 
4340 	/* Remove all the handlers. */
4341 	domain->conn[i]->remove_event_handler(domain->conn[i],
4342 					      ll_event_handler,
4343 					      domain);
4344 	domain->conn[i]->remove_con_change_handler(domain->conn[i],
4345 						   ll_con_changed,
4346 						   domain);
4347 	domain->conn[i]->remove_ipmb_addr_handler(domain->conn[i],
4348 						  ll_addr_changed,
4349 						  domain);
4350 	domain->conn[i] = NULL;
4351     }
4352 
4353     /* No lock needed here, this is single threaded until we start
4354        actually closing the connections. */
4355     domain->close_count = 0;
4356     for (i=0; i<MAX_CONS; i++) {
4357 	if (ipmi[i])
4358 	    domain->close_count++;
4359     }
4360     for (i=0; i<MAX_CONS; i++) {
4361 	if (ipmi[i]) {
4362 	    if (ipmi[i]->register_stat_handler)
4363 		ipmi[i]->unregister_stat_handler(ipmi[i],
4364 						 domain->con_stat_info);
4365 	    ipmi[i]->close_connection_done(ipmi[i], conn_close, domain);
4366 	}
4367     }
4368 }
4369 
4370 int
ipmi_domain_close(ipmi_domain_t * domain,ipmi_domain_close_done_cb close_done,void * cb_data)4371 ipmi_domain_close(ipmi_domain_t             *domain,
4372 		  ipmi_domain_close_done_cb close_done,
4373 		  void                      *cb_data)
4374 {
4375     CHECK_DOMAIN_LOCK(domain);
4376 
4377     if (domain->in_shutdown)
4378 	return EINVAL;
4379 
4380     domain->in_shutdown = 1;
4381     domain->close_done = close_done;
4382     domain->close_done_cb_data = cb_data;
4383 
4384     locked_list_remove(domains_list, domain, NULL);
4385 
4386     /* We don't actually do the destroy here, since the domain should
4387        be in use.  We wait until the usecount goes to zero. */
4388 
4389     return 0;
4390 }
4391 
4392 int
ipmi_domain_add_connect_change_handler(ipmi_domain_t * domain,ipmi_domain_con_cb handler,void * cb_data)4393 ipmi_domain_add_connect_change_handler(ipmi_domain_t      *domain,
4394 				       ipmi_domain_con_cb handler,
4395 				       void               *cb_data)
4396 {
4397     if (locked_list_add(domain->con_change_handlers, handler, cb_data))
4398 	return 0;
4399     else
4400 	return ENOMEM;
4401 }
4402 
4403 int
ipmi_domain_remove_connect_change_handler(ipmi_domain_t * domain,ipmi_domain_con_cb handler,void * cb_data)4404 ipmi_domain_remove_connect_change_handler(ipmi_domain_t      *domain,
4405 					  ipmi_domain_con_cb handler,
4406 					  void               *cb_data)
4407 {
4408     if (locked_list_remove(domain->con_change_handlers, handler, cb_data))
4409 	return 0;
4410     else
4411 	return EINVAL;
4412 }
4413 
4414 typedef struct con_change_cl_info_s
4415 {
4416     ipmi_domain_con_cb handler;
4417     void               *handler_data;
4418 } con_change_cl_info_t;
4419 
4420 static int
iterate_con_change_cl(void * cb_data,void * item1,void * item2)4421 iterate_con_change_cl(void *cb_data, void *item1, void *item2)
4422 {
4423     con_change_cl_info_t  *info = cb_data;
4424     ipmi_domain_con_cl_cb handler = item1;
4425 
4426     handler(info->handler, info->handler_data, item2);
4427     return LOCKED_LIST_ITER_CONTINUE;
4428 }
4429 
4430 static void
call_con_change_cl_handlers(ipmi_domain_t * domain,ipmi_domain_con_cb handler,void * handler_data)4431 call_con_change_cl_handlers(ipmi_domain_t      *domain,
4432 			    ipmi_domain_con_cb handler,
4433 			    void               *handler_data)
4434 {
4435     con_change_cl_info_t info;
4436 
4437     info.handler = handler;
4438     info.handler_data = handler_data;
4439     locked_list_iterate(domain->con_change_cl_handlers, iterate_con_change_cl,
4440 			&info);
4441 }
4442 
4443 int
ipmi_domain_add_connect_change_handler_cl(ipmi_domain_t * domain,ipmi_domain_con_cl_cb handler,void * cb_data)4444 ipmi_domain_add_connect_change_handler_cl(ipmi_domain_t         *domain,
4445 					  ipmi_domain_con_cl_cb handler,
4446 					  void                  *cb_data)
4447 {
4448     if (locked_list_add(domain->con_change_cl_handlers, handler, cb_data))
4449 	return 0;
4450     else
4451 	return ENOMEM;
4452 }
4453 
4454 int
ipmi_domain_remove_connect_change_handler_cl(ipmi_domain_t * domain,ipmi_domain_con_cl_cb handler,void * cb_data)4455 ipmi_domain_remove_connect_change_handler_cl(ipmi_domain_t         *domain,
4456 					     ipmi_domain_con_cl_cb handler,
4457 					     void                  *cb_data)
4458 {
4459     if (locked_list_remove(domain->con_change_cl_handlers, handler, cb_data))
4460 	return 0;
4461     else
4462 	return EINVAL;
4463 }
4464 
4465 typedef struct con_change_info_s
4466 {
4467     ipmi_domain_t *domain;
4468     int           err;
4469     unsigned int  conn_num;
4470     unsigned int  port_num;
4471     int           still_connected;
4472 } con_change_info_t;
4473 
4474 static int
iterate_con_changes(void * cb_data,void * item1,void * item2)4475 iterate_con_changes(void *cb_data, void *item1, void *item2)
4476 {
4477     con_change_info_t  *info = cb_data;
4478     ipmi_domain_con_cb handler = item1;
4479 
4480     handler(info->domain, info->err, info->conn_num, info->port_num,
4481 	    info->still_connected, item2);
4482     return LOCKED_LIST_ITER_CONTINUE;
4483 }
4484 
4485 static void
call_con_change(ipmi_domain_t * domain,int err,unsigned int conn_num,unsigned int port_num,int still_connected)4486 call_con_change(ipmi_domain_t *domain,
4487 		int           err,
4488 		unsigned int  conn_num,
4489 		unsigned int  port_num,
4490 		int           still_connected)
4491 {
4492     con_change_info_t info = {domain, err, conn_num, port_num,
4493 			      still_connected};
4494     locked_list_iterate(domain->con_change_handlers, iterate_con_changes,
4495 			&info);
4496 }
4497 
4498 static void
call_con_fails(ipmi_domain_t * domain,int err,unsigned int conn_num,unsigned int port_num,int still_connected)4499 call_con_fails(ipmi_domain_t *domain,
4500 	       int           err,
4501 	       unsigned int  conn_num,
4502 	       unsigned int  port_num,
4503 	       int           still_connected)
4504 {
4505     ipmi_lock(domain->con_lock);
4506     domain->connecting = 0;
4507     if (err) {
4508 	/* Nothing really to do, can't start anything up, just report it. */
4509 	ipmi_unlock(domain->con_lock);
4510     } else if (domain->in_startup) {
4511 	domain->in_startup = 0;
4512 	ipmi_unlock(domain->con_lock);
4513     } else
4514 	ipmi_unlock(domain->con_lock);
4515 
4516     call_con_change(domain, err, conn_num, port_num, still_connected);
4517 }
4518 
4519 static void
con_up_complete(ipmi_domain_t * domain)4520 con_up_complete(ipmi_domain_t *domain)
4521 {
4522     int                i, j;
4523     ipmi_domain_ptr_cb con_up_handler;
4524     void               *con_up_handler_cb_data;
4525     ipmi_domain_cb     SDRs_read_handler;
4526     void               *SDRs_read_handler_cb_data;
4527 
4528     if (domain->in_shutdown)
4529 	return;
4530 
4531     /* This is an unusual looking piece of code, but is required for
4532        systems that do not implement the get channel command.  For
4533        those, it is required that channel 0 be an IPMB channel.
4534        Basically, if all of the channel info commands failed, set
4535        channel 0 to IPMB. */
4536     for (i=0; i<MAX_IPMI_USED_CHANNELS; i++) {
4537 	if (domain->chan_set[i])
4538 	    break;
4539     }
4540     if (i == MAX_IPMI_USED_CHANNELS) {
4541 	domain->chan[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
4542 	domain->chan[0].xmit_support = 1;
4543 	domain->chan[0].recv_lun = 0;
4544 	domain->chan[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
4545 	domain->chan[0].session_support = IPMI_CHANNEL_SESSION_LESS;
4546 	domain->chan[0].vendor_id = IPMI_ENTERPRISE_NUMBER;
4547 	domain->chan[0].aux_info = 0;
4548     }
4549 
4550     domain->connection_up = 1;
4551 
4552     if (domain->working_conn != -1)
4553 	domain->con_up[domain->working_conn] = 1;
4554 
4555     for (i=0; i<MAX_CONS; i++) {
4556 	for (j=0; j<MAX_PORTS_PER_CON; j++) {
4557 	    if (domain->port_up[j][i] == 1)
4558 		call_con_fails(domain, 0, i, j, 1);
4559 	}
4560     }
4561 
4562     ipmi_lock(domain->domain_lock);
4563     con_up_handler = domain->con_up_handler;
4564     con_up_handler_cb_data = domain->con_up_handler_cb_data;
4565     ipmi_unlock(domain->domain_lock);
4566     if (con_up_handler)
4567 	con_up_handler(domain, con_up_handler_cb_data);
4568 
4569     ipmi_domain_start_full_ipmb_scan(domain);
4570 
4571     ipmi_detect_ents_presence_changes(domain->entities, 1);
4572 
4573     ipmi_entity_scan_sdrs(domain, NULL, domain->entities, domain->main_sdrs);
4574     ipmi_sensor_handle_sdrs(domain, NULL, domain->main_sdrs);
4575     ipmi_lock(domain->domain_lock);
4576     SDRs_read_handler = domain->SDRs_read_handler;
4577     SDRs_read_handler_cb_data = domain->SDRs_read_handler_cb_data;
4578     ipmi_unlock(domain->domain_lock);
4579     if (SDRs_read_handler)
4580 	SDRs_read_handler(domain, 0, SDRs_read_handler_cb_data);
4581     i_ipmi_entities_report_sdrs_read(domain->entities);
4582     i_ipmi_put_domain_fully_up(domain, "con_up_complete");
4583 }
4584 
4585 static void
chan_info_rsp_handler(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)4586 chan_info_rsp_handler(ipmi_mc_t  *mc,
4587 		      ipmi_msg_t *rsp,
4588 		      void       *rsp_data)
4589 {
4590     int           rv = 0;
4591     long          curr = (long) rsp_data;
4592     ipmi_domain_t *domain;
4593 
4594     if (!mc)
4595 	return;
4596 
4597     domain = ipmi_mc_get_domain(mc);
4598 
4599     if (rsp->data[0] != 0) {
4600 	rv = IPMI_IPMI_ERR_VAL(rsp->data[0]);
4601     } else if (rsp->data_len < 8) {
4602 	rv = EINVAL;
4603     }
4604 
4605     if (rv) {
4606 	/* Got an error, invalidate the channel.  IPMI requires that
4607 	   1.5 systems implement this command if they have
4608 	   channels. */
4609 	memset(&domain->chan[curr], 0, sizeof(domain->chan[curr]));
4610 	/* Keep going, there may be more channels. */
4611     } else {
4612 	domain->chan_set[curr] = 1;
4613 
4614         /* Get the info from the channel info response. */
4615         domain->chan[curr].medium = rsp->data[2] & 0x7f;
4616 	domain->chan[curr].xmit_support = rsp->data[2] >> 7;
4617 	domain->chan[curr].recv_lun = (rsp->data[2] >> 4) & 0x7;
4618 	domain->chan[curr].protocol = rsp->data[3] & 0x1f;
4619 	domain->chan[curr].session_support = rsp->data[4] >> 6;
4620 	domain->chan[curr].vendor_id = (rsp->data[5]
4621 					| (rsp->data[6] << 8)
4622 					| (rsp->data[7] << 16));
4623 	domain->chan[curr].aux_info = rsp->data[8] | (rsp->data[9] << 8);
4624     }
4625 
4626     curr++;
4627     if (curr < MAX_IPMI_USED_CHANNELS) {
4628 	ipmi_msg_t    cmd_msg;
4629 	unsigned char cmd_data[1];
4630 
4631 	cmd_msg.netfn = IPMI_APP_NETFN;
4632 	cmd_msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
4633 	cmd_msg.data = cmd_data;
4634 	cmd_msg.data_len = 1;
4635 	cmd_data[0] = curr;
4636 
4637 	rv = ipmi_mc_send_command(mc, 0, &cmd_msg, chan_info_rsp_handler,
4638 				  (void *) curr);
4639     } else {
4640 	goto chan_info_done;
4641     }
4642 
4643     if (rv) {
4644 	call_con_fails(domain, rv, 0, 0, 0);
4645 	return;
4646     }
4647 
4648     return;
4649 
4650  chan_info_done:
4651     domain->msg_int_type = 0xff;
4652     domain->event_msg_int_type = 0xff;
4653     con_up_complete(domain);
4654 }
4655 
4656 static int
get_channels(ipmi_domain_t * domain)4657 get_channels(ipmi_domain_t *domain)
4658 {
4659     int rv;
4660 
4661     if (domain->in_shutdown)
4662 	return ECANCELED;
4663 
4664     if ((domain->major_version > 1)
4665 	|| ((domain->major_version == 1) && (domain->minor_version >= 5)))
4666     {
4667 	ipmi_msg_t    cmd_msg;
4668 	unsigned char cmd_data[1];
4669 
4670 	/* IPMI 1.5 or later, use a get channel command. */
4671 	cmd_msg.netfn = IPMI_APP_NETFN;
4672 	cmd_msg.cmd = IPMI_GET_CHANNEL_INFO_CMD;
4673 	cmd_msg.data = cmd_data;
4674 	cmd_msg.data_len = 1;
4675 	cmd_data[0] = 0;
4676 
4677 	i_ipmi_mc_get(domain->si_mc);
4678 	rv = ipmi_mc_send_command(domain->si_mc, 0, &cmd_msg,
4679 				  chan_info_rsp_handler, (void *) 0);
4680 	i_ipmi_mc_put(domain->si_mc);
4681     } else {
4682 	ipmi_sdr_t sdr;
4683 
4684 	/* Get the channel info record. */
4685 	rv = ipmi_get_sdr_by_type(domain->main_sdrs, 0x14, &sdr);
4686 	if (rv) {
4687 	    domain->chan_set[0] = 1;
4688 
4689 	    /* Add a dummy channel zero and finish. */
4690 	    domain->chan[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
4691 	    domain->chan[0].xmit_support = 1;
4692 	    domain->chan[0].recv_lun = 0;
4693 	    domain->chan[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
4694 	    domain->chan[0].session_support = IPMI_CHANNEL_SESSION_LESS;
4695 	    domain->chan[0].vendor_id = IPMI_ENTERPRISE_NUMBER;
4696 	    domain->chan[0].aux_info = 0;
4697 	    domain->msg_int_type = 0xff;
4698 	    domain->event_msg_int_type = 0xff;
4699 	    domain->msg_int_type = 0xff;
4700 	    domain->event_msg_int_type = 0xff;
4701 	    rv = 0;
4702 	} else {
4703 	    int i;
4704 
4705 	    for (i=0; i<MAX_IPMI_USED_CHANNELS; i++) {
4706 		int protocol = sdr.data[i] & 0xf;
4707 
4708 		if (protocol != 0) {
4709 		    domain->chan_set[i] = 1;
4710 
4711 		    domain->chan[i].medium = IPMI_CHANNEL_MEDIUM_IPMB;
4712 		    domain->chan[i].xmit_support = 1;
4713 		    domain->chan[i].recv_lun = 0;
4714 		    domain->chan[i].protocol = protocol;
4715 		    domain->chan[i].session_support= IPMI_CHANNEL_SESSION_LESS;
4716 		    domain->chan[i].vendor_id = IPMI_ENTERPRISE_NUMBER;
4717 		    domain->chan[i].aux_info = 0;
4718 		}
4719 	    }
4720 	    domain->msg_int_type = sdr.data[8];
4721 	    domain->event_msg_int_type = sdr.data[9];
4722 	}
4723 
4724 	con_up_complete(domain);
4725     }
4726 
4727     return rv;
4728 }
4729 
4730 static void
sdr_handler(ipmi_sdr_info_t * sdrs,int err,int changed,unsigned int count,void * cb_data)4731 sdr_handler(ipmi_sdr_info_t *sdrs,
4732 	    int             err,
4733 	    int             changed,
4734 	    unsigned int    count,
4735 	    void            *cb_data)
4736 {
4737     ipmi_domain_t *domain = cb_data;
4738     int           rv;
4739 
4740     if (err) {
4741 	/* Just report an error, it shouldn't be a big deal if this
4742            fails. */
4743 	ipmi_log(IPMI_LOG_WARNING,
4744 		 "%sdomain.c(sdr_handler): "
4745 		 "Could not get main SDRs, error 0x%x",
4746 		 DOMAIN_NAME(domain), err);
4747     }
4748 
4749     if (domain->fixup_sdrs_handler)
4750 	domain->fixup_sdrs_handler(domain, domain->main_sdrs,
4751 				   domain->fixup_sdrs_cb_data);
4752 
4753     rv = get_channels(domain);
4754     if (rv)
4755 	call_con_fails(domain, rv, 0, 0, 0);
4756 }
4757 
4758 static void
got_guid(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)4759 got_guid(ipmi_mc_t  *mc,
4760 	 ipmi_msg_t *rsp,
4761 	 void       *rsp_data)
4762 {
4763     ipmi_domain_t *domain = rsp_data;
4764     int           rv;
4765 
4766     if (!mc)
4767 	return; /* domain went away while processing. */
4768 
4769     if ((rsp->data[0] == 0) && (rsp->data_len >= 17)) {
4770 	/* We have a GUID, save it */
4771 	ipmi_mc_set_guid(mc, rsp->data+1);
4772     }
4773 
4774     if (domain->SDR_repository_support && ipmi_option_SDRs(domain)) {
4775 	rv = ipmi_sdr_fetch(domain->main_sdrs, sdr_handler, domain);
4776     } else {
4777 	rv = get_channels(domain);
4778     }
4779     if (rv)
4780 	call_con_fails(domain, rv, 0, 0, 0);
4781 }
4782 
4783 static void
domain_oem_handlers_checked(ipmi_domain_t * domain,int err,void * cb_data)4784 domain_oem_handlers_checked(ipmi_domain_t *domain, int err, void *cb_data)
4785 {
4786     ipmi_msg_t msg;
4787     int        rv;
4788 
4789     /* FIXME - handle errors setting up OEM comain information. */
4790 
4791     msg.netfn = IPMI_APP_NETFN;
4792     msg.cmd = IPMI_GET_SYSTEM_GUID_CMD;
4793     msg.data_len = 0;
4794     msg.data = NULL;
4795 
4796     i_ipmi_mc_get(domain->si_mc);
4797     rv = ipmi_mc_send_command(domain->si_mc, 0, &msg, got_guid, domain);
4798     i_ipmi_mc_put(domain->si_mc);
4799     if (rv)
4800 	call_con_fails(domain, rv, 0, 0, 0);
4801 }
4802 
4803 static void
got_dev_id(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)4804 got_dev_id(ipmi_mc_t  *mc,
4805 	   ipmi_msg_t *rsp,
4806 	   void       *rsp_data)
4807 {
4808     ipmi_domain_t *domain = rsp_data;
4809     int           rv;
4810 
4811     if (!mc)
4812 	return; /* domain went away while processing. */
4813 
4814     rv = i_ipmi_mc_get_device_id_data_from_rsp(mc, rsp);
4815     if (rv) {
4816 	/* At least the get device id has to work. */
4817 	if ((rsp->data[0] == 0) && (rsp->data_len >= 6)) {
4818 	    int major_version = rsp->data[5] & 0xf;
4819 	    int minor_version = (rsp->data[5] >> 4) & 0xf;
4820 
4821 	    if (major_version < 1) {
4822 		ipmi_log(IPMI_LOG_ERR_INFO,
4823 			 "%sdomain.c(got_dev_id): "
4824 			 "IPMI version of the BMC is %d.%d, which is older"
4825 			 " than OpenIPMI supports",
4826 			 DOMAIN_NAME(domain), major_version, minor_version);
4827 		domain->got_invalid_dev_id = 1;
4828 		call_con_fails(domain, ENOSYS, 0, 0, 0);
4829 		return;
4830 	    }
4831 	}
4832 	ipmi_log(IPMI_LOG_ERR_INFO,
4833 		 "%sdomain.c(got_dev_id): "
4834 		 "Invalid return from IPMI Get Device ID, something is"
4835 		 " seriously wrong with the BMC",
4836 		 DOMAIN_NAME(domain));
4837 	domain->got_invalid_dev_id = 1;
4838 	call_con_fails(domain, rv, 0, 0, 0);
4839 	return;
4840     }
4841 
4842     domain->got_invalid_dev_id = 0;
4843 
4844     /* Get the information from the MC, not the message, since it may have
4845        been fixed up. */
4846     domain->major_version = ipmi_mc_major_version(mc);
4847     domain->minor_version = ipmi_mc_minor_version(mc);
4848     domain->SDR_repository_support = ipmi_mc_sdr_repository_support(mc);
4849 
4850     if (((domain->major_version < 1) || (domain->major_version > 2))
4851 	|| ((domain->major_version == 1)
4852 	    && (domain->minor_version != 5)
4853 	    && (domain->minor_version != 0))
4854 	|| ((domain->major_version == 2)
4855 	    && (domain->minor_version != 0)))
4856     {
4857 	ipmi_log(IPMI_LOG_WARNING,
4858 		 "%sdomain.c(got_dev_id): "
4859 		 "IPMI version of the BMC is %d.%d, which is not directly"
4860 		 " supported by OpenIPMI.  It may work, but there may be"
4861 		 " issues.",
4862 		 DOMAIN_NAME(domain),
4863 		 domain->major_version, domain->minor_version);
4864     }
4865 
4866     if (domain->major_version < 1) {
4867 	/* We only support 1.0 and greater. */
4868 	domain->got_invalid_dev_id = 0;
4869 	call_con_fails(domain, EINVAL, 0, 0, 0);
4870 	return;
4871     }
4872 
4873     if (ipmi_option_OEM_init(domain)) {
4874 	rv = check_oem_handlers(domain, domain_oem_handlers_checked, NULL);
4875 	if (rv)
4876 	    call_con_fails(domain, rv, 0, 0, 0);
4877 	rv = check_mc_oem_handlers(domain);
4878 	if (rv)
4879 	    call_con_fails(domain, rv, 0, 0, 0);
4880     } else {
4881 	domain_oem_handlers_checked(domain, 0, NULL);
4882     }
4883 }
4884 
4885 static int
domain_send_mc_id(ipmi_domain_t * domain)4886 domain_send_mc_id(ipmi_domain_t *domain)
4887 {
4888     ipmi_msg_t msg;
4889     int        rv;
4890 
4891     msg.netfn = IPMI_APP_NETFN;
4892     msg.cmd = IPMI_GET_DEVICE_ID_CMD;
4893     msg.data_len = 0;
4894     msg.data = NULL;
4895 
4896     i_ipmi_mc_get(domain->si_mc);
4897     rv = ipmi_mc_send_command(domain->si_mc, 0, &msg, got_dev_id, domain);
4898     i_ipmi_mc_put(domain->si_mc);
4899 
4900     return rv;
4901 }
4902 
4903 static int
start_con_up(ipmi_domain_t * domain)4904 start_con_up(ipmi_domain_t *domain)
4905 {
4906     ipmi_lock(domain->con_lock);
4907     if (domain->connecting || domain->connection_up) {
4908 	ipmi_unlock(domain->con_lock);
4909 	return 0;
4910     }
4911     domain->connecting = 1;
4912     ipmi_unlock(domain->con_lock);
4913 
4914     return domain_send_mc_id(domain);
4915 }
4916 
4917 static void start_activate_timer(ipmi_domain_t *domain);
4918 
4919 static void
initial_ipmb_addr_cb(ipmi_con_t * ipmi,int err,const unsigned char ipmb_addr[],unsigned int num_ipmb_addr,int active,unsigned int hacks,void * cb_data)4920 initial_ipmb_addr_cb(ipmi_con_t    *ipmi,
4921 		     int           err,
4922 		     const unsigned char ipmb_addr[],
4923 		     unsigned int  num_ipmb_addr,
4924 		     int           active,
4925 		     unsigned int  hacks,
4926 		     void          *cb_data)
4927 {
4928     ipmi_domain_t *domain = cb_data;
4929     int           u;
4930     int           rv;
4931 
4932     rv = i_ipmi_domain_get(domain);
4933     if (rv)
4934 	/* So the connection failed.  So what, there's nothing to talk to. */
4935 	return;
4936 
4937     u = get_con_num(domain, ipmi);
4938     if (u == -1)
4939 	goto out_unlock;
4940 
4941     if (err) {
4942 	call_con_fails(domain, err, u, 0, domain->connection_up);
4943 	goto out_unlock;
4944     }
4945 
4946     /* If we are not activating connections, just use whatever we get
4947        and don't worry if it is active or not. */
4948     if (! domain->option_activate_if_possible)
4949 	active = 1;
4950 
4951     if (active) {
4952         domain->working_conn = u;
4953 	rv = start_con_up(domain);
4954 	if (rv)
4955 	    call_con_fails(domain, rv, u, 0, domain->connection_up);
4956     } else {
4957 	/* Start the timer to activate the connection, if necessary. */
4958 	start_activate_timer(domain);
4959     }
4960 
4961  out_unlock:
4962     i_ipmi_domain_put(domain);
4963 }
4964 
4965 static void
activate_timer_cb(void * cb_data,os_hnd_timer_id_t * id)4966 activate_timer_cb(void *cb_data, os_hnd_timer_id_t *id)
4967 {
4968     activate_timer_info_t *info = cb_data;
4969     ipmi_domain_t         *domain = info->domain;
4970     int                   to_activate;
4971     int                   u;
4972     int                   rv;
4973 
4974     ipmi_lock(info->lock);
4975     if (info->cancelled) {
4976 	info->os_hnd->free_timer(info->os_hnd, id);
4977 	ipmi_unlock(info->lock);
4978 	ipmi_destroy_lock(info->lock);
4979 	ipmi_mem_free(info);
4980 	return;
4981     }
4982     info->running = 0;
4983 
4984     rv = i_ipmi_domain_get(domain);
4985     if (rv)
4986 	/* Domain is gone, just give up. */
4987 	goto out_unlock;
4988 
4989     /* If no one is active, activate one. */
4990     to_activate = -1;
4991     for (u=0; u<MAX_CONS; u++) {
4992 	if (!domain->conn[u]
4993 	    || !domain->con_up[u])
4994 	{
4995 	    continue;
4996 	}
4997 	if (domain->con_active[u]) {
4998 	    to_activate = u;
4999 	    break;
5000 	}
5001 	to_activate = u;
5002     }
5003     u = to_activate;
5004     if ((u != -1)
5005 	&& domain->option_activate_if_possible
5006 	&& ! domain->con_active[u]
5007 	&& domain->conn[u]->set_active_state)
5008     {
5009 	/* If we didn't find an active connection, but we found a
5010 	   working one, activate it.  Note that we may re-activate
5011 	   the connection that just went inactive if it is the
5012 	   only working connection. */
5013 	domain->conn[u]->set_active_state(
5014 	    domain->conn[u],
5015 	    1,
5016 	    ll_addr_changed,
5017 	    domain);
5018     }
5019 
5020     i_ipmi_domain_put(domain);
5021 
5022  out_unlock:
5023     ipmi_unlock(info->lock);
5024 }
5025 
5026 int
ipmi_domain_activate_connection(ipmi_domain_t * domain,unsigned int connection)5027 ipmi_domain_activate_connection(ipmi_domain_t *domain, unsigned int connection)
5028 {
5029     CHECK_DOMAIN_LOCK(domain);
5030 
5031     if ((connection >= MAX_CONS) || !domain->conn[connection])
5032 	return EINVAL;
5033 
5034     if (!domain->conn[connection]->set_active_state
5035 	|| !domain->option_activate_if_possible)
5036 	return ENOSYS;
5037 
5038     domain->conn[connection]->set_active_state(domain->conn[connection], 1,
5039 					       ll_addr_changed, domain);
5040 
5041     /* The other connections will be deactivated when this one
5042        activates, if that is required. */
5043     return 0;
5044 }
5045 
5046 int
ipmi_domain_is_connection_active(ipmi_domain_t * domain,unsigned int connection,unsigned int * active)5047 ipmi_domain_is_connection_active(ipmi_domain_t *domain,
5048 				 unsigned int  connection,
5049 				 unsigned int  *active)
5050 {
5051     CHECK_DOMAIN_LOCK(domain);
5052 
5053     if ((connection >= MAX_CONS) || !domain->conn[connection])
5054 	return EINVAL;
5055 
5056     *active = domain->con_active[connection];
5057     return 0;
5058 }
5059 
5060 int
ipmi_domain_is_connection_up(ipmi_domain_t * domain,unsigned int connection,unsigned int * up)5061 ipmi_domain_is_connection_up(ipmi_domain_t *domain,
5062 			     unsigned int  connection,
5063 			     unsigned int  *up)
5064 {
5065     int          port;
5066     unsigned int val;
5067 
5068     CHECK_DOMAIN_LOCK(domain);
5069 
5070     if ((connection >= MAX_CONS) || !domain->conn[connection])
5071 	return EINVAL;
5072 
5073     val = 0;
5074     for (port=0; port<MAX_PORTS_PER_CON; port++) {
5075 	if (domain->port_up[port][connection] == 1)
5076 	    val = 1;
5077     }
5078 
5079     *up = val;
5080     return 0;
5081 }
5082 
5083 int
ipmi_domain_num_connection_ports(ipmi_domain_t * domain,unsigned int connection,unsigned int * ports)5084 ipmi_domain_num_connection_ports(ipmi_domain_t *domain,
5085 				 unsigned int  connection,
5086 				 unsigned int  *ports)
5087 {
5088     int          port;
5089     unsigned int val = 0;
5090 
5091     CHECK_DOMAIN_LOCK(domain);
5092 
5093     if ((connection >= MAX_CONS) || !domain->conn[connection])
5094 	return EINVAL;
5095 
5096     for (port=0; port<MAX_PORTS_PER_CON; port++) {
5097 	if (domain->port_up[port][connection] != -1)
5098 	    val = port+1;
5099     }
5100 
5101     *ports = val;
5102     return 0;
5103 }
5104 
5105 int
ipmi_domain_is_connection_port_up(ipmi_domain_t * domain,unsigned int connection,unsigned int port,unsigned int * up)5106 ipmi_domain_is_connection_port_up(ipmi_domain_t *domain,
5107 				  unsigned int  connection,
5108 				  unsigned int  port,
5109 				  unsigned int  *up)
5110 {
5111     CHECK_DOMAIN_LOCK(domain);
5112 
5113     if ((connection >= MAX_CONS) || !domain->conn[connection])
5114 	return EINVAL;
5115 
5116     if (port >= MAX_PORTS_PER_CON)
5117 	return EINVAL;
5118 
5119     if (domain->port_up[port][connection] == -1)
5120 	return ENOSYS;
5121 
5122     *up = domain->port_up[port][connection];
5123 
5124     return 0;
5125 }
5126 
5127 int
ipmi_domain_get_port_info(ipmi_domain_t * domain,unsigned int connection,unsigned int port,char * info,int * info_len)5128 ipmi_domain_get_port_info(ipmi_domain_t *domain,
5129 			  unsigned int  connection,
5130 			  unsigned int  port,
5131 			  char          *info,
5132 			  int           *info_len)
5133 {
5134     CHECK_DOMAIN_LOCK(domain);
5135 
5136     if ((connection >= MAX_CONS) || !domain->conn[connection])
5137 	return EINVAL;
5138 
5139     if (port >= MAX_PORTS_PER_CON)
5140 	return EINVAL;
5141 
5142     if (!domain->conn[connection]->get_port_info)
5143 	return ENOSYS;
5144 
5145     return domain->conn[connection]->get_port_info(domain->conn[connection],
5146 						   port, info, info_len);
5147 }
5148 
5149 int
i_ipmi_domain_get_connection(ipmi_domain_t * domain,int con_num,ipmi_con_t ** con)5150 i_ipmi_domain_get_connection(ipmi_domain_t *domain,
5151 			     int           con_num,
5152 			     ipmi_con_t    **con)
5153 {
5154     if (con_num >= MAX_CONS)
5155 	return EINVAL;
5156     *con = domain->conn[con_num];
5157     return 0;
5158 }
5159 
5160 void
ipmi_domain_iterate_connections(ipmi_domain_t * domain,ipmi_connection_ptr_cb handler,void * cb_data)5161 ipmi_domain_iterate_connections(ipmi_domain_t          *domain,
5162 				ipmi_connection_ptr_cb handler,
5163 				void                   *cb_data)
5164 {
5165     int i;
5166 
5167     CHECK_DOMAIN_LOCK(domain);
5168 
5169     for (i=0; i<MAX_CONS; i++) {
5170 	if (domain->conn[i])
5171 	    handler(domain, i, cb_data);
5172     }
5173 }
5174 
5175 ipmi_args_t *
ipmi_domain_get_connection_args(ipmi_domain_t * domain,unsigned int con)5176 ipmi_domain_get_connection_args(ipmi_domain_t *domain,
5177 				unsigned int  con)
5178 {
5179     CHECK_DOMAIN_LOCK(domain);
5180 
5181     if (con >= MAX_CONS)
5182 	return NULL;
5183 
5184     if (!domain->conn[con])
5185 	return NULL;
5186 
5187     if (! domain->conn[con]->get_startup_args)
5188 	return NULL;
5189 
5190     return domain->conn[con]->get_startup_args(domain->conn[con]);
5191 }
5192 
5193 char *
ipmi_domain_get_connection_type(ipmi_domain_t * domain,unsigned int connection)5194 ipmi_domain_get_connection_type(ipmi_domain_t *domain,
5195 				unsigned int  connection)
5196 {
5197     CHECK_DOMAIN_LOCK(domain);
5198 
5199     if (connection >= MAX_CONS)
5200 	return NULL;
5201 
5202     if (!domain->conn[connection])
5203 	return NULL;
5204 
5205     return domain->conn[connection]->con_type;
5206 }
5207 
5208 ipmi_con_t *
ipmi_domain_get_connection(ipmi_domain_t * domain,unsigned int connection)5209 ipmi_domain_get_connection(ipmi_domain_t *domain,
5210 			   unsigned int  connection)
5211 {
5212     CHECK_DOMAIN_LOCK(domain);
5213 
5214     if (connection >= MAX_CONS)
5215 	return NULL;
5216 
5217     if (!domain->conn[connection])
5218 	return NULL;
5219 
5220     if (! domain->conn[connection]->use_connection)
5221 	return NULL;
5222 
5223     domain->conn[connection]->use_connection(domain->conn[connection]);
5224     return domain->conn[connection];
5225 }
5226 
5227 /* If the activate timer is not running, then start it.  This
5228    allows some time for other connections to become active before
5229    we go off and start activating things.  We wait a random amount
5230    of time so that if we get into a war with another program about
5231    who is active, someone will eventually win. */
5232 static void
start_activate_timer(ipmi_domain_t * domain)5233 start_activate_timer(ipmi_domain_t *domain)
5234 {
5235     ipmi_lock(domain->activate_timer_info->lock);
5236     if (!domain->activate_timer_info->running) {
5237 	struct timeval tv;
5238 	domain->os_hnd->get_random(domain->os_hnd,
5239 				   &tv.tv_sec,
5240 				   sizeof(tv.tv_sec));
5241 	/* Wait a random value between 5 and 15 seconds */
5242 	tv.tv_sec = (tv.tv_sec % 10) + 5;
5243 	tv.tv_usec = 0;
5244 	domain->os_hnd->start_timer(domain->os_hnd,
5245 				    domain->activate_timer,
5246 				    &tv,
5247 				    activate_timer_cb,
5248 				    domain->activate_timer_info);
5249 	domain->activate_timer_info->running = 1;
5250     }
5251     ipmi_unlock(domain->activate_timer_info->lock);
5252 }
5253 
5254 static void
ll_addr_changed(ipmi_con_t * ipmi,int err,const unsigned char ipmb_addr[],unsigned int num_ipmb_addr,int active,unsigned int hacks,void * cb_data)5255 ll_addr_changed(ipmi_con_t    *ipmi,
5256 		int           err,
5257 		const unsigned char ipmb_addr[],
5258 		unsigned int  num_ipmb_addr,
5259 		int           active,
5260 		unsigned int  hacks,
5261 		void          *cb_data)
5262 {
5263     ipmi_domain_t *domain = cb_data;
5264     int           rv;
5265     int           u;
5266     int           start_connection;
5267     unsigned char old_addr[MAX_IPMI_USED_CHANNELS];
5268     unsigned int  i;
5269 
5270     rv = i_ipmi_domain_get(domain);
5271     if (rv)
5272 	/* So the connection failed.  So what, there's nothing to talk to. */
5273 	return;
5274 
5275     if (err)
5276 	goto out_unlock;
5277 
5278     u = get_con_num(domain, ipmi);
5279     if (u == -1)
5280 	goto out_unlock;
5281 
5282     memcpy(old_addr, domain->con_ipmb_addr[u], sizeof(old_addr));
5283 
5284     for (i=0; i<num_ipmb_addr && i<MAX_IPMI_USED_CHANNELS; i++) {
5285 	if (! ipmb_addr[i])
5286 	    continue;
5287 	domain->con_ipmb_addr[u][i] = ipmb_addr[i];
5288     }
5289 
5290     if (!domain->in_startup) {
5291 	/* Only scan the IPMBs if we are not in startup.  Otherwise things
5292 	   get reported before we are ready. */
5293 	for (i=0; i<num_ipmb_addr && i<MAX_IPMI_USED_CHANNELS; i++) {
5294 	    if (! ipmb_addr[i])
5295 		continue;
5296 	    if (ipmb_addr[i] != old_addr[i]) {
5297 		/* First scan the old address to remove it. */
5298 		if (domain->con_ipmb_addr[u] != 0)
5299 		    ipmi_start_ipmb_mc_scan(domain, i,
5300 					    old_addr[i], old_addr[i],
5301 					    NULL, NULL);
5302 	    }
5303 
5304 	    /* Scan the new address.  Even though the address may not have
5305 	       changed, it may have changed modes and need to be rescanned. */
5306 	    ipmi_start_ipmb_mc_scan(domain, i, ipmb_addr[i], ipmb_addr[i],
5307 				    NULL, NULL);
5308 	}
5309     }
5310 
5311     /* If we are not activating connections, just use whatever we get
5312        and don't worry if it is active or not. */
5313     if (! domain->option_activate_if_possible)
5314 	active = 1;
5315 
5316     start_connection = (active && (first_active_con(domain) == -1));
5317 
5318     if (domain->con_active[u] != active) {
5319 	domain->con_active[u] = active;
5320 	if (active) {
5321 	    /* Deactivate all the other connections, if they support
5322 	       it. */
5323 	    for (u=0; u<MAX_CONS; u++) {
5324 		if (u == domain->working_conn
5325 		    || !domain->conn[u]
5326 		    || !domain->con_up[u])
5327 		{
5328 		    continue;
5329 		}
5330 
5331 		if (domain->conn[u]->set_active_state
5332 		    && domain->option_activate_if_possible)
5333 		{
5334 		    domain->conn[u]->set_active_state(
5335 			domain->conn[u],
5336 			0,
5337 			ll_addr_changed,
5338 			domain);
5339 		}
5340 	    }
5341 	} else {
5342 	    /* The connection went inactive, route message from it to
5343 	       the current working connection. */
5344 	    reroute_cmds(domain, u, domain->working_conn);
5345 	}
5346     } else if (active) {
5347         /* Always pick the last working active connection to use. */
5348 	domain->working_conn = u;
5349     } else if (domain->conn[u]->set_active_state
5350 	       && domain->option_activate_if_possible)
5351     {
5352         /* Start the timer to activate the connection, if necessary. */
5353 	start_activate_timer(domain);
5354     }
5355 
5356     if (start_connection) {
5357 	/* We now have an active connection and we didn't before,
5358            attempt to start up the connection. */
5359 	rv = start_con_up(domain);
5360 	if (rv)
5361 	    call_con_fails(domain, rv, u, 0, domain->connection_up);
5362     }
5363 
5364  out_unlock:
5365     i_ipmi_domain_put(domain);
5366 }
5367 
5368 static void
ll_con_changed(ipmi_con_t * ipmi,int err,unsigned int port_num,int still_connected,void * cb_data)5369 ll_con_changed(ipmi_con_t   *ipmi,
5370 	       int          err,
5371 	       unsigned int port_num,
5372 	       int          still_connected,
5373 	       void         *cb_data)
5374 {
5375     ipmi_domain_t   *domain = cb_data;
5376     int             rv;
5377     int             u;
5378 
5379     if (port_num >= MAX_PORTS_PER_CON) {
5380 	ipmi_log(IPMI_LOG_SEVERE,
5381 		 "%sdomain.c(ll_con_changed): Got port number %d,"
5382 		 " but %d is the max number of ports",
5383 		 DOMAIN_NAME(domain), port_num, MAX_PORTS_PER_CON);
5384 	return;
5385     }
5386 
5387     rv = i_ipmi_domain_get(domain);
5388     if (rv)
5389 	/* So the connection failed.  So what, there's nothing to talk to. */
5390 	return;
5391 
5392     u = get_con_num(domain, ipmi);
5393     if (u == -1)
5394 	goto out_unlock;
5395 
5396     if (err == ENOENT)
5397 	domain->port_up[port_num][u] = -1;
5398     else if (err)
5399 	domain->port_up[port_num][u] = 0;
5400     else
5401 	domain->port_up[port_num][u] = 1;
5402 
5403     /* If we are not starting up, if we gain or lose a connection
5404        then scan the address. */
5405     if ((!domain->in_startup) && (ipmi->scan_sysaddr))
5406     	ipmi_start_si_scan(domain, u, NULL, NULL);
5407 
5408     if (still_connected) {
5409 	domain->con_up[u] = 1;
5410 	if (domain->connecting) {
5411 	    /* If we are connecting, don't report it, it will be
5412 	       reported when the connection is finished. */
5413 	} else if (domain->connection_up) {
5414 	    /* We already have a connection, just report this. */
5415 	    call_con_change(domain, err, u, port_num, domain->connection_up);
5416 	} else {
5417 	    /* We don't have a working connection, so start up the
5418                process. */
5419 	    domain->working_conn = u;
5420 
5421 	    if (domain->conn[u]->get_ipmb_addr)
5422 		/* If we can fetch the IPMB address, see if this is an
5423                    active connection first. */
5424 		rv = domain->conn[u]->get_ipmb_addr(domain->conn[u],
5425 						    initial_ipmb_addr_cb,
5426 						    domain);
5427 	    else
5428 		/* When a connection comes back up, start the process of
5429 		   getting SDRs, scanning the bus, and the like. */
5430 		rv = start_con_up(domain);
5431 
5432 	    if (rv)
5433 		call_con_fails(domain, rv, u, port_num, domain->connection_up);
5434 	}
5435     } else {
5436 	/* A connection failed, try to find a working connection and
5437            activate it, if necessary. */
5438 	domain->con_up[u] = 0;
5439 	domain->working_conn = first_working_con(domain);
5440 	if (domain->working_conn == -1)
5441 	    domain->connection_up = 0;
5442 	else if ((!domain->con_active[domain->working_conn])
5443 		 && (domain->conn[domain->working_conn]->set_active_state)
5444 		 && domain->option_activate_if_possible)
5445 	{
5446 	    domain->conn[domain->working_conn]->set_active_state(
5447 		domain->conn[domain->working_conn],
5448 		1,
5449 		ll_addr_changed,
5450 		domain);
5451 	} else {
5452 	    reroute_cmds(domain, u, domain->working_conn);
5453 	}
5454 	call_con_fails(domain, err, u, port_num, domain->connection_up);
5455     }
5456 
5457  out_unlock:
5458     i_ipmi_domain_put(domain);
5459 }
5460 
5461 int
ipmi_option_SDRs(ipmi_domain_t * domain)5462 ipmi_option_SDRs(ipmi_domain_t *domain)
5463 {
5464     return domain->option_all || domain->option_SDRs;
5465 }
5466 
5467 int
ipmi_option_SEL(ipmi_domain_t * domain)5468 ipmi_option_SEL(ipmi_domain_t *domain)
5469 {
5470     return domain->option_all || domain->option_SEL;
5471 }
5472 
5473 int
ipmi_option_FRUs(ipmi_domain_t * domain)5474 ipmi_option_FRUs(ipmi_domain_t *domain)
5475 {
5476     return domain->option_all || domain->option_FRUs;
5477 }
5478 
5479 int
ipmi_option_IPMB_scan(ipmi_domain_t * domain)5480 ipmi_option_IPMB_scan(ipmi_domain_t *domain)
5481 {
5482     if (domain->option_local_only)
5483 	return 0;
5484     return domain->option_all || domain->option_IPMB_scan;
5485 }
5486 
5487 int
ipmi_option_OEM_init(ipmi_domain_t * domain)5488 ipmi_option_OEM_init(ipmi_domain_t *domain)
5489 {
5490     return domain->option_all || domain->option_OEM_init;
5491 }
5492 
5493 int
ipmi_option_set_event_rcvr(ipmi_domain_t * domain)5494 ipmi_option_set_event_rcvr(ipmi_domain_t *domain)
5495 {
5496     if (domain->option_local_only)
5497 	return 0;
5498     return domain->option_set_event_rcvr;
5499 }
5500 
5501 int
ipmi_option_set_sel_time(ipmi_domain_t * domain)5502 ipmi_option_set_sel_time(ipmi_domain_t *domain)
5503 {
5504     return domain->option_set_sel_time;
5505 }
5506 
5507 int
ipmi_option_use_cache(ipmi_domain_t * domain)5508 ipmi_option_use_cache(ipmi_domain_t *domain)
5509 {
5510     return domain->option_use_cache;
5511 }
5512 
5513 int
ipmi_option_activate_if_possible(ipmi_domain_t * domain)5514 ipmi_option_activate_if_possible(ipmi_domain_t *domain)
5515 {
5516     return domain->option_activate_if_possible;
5517 }
5518 
5519 int
ipmi_option_local_only(ipmi_domain_t * domain)5520 ipmi_option_local_only(ipmi_domain_t *domain)
5521 {
5522     return domain->option_local_only;
5523 }
5524 
5525 void
i_ipmi_option_set_local_only_if_not_specified(ipmi_domain_t * domain,int val)5526 i_ipmi_option_set_local_only_if_not_specified(ipmi_domain_t *domain, int val)
5527 {
5528     if (domain->option_local_only_set)
5529 	return;
5530     domain->option_local_only = val != 0;
5531 }
5532 
5533 
5534 int
ipmi_open_domain(const char * name,ipmi_con_t * con[],unsigned int num_con,ipmi_domain_con_cb con_change_handler,void * con_change_cb_data,ipmi_domain_ptr_cb domain_fully_up,void * domain_fully_up_cb_data,ipmi_open_option_t * options,unsigned int num_options,ipmi_domain_id_t * new_domain)5535 ipmi_open_domain(const char         *name,
5536 		 ipmi_con_t         *con[],
5537 		 unsigned int       num_con,
5538 		 ipmi_domain_con_cb con_change_handler,
5539 		 void               *con_change_cb_data,
5540 		 ipmi_domain_ptr_cb domain_fully_up,
5541 		 void               *domain_fully_up_cb_data,
5542 		 ipmi_open_option_t *options,
5543 		 unsigned int       num_options,
5544 		 ipmi_domain_id_t   *new_domain)
5545 {
5546     int           rv;
5547     ipmi_domain_t *domain = NULL;
5548     unsigned int  i;
5549 
5550     if ((num_con < 1) || (num_con > MAX_CONS))
5551 	return EINVAL;
5552 
5553     rv = setup_domain(name, con, num_con, options, num_options, &domain);
5554     if (rv)
5555 	return rv;
5556 
5557     domain->domain_fully_up = domain_fully_up;
5558     domain->domain_fully_up_cb_data = domain_fully_up_cb_data;
5559     domain->fully_up_count = 1;
5560 
5561     for (i=0; i<num_con; i++) {
5562 	rv = con[i]->add_con_change_handler(con[i], ll_con_changed, domain);
5563 	if (rv)
5564 	    goto out_err;
5565 	rv = con[i]->add_ipmb_addr_handler(con[i], ll_addr_changed, domain);
5566 	if (rv)
5567 	    goto out_err;
5568     }
5569 
5570     add_known_domain(domain);
5571 
5572     if (con_change_handler) {
5573 	rv = ipmi_domain_add_connect_change_handler(domain,
5574 						    con_change_handler,
5575 						    con_change_cb_data);
5576 	if (rv)
5577 	    goto out_err;
5578     }
5579 
5580     for (i=0; i<num_con; i++) {
5581 	/* Set the ports that we will have valid and unconnected. */
5582 	if (con[i]->get_num_ports) {
5583 	    int m = con[i]->get_num_ports(con[i]);
5584 	    int j;
5585 	    for (j=0; j<m; j++)
5586 		domain->port_up[j][i] = 0;
5587 	} else
5588 	    /* Only one port 0 */
5589 	    domain->port_up[0][i] = 0;
5590 	rv = con[i]->start_con(con[i]);
5591 	if (rv)
5592 	    break;
5593     }
5594     if (rv)
5595 	goto out_err;
5596 
5597     if (new_domain)
5598 	*new_domain = ipmi_domain_convert_to_id(domain);
5599 
5600     if (! locked_list_add(domains_list, domain, NULL)) {
5601 	ipmi_log(IPMI_LOG_SEVERE,
5602 		 "%sdomain.c(sdr_handler): "
5603 		 "Out of memory, could not add domain to the domains list",
5604 		 DOMAIN_NAME(domain));
5605     }
5606 
5607     call_domain_change(domain, IPMI_ADDED);
5608 
5609     i_ipmi_domain_put(domain);
5610     return rv;
5611 
5612  out_err:
5613     for (i=0; i<num_con; i++) {
5614 	con[i]->remove_con_change_handler(con[i], ll_con_changed, domain);
5615 	con[i]->remove_ipmb_addr_handler(con[i], ll_addr_changed, domain);
5616 	if (con[i]->register_stat_handler)
5617 	    con[i]->unregister_stat_handler(con[i],
5618 					    domain->con_stat_info);
5619     }
5620     remove_known_domain(domain);
5621     cleanup_domain(domain);
5622     return rv;
5623 }
5624 
5625 /***********************************************************************
5626  *
5627  * Handle misc data about domains.
5628  *
5629  **********************************************************************/
5630 
5631 typedef struct domains_iter_s
5632 {
5633     ipmi_domain_ptr_cb handler;
5634     void               *cb_data;
5635 } domains_iter_t;
5636 
5637 static int
iterate_domains(void * cb_data,void * item1,void * item2)5638 iterate_domains(void *cb_data, void *item1, void *item2)
5639 {
5640     domains_iter_t *info = cb_data;
5641     ipmi_domain_t  *domain = item1;
5642     int            rv;
5643 
5644     rv = i_ipmi_domain_get(domain);
5645     if (!rv) {
5646 	info->handler(item1, info->cb_data);
5647 	i_ipmi_domain_put(domain);
5648     }
5649     return LOCKED_LIST_ITER_CONTINUE;
5650 }
5651 
5652 void
ipmi_domain_iterate_domains(ipmi_domain_ptr_cb handler,void * cb_data)5653 ipmi_domain_iterate_domains(ipmi_domain_ptr_cb handler,
5654 			    void               *cb_data)
5655 {
5656     domains_iter_t info;
5657 
5658     if (!handler)
5659 	return;
5660     if (!domains_list)
5661 	return;
5662 
5663     info.handler = handler;
5664     info.cb_data = cb_data;
5665     locked_list_iterate(domains_list, iterate_domains, &info);
5666 }
5667 
5668 ipmi_sdr_info_t *
ipmi_domain_get_main_sdrs(ipmi_domain_t * domain)5669 ipmi_domain_get_main_sdrs(ipmi_domain_t *domain)
5670 {
5671     return domain->main_sdrs;
5672 }
5673 
5674 int
ipmi_domain_get_num_channels(ipmi_domain_t * domain,int * val)5675 ipmi_domain_get_num_channels(ipmi_domain_t *domain, int *val)
5676 {
5677     CHECK_DOMAIN_LOCK(domain);
5678 
5679     *val = MAX_IPMI_USED_CHANNELS;
5680     return 0;
5681 }
5682 
5683 int
ipmi_domain_get_channel(ipmi_domain_t * domain,int index,ipmi_chan_info_t * chan)5684 ipmi_domain_get_channel(ipmi_domain_t    *domain,
5685 			int              index,
5686 			ipmi_chan_info_t *chan)
5687 {
5688     CHECK_DOMAIN_LOCK(domain);
5689 
5690     if (index >= MAX_IPMI_USED_CHANNELS)
5691 	return EINVAL;
5692 
5693     *chan = domain->chan[index];
5694     return 0;
5695 }
5696 
5697 int
ipmi_domain_get_guid(ipmi_domain_t * domain,unsigned char * guid)5698 ipmi_domain_get_guid(ipmi_domain_t *domain, unsigned char *guid)
5699 {
5700     int rv;
5701     i_ipmi_mc_get(domain->si_mc);
5702     rv = ipmi_mc_get_guid(domain->si_mc, guid);
5703     i_ipmi_mc_put(domain->si_mc);
5704     return rv;
5705 }
5706 
5707 int
ipmi_domain_con_up(ipmi_domain_t * domain)5708 ipmi_domain_con_up(ipmi_domain_t *domain)
5709 {
5710     CHECK_DOMAIN_LOCK(domain);
5711     return domain->connection_up;
5712 }
5713 
5714 static void
check_event_rcvr(ipmi_domain_t * domain,ipmi_mc_t * mc,void * cb_data)5715 check_event_rcvr(ipmi_domain_t *domain, ipmi_mc_t *mc, void *cb_data)
5716 {
5717     unsigned int *addr = cb_data;
5718     if (*addr)
5719 	return;
5720     if (!ipmi_mc_ipmb_event_receiver_support(mc))
5721 	return;
5722     if (ipmi_mc_get_channel(mc) == IPMI_BMC_CHANNEL)
5723 	return;
5724     *addr = ipmi_mc_get_address(mc);
5725 }
5726 
5727 int
ipmi_domain_get_event_rcvr(ipmi_domain_t * domain)5728 ipmi_domain_get_event_rcvr(ipmi_domain_t *domain)
5729 {
5730     unsigned int addr = 0;
5731 
5732     ipmi_domain_iterate_mcs(domain, check_event_rcvr, &addr);
5733     return addr;
5734 }
5735 
5736 const char *
i_ipmi_domain_name(const ipmi_domain_t * domain)5737 i_ipmi_domain_name(const ipmi_domain_t *domain)
5738 {
5739     return domain->name;
5740 }
5741 
5742 int
ipmi_domain_get_name(ipmi_domain_t * domain,char * name,int length)5743 ipmi_domain_get_name(ipmi_domain_t *domain, char *name, int length)
5744 {
5745     int  slen;
5746 
5747     if (length <= 0)
5748 	return 0;
5749 
5750     /* Never changes, no lock needed. */
5751     slen = strlen(domain->name);
5752     if (slen == 0) {
5753 	if (name)
5754 	    *name = '\0';
5755 	goto out;
5756     }
5757 
5758     slen -= 1; /* Remove the trailing ' ' */
5759     if (slen >= length) {
5760 	slen = length - 1;
5761     }
5762 
5763     if (name) {
5764 	memcpy(name, domain->name, slen);
5765 	name[slen] = '\0';
5766     }
5767  out:
5768     return slen;
5769 }
5770 
5771 void
ipmi_domain_set_oem_data(ipmi_domain_t * domain,void * oem_data,ipmi_domain_destroy_oem_data_cb destroyer)5772 ipmi_domain_set_oem_data(ipmi_domain_t                   *domain,
5773 			 void                            *oem_data,
5774 			 ipmi_domain_destroy_oem_data_cb destroyer)
5775 {
5776     domain->oem_data = oem_data;
5777     domain->oem_data_destroyer = destroyer;
5778 }
5779 
5780 void *
ipmi_domain_get_oem_data(ipmi_domain_t * domain)5781 ipmi_domain_get_oem_data(ipmi_domain_t *domain)
5782 {
5783     return domain->oem_data;
5784 }
5785 
5786 enum ipmi_domain_type
ipmi_domain_get_type(ipmi_domain_t * domain)5787 ipmi_domain_get_type(ipmi_domain_t *domain)
5788 {
5789     return domain->domain_type;
5790 }
5791 
5792 void
ipmi_domain_set_type(ipmi_domain_t * domain,enum ipmi_domain_type dtype)5793 ipmi_domain_set_type(ipmi_domain_t *domain, enum ipmi_domain_type dtype)
5794 {
5795     domain->domain_type = dtype;
5796 }
5797 
5798 unsigned int
ipmi_domain_get_unique_num(ipmi_domain_t * domain)5799 ipmi_domain_get_unique_num(ipmi_domain_t *domain)
5800 {
5801     unsigned int rv;
5802 
5803     ipmi_lock(domain->domain_lock);
5804     rv = domain->uniq_num;
5805     domain->uniq_num++;
5806     ipmi_unlock(domain->domain_lock);
5807     return rv;
5808 }
5809 
5810 
5811 /*OEM-specific sensors handling*/
5812 int
ipmi_domain_add_new_sensor_handler(ipmi_domain_t * domain,ipmi_domain_sensor_cb handler,void * cb_data)5813 ipmi_domain_add_new_sensor_handler(ipmi_domain_t         *domain,
5814                                    ipmi_domain_sensor_cb handler,
5815                                    void                  *cb_data)
5816 {
5817     if (locked_list_add(domain->new_sensor_handlers, handler, cb_data))
5818         return 0;
5819     else
5820         return ENOMEM;
5821 }
5822 
5823 int
ipmi_domain_remove_new_sensor_handler(ipmi_domain_t * domain,ipmi_domain_sensor_cb handler,void * cb_data)5824 ipmi_domain_remove_new_sensor_handler(ipmi_domain_t        *domain,
5825                                       ipmi_domain_sensor_cb handler,
5826                                        void                *cb_data)
5827 {
5828     if (locked_list_remove(domain->new_sensor_handlers, handler, cb_data))
5829         return 0;
5830     else
5831         return EINVAL;
5832 }
5833 
5834 typedef struct new_sensor_handler_info_s
5835 {
5836     ipmi_domain_t *domain;
5837     ipmi_sensor_t *sensor;
5838 } new_sensor_handler_info_t;
5839 
5840 static int
call_new_sensor_handler(void * cb_data,void * item1,void * item2)5841 call_new_sensor_handler(void *cb_data, void *item1, void *item2)
5842 {
5843     new_sensor_handler_info_t *info = cb_data;
5844     ipmi_domain_sensor_cb     handler = item1;
5845 
5846     handler(info->domain, info->sensor, item2);
5847     return 0;
5848 }
5849 
5850 int
i_call_new_sensor_handlers(ipmi_domain_t * domain,ipmi_sensor_t * sensor)5851 i_call_new_sensor_handlers(ipmi_domain_t *domain,
5852 			   ipmi_sensor_t *sensor)
5853 {
5854     new_sensor_handler_info_t info;
5855 
5856     info.domain = domain;
5857     info.sensor = sensor;
5858 
5859     locked_list_iterate(domain->new_sensor_handlers, call_new_sensor_handler,
5860 		        &info);
5861     return 0;
5862 }
5863 
5864 /***********************************************************************
5865  *
5866  * Handling anonmymous attributes for domains
5867  *
5868  **********************************************************************/
5869 
5870 struct ipmi_domain_attr_s
5871 {
5872     char *name;
5873     void *data;
5874 
5875     ipmi_lock_t *lock;
5876     unsigned int refcount;
5877 
5878     ipmi_domain_attr_kill_cb destroy;
5879     void                     *cb_data;
5880 };
5881 
5882 static int
destroy_attr(void * cb_data,void * item1,void * item2)5883 destroy_attr(void *cb_data, void *item1, void *item2)
5884 {
5885     ipmi_domain_t      *domain = cb_data;
5886     ipmi_domain_attr_t *attr = item1;
5887 
5888     locked_list_remove(domain->attr, item1, item2);
5889     ipmi_domain_attr_put(attr);
5890     return LOCKED_LIST_ITER_CONTINUE;
5891 }
5892 
5893 typedef struct domain_attr_cmp_s
5894 {
5895     char               *name;
5896     ipmi_domain_attr_t *attr;
5897 } domain_attr_cmp_t;
5898 
5899 static int
domain_attr_cmp(void * cb_data,void * item1,void * item2)5900 domain_attr_cmp(void *cb_data, void *item1, void *item2)
5901 {
5902     domain_attr_cmp_t  *info = cb_data;
5903     ipmi_domain_attr_t *attr = item1;
5904 
5905     if (strcmp(info->name, attr->name) == 0) {
5906 	info->attr = attr;
5907 	return LOCKED_LIST_ITER_STOP;
5908     }
5909 
5910     return LOCKED_LIST_ITER_CONTINUE;
5911 }
5912 
5913 int
ipmi_domain_register_attribute(ipmi_domain_t * domain,char * name,ipmi_domain_attr_init_cb init,ipmi_domain_attr_kill_cb destroy,void * cb_data,ipmi_domain_attr_t ** attr)5914 ipmi_domain_register_attribute(ipmi_domain_t            *domain,
5915 			       char                     *name,
5916 			       ipmi_domain_attr_init_cb init,
5917 			       ipmi_domain_attr_kill_cb destroy,
5918 			       void                     *cb_data,
5919 			       ipmi_domain_attr_t       **attr)
5920 {
5921     ipmi_domain_attr_t  *val = NULL;
5922     domain_attr_cmp_t   info;
5923     int                 rv = 0;
5924     locked_list_entry_t *entry;
5925 
5926     info.name = name;
5927     info.attr = NULL;
5928     locked_list_lock(domain->attr);
5929     locked_list_iterate_nolock(domain->attr, domain_attr_cmp, &info);
5930     if (info.attr) {
5931 	ipmi_lock(info.attr->lock);
5932 	info.attr->refcount++;
5933 	ipmi_unlock(info.attr->lock);
5934 	*attr = info.attr;
5935 	goto out_unlock;
5936     }
5937 
5938     val = ipmi_mem_alloc(sizeof(*val));
5939     if (!val) {
5940 	rv = ENOMEM;
5941 	goto out_unlock;
5942     }
5943 
5944     val->name = ipmi_strdup(name);
5945     if (!val->name) {
5946 	ipmi_mem_free(val);
5947 	rv = ENOMEM;
5948 	goto out_unlock;
5949     }
5950 
5951     entry = locked_list_alloc_entry();
5952     if (!entry) {
5953 	ipmi_mem_free(val->name);
5954 	ipmi_mem_free(val);
5955 	rv = ENOMEM;
5956 	goto out_unlock;
5957     }
5958 
5959     rv = ipmi_create_lock(domain, &val->lock);
5960     if (rv) {
5961 	locked_list_free_entry(entry);
5962 	ipmi_mem_free(val->name);
5963 	ipmi_mem_free(val);
5964 	goto out_unlock;
5965     }
5966 
5967     val->refcount = 2;
5968     val->destroy = destroy;
5969     val->cb_data = cb_data;
5970     val->data = NULL;
5971 
5972     if (init) {
5973 	rv = init(domain, cb_data, &val->data);
5974 	if (rv) {
5975 	    ipmi_destroy_lock(val->lock);
5976 	    locked_list_free_entry(entry);
5977 	    ipmi_mem_free(val->name);
5978 	    ipmi_mem_free(val);
5979 	    rv = ENOMEM;
5980 	    goto out_unlock;
5981 	}
5982     }
5983 
5984     locked_list_add_entry_nolock(domain->attr, val, NULL, entry);
5985 
5986     *attr = val;
5987 
5988  out_unlock:
5989     locked_list_unlock(domain->attr);
5990     return rv;
5991 }
5992 
5993 int
ipmi_domain_find_attribute(ipmi_domain_t * domain,char * name,ipmi_domain_attr_t ** attr)5994 ipmi_domain_find_attribute(ipmi_domain_t      *domain,
5995 			   char               *name,
5996 			   ipmi_domain_attr_t **attr)
5997 {
5998     domain_attr_cmp_t info;
5999 
6000     if (!domain->attr)
6001 	return EINVAL;
6002 
6003     /* Attributes are immutable, no lock is required. */
6004     info.name = name;
6005     info.attr = NULL;
6006     locked_list_iterate(domain->attr, domain_attr_cmp, &info);
6007     if (info.attr) {
6008 	ipmi_lock(info.attr->lock);
6009 	info.attr->refcount++;
6010 	ipmi_unlock(info.attr->lock);
6011 	*attr = info.attr;
6012 	return 0;
6013     }
6014     return EINVAL;
6015 }
6016 
6017 void *
ipmi_domain_attr_get_data(ipmi_domain_attr_t * attr)6018 ipmi_domain_attr_get_data(ipmi_domain_attr_t *attr)
6019 {
6020     return attr->data;
6021 }
6022 
6023 void
ipmi_domain_attr_put(ipmi_domain_attr_t * attr)6024 ipmi_domain_attr_put(ipmi_domain_attr_t *attr)
6025 {
6026     ipmi_lock(attr->lock);
6027     attr->refcount--;
6028     if (attr->refcount > 0) {
6029 	ipmi_unlock(attr->lock);
6030 	return;
6031     }
6032     ipmi_unlock(attr->lock);
6033     if (attr->destroy)
6034 	attr->destroy(attr->cb_data, attr->data);
6035     ipmi_destroy_lock(attr->lock);
6036     ipmi_mem_free(attr->name);
6037     ipmi_mem_free(attr);
6038 }
6039 
6040 typedef struct find_attr_s
6041 {
6042     char               *name;
6043     ipmi_domain_attr_t **attr;
6044     int                rv;
6045 } find_attr_t;
6046 
6047 static void
find_attr_2(ipmi_domain_t * domain,void * cb_data)6048 find_attr_2(ipmi_domain_t *domain, void *cb_data)
6049 {
6050     find_attr_t *info = cb_data;
6051 
6052     info->rv = ipmi_domain_find_attribute(domain, info->name, info->attr);
6053 }
6054 
6055 int
ipmi_domain_id_find_attribute(ipmi_domain_id_t domain_id,char * name,ipmi_domain_attr_t ** attr)6056 ipmi_domain_id_find_attribute(ipmi_domain_id_t   domain_id,
6057 			      char               *name,
6058 			      ipmi_domain_attr_t **attr)
6059 {
6060     find_attr_t info = { name, attr, 0 };
6061     int  rv;
6062 
6063     rv = ipmi_domain_pointer_cb(domain_id, find_attr_2, &info);
6064     if (!rv)
6065 	rv = info.rv;
6066     return rv;
6067 }
6068 
6069 /***********************************************************************
6070  *
6071  * Statistics
6072  *
6073  **********************************************************************/
6074 
6075 struct ipmi_domain_stat_s
6076 {
6077     char               *name;
6078     char               *instance;
6079     ipmi_lock_t        *lock;
6080     unsigned int       count;
6081     ipmi_domain_stat_t *stat;
6082     unsigned int       refcount;
6083 };
6084 
6085 static int
destroy_stat(void * cb_data,void * item1,void * item2)6086 destroy_stat(void *cb_data, void *item1, void *item2)
6087 {
6088     ipmi_domain_t      *domain = cb_data;
6089     ipmi_domain_stat_t *stat = item1;
6090 
6091     locked_list_remove(domain->stats, item1, item2);
6092     ipmi_domain_stat_put(stat);
6093     return LOCKED_LIST_ITER_CONTINUE;
6094 }
6095 
6096 typedef struct domain_stat_cmp_s
6097 {
6098     const char         *name;
6099     const char         *instance;
6100     ipmi_domain_stat_t *stat;
6101 } domain_stat_cmp_t;
6102 
6103 static int
domain_stat_cmp(void * cb_data,void * item1,void * item2)6104 domain_stat_cmp(void *cb_data, void *item1, void *item2)
6105 {
6106     domain_stat_cmp_t  *info = cb_data;
6107     ipmi_domain_stat_t *stat = item1;
6108 
6109     if ((strcmp(info->name, stat->name) == 0)
6110 	&& (strcmp(info->instance, stat->instance) == 0))
6111     {
6112 	info->stat = stat;
6113 	return LOCKED_LIST_ITER_STOP;
6114     }
6115 
6116     return LOCKED_LIST_ITER_CONTINUE;
6117 }
6118 
6119 int
ipmi_domain_stat_register(ipmi_domain_t * domain,const char * name,const char * instance,ipmi_domain_stat_t ** stat)6120 ipmi_domain_stat_register(ipmi_domain_t      *domain,
6121 			  const char         *name,
6122 			  const char         *instance,
6123 			  ipmi_domain_stat_t **stat)
6124 {
6125     ipmi_domain_stat_t  *val = NULL;
6126     domain_stat_cmp_t   info;
6127     int                 rv = 0;
6128     locked_list_entry_t *entry;
6129 
6130     info.name = name;
6131     info.instance = instance;
6132     info.stat = NULL;
6133     locked_list_lock(domain->stats);
6134     locked_list_iterate_nolock(domain->stats, domain_stat_cmp, &info);
6135     if (info.stat) {
6136 	ipmi_lock(info.stat->lock);
6137 	info.stat->refcount++;
6138 	ipmi_unlock(info.stat->lock);
6139 	*stat = info.stat;
6140 	goto out_unlock;
6141     }
6142 
6143     val = ipmi_mem_alloc(sizeof(*val));
6144     if (!val) {
6145 	rv = ENOMEM;
6146 	goto out_unlock;
6147     }
6148 
6149     val->name = ipmi_strdup(name);
6150     if (!val->name) {
6151 	ipmi_mem_free(val);
6152 	rv = ENOMEM;
6153 	goto out_unlock;
6154     }
6155 
6156     val->instance = ipmi_strdup(instance);
6157     if (!val->instance) {
6158 	ipmi_mem_free(val->name);
6159 	ipmi_mem_free(val);
6160 	rv = ENOMEM;
6161 	goto out_unlock;
6162     }
6163 
6164     entry = locked_list_alloc_entry();
6165     if (!entry) {
6166 	ipmi_mem_free(val->instance);
6167 	ipmi_mem_free(val->name);
6168 	ipmi_mem_free(val);
6169 	rv = ENOMEM;
6170 	goto out_unlock;
6171     }
6172 
6173     rv = ipmi_create_lock(domain, &val->lock);
6174     if (rv) {
6175 	locked_list_free_entry(entry);
6176 	ipmi_mem_free(val->instance);
6177 	ipmi_mem_free(val->name);
6178 	ipmi_mem_free(val);
6179 	goto out_unlock;
6180     }
6181 
6182     val->refcount = 2;
6183     val->count = 0;
6184 
6185     locked_list_add_entry_nolock(domain->stats, val, NULL, entry);
6186 
6187     *stat = val;
6188 
6189  out_unlock:
6190     locked_list_unlock(domain->stats);
6191     return 0;
6192 }
6193 
6194 int
ipmi_domain_find_stat(ipmi_domain_t * domain,const char * name,const char * instance,ipmi_domain_stat_t ** stat)6195 ipmi_domain_find_stat(ipmi_domain_t      *domain,
6196 		      const char         *name,
6197 		      const char         *instance,
6198 		      ipmi_domain_stat_t **stat)
6199 {
6200     domain_stat_cmp_t   info;
6201     int                 rv = ENOENT;
6202 
6203     info.name = name;
6204     info.instance = instance;
6205     info.stat = NULL;
6206     locked_list_lock(domain->stats);
6207     locked_list_iterate_nolock(domain->stats, domain_stat_cmp, &info);
6208     if (info.stat) {
6209 	ipmi_lock(info.stat->lock);
6210 	info.stat->refcount++;
6211 	ipmi_unlock(info.stat->lock);
6212 	*stat = info.stat;
6213 	rv = 0;
6214     }
6215     locked_list_unlock(domain->stats);
6216 
6217     return rv;
6218 }
6219 
6220 void
ipmi_domain_stat_put(ipmi_domain_stat_t * stat)6221 ipmi_domain_stat_put(ipmi_domain_stat_t *stat)
6222 {
6223     ipmi_lock(stat->lock);
6224     stat->refcount--;
6225     if (stat->refcount > 0) {
6226 	ipmi_unlock(stat->lock);
6227 	return;
6228     }
6229     ipmi_unlock(stat->lock);
6230     ipmi_destroy_lock(stat->lock);
6231     ipmi_mem_free(stat->name);
6232     ipmi_mem_free(stat->instance);
6233     ipmi_mem_free(stat);
6234 }
6235 
6236 void
ipmi_domain_stat_add(ipmi_domain_stat_t * stat,int amount)6237 ipmi_domain_stat_add(ipmi_domain_stat_t *stat, int amount)
6238 {
6239     ipmi_lock(stat->lock);
6240     stat->count += amount;
6241     ipmi_unlock(stat->lock);
6242 }
6243 
6244 unsigned int
ipmi_domain_stat_get(ipmi_domain_stat_t * stat)6245 ipmi_domain_stat_get(ipmi_domain_stat_t *stat)
6246 {
6247     unsigned int rv;
6248     ipmi_lock(stat->lock);
6249     rv = stat->count;
6250     ipmi_unlock(stat->lock);
6251     return rv;
6252 }
6253 
6254 unsigned int
ipmi_domain_stat_get_and_zero(ipmi_domain_stat_t * stat)6255 ipmi_domain_stat_get_and_zero(ipmi_domain_stat_t *stat)
6256 {
6257     unsigned int rv;
6258     ipmi_lock(stat->lock);
6259     rv = stat->count;
6260     stat->count = 0;
6261     ipmi_unlock(stat->lock);
6262     return rv;
6263 }
6264 
6265 const char *
ipmi_domain_stat_get_name(ipmi_domain_stat_t * stat)6266 ipmi_domain_stat_get_name(ipmi_domain_stat_t *stat)
6267 {
6268     return stat->name;
6269 }
6270 
6271 const char *
ipmi_domain_stat_get_instance(ipmi_domain_stat_t * stat)6272 ipmi_domain_stat_get_instance(ipmi_domain_stat_t *stat)
6273 {
6274     return stat->instance;
6275 }
6276 
6277 typedef struct stat_iterate_s
6278 {
6279     ipmi_domain_t *domain;
6280     const char    *name;
6281     const char    *instance;
6282     ipmi_stat_cb  handler;
6283     void          *cb_data;
6284 } stat_iterate_t;
6285 
6286 static int
domain_stat_iter_pre(void * cb_data,void * item1,void * item2)6287 domain_stat_iter_pre(void *cb_data, void *item1, void *item2)
6288 {
6289     stat_iterate_t     *info = cb_data;
6290     ipmi_domain_stat_t *stat = item1;
6291 
6292     if (info->name && (strcmp(info->name, stat->name) != 0))
6293 	return LOCKED_LIST_ITER_SKIP;
6294     if (info->instance && (strcmp(info->instance, stat->instance) != 0))
6295 	return LOCKED_LIST_ITER_SKIP;
6296 
6297     ipmi_lock(stat->lock);
6298     stat->refcount++;
6299     ipmi_unlock(stat->lock);
6300 
6301     return LOCKED_LIST_ITER_CONTINUE;
6302 }
6303 
6304 static int
domain_stat_iter(void * cb_data,void * item1,void * item2)6305 domain_stat_iter(void *cb_data, void *item1, void *item2)
6306 {
6307     stat_iterate_t     *info = cb_data;
6308     ipmi_domain_stat_t *stat = item1;
6309 
6310     /* Prefunc already matched, this is a good one. */
6311     info->handler(info->domain, stat, info->cb_data);
6312     ipmi_domain_stat_put(stat);
6313 
6314     return LOCKED_LIST_ITER_CONTINUE;
6315 }
6316 
6317 void
ipmi_domain_stat_iterate(ipmi_domain_t * domain,const char * name,const char * instance,ipmi_stat_cb handler,void * cb_data)6318 ipmi_domain_stat_iterate(ipmi_domain_t *domain,
6319 			 const char    *name,
6320 			 const char    *instance,
6321 			 ipmi_stat_cb  handler,
6322 			 void          *cb_data)
6323 {
6324     stat_iterate_t info;
6325 
6326     info.domain = domain;
6327     info.name = name;
6328     info.instance = instance;
6329     info.handler = handler;
6330     info.cb_data = cb_data;
6331     locked_list_iterate_prefunc(domain->stats, domain_stat_iter_pre,
6332 				domain_stat_iter, &info);
6333 }
6334 
6335 /***********************************************************************
6336  *
6337  * Initialization and shutdown
6338  *
6339  **********************************************************************/
6340 
6341 int
i_ipmi_domain_init(void)6342 i_ipmi_domain_init(void)
6343 {
6344     int rv;
6345 
6346     if (domains_initialized)
6347 	return 0;
6348 
6349     mc_oem_handlers = locked_list_alloc(ipmi_get_global_os_handler());
6350     if (!mc_oem_handlers)
6351 	return ENOMEM;
6352 
6353     domain_change_handlers = locked_list_alloc(ipmi_get_global_os_handler());
6354     if (!domain_change_handlers)
6355 	return ENOMEM;
6356 
6357     domains_list = locked_list_alloc(ipmi_get_global_os_handler());
6358     if (!domains_list) {
6359 	locked_list_destroy(domain_change_handlers);
6360 	return ENOMEM;
6361     }
6362 
6363     oem_handlers = alloc_ilist();
6364     if (!oem_handlers) {
6365 	locked_list_destroy(domain_change_handlers);
6366 	locked_list_destroy(domains_list);
6367 	domains_list = NULL;
6368 	return ENOMEM;
6369     }
6370 
6371     rv = ipmi_create_global_lock(&domains_lock);
6372     if (rv) {
6373 	locked_list_destroy(domain_change_handlers);
6374 	locked_list_destroy(domains_list);
6375 	domains_list = NULL;
6376 	free_ilist(oem_handlers);
6377 	oem_handlers = NULL;
6378 	return rv;
6379     }
6380 
6381     domains_initialized = 1;
6382 
6383     return 0;
6384 }
6385 
6386 void
i_ipmi_domain_shutdown(void)6387 i_ipmi_domain_shutdown(void)
6388 {
6389     domains_initialized = 0;
6390 
6391     locked_list_destroy(domain_change_handlers);
6392     locked_list_destroy(mc_oem_handlers);
6393     locked_list_destroy(domains_list);
6394     domains_list = NULL;
6395     free_ilist(oem_handlers);
6396     oem_handlers = NULL;
6397     ipmi_destroy_lock(domains_lock);
6398     domains_lock = NULL;
6399 }
6400 
6401 
6402 /***********************************************************************
6403  *
6404  * Cruft
6405  *
6406  **********************************************************************/
6407 
6408 struct ipmi_domain_mc_upd_s
6409 {
6410     ipmi_domain_mc_upd_cb handler;
6411     void                  *cb_data;
6412     struct ipmi_domain_mc_upd_s *next, *prev;
6413 };
6414 
6415 int
ipmi_domain_register_mc_update_handler(ipmi_domain_t * domain,ipmi_domain_mc_upd_cb handler,void * cb_data,struct ipmi_domain_mc_upd_s ** id)6416 ipmi_domain_register_mc_update_handler(ipmi_domain_t         *domain,
6417 				       ipmi_domain_mc_upd_cb handler,
6418 				       void                  *cb_data,
6419 				       struct ipmi_domain_mc_upd_s **id)
6420 {
6421     struct ipmi_domain_mc_upd_s *info;
6422     int                         rv;
6423 
6424     info = ipmi_mem_alloc(sizeof(*info));
6425     if (!info)
6426 	return ENOMEM;
6427     rv = ipmi_domain_add_mc_updated_handler(domain, handler, cb_data);
6428     if (rv) {
6429 	ipmi_mem_free(info);
6430     } else {
6431 	info->handler = handler;
6432 	info->cb_data = cb_data;
6433 	ipmi_lock(domain->domain_lock);
6434 	info->next = domain->mc_upd_cruft;
6435 	info->prev = NULL;
6436 	domain->mc_upd_cruft = info;
6437 	ipmi_unlock(domain->domain_lock);
6438 
6439 	if (id)
6440 	    *id = info;
6441     }
6442 
6443     return rv;
6444 }
6445 
6446 void
ipmi_domain_remove_mc_update_handler(ipmi_domain_t * domain,struct ipmi_domain_mc_upd_s * id)6447 ipmi_domain_remove_mc_update_handler(ipmi_domain_t               *domain,
6448 				     struct ipmi_domain_mc_upd_s *id)
6449 {
6450     ipmi_domain_remove_mc_updated_handler(domain, id->handler, id->cb_data);
6451     ipmi_lock(domain->domain_lock);
6452     if (id->next)
6453 	id->next->prev = id->prev;
6454     if (id->prev)
6455 	id->prev->next = id->next;
6456     else
6457 	domain->mc_upd_cruft = id->next;
6458     ipmi_unlock(domain->domain_lock);
6459     ipmi_mem_free(id);
6460 }
6461 
6462 struct ipmi_event_handler_id_s
6463 {
6464     ipmi_event_handler_cb   handler;
6465     void                    *event_data;
6466     struct ipmi_event_handler_id_s *next, *prev;
6467 };
6468 
6469 int
ipmi_register_for_events(ipmi_domain_t * domain,ipmi_event_handler_cb handler,void * event_data,struct ipmi_event_handler_id_s ** id)6470 ipmi_register_for_events(ipmi_domain_t                  *domain,
6471 			 ipmi_event_handler_cb          handler,
6472 			 void                           *event_data,
6473 			 struct ipmi_event_handler_id_s **id)
6474 {
6475     struct ipmi_event_handler_id_s *info;
6476     int                            rv;
6477 
6478     info = ipmi_mem_alloc(sizeof(*info));
6479     if (!info)
6480 	return ENOMEM;
6481     rv = ipmi_domain_add_event_handler(domain, handler, event_data);
6482     if (rv) {
6483 	ipmi_mem_free(info);
6484     } else {
6485 	info->handler = handler;
6486 	info->event_data = event_data;
6487 	ipmi_lock(domain->domain_lock);
6488 	info->next = domain->event_cruft;
6489 	info->prev = NULL;
6490 	domain->event_cruft = info;
6491 	ipmi_unlock(domain->domain_lock);
6492 
6493 	if (id)
6494 	    *id = info;
6495     }
6496 
6497     return rv;
6498 }
6499 
6500 int
ipmi_deregister_for_events(ipmi_domain_t * domain,struct ipmi_event_handler_id_s * id)6501 ipmi_deregister_for_events(ipmi_domain_t                  *domain,
6502 			   struct ipmi_event_handler_id_s *id)
6503 {
6504     int rv;
6505     rv = ipmi_domain_remove_event_handler(domain, id->handler, id->event_data);
6506     ipmi_lock(domain->domain_lock);
6507     if (id->next)
6508 	id->next->prev = id->prev;
6509     if (id->prev)
6510 	id->prev->next = id->next;
6511     else
6512 	domain->event_cruft = id->next;
6513     ipmi_unlock(domain->domain_lock);
6514     ipmi_mem_free(id);
6515     return rv;
6516 }
6517 
6518 struct ipmi_domain_con_change_s
6519 {
6520     ipmi_domain_con_cb              handler;
6521     void                            *cb_data;
6522     struct ipmi_domain_con_change_s *next, *prev;
6523 };
6524 
6525 static int
ipmi_domain_add_con_change_handler_nd(ipmi_domain_t * domain,ipmi_domain_con_cb handler,void * cb_data,struct ipmi_domain_con_change_s ** id)6526 ipmi_domain_add_con_change_handler_nd(ipmi_domain_t                   *domain,
6527 				      ipmi_domain_con_cb              handler,
6528 				      void                            *cb_data,
6529 				      struct ipmi_domain_con_change_s **id)
6530 {
6531     struct ipmi_domain_con_change_s *info;
6532     int                             rv;
6533 
6534     info = ipmi_mem_alloc(sizeof(*info));
6535     if (!info)
6536 	return ENOMEM;
6537     rv = ipmi_domain_add_connect_change_handler(domain, handler, cb_data);
6538     if (rv) {
6539 	ipmi_mem_free(info);
6540     } else {
6541 	info->handler = handler;
6542 	info->cb_data = cb_data;
6543 	ipmi_lock(domain->domain_lock);
6544 	info->next = domain->con_change_cruft;
6545 	info->prev = NULL;
6546 	domain->con_change_cruft = info;
6547 	ipmi_unlock(domain->domain_lock);
6548 
6549 	if (id)
6550 	    *id = info;
6551     }
6552 
6553     return rv;
6554 }
6555 
6556 int
ipmi_domain_add_con_change_handler(ipmi_domain_t * domain,ipmi_domain_con_cb handler,void * cb_data,struct ipmi_domain_con_change_s ** id)6557 ipmi_domain_add_con_change_handler(ipmi_domain_t                   *domain,
6558 				   ipmi_domain_con_cb              handler,
6559 				   void                            *cb_data,
6560 				   struct ipmi_domain_con_change_s **id)
6561 {
6562     return ipmi_domain_add_con_change_handler_nd(domain,
6563 						 handler,
6564 						 cb_data,
6565 						 id);
6566 }
6567 
6568 void
ipmi_domain_remove_con_change_handler(ipmi_domain_t * domain,struct ipmi_domain_con_change_s * id)6569 ipmi_domain_remove_con_change_handler(ipmi_domain_t                   *domain,
6570 				      struct ipmi_domain_con_change_s *id)
6571 {
6572     ipmi_domain_remove_connect_change_handler(domain, id->handler,
6573 					      id->cb_data);
6574     ipmi_lock(domain->domain_lock);
6575     if (id->next)
6576 	id->next->prev = id->prev;
6577     if (id->prev)
6578 	id->prev->next = id->next;
6579     else
6580 	domain->con_change_cruft = id->next;
6581     ipmi_unlock(domain->domain_lock);
6582     ipmi_mem_free(id);
6583 }
6584 
6585 int
ipmi_init_domain(ipmi_con_t * con[],unsigned int num_con,ipmi_domain_con_cb con_change_handler,void * con_change_cb_data,struct ipmi_domain_con_change_s ** con_change_id,ipmi_domain_id_t * new_domain)6586 ipmi_init_domain(ipmi_con_t               *con[],
6587 		 unsigned int             num_con,
6588 		 ipmi_domain_con_cb       con_change_handler,
6589 		 void                     *con_change_cb_data,
6590 		 struct ipmi_domain_con_change_s **con_change_id,
6591 		 ipmi_domain_id_t         *new_domain)
6592 {
6593     int           rv;
6594     ipmi_domain_t *domain;
6595     unsigned int  i;
6596 
6597     if ((num_con < 1) || (num_con > MAX_CONS))
6598 	return EINVAL;
6599 
6600     rv = setup_domain("", con, num_con, NULL, 0, &domain);
6601     if (rv)
6602 	return rv;
6603 
6604     domain->in_startup = 1;
6605     for (i=0; i<num_con; i++) {
6606 	rv = con[i]->add_con_change_handler(con[i], ll_con_changed, domain);
6607 	if (rv)
6608 	    return rv;
6609 	rv = con[i]->add_ipmb_addr_handler(con[i], ll_addr_changed, domain);
6610 	if (rv)
6611 	    return rv;
6612     }
6613 
6614     add_known_domain(domain);
6615 
6616     if (con_change_handler) {
6617 	rv = ipmi_domain_add_con_change_handler_nd(domain, con_change_handler,
6618 						   con_change_cb_data,
6619 						   con_change_id);
6620 	if (rv)
6621 	    goto out_err;
6622     }
6623 
6624     for (i=0; i<num_con; i++)
6625 	rv = con[i]->start_con(con[i]);
6626     if (rv)
6627 	goto out_err;
6628 
6629     if (new_domain)
6630 	*new_domain = ipmi_domain_convert_to_id(domain);
6631 
6632     if (! locked_list_add(domains_list, domain, NULL)) {
6633 	ipmi_log(IPMI_LOG_SEVERE,
6634 		 "%sdomain.c(sdr_handler): "
6635 		 "Out of memory, could not add domain to the domains list",
6636 		 DOMAIN_NAME(domain));
6637     }
6638 
6639  out:
6640     i_ipmi_domain_put(domain);
6641     return rv;
6642 
6643  out_err:
6644     for (i=0; i<num_con; i++) {
6645 	con[i]->remove_con_change_handler(con[i], ll_con_changed, domain);
6646 	con[i]->remove_ipmb_addr_handler(con[i], ll_addr_changed, domain);
6647 	if (con[i]->register_stat_handler)
6648 	    con[i]->unregister_stat_handler(con[i],
6649 					    domain->con_stat_info);
6650     }
6651     remove_known_domain(domain);
6652     cleanup_domain(domain);
6653     goto out;
6654 }
6655 
6656 int
ipmi_domain_set_entity_update_handler(ipmi_domain_t * domain,ipmi_domain_entity_cb handler,void * cb_data)6657 ipmi_domain_set_entity_update_handler(ipmi_domain_t         *domain,
6658 				      ipmi_domain_entity_cb handler,
6659 				      void                  *cb_data)
6660 {
6661     int rv = 0;
6662 
6663     CHECK_DOMAIN_LOCK(domain);
6664 
6665     ipmi_lock(domain->domain_lock);
6666     if (domain->cruft_entity_update_handler)
6667 	ipmi_entity_info_remove_update_handler
6668 	    (domain->entities,
6669 	     domain->cruft_entity_update_handler,
6670 	     domain->cruft_entity_update_cb_data);
6671 
6672     domain->cruft_entity_update_handler = handler;
6673     domain->cruft_entity_update_cb_data = cb_data;
6674     if (handler)
6675 	rv = ipmi_entity_info_add_update_handler(domain->entities,
6676 						 handler,
6677 						 cb_data);
6678     ipmi_unlock(domain->domain_lock);
6679     return rv;
6680 }
6681 
6682 int
ipmi_close_connection(ipmi_domain_t * domain,ipmi_domain_close_done_cb close_done,void * cb_data)6683 ipmi_close_connection(ipmi_domain_t             *domain,
6684 		      ipmi_domain_close_done_cb close_done,
6685 		      void                      *cb_data)
6686 {
6687     return ipmi_domain_close(domain, close_done, cb_data);
6688 }
6689 
6690 static void
free_domain_cruft(ipmi_domain_t * domain)6691 free_domain_cruft(ipmi_domain_t *domain)
6692 {
6693     while (domain->mc_upd_cruft) {
6694 	struct ipmi_domain_mc_upd_s *to_free;
6695 	to_free = domain->mc_upd_cruft;
6696 	domain->mc_upd_cruft = to_free->next;
6697 	ipmi_mem_free(to_free);
6698     }
6699 
6700     while (domain->event_cruft) {
6701 	struct ipmi_event_handler_id_s *to_free;
6702 	to_free = domain->event_cruft;
6703 	domain->event_cruft = to_free->next;
6704 	ipmi_mem_free(to_free);
6705     }
6706 
6707     while (domain->con_change_cruft) {
6708 	struct ipmi_domain_con_change_s *to_free;
6709 	to_free = domain->con_change_cruft;
6710 	domain->con_change_cruft = to_free->next;
6711 	ipmi_mem_free(to_free);
6712     }
6713 }
6714