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