1 /*
2 * control.c
3 *
4 * MontaVista IPMI code for handling controls
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 <limits.h>
37
38 #include <OpenIPMI/ipmiif.h>
39 #include <OpenIPMI/ipmi_err.h>
40
41 #include <OpenIPMI/internal/opq.h>
42 #include <OpenIPMI/internal/locked_list.h>
43 #include <OpenIPMI/internal/ipmi_int.h>
44 #include <OpenIPMI/internal/ipmi_domain.h>
45 #include <OpenIPMI/internal/ipmi_mc.h>
46 #include <OpenIPMI/internal/ipmi_control.h>
47
48 struct ipmi_control_info_s
49 {
50 int destroyed;
51
52 /* Indexed by control # */
53 ipmi_control_t **controls_by_idx;
54 /* Size of above control array. This will be 0 if the LUN has no
55 controls. */
56 unsigned int idx_size;
57
58 ipmi_lock_t *idx_lock;
59
60 /* Total number of controls we have in this. */
61 unsigned int control_count;
62
63 opq_t *control_wait_q;
64 int wait_err;
65 };
66
67 #define CONTROL_ID_LEN 32
68 struct ipmi_control_s
69 {
70 unsigned int usecount;
71
72 ipmi_domain_t *domain;
73 ipmi_mc_t *mc;
74 unsigned char lun;
75 unsigned char num;
76
77 ipmi_mc_t *source_mc;
78
79 ipmi_entity_t *entity;
80
81 int destroyed;
82
83 /* After the control is added, it will not be reported immediately.
84 Instead, it will wait until the usecount goes to zero before
85 being reported. This marks that the add report is pending */
86 int add_pending;
87
88 int type;
89 const char *type_str;
90
91 int settable;
92 int readable;
93
94 unsigned int num_vals;
95
96 int hot_swap_indicator;
97 int hot_swap_active_val;
98 int hot_swap_inactive_val;
99 int hot_swap_req_act_val;
100 int hot_swap_req_deact_val;
101
102 int hot_swap_power;
103
104 int has_events;
105
106 int ignore_if_no_entity : 1;
107 int ignore_for_presence : 1;
108
109 /* A list of handlers to call when an event for the control comes
110 in. */
111 locked_list_t *handler_list, *handler_list_cl;
112
113 /* For light types. */
114 #define MAX_LIGHTS 10
115 ipmi_control_light_t *lights;
116 unsigned int colors[MAX_LIGHTS];
117 int has_local_control[MAX_LIGHTS];
118
119 /* For display types. */
120 unsigned int columns;
121 unsigned int rows;
122
123 /* For identifier types. */
124 unsigned int identifier_length;
125
126 /* Note that this is *not* nil terminated. */
127 enum ipmi_str_type_e id_type;
128 unsigned int id_len;
129 char id[CONTROL_ID_LEN];
130
131 ipmi_control_cbs_t cbs;
132 opq_t *waitq;
133
134 void *oem_info;
135 ipmi_control_cleanup_oem_info_cb oem_info_cleanup_handler;
136
137 ipmi_control_destroy_cb destroy_handler;
138 void *destroy_handler_cb_data;
139
140 /* Name we use for reporting. We add a ' ' onto the end, thus
141 the +1. */
142 char name[IPMI_CONTROL_NAME_LEN+1];
143 };
144
145 static void control_final_destroy(ipmi_control_t *control);
146
147 /***********************************************************************
148 *
149 * Control ID handling.
150 *
151 **********************************************************************/
152
153 /* Must be called with the domain entity lock held. */
154 int
i_ipmi_control_get(ipmi_control_t * control)155 i_ipmi_control_get(ipmi_control_t *control)
156 {
157 if (control->destroyed)
158 return EINVAL;
159 control->usecount++;
160 return 0;
161 }
162
163 void
i_ipmi_control_put(ipmi_control_t * control)164 i_ipmi_control_put(ipmi_control_t *control)
165 {
166 i_ipmi_domain_entity_lock(control->domain);
167 if (control->usecount == 1) {
168 if (control->add_pending) {
169 control->add_pending = 0;
170 i_ipmi_domain_entity_unlock(control->domain);
171 i_ipmi_entity_call_control_handlers(control->entity,
172 control, IPMI_ADDED);
173 i_ipmi_domain_entity_lock(control->domain);
174 }
175 if (control->destroyed
176 && (!control->waitq
177 || (!opq_stuff_in_progress(control->waitq))))
178 {
179 i_ipmi_domain_entity_unlock(control->domain);
180 control_final_destroy(control);
181 return;
182 }
183 }
184 control->usecount--;
185 i_ipmi_domain_entity_unlock(control->domain);
186 }
187
188 ipmi_control_id_t
ipmi_control_convert_to_id(ipmi_control_t * control)189 ipmi_control_convert_to_id(ipmi_control_t *control)
190 {
191 ipmi_control_id_t val;
192
193 CHECK_CONTROL_LOCK(control);
194
195 val.mcid = ipmi_mc_convert_to_id(control->mc);
196 val.lun = control->lun;
197 val.control_num = control->num;
198
199 return val;
200 }
201
202 typedef struct mc_cb_info_s
203 {
204 ipmi_control_ptr_cb handler;
205 void *cb_data;
206 ipmi_control_id_t id;
207 int err;
208 } mc_cb_info_t;
209
210 static void
mc_cb(ipmi_mc_t * mc,void * cb_data)211 mc_cb(ipmi_mc_t *mc, void *cb_data)
212 {
213 mc_cb_info_t *info = cb_data;
214 ipmi_control_info_t *controls;
215 ipmi_domain_t *domain = ipmi_mc_get_domain(mc);
216 ipmi_control_t *control;
217 ipmi_entity_t *entity = NULL;
218
219 controls = i_ipmi_mc_get_controls(mc);
220 i_ipmi_domain_entity_lock(domain);
221 if (info->id.lun > 4) {
222 info->err = EINVAL;
223 goto out_unlock;
224 }
225
226 if (info->id.control_num >= controls->idx_size) {
227 info->err = EINVAL;
228 goto out_unlock;
229 }
230
231 control = controls->controls_by_idx[info->id.control_num];
232 if (!control) {
233 info->err = EINVAL;
234 goto out_unlock;
235 }
236
237 info->err = i_ipmi_entity_get(control->entity);
238 if (info->err)
239 goto out_unlock;
240 entity = control->entity;
241
242 info->err = i_ipmi_control_get(control);
243 if (info->err)
244 goto out_unlock;
245
246 i_ipmi_domain_entity_unlock(domain);
247
248 info->handler(control, info->cb_data);
249
250 i_ipmi_control_put(control);
251 i_ipmi_entity_put(entity);
252 return;
253
254 out_unlock:
255 i_ipmi_domain_entity_unlock(domain);
256 if (entity)
257 i_ipmi_entity_put(entity);
258 }
259
260 int
ipmi_control_pointer_cb(ipmi_control_id_t id,ipmi_control_ptr_cb handler,void * cb_data)261 ipmi_control_pointer_cb(ipmi_control_id_t id,
262 ipmi_control_ptr_cb handler,
263 void *cb_data)
264 {
265 int rv;
266 mc_cb_info_t info;
267
268 if (id.lun >= 5)
269 return EINVAL;
270
271 info.handler = handler;
272 info.cb_data = cb_data;
273 info.id = id;
274 info.err = 0;
275
276 rv = ipmi_mc_pointer_cb(id.mcid, mc_cb, &info);
277 if (!rv)
278 rv = info.err;
279
280 return rv;
281 }
282
283 int
ipmi_control_pointer_noseq_cb(ipmi_control_id_t id,ipmi_control_ptr_cb handler,void * cb_data)284 ipmi_control_pointer_noseq_cb(ipmi_control_id_t id,
285 ipmi_control_ptr_cb handler,
286 void *cb_data)
287 {
288 int rv;
289 mc_cb_info_t info;
290
291 if (id.lun >= 5)
292 return EINVAL;
293
294 info.handler = handler;
295 info.cb_data = cb_data;
296 info.id = id;
297 info.err = 0;
298
299 rv = ipmi_mc_pointer_noseq_cb(id.mcid, mc_cb, &info);
300 if (!rv)
301 rv = info.err;
302
303 return rv;
304 }
305
306 typedef struct control_find_info_s
307 {
308 ipmi_control_id_t id;
309 char *id_name;
310 int rv;
311 } control_find_info_t;
312
313 static void
control_search_cmp(ipmi_entity_t * entity,ipmi_control_t * control,void * cb_data)314 control_search_cmp(ipmi_entity_t *entity,
315 ipmi_control_t *control,
316 void *cb_data)
317 {
318 control_find_info_t *info = cb_data;
319 char id[33];
320 int rv;
321
322 rv = ipmi_control_get_id(control, id, 33);
323 if (rv)
324 return;
325 if (strcmp(info->id_name, id) == 0) {
326 info->id = ipmi_control_convert_to_id(control);
327 info->rv = 0;
328 }
329 }
330
331 static void
control_search(ipmi_entity_t * entity,void * cb_data)332 control_search(ipmi_entity_t *entity, void *cb_data)
333 {
334 control_find_info_t *info = cb_data;
335
336 ipmi_entity_iterate_controls(entity, control_search_cmp, info);
337 }
338
339 int
ipmi_control_find_id(ipmi_domain_id_t domain_id,int entity_id,int entity_instance,int channel,int slave_address,char * id_name,ipmi_control_id_t * id)340 ipmi_control_find_id(ipmi_domain_id_t domain_id,
341 int entity_id, int entity_instance,
342 int channel, int slave_address,
343 char *id_name,
344 ipmi_control_id_t *id)
345 {
346 int rv;
347 ipmi_entity_id_t entity;
348 control_find_info_t info;
349
350 rv = ipmi_entity_find_id(domain_id, entity_id, entity_instance,
351 channel, slave_address, &entity);
352 if (rv)
353 return rv;
354
355 info.id_name = id_name;
356 info.rv = EINVAL;
357
358 rv = ipmi_entity_pointer_cb(entity, control_search, &info);
359 if (!rv)
360 rv = info.rv;
361 if (!rv)
362 *id = info.id;
363
364 return rv;
365 }
366
367 /***********************************************************************
368 *
369 * Various control allocation/deallocation/opq/etc.
370 *
371 **********************************************************************/
372
373 static int
control_ok_to_use(ipmi_control_t * control)374 control_ok_to_use(ipmi_control_t *control)
375 {
376 return ( !control->destroyed
377 && !i_ipmi_domain_in_shutdown(control->domain));
378 }
379
380 typedef struct handler_cl_info_s
381 {
382 ipmi_control_val_event_cb handler;
383 void *handler_data;
384 } handler_cl_info_t;
385
386 static int
iterate_handler_cl(void * cb_data,void * item1,void * item2)387 iterate_handler_cl(void *cb_data, void *item1, void *item2)
388 {
389 handler_cl_info_t *info = cb_data;
390 ipmi_control_val_event_cl_cb handler = item1;
391
392 handler(info->handler, info->handler_data, item2);
393 return LOCKED_LIST_ITER_CONTINUE;
394 }
395
396 static int
handler_list_cleanup(void * cb_data,void * item1,void * item2)397 handler_list_cleanup(void *cb_data, void *item1, void *item2)
398 {
399 ipmi_control_t *control = cb_data;
400 handler_cl_info_t info;
401
402 info.handler = item1;
403 info.handler_data = item2;
404 locked_list_iterate(control->handler_list_cl,
405 iterate_handler_cl,
406 &info);
407 return LOCKED_LIST_ITER_CONTINUE;
408 }
409
410 static void
control_final_destroy(ipmi_control_t * control)411 control_final_destroy(ipmi_control_t *control)
412 {
413 i_ipmi_entity_get(control->entity);
414 i_ipmi_entity_call_control_handlers(control->entity, control, IPMI_DELETED);
415
416 control->mc = NULL;
417
418 if (control->destroy_handler)
419 control->destroy_handler(control,
420 control->destroy_handler_cb_data);
421
422 if (control->handler_list) {
423 locked_list_iterate(control->handler_list_cl, handler_list_cleanup,
424 control);
425 locked_list_destroy(control->handler_list);
426 }
427
428 if (control->handler_list_cl)
429 locked_list_destroy(control->handler_list_cl);
430
431 if (control->waitq)
432 opq_destroy(control->waitq);
433
434 ipmi_entity_remove_control(control->entity, control);
435
436 if (control->oem_info_cleanup_handler)
437 control->oem_info_cleanup_handler(control, control->oem_info);
438
439 i_ipmi_entity_put(control->entity);
440 ipmi_mem_free(control);
441 }
442
443 int
ipmi_control_destroy(ipmi_control_t * control)444 ipmi_control_destroy(ipmi_control_t *control)
445 {
446 ipmi_control_info_t *controls;
447 ipmi_mc_t *mc = control->mc;
448
449 i_ipmi_domain_mc_lock(control->domain);
450 i_ipmi_mc_get(mc);
451 i_ipmi_domain_mc_unlock(control->domain);
452 controls = i_ipmi_mc_get_controls(control->mc);
453
454 ipmi_lock(controls->idx_lock);
455 if (controls->controls_by_idx[control->num] == control) {
456 controls->control_count--;
457 controls->controls_by_idx[control->num] = NULL;
458 }
459
460 i_ipmi_control_get(control);
461
462 ipmi_unlock(controls->idx_lock);
463
464 control->destroyed = 1;
465 i_ipmi_control_put(control);
466 i_ipmi_mc_put(mc);
467
468 return 0;
469 }
470
471 static void
control_set_name(ipmi_control_t * control)472 control_set_name(ipmi_control_t *control)
473 {
474 int length;
475
476 length = ipmi_entity_get_name(control->entity, control->name,
477 sizeof(control->name)-2);
478 control->name[length] = '.';
479 length++;
480 length += snprintf(control->name+length, IPMI_CONTROL_NAME_LEN-length-2,
481 "%s", control->id);
482 control->name[length] = ' ';
483 length++;
484 control->name[length] = '\0';
485 length++;
486 }
487
488 const char *
i_ipmi_control_name(const ipmi_control_t * control)489 i_ipmi_control_name(const ipmi_control_t *control)
490 {
491 return control->name;
492 }
493
494 int
ipmi_control_get_name(ipmi_control_t * control,char * name,int length)495 ipmi_control_get_name(ipmi_control_t *control, char *name, int length)
496 {
497 int rv = 0;
498
499 if (control->entity)
500 rv = ipmi_entity_get_name(control->entity, name, length);
501 if (length > (int) (control->id_len + 2))
502 length = control->id_len + 2; /* Leave space for the nil */
503 rv += snprintf(name+rv, length, ".%s", control->id);
504 return rv;
505 }
506
507 /***********************************************************************
508 *
509 * Control message handling.
510 *
511 **********************************************************************/
512
513 static void
control_opq_ready2(ipmi_control_t * control,void * cb_data)514 control_opq_ready2(ipmi_control_t *control, void *cb_data)
515 {
516 ipmi_control_op_info_t *info = cb_data;
517 if (info->__handler)
518 info->__handler(control, 0, info->__cb_data);
519 }
520
521 static int
control_opq_ready(void * cb_data,int shutdown)522 control_opq_ready(void *cb_data, int shutdown)
523 {
524 ipmi_control_op_info_t *info = cb_data;
525 int rv;
526
527 if (shutdown) {
528 ipmi_log(IPMI_LOG_ERR_INFO,
529 "%scontrol.c(control_opq_ready): "
530 "Control was destroyed while an operation was in progress",
531 CONTROL_NAME(info->__control));
532 if (info->__handler)
533 info->__handler(info->__control, ECANCELED, info->__cb_data);
534 return OPQ_HANDLER_STARTED;
535 }
536
537 rv = ipmi_control_pointer_cb(info->__control_id, control_opq_ready2, info);
538 if (rv)
539 if (info->__handler)
540 info->__handler(info->__control, rv, info->__cb_data);
541 return OPQ_HANDLER_STARTED;
542 }
543
544 int
ipmi_control_add_opq(ipmi_control_t * control,ipmi_control_op_cb handler,ipmi_control_op_info_t * info,void * cb_data)545 ipmi_control_add_opq(ipmi_control_t *control,
546 ipmi_control_op_cb handler,
547 ipmi_control_op_info_t *info,
548 void *cb_data)
549 {
550 if (control->destroyed)
551 return EINVAL;
552
553 info->__control = control;
554 info->__control_id = ipmi_control_convert_to_id(control);
555 info->__cb_data = cb_data;
556 info->__handler = handler;
557 if (!opq_new_op(control->waitq, control_opq_ready, info, 0))
558 return ENOMEM;
559 return 0;
560 }
561
562 void
ipmi_control_opq_done(ipmi_control_t * control)563 ipmi_control_opq_done(ipmi_control_t *control)
564 {
565 /* Protect myself from NULL controls. This way, it doesn't have to
566 be done in each call. */
567 if (!control)
568 return;
569
570 /* This gets called on ECANCELED error cases, if the control is
571 already we need to clear out the opq. */
572 if (control->destroyed) {
573 if (control->waitq) {
574 opq_destroy(control->waitq);
575 control->waitq = NULL;
576 }
577 return;
578 }
579
580 /* No check for the lock. It will sometimes fail at destruction
581 time. */
582
583 opq_op_done(control->waitq);
584 }
585
586 static void
control_rsp_handler2(ipmi_control_t * control,void * cb_data)587 control_rsp_handler2(ipmi_control_t *control, void *cb_data)
588 {
589 ipmi_control_op_info_t *info = cb_data;
590
591 if (info->__rsp_handler)
592 info->__rsp_handler(control, 0, info->__rsp, info->__cb_data);
593 }
594
595 static void
control_rsp_handler(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)596 control_rsp_handler(ipmi_mc_t *mc,
597 ipmi_msg_t *rsp,
598 void *rsp_data)
599 {
600 ipmi_control_op_info_t *info = rsp_data;
601 int rv;
602 ipmi_control_t *control = info->__control;
603 ipmi_entity_t *entity = NULL;
604
605 if (control->destroyed) {
606 ipmi_entity_t *entity = NULL;
607
608 i_ipmi_domain_entity_lock(control->domain);
609 control->usecount++;
610 i_ipmi_domain_entity_unlock(control->domain);
611
612 rv = i_ipmi_entity_get(control->entity);
613 if (! rv)
614 entity = control->entity;
615
616 ipmi_log(IPMI_LOG_ERR_INFO,
617 "%scontrol.c(control_rsp_handler): "
618 "Control was destroyed while an operation was in progress",
619 CONTROL_NAME(control));
620 if (info->__rsp_handler)
621 info->__rsp_handler(control, ECANCELED, NULL, info->__cb_data);
622
623 i_ipmi_control_put(control);
624 if (entity)
625 i_ipmi_entity_put(entity);
626 return;
627 }
628
629 if (!mc) {
630 ipmi_log(IPMI_LOG_ERR_INFO,
631 "control.c(control_rsp_handler): "
632 "MC was destroyed while a control operation was in progress");
633
634 i_ipmi_domain_entity_lock(control->domain);
635 control->usecount++;
636 i_ipmi_domain_entity_unlock(control->domain);
637
638 rv = i_ipmi_entity_get(control->entity);
639 if (! rv)
640 entity = control->entity;
641
642 if (info->__rsp_handler)
643 info->__rsp_handler(control, ECANCELED, NULL, info->__cb_data);
644
645 i_ipmi_control_put(control);
646 if (entity)
647 i_ipmi_entity_put(entity);
648
649 return;
650 }
651
652 /* Call the next stage with the lock held. */
653 info->__rsp = rsp;
654 rv = ipmi_control_pointer_cb(info->__control_id,
655 control_rsp_handler2,
656 info);
657 if (rv) {
658 int nrv;
659
660 ipmi_log(IPMI_LOG_ERR_INFO,
661 "%scontrol.c(control_rsp_handler): "
662 "Could not convert control id to a pointer",
663 MC_NAME(mc));
664 i_ipmi_domain_entity_lock(control->domain);
665 control->usecount++;
666 i_ipmi_domain_entity_unlock(control->domain);
667
668 nrv = i_ipmi_entity_get(control->entity);
669 if (! nrv)
670 entity = control->entity;
671
672 if (info->__rsp_handler)
673 info->__rsp_handler(control, rv, NULL, info->__cb_data);
674
675 i_ipmi_control_put(control);
676 if (entity)
677 i_ipmi_entity_put(entity);
678 }
679 }
680
681 int
ipmi_control_send_command(ipmi_control_t * control,ipmi_mc_t * mc,unsigned int lun,ipmi_msg_t * msg,ipmi_control_rsp_cb handler,ipmi_control_op_info_t * info,void * cb_data)682 ipmi_control_send_command(ipmi_control_t *control,
683 ipmi_mc_t *mc,
684 unsigned int lun,
685 ipmi_msg_t *msg,
686 ipmi_control_rsp_cb handler,
687 ipmi_control_op_info_t *info,
688 void *cb_data)
689 {
690 int rv;
691
692 CHECK_MC_LOCK(mc);
693 CHECK_CONTROL_LOCK(control);
694
695 if (control->destroyed)
696 return EINVAL;
697
698 info->__control = control;
699 info->__control_id = ipmi_control_convert_to_id(control);
700 info->__cb_data = cb_data;
701 info->__rsp_handler = handler;
702 rv = ipmi_mc_send_command(mc, lun, msg, control_rsp_handler, info);
703 return rv;
704 }
705
706 static int
control_addr_response_handler(ipmi_domain_t * domain,ipmi_msgi_t * rspi)707 control_addr_response_handler(ipmi_domain_t *domain, ipmi_msgi_t *rspi)
708 {
709 ipmi_msg_t *msg = &rspi->msg;
710 ipmi_control_op_info_t *info = rspi->data1;
711 int rv;
712 ipmi_control_t *control = info->__control;
713
714 if (control->destroyed) {
715 ipmi_log(IPMI_LOG_ERR_INFO,
716 "%scontrol.c(control_addr_response_handler): "
717 "Control was destroyed while an operation was in progress",
718 DOMAIN_NAME(domain));
719 if (info->__rsp_handler)
720 info->__rsp_handler(control, ECANCELED, NULL, info->__cb_data);
721
722 i_ipmi_domain_entity_lock(control->domain);
723 control->usecount++;
724 i_ipmi_domain_entity_unlock(control->domain);
725 i_ipmi_control_put(control);
726 return IPMI_MSG_ITEM_NOT_USED;
727 }
728
729 /* Call the next stage with the lock held. */
730 info->__rsp = msg;
731 rv = ipmi_control_pointer_cb(info->__control_id,
732 control_rsp_handler2,
733 info);
734 if (rv) {
735 ipmi_log(IPMI_LOG_ERR_INFO,
736 "%scontrol.c(control_addr_response_handler): "
737 "Could not convert control id to a pointer",
738 DOMAIN_NAME(domain));
739 if (info->__rsp_handler) {
740 i_ipmi_domain_entity_lock(control->domain);
741 control->usecount++;
742 i_ipmi_domain_entity_unlock(control->domain);
743 info->__rsp_handler(control, rv, NULL, info->__cb_data);
744 i_ipmi_control_put(control);
745 }
746 }
747 return IPMI_MSG_ITEM_NOT_USED;
748 }
749
750 int
ipmi_control_send_command_addr(ipmi_domain_t * domain,ipmi_control_t * control,ipmi_addr_t * addr,unsigned int addr_len,ipmi_msg_t * msg,ipmi_control_rsp_cb handler,ipmi_control_op_info_t * info,void * cb_data)751 ipmi_control_send_command_addr(ipmi_domain_t *domain,
752 ipmi_control_t *control,
753 ipmi_addr_t *addr,
754 unsigned int addr_len,
755 ipmi_msg_t *msg,
756 ipmi_control_rsp_cb handler,
757 ipmi_control_op_info_t *info,
758 void *cb_data)
759 {
760 int rv;
761
762 CHECK_CONTROL_LOCK(control);
763 CHECK_MC_LOCK(control->mc);
764
765 info->__control = control;
766 info->__control_id = ipmi_control_convert_to_id(control);
767 info->__cb_data = cb_data;
768 info->__rsp_handler = handler;
769 rv = ipmi_send_command_addr(domain, addr, addr_len,
770 msg, control_addr_response_handler, info, NULL);
771 return rv;
772 }
773
774 int
ipmi_controls_alloc(ipmi_mc_t * mc,ipmi_control_info_t ** new_controls)775 ipmi_controls_alloc(ipmi_mc_t *mc, ipmi_control_info_t **new_controls)
776 {
777 ipmi_control_info_t *controls;
778 ipmi_domain_t *domain;
779 os_handler_t *os_hnd;
780 int rv;
781
782 CHECK_MC_LOCK(mc);
783
784 domain = ipmi_mc_get_domain(mc);
785 os_hnd = ipmi_domain_get_os_hnd(domain);
786
787 controls = ipmi_mem_alloc(sizeof(*controls));
788 if (!controls)
789 return ENOMEM;
790 memset(controls, 0, sizeof(*controls));
791
792 controls->control_wait_q = opq_alloc(os_hnd);
793 if (! controls->control_wait_q) {
794 ipmi_mem_free(controls);
795 return ENOMEM;
796 }
797
798 rv = ipmi_create_lock_os_hnd(os_hnd, &controls->idx_lock);
799 if (rv) {
800 opq_destroy(controls->control_wait_q);
801 ipmi_mem_free(controls);
802 return rv;
803 }
804
805 *new_controls = controls;
806 return 0;
807 }
808
809 unsigned int
ipmi_controls_get_count(ipmi_control_info_t * controls)810 ipmi_controls_get_count(ipmi_control_info_t *controls)
811 {
812 return controls->control_count;
813 }
814
815 int
ipmi_control_alloc_nonstandard(ipmi_control_t ** new_control)816 ipmi_control_alloc_nonstandard(ipmi_control_t **new_control)
817 {
818 ipmi_control_t *control;
819
820 control = ipmi_mem_alloc(sizeof(*control));
821 if (!control)
822 return ENOMEM;
823
824 memset(control, 0, sizeof(*control));
825
826 control->usecount = 1;
827 *new_control = control;
828 return 0;
829 }
830
831 int
ipmi_control_add_nonstandard(ipmi_mc_t * mc,ipmi_mc_t * source_mc,ipmi_control_t * control,unsigned int num,ipmi_entity_t * ent,ipmi_control_destroy_cb destroy_handler,void * destroy_handler_cb_data)832 ipmi_control_add_nonstandard(ipmi_mc_t *mc,
833 ipmi_mc_t *source_mc,
834 ipmi_control_t *control,
835 unsigned int num,
836 ipmi_entity_t *ent,
837 ipmi_control_destroy_cb destroy_handler,
838 void *destroy_handler_cb_data)
839 {
840 ipmi_domain_t *domain;
841 os_handler_t *os_hnd;
842 ipmi_control_info_t *controls = i_ipmi_mc_get_controls(mc);
843 locked_list_entry_t *link;
844 int err;
845 unsigned int i;
846
847 CHECK_MC_LOCK(mc);
848 CHECK_ENTITY_LOCK(ent);
849
850 domain = ipmi_mc_get_domain(mc);
851 os_hnd = ipmi_domain_get_os_hnd(domain);
852
853 if ((num >= 256) && (num != UINT_MAX))
854 return EINVAL;
855
856 i_ipmi_domain_entity_lock(domain);
857 ipmi_lock(controls->idx_lock);
858
859 if (num == UINT_MAX){
860 for (i=0; i<controls->idx_size; i++) {
861 if (! controls->controls_by_idx[i])
862 break;
863 }
864 num = i;
865 if (num >= 256) {
866 err = EAGAIN;
867 goto out_err;
868 }
869 }
870
871 if (num >= controls->idx_size) {
872 ipmi_control_t **new_array;
873 unsigned int new_size;
874 unsigned int i;
875
876 /* Allocate the array in multiples of 16 (to avoid thrashing malloc
877 too much). */
878 new_size = ((num / 16) * 16) + 16;
879 new_array = ipmi_mem_alloc(sizeof(*new_array) * new_size);
880 if (!new_array) {
881 err = ENOMEM;
882 goto out_err;
883 }
884 if (controls->controls_by_idx)
885 memcpy(new_array, controls->controls_by_idx,
886 sizeof(*new_array) * (controls->idx_size));
887 for (i=controls->idx_size; i<new_size; i++)
888 new_array[i] = NULL;
889 if (controls->controls_by_idx)
890 ipmi_mem_free(controls->controls_by_idx);
891 controls->controls_by_idx = new_array;
892 controls->idx_size = new_size;
893 }
894
895 control->waitq = opq_alloc(os_hnd);
896 if (! control->waitq) {
897 err = ENOMEM;
898 goto out_err;
899 }
900
901 control->handler_list_cl = locked_list_alloc(os_hnd);
902 if (! control->handler_list_cl) {
903 opq_destroy(control->waitq);
904 err = ENOMEM;
905 goto out_err;
906 }
907
908 control->handler_list = locked_list_alloc(os_hnd);
909 if (! control->handler_list) {
910 opq_destroy(control->waitq);
911 locked_list_destroy(control->handler_list_cl);
912 err = ENOMEM;
913 goto out_err;
914 }
915
916 link = locked_list_alloc_entry();
917 if (!link) {
918 opq_destroy(control->waitq);
919 control->waitq = NULL;
920 locked_list_destroy(control->handler_list);
921 locked_list_destroy(control->handler_list_cl);
922 control->handler_list = NULL;
923 err = ENOMEM;
924 goto out_err;
925 }
926
927 control->domain = domain;
928 control->mc = mc;
929 control->source_mc = source_mc;
930 control->entity = ent;
931 control->lun = 4;
932 control->num = num;
933 if (controls->controls_by_idx[num]) {
934 ipmi_log(IPMI_LOG_WARNING,
935 "%scontrol.c(ipmi_control_add_nonstandard): "
936 " Add a control at index %d, but there was already a"
937 " control there, overwriting the old control",
938 MC_NAME(mc), num);
939 } else {
940 controls->control_count++;
941 }
942 controls->controls_by_idx[num] = control;
943 control->destroy_handler = destroy_handler;
944 control->destroy_handler_cb_data = destroy_handler_cb_data;
945 control_set_name(control);
946
947 ipmi_unlock(controls->idx_lock);
948
949 i_ipmi_domain_entity_unlock(domain);
950
951 ipmi_entity_add_control(ent, control, link);
952
953 control->add_pending = 1;
954
955 return 0;
956
957 out_err:
958 ipmi_unlock(controls->idx_lock);
959 i_ipmi_domain_entity_unlock(domain);
960 return err;
961 }
962
963 int
ipmi_controls_destroy(ipmi_control_info_t * controls)964 ipmi_controls_destroy(ipmi_control_info_t *controls)
965 {
966 unsigned int j;
967
968 if (controls->destroyed)
969 return EINVAL;
970
971 controls->destroyed = 1;
972 for (j=0; j<controls->idx_size; j++) {
973 if (controls->controls_by_idx[j]) {
974 ipmi_control_destroy(controls->controls_by_idx[j]);
975 }
976 }
977 if (controls->controls_by_idx)
978 ipmi_mem_free(controls->controls_by_idx);
979
980 if (controls->control_wait_q)
981 opq_destroy(controls->control_wait_q);
982 if (controls->idx_lock)
983 ipmi_destroy_lock(controls->idx_lock);
984 ipmi_mem_free(controls);
985 return 0;
986 }
987
988 /***********************************************************************
989 *
990 * Polymorphic calls to the callback handlers.
991 *
992 **********************************************************************/
993
994 int
ipmi_control_set_val(ipmi_control_t * control,int * val,ipmi_control_op_cb handler,void * cb_data)995 ipmi_control_set_val(ipmi_control_t *control,
996 int *val,
997 ipmi_control_op_cb handler,
998 void *cb_data)
999 {
1000 if (!control_ok_to_use(control))
1001 return ECANCELED;
1002
1003 CHECK_CONTROL_LOCK(control);
1004
1005 if (!control->cbs.set_val)
1006 return ENOSYS;
1007 return control->cbs.set_val(control, val, handler, cb_data);
1008 }
1009
1010 int
ipmi_control_get_val(ipmi_control_t * control,ipmi_control_val_cb handler,void * cb_data)1011 ipmi_control_get_val(ipmi_control_t *control,
1012 ipmi_control_val_cb handler,
1013 void *cb_data)
1014 {
1015 if (!control_ok_to_use(control))
1016 return ECANCELED;
1017
1018 CHECK_CONTROL_LOCK(control);
1019
1020 if (!control->cbs.get_val)
1021 return ENOSYS;
1022 return control->cbs.get_val(control, handler, cb_data);
1023 }
1024
1025 int
ipmi_control_set_display_string(ipmi_control_t * control,unsigned int start_row,unsigned int start_column,char * str,unsigned int len,ipmi_control_op_cb handler,void * cb_data)1026 ipmi_control_set_display_string(ipmi_control_t *control,
1027 unsigned int start_row,
1028 unsigned int start_column,
1029 char *str,
1030 unsigned int len,
1031 ipmi_control_op_cb handler,
1032 void *cb_data)
1033 {
1034 if (!control_ok_to_use(control))
1035 return ECANCELED;
1036
1037 CHECK_CONTROL_LOCK(control);
1038
1039 if (!control->cbs.set_display_string)
1040 return ENOSYS;
1041 return control->cbs.set_display_string(control,
1042 start_row,
1043 start_column,
1044 str, len,
1045 handler, cb_data);
1046 }
1047
1048 int
ipmi_control_get_display_string(ipmi_control_t * control,unsigned int start_row,unsigned int start_column,unsigned int len,ipmi_control_str_cb handler,void * cb_data)1049 ipmi_control_get_display_string(ipmi_control_t *control,
1050 unsigned int start_row,
1051 unsigned int start_column,
1052 unsigned int len,
1053 ipmi_control_str_cb handler,
1054 void *cb_data)
1055 {
1056 if (!control_ok_to_use(control))
1057 return ECANCELED;
1058
1059 CHECK_CONTROL_LOCK(control);
1060
1061 if (!control->cbs.get_display_string)
1062 return ENOSYS;
1063 return control->cbs.get_display_string(control,
1064 start_row,
1065 start_column,
1066 len,
1067 handler, cb_data);
1068 }
1069
1070 int
ipmi_control_identifier_get_val(ipmi_control_t * control,ipmi_control_identifier_val_cb handler,void * cb_data)1071 ipmi_control_identifier_get_val(ipmi_control_t *control,
1072 ipmi_control_identifier_val_cb handler,
1073 void *cb_data)
1074 {
1075 if (!control_ok_to_use(control))
1076 return ECANCELED;
1077
1078 CHECK_CONTROL_LOCK(control);
1079
1080 if (!control->cbs.get_identifier_val)
1081 return ENOSYS;
1082 return control->cbs.get_identifier_val(control, handler, cb_data);
1083 }
1084
1085 int
ipmi_control_identifier_set_val(ipmi_control_t * control,unsigned char * val,int length,ipmi_control_op_cb handler,void * cb_data)1086 ipmi_control_identifier_set_val(ipmi_control_t *control,
1087 unsigned char *val,
1088 int length,
1089 ipmi_control_op_cb handler,
1090 void *cb_data)
1091 {
1092 if (!control_ok_to_use(control))
1093 return ECANCELED;
1094
1095 CHECK_CONTROL_LOCK(control);
1096
1097 if (!control->cbs.set_identifier_val)
1098 return ENOSYS;
1099 return control->cbs.set_identifier_val(control,
1100 val,
1101 length,
1102 handler,
1103 cb_data);
1104 }
1105
1106 /***********************************************************************
1107 *
1108 * Polymorphic calls that take control ids.
1109 *
1110 **********************************************************************/
1111
1112 typedef struct control_id_set_val_s
1113 {
1114 int *val;
1115 ipmi_control_op_cb handler;
1116 void *cb_data;
1117 int rv;
1118 } control_id_set_val_t;
1119
1120 static void
control_id_set_val_cb(ipmi_control_t * control,void * cb_data)1121 control_id_set_val_cb(ipmi_control_t *control, void *cb_data)
1122 {
1123 control_id_set_val_t *info = cb_data;
1124
1125 info->rv = ipmi_control_set_val(control,
1126 info->val,
1127 info->handler,
1128 info->cb_data);
1129 }
1130
1131 int
ipmi_control_id_set_val(ipmi_control_id_t control_id,int * val,ipmi_control_op_cb handler,void * cb_data)1132 ipmi_control_id_set_val(ipmi_control_id_t control_id,
1133 int *val,
1134 ipmi_control_op_cb handler,
1135 void *cb_data)
1136 {
1137 control_id_set_val_t info;
1138 int rv;
1139
1140 info.val = val;
1141 info.handler = handler;
1142 info.cb_data = cb_data;
1143 rv = ipmi_control_pointer_cb(control_id, control_id_set_val_cb, &info);
1144 if (!rv)
1145 rv = info.rv;
1146 return rv;
1147 }
1148
1149 typedef struct control_id_get_val_s
1150 {
1151 ipmi_control_val_cb handler;
1152 void *cb_data;
1153 int rv;
1154 } control_id_get_val_t;
1155
1156 static void
control_id_get_val_cb(ipmi_control_t * control,void * cb_data)1157 control_id_get_val_cb(ipmi_control_t *control, void *cb_data)
1158 {
1159 control_id_get_val_t *info = cb_data;
1160
1161 info->rv = ipmi_control_get_val(control,
1162 info->handler,
1163 info->cb_data);
1164 }
1165
1166 int
ipmi_control_id_get_val(ipmi_control_id_t control_id,ipmi_control_val_cb handler,void * cb_data)1167 ipmi_control_id_get_val(ipmi_control_id_t control_id,
1168 ipmi_control_val_cb handler,
1169 void *cb_data)
1170 {
1171 control_id_get_val_t info;
1172 int rv;
1173
1174 info.handler = handler;
1175 info.cb_data = cb_data;
1176 rv = ipmi_control_pointer_cb(control_id, control_id_get_val_cb, &info);
1177 if (!rv)
1178 rv = info.rv;
1179 return rv;
1180 }
1181
1182 typedef struct control_id_identifier_set_val_s
1183 {
1184 unsigned char *val;
1185 int length;
1186 ipmi_control_op_cb handler;
1187 void *cb_data;
1188 int rv;
1189 } control_id_identifier_set_val_t;
1190
1191 static void
control_id_identifier_set_val_cb(ipmi_control_t * control,void * cb_data)1192 control_id_identifier_set_val_cb(ipmi_control_t *control, void *cb_data)
1193 {
1194 control_id_identifier_set_val_t *info = cb_data;
1195
1196 info->rv = ipmi_control_identifier_set_val(control,
1197 info->val,
1198 info->length,
1199 info->handler,
1200 info->cb_data);
1201 }
1202
1203 int
ipmi_control_id_identifier_set_val(ipmi_control_id_t control_id,unsigned char * val,int length,ipmi_control_op_cb handler,void * cb_data)1204 ipmi_control_id_identifier_set_val(ipmi_control_id_t control_id,
1205 unsigned char *val,
1206 int length,
1207 ipmi_control_op_cb handler,
1208 void *cb_data)
1209 {
1210 control_id_identifier_set_val_t info;
1211 int rv;
1212
1213 info.val = val;
1214 info.length = length;
1215 info.handler = handler;
1216 info.cb_data = cb_data;
1217 rv = ipmi_control_pointer_cb(control_id,
1218 control_id_identifier_set_val_cb, &info);
1219 if (!rv)
1220 rv = info.rv;
1221 return rv;
1222 }
1223
1224 typedef struct control_id_identifier_get_val_s
1225 {
1226 ipmi_control_identifier_val_cb handler;
1227 void *cb_data;
1228 int rv;
1229 } control_id_identifier_get_val_t;
1230
1231 static void
control_id_identifier_get_val_cb(ipmi_control_t * control,void * cb_data)1232 control_id_identifier_get_val_cb(ipmi_control_t *control, void *cb_data)
1233 {
1234 control_id_identifier_get_val_t *info = cb_data;
1235
1236 info->rv = ipmi_control_identifier_get_val(control,
1237 info->handler,
1238 info->cb_data);
1239 }
1240
1241 int
ipmi_control_id_identifier_get_val(ipmi_control_id_t control_id,ipmi_control_identifier_val_cb handler,void * cb_data)1242 ipmi_control_id_identifier_get_val(ipmi_control_id_t control_id,
1243 ipmi_control_identifier_val_cb handler,
1244 void *cb_data)
1245 {
1246 control_id_identifier_get_val_t info;
1247 int rv;
1248
1249 info.handler = handler;
1250 info.cb_data = cb_data;
1251 rv = ipmi_control_pointer_cb(control_id,
1252 control_id_identifier_get_val_cb, &info);
1253 if (!rv)
1254 rv = info.rv;
1255 return rv;
1256 }
1257
1258 /***********************************************************************
1259 *
1260 * Event handling for controls.
1261 *
1262 **********************************************************************/
1263
1264 void
ipmi_control_set_has_events(ipmi_control_t * control,int val)1265 ipmi_control_set_has_events(ipmi_control_t *control, int val)
1266 {
1267 control->has_events = val;
1268 }
1269
1270 int
ipmi_control_has_events(ipmi_control_t * control)1271 ipmi_control_has_events(ipmi_control_t *control)
1272 {
1273 return control->has_events;
1274 }
1275
1276 typedef struct control_event_info_s
1277 {
1278 ipmi_control_t *control;
1279 int handled;
1280
1281 int *valid_vals;
1282 int *vals;
1283
1284 ipmi_event_t *event;
1285 } control_event_info_t;
1286
1287 static int
control_val_event_call_handler(void * cb_data,void * item1,void * item2)1288 control_val_event_call_handler(void *cb_data, void *item1, void *item2)
1289 {
1290 ipmi_control_val_event_cb handler = item1;
1291 control_event_info_t *info = cb_data;
1292 int handled;
1293
1294 handled = handler(info->control,
1295 info->valid_vals,
1296 info->vals,
1297 item2,
1298 info->event);
1299 if (handled != IPMI_EVENT_NOT_HANDLED) {
1300 if (info->handled != IPMI_EVENT_HANDLED)
1301 /* Allow handled to override handled_pass, but not the
1302 other way. */
1303 info->handled = handled;
1304 if (handled == IPMI_EVENT_HANDLED)
1305 info->event = NULL;
1306 }
1307 return LOCKED_LIST_ITER_CONTINUE;
1308 }
1309
1310 void
ipmi_control_call_val_event_handlers(ipmi_control_t * control,int * valid_vals,int * vals,ipmi_event_t ** event,int * handled)1311 ipmi_control_call_val_event_handlers(ipmi_control_t *control,
1312 int *valid_vals,
1313 int *vals,
1314 ipmi_event_t **event,
1315 int *handled)
1316 {
1317 control_event_info_t info;
1318
1319 info.control = control;
1320 info.valid_vals = valid_vals;
1321 info.vals = vals;
1322 info.event = *event;
1323 info.handled = IPMI_EVENT_NOT_HANDLED;
1324
1325 locked_list_iterate(control->handler_list,
1326 control_val_event_call_handler, &info);
1327
1328 if (handled)
1329 *handled = info.handled;
1330 *event = info.event;
1331 }
1332
1333 int
ipmi_control_add_val_event_handler(ipmi_control_t * control,ipmi_control_val_event_cb handler,void * cb_data)1334 ipmi_control_add_val_event_handler(ipmi_control_t *control,
1335 ipmi_control_val_event_cb handler,
1336 void *cb_data)
1337 {
1338 CHECK_CONTROL_LOCK(control);
1339
1340 if (! locked_list_add(control->handler_list, handler, cb_data))
1341 return ENOMEM;
1342
1343 return 0;
1344 }
1345
ipmi_control_remove_val_event_handler(ipmi_control_t * control,ipmi_control_val_event_cb handler,void * cb_data)1346 int ipmi_control_remove_val_event_handler(ipmi_control_t *control,
1347 ipmi_control_val_event_cb handler,
1348 void *cb_data)
1349 {
1350 CHECK_CONTROL_LOCK(control);
1351
1352 if (! locked_list_remove(control->handler_list, handler, cb_data))
1353 return ENOENT;
1354
1355 return 0;
1356 }
1357
1358 int
ipmi_control_add_val_event_handler_cl(ipmi_control_t * control,ipmi_control_val_event_cl_cb handler,void * cb_data)1359 ipmi_control_add_val_event_handler_cl(ipmi_control_t *control,
1360 ipmi_control_val_event_cl_cb handler,
1361 void *cb_data)
1362 {
1363 CHECK_CONTROL_LOCK(control);
1364
1365 if (! locked_list_add(control->handler_list_cl, handler, cb_data))
1366 return ENOMEM;
1367
1368 return 0;
1369 }
1370
ipmi_control_remove_val_event_handler_cl(ipmi_control_t * control,ipmi_control_val_event_cl_cb handler,void * cb_data)1371 int ipmi_control_remove_val_event_handler_cl(ipmi_control_t *control,
1372 ipmi_control_val_event_cl_cb handler,
1373 void *cb_data)
1374 {
1375 CHECK_CONTROL_LOCK(control);
1376
1377 if (! locked_list_remove(control->handler_list_cl, handler, cb_data))
1378 return ENOENT;
1379
1380 return 0;
1381 }
1382
1383 /***********************************************************************
1384 *
1385 * Get/set various local information about a control.
1386 *
1387 **********************************************************************/
1388
1389 int
ipmi_control_get_type(ipmi_control_t * control)1390 ipmi_control_get_type(ipmi_control_t *control)
1391 {
1392 CHECK_CONTROL_LOCK(control);
1393
1394 return control->type;
1395 }
1396
1397 void
ipmi_control_set_type(ipmi_control_t * control,int val)1398 ipmi_control_set_type(ipmi_control_t *control, int val)
1399 {
1400 control->type = val;
1401 control->type_str = ipmi_get_control_type_string(val);
1402 }
1403
1404 const char *
ipmi_control_get_type_string(ipmi_control_t * control)1405 ipmi_control_get_type_string(ipmi_control_t *control)
1406 {
1407 CHECK_CONTROL_LOCK(control);
1408
1409 return control->type_str;
1410 }
1411
1412 int
ipmi_control_get_id_length(ipmi_control_t * control)1413 ipmi_control_get_id_length(ipmi_control_t *control)
1414 {
1415 CHECK_CONTROL_LOCK(control);
1416
1417 if (control->id_type == IPMI_ASCII_STR)
1418 return control->id_len+1;
1419 else
1420 return control->id_len;
1421 }
1422
1423 enum ipmi_str_type_e
ipmi_control_get_id_type(ipmi_control_t * control)1424 ipmi_control_get_id_type(ipmi_control_t *control)
1425 {
1426 CHECK_CONTROL_LOCK(control);
1427
1428 return control->id_type;
1429 }
1430
1431 int
ipmi_control_get_id(ipmi_control_t * control,char * id,int length)1432 ipmi_control_get_id(ipmi_control_t *control, char *id, int length)
1433 {
1434 int clen;
1435
1436 CHECK_CONTROL_LOCK(control);
1437
1438 if ((int) control->id_len > length)
1439 clen = length;
1440 else
1441 clen = control->id_len;
1442 memcpy(id, control->id, clen);
1443
1444 if (control->id_type == IPMI_ASCII_STR) {
1445 /* NIL terminate the ASCII string. */
1446 if (clen == length)
1447 clen--;
1448
1449 id[clen] = '\0';
1450 }
1451
1452 return clen;
1453 }
1454
1455 void
ipmi_control_set_id(ipmi_control_t * control,char * id,enum ipmi_str_type_e type,int length)1456 ipmi_control_set_id(ipmi_control_t *control, char *id,
1457 enum ipmi_str_type_e type, int length)
1458 {
1459 if (length > CONTROL_ID_LEN)
1460 length = CONTROL_ID_LEN;
1461
1462 memcpy(control->id, id, length);
1463 control->id_type = type;
1464 control->id_len = length;
1465 if (control->entity)
1466 control_set_name(control);
1467 }
1468
1469 int
ipmi_control_is_settable(ipmi_control_t * control)1470 ipmi_control_is_settable(ipmi_control_t *control)
1471 {
1472 CHECK_CONTROL_LOCK(control);
1473
1474 return control->settable;
1475 }
1476
1477 int
ipmi_control_is_readable(ipmi_control_t * control)1478 ipmi_control_is_readable(ipmi_control_t *control)
1479 {
1480 CHECK_CONTROL_LOCK(control);
1481
1482 return control->readable;
1483 }
1484
1485 void
ipmi_control_set_settable(ipmi_control_t * control,int val)1486 ipmi_control_set_settable(ipmi_control_t *control, int val)
1487 {
1488 control->settable = val;
1489 }
1490
1491 void
ipmi_control_set_readable(ipmi_control_t * control,int val)1492 ipmi_control_set_readable(ipmi_control_t *control, int val)
1493 {
1494 control->readable = val;
1495 }
1496
1497 int
ipmi_control_get_entity_id(ipmi_control_t * control)1498 ipmi_control_get_entity_id(ipmi_control_t *control)
1499 {
1500 return ipmi_entity_get_entity_id(control->entity);
1501 }
1502
1503 int
ipmi_control_get_entity_instance(ipmi_control_t * control)1504 ipmi_control_get_entity_instance(ipmi_control_t *control)
1505 {
1506 CHECK_CONTROL_LOCK(control);
1507
1508 return ipmi_entity_get_entity_instance(control->entity);
1509 }
1510
1511 ipmi_entity_t *
ipmi_control_get_entity(ipmi_control_t * control)1512 ipmi_control_get_entity(ipmi_control_t *control)
1513 {
1514 return control->entity;
1515 }
1516
1517 void
ipmi_control_set_oem_info(ipmi_control_t * control,void * oem_info,ipmi_control_cleanup_oem_info_cb cleanup_handler)1518 ipmi_control_set_oem_info(ipmi_control_t *control, void *oem_info,
1519 ipmi_control_cleanup_oem_info_cb cleanup_handler)
1520 {
1521 control->oem_info = oem_info;
1522 control->oem_info_cleanup_handler = cleanup_handler;
1523 }
1524
1525 void *
ipmi_control_get_oem_info(ipmi_control_t * control)1526 ipmi_control_get_oem_info(ipmi_control_t *control)
1527 {
1528 CHECK_CONTROL_LOCK(control);
1529
1530 return control->oem_info;
1531 }
1532
1533 void
ipmi_control_get_display_dimensions(ipmi_control_t * control,unsigned int * columns,unsigned int * rows)1534 ipmi_control_get_display_dimensions(ipmi_control_t *control,
1535 unsigned int *columns,
1536 unsigned int *rows)
1537 {
1538 CHECK_CONTROL_LOCK(control);
1539
1540 *columns = control->columns;
1541 *rows = control->rows;
1542 }
1543
1544 void
ipmi_control_set_num_elements(ipmi_control_t * control,unsigned int val)1545 ipmi_control_set_num_elements(ipmi_control_t *control, unsigned int val)
1546 {
1547 control->num_vals = val;
1548 }
1549
1550 unsigned int
ipmi_control_identifier_get_max_length(ipmi_control_t * control)1551 ipmi_control_identifier_get_max_length(ipmi_control_t *control)
1552 {
1553 CHECK_CONTROL_LOCK(control);
1554
1555 return control->identifier_length;
1556 }
1557
1558 void
ipmi_control_identifier_set_max_length(ipmi_control_t * control,unsigned int val)1559 ipmi_control_identifier_set_max_length(ipmi_control_t *control,
1560 unsigned int val)
1561 {
1562 control->identifier_length = val;
1563 }
1564
1565 void
ipmi_control_get_callbacks(ipmi_control_t * control,ipmi_control_cbs_t * cbs)1566 ipmi_control_get_callbacks(ipmi_control_t *control, ipmi_control_cbs_t *cbs)
1567 {
1568 *cbs = control->cbs;
1569 }
1570
1571 void
ipmi_control_set_callbacks(ipmi_control_t * control,ipmi_control_cbs_t * cbs)1572 ipmi_control_set_callbacks(ipmi_control_t *control, ipmi_control_cbs_t *cbs)
1573 {
1574 control->cbs = *cbs;
1575 }
1576
1577 ipmi_mc_t *
ipmi_control_get_mc(ipmi_control_t * control)1578 ipmi_control_get_mc(ipmi_control_t *control)
1579 {
1580 return control->mc;
1581 }
1582
1583 ipmi_mc_t *
ipmi_control_get_source_mc(ipmi_control_t * control)1584 ipmi_control_get_source_mc(ipmi_control_t *control)
1585 {
1586 CHECK_CONTROL_LOCK(control);
1587
1588 return control->source_mc;
1589 }
1590
1591 int
ipmi_control_get_num(ipmi_control_t * control,int * lun,int * num)1592 ipmi_control_get_num(ipmi_control_t *control,
1593 int *lun,
1594 int *num)
1595 {
1596 CHECK_CONTROL_LOCK(control);
1597
1598 if (lun)
1599 *lun = control->lun;
1600 if (num)
1601 *num = control->num;
1602 return 0;
1603 }
1604
1605 int
ipmi_control_light_set_with_setting(ipmi_control_t * control)1606 ipmi_control_light_set_with_setting(ipmi_control_t *control)
1607 {
1608 return ((control->cbs.set_light != NULL)
1609 || (control->cbs.get_light != NULL));
1610 }
1611
1612 void
ipmi_control_light_set_lights(ipmi_control_t * control,unsigned int num_lights,ipmi_control_light_t * lights)1613 ipmi_control_light_set_lights(ipmi_control_t *control,
1614 unsigned int num_lights,
1615 ipmi_control_light_t *lights)
1616 {
1617 control->num_vals = num_lights;
1618 control->lights = lights;
1619 }
1620
1621 int
ipmi_control_get_num_vals(ipmi_control_t * control)1622 ipmi_control_get_num_vals(ipmi_control_t *control)
1623 {
1624 CHECK_CONTROL_LOCK(control);
1625
1626 return control->num_vals;
1627 }
1628
1629 int
ipmi_control_get_num_light_values(ipmi_control_t * control,unsigned int light)1630 ipmi_control_get_num_light_values(ipmi_control_t *control,
1631 unsigned int light)
1632 {
1633 CHECK_CONTROL_LOCK(control);
1634
1635 if (!control->lights)
1636 return -1;
1637 if (light >= control->num_vals)
1638 return -1;
1639
1640 return control->lights[light].num_values;
1641 }
1642
1643 int
ipmi_control_get_num_light_transitions(ipmi_control_t * control,unsigned int light,unsigned int set)1644 ipmi_control_get_num_light_transitions(ipmi_control_t *control,
1645 unsigned int light,
1646 unsigned int set)
1647 {
1648 CHECK_CONTROL_LOCK(control);
1649
1650 if (!control->lights)
1651 return -1;
1652 if (light >= control->num_vals)
1653 return -1;
1654 if (set >= control->lights[light].num_values)
1655 return -1;
1656
1657 return control->lights[light].values[set].num_transitions;
1658 }
1659
1660 int
ipmi_control_get_light_color(ipmi_control_t * control,unsigned int light,unsigned int set,unsigned int num)1661 ipmi_control_get_light_color(ipmi_control_t *control,
1662 unsigned int light,
1663 unsigned int set,
1664 unsigned int num)
1665 {
1666 CHECK_CONTROL_LOCK(control);
1667
1668 if (!control->lights)
1669 return -1;
1670 if (light >= control->num_vals)
1671 return -1;
1672 if (set >= control->lights[light].num_values)
1673 return -1;
1674 if (num > control->lights[light].values[set].num_transitions)
1675 return -1;
1676
1677 return control->lights[light].values[set].transitions[num].color;
1678 }
1679
1680 int
ipmi_control_get_light_color_time(ipmi_control_t * control,unsigned int light,unsigned int set,unsigned int num)1681 ipmi_control_get_light_color_time(ipmi_control_t *control,
1682 unsigned int light,
1683 unsigned int set,
1684 unsigned int num)
1685 {
1686 CHECK_CONTROL_LOCK(control);
1687
1688 if (!control->lights)
1689 return -1;
1690 if (light >= control->num_vals)
1691 return -1;
1692 if (set >= control->lights[light].num_values)
1693 return -1;
1694 if (num > control->lights[light].values[set].num_transitions)
1695 return -1;
1696
1697 return control->lights[light].values[set].transitions[num].time;
1698 }
1699
1700 int
ipmi_control_set_light(ipmi_control_t * control,ipmi_light_setting_t * settings,ipmi_control_op_cb handler,void * cb_data)1701 ipmi_control_set_light(ipmi_control_t *control,
1702 ipmi_light_setting_t *settings,
1703 ipmi_control_op_cb handler,
1704 void *cb_data)
1705 {
1706 CHECK_CONTROL_LOCK(control);
1707
1708 if (!control->cbs.set_light)
1709 return ENOSYS;
1710 return control->cbs.set_light(control, settings, handler, cb_data);
1711 }
1712
1713 int
ipmi_control_get_light(ipmi_control_t * control,ipmi_light_settings_cb handler,void * cb_data)1714 ipmi_control_get_light(ipmi_control_t *control,
1715 ipmi_light_settings_cb handler,
1716 void *cb_data)
1717 {
1718 CHECK_CONTROL_LOCK(control);
1719
1720 if (!control->cbs.get_light)
1721 return ENOSYS;
1722 return control->cbs.get_light(control, handler, cb_data);
1723 }
1724
1725
1726 typedef struct ipmi_light_s
1727 {
1728 int color;
1729 int on_time;
1730 int off_time;
1731 int local_control;
1732 } ipmi_light_t;
1733
1734 struct ipmi_light_setting_s
1735 {
1736 int count;
1737 ipmi_light_t *lights;
1738 };
1739
1740 unsigned int
ipmi_light_setting_get_count(ipmi_light_setting_t * setting)1741 ipmi_light_setting_get_count(ipmi_light_setting_t *setting)
1742 {
1743 return setting->count;
1744 }
1745
1746 int
ipmi_light_setting_in_local_control(ipmi_light_setting_t * setting,int num,int * lc)1747 ipmi_light_setting_in_local_control(ipmi_light_setting_t *setting,
1748 int num,
1749 int *lc)
1750 {
1751 if (num > setting->count)
1752 return EINVAL;
1753
1754 *lc = setting->lights[num].local_control;
1755 return 0;
1756 }
1757
1758 int
ipmi_light_setting_set_local_control(ipmi_light_setting_t * setting,int num,int lc)1759 ipmi_light_setting_set_local_control(ipmi_light_setting_t *setting,
1760 int num,
1761 int lc)
1762 {
1763 if (num > setting->count)
1764 return EINVAL;
1765
1766 setting->lights[num].local_control = lc;
1767 return 0;
1768 }
1769
1770 int
ipmi_light_setting_get_color(ipmi_light_setting_t * setting,int num,int * color)1771 ipmi_light_setting_get_color(ipmi_light_setting_t *setting, int num,
1772 int *color)
1773 {
1774 if (num > setting->count)
1775 return EINVAL;
1776
1777 *color = setting->lights[num].color;
1778 return 0;
1779 }
1780
1781 int
ipmi_light_setting_set_color(ipmi_light_setting_t * setting,int num,int color)1782 ipmi_light_setting_set_color(ipmi_light_setting_t *setting, int num,
1783 int color)
1784 {
1785 if (num > setting->count)
1786 return EINVAL;
1787
1788 setting->lights[num].color = color;
1789 return 0;
1790 }
1791
1792 int
ipmi_light_setting_get_on_time(ipmi_light_setting_t * setting,int num,int * time)1793 ipmi_light_setting_get_on_time(ipmi_light_setting_t *setting, int num,
1794 int *time)
1795 {
1796 if (num > setting->count)
1797 return EINVAL;
1798
1799 *time = setting->lights[num].on_time;
1800 return 0;
1801 }
1802
1803 int
ipmi_light_setting_set_on_time(ipmi_light_setting_t * setting,int num,int time)1804 ipmi_light_setting_set_on_time(ipmi_light_setting_t *setting, int num,
1805 int time)
1806 {
1807 if (num > setting->count)
1808 return EINVAL;
1809
1810 setting->lights[num].on_time = time;
1811 return 0;
1812 }
1813
1814 int
ipmi_light_setting_get_off_time(ipmi_light_setting_t * setting,int num,int * time)1815 ipmi_light_setting_get_off_time(ipmi_light_setting_t *setting, int num,
1816 int *time)
1817 {
1818 if (num > setting->count)
1819 return EINVAL;
1820
1821 *time = setting->lights[num].off_time;
1822 return 0;
1823 }
1824
1825 int
ipmi_light_setting_set_off_time(ipmi_light_setting_t * setting,int num,int time)1826 ipmi_light_setting_set_off_time(ipmi_light_setting_t *setting, int num,
1827 int time)
1828 {
1829 if (num > setting->count)
1830 return EINVAL;
1831
1832 setting->lights[num].off_time = time;
1833 return 0;
1834 }
1835
1836 ipmi_light_setting_t *
ipmi_alloc_light_settings(unsigned int count)1837 ipmi_alloc_light_settings(unsigned int count)
1838 {
1839 ipmi_light_setting_t *rv;
1840
1841 if (count == 0)
1842 return NULL;
1843
1844 rv = ipmi_mem_alloc(sizeof(*rv));
1845 if (!rv)
1846 return NULL;
1847
1848 rv->lights = ipmi_mem_alloc(sizeof(ipmi_light_t) * count);
1849 if (!rv->lights) {
1850 ipmi_mem_free(rv);
1851 return NULL;
1852 }
1853
1854 rv->count = count;
1855 memset(rv->lights, 0, sizeof(ipmi_light_t) * count);
1856 return rv;
1857 }
1858
1859 void
ipmi_free_light_settings(ipmi_light_setting_t * settings)1860 ipmi_free_light_settings(ipmi_light_setting_t *settings)
1861 {
1862 ipmi_mem_free(settings->lights);
1863 ipmi_mem_free(settings);
1864 }
1865
1866 ipmi_light_setting_t *
ipmi_light_settings_dup(ipmi_light_setting_t * settings)1867 ipmi_light_settings_dup(ipmi_light_setting_t *settings)
1868 {
1869 ipmi_light_setting_t *rv;
1870
1871 rv = ipmi_mem_alloc(sizeof(*rv));
1872 if (!rv)
1873 return NULL;
1874
1875 rv->lights = ipmi_mem_alloc(sizeof(ipmi_light_t) * settings->count);
1876 if (!rv->lights) {
1877 ipmi_mem_free(rv);
1878 return NULL;
1879 }
1880
1881 rv->count = settings->count;
1882 memcpy(rv->lights, settings->lights,
1883 sizeof(ipmi_light_t) * settings->count);
1884 return rv;
1885 }
1886
1887 int
ipmi_control_add_light_color_support(ipmi_control_t * control,int light_num,unsigned int color)1888 ipmi_control_add_light_color_support(ipmi_control_t *control,
1889 int light_num,
1890 unsigned int color)
1891 {
1892 if (light_num >= MAX_LIGHTS)
1893 return EINVAL;
1894 control->colors[light_num] |= (1 << color);
1895 return 0;
1896 }
1897
1898 int
ipmi_control_light_is_color_sup(ipmi_control_t * control,int light_num,unsigned int color)1899 ipmi_control_light_is_color_sup(ipmi_control_t *control,
1900 int light_num,
1901 unsigned int color)
1902 {
1903 CHECK_CONTROL_LOCK(control);
1904
1905 if (light_num >= MAX_LIGHTS)
1906 return 0;
1907 return (control->colors[light_num] & (1 << color)) != 0;
1908 }
1909
1910 int
ipmi_control_light_set_has_local_control(ipmi_control_t * control,int light_num,int val)1911 ipmi_control_light_set_has_local_control(ipmi_control_t *control,
1912 int light_num,
1913 int val)
1914 {
1915 if (light_num >= MAX_LIGHTS)
1916 return EINVAL;
1917 control->has_local_control[light_num] = val;
1918 return 0;
1919 }
1920
1921 int
ipmi_control_light_has_loc_ctrl(ipmi_control_t * control,int light_num)1922 ipmi_control_light_has_loc_ctrl(ipmi_control_t *control,
1923 int light_num)
1924 {
1925 CHECK_CONTROL_LOCK(control);
1926
1927 if (light_num >= MAX_LIGHTS)
1928 return 0;
1929 return control->has_local_control[light_num];
1930 }
1931
1932 int
ipmi_cmp_control_id(ipmi_control_id_t id1,ipmi_control_id_t id2)1933 ipmi_cmp_control_id(ipmi_control_id_t id1, ipmi_control_id_t id2)
1934 {
1935 int rv = ipmi_cmp_mc_id(id1.mcid, id2.mcid);
1936 if (rv)
1937 return rv;
1938 if (id1.lun > id2.lun)
1939 return 1;
1940 if (id1.lun < id2.lun)
1941 return -1;
1942 if (id1.control_num > id2.control_num)
1943 return 1;
1944 if (id1.control_num < id2.control_num)
1945 return -1;
1946 return 0;
1947 }
1948
1949 void
ipmi_control_id_set_invalid(ipmi_control_id_t * id)1950 ipmi_control_id_set_invalid(ipmi_control_id_t *id)
1951 {
1952 memset(id, 0, sizeof(*id));
1953 }
1954
1955 int
ipmi_control_id_is_invalid(const ipmi_control_id_t * id)1956 ipmi_control_id_is_invalid(const ipmi_control_id_t *id)
1957 {
1958 return (id->mcid.domain_id.domain == NULL);
1959 }
1960
1961
1962 void
ipmi_control_set_hot_swap_indicator(ipmi_control_t * control,int val,int req_act_val,int active_val,int req_deact_val,int inactive_val)1963 ipmi_control_set_hot_swap_indicator(ipmi_control_t *control,
1964 int val,
1965 int req_act_val,
1966 int active_val,
1967 int req_deact_val,
1968 int inactive_val)
1969 {
1970 control->hot_swap_indicator = val;
1971 control->hot_swap_active_val = active_val;
1972 control->hot_swap_inactive_val = inactive_val;
1973 control->hot_swap_req_act_val = req_act_val;
1974 control->hot_swap_req_deact_val = req_deact_val;
1975 }
1976
1977 int
ipmi_control_is_hot_swap_indicator(ipmi_control_t * control,int * req_act_val,int * active_val,int * req_deact_val,int * inactive_val)1978 ipmi_control_is_hot_swap_indicator(ipmi_control_t *control,
1979 int *req_act_val,
1980 int *active_val,
1981 int *req_deact_val,
1982 int *inactive_val)
1983 {
1984 CHECK_CONTROL_LOCK(control);
1985
1986 if (control->hot_swap_indicator) {
1987 if (active_val)
1988 *active_val = control->hot_swap_active_val;
1989 if (inactive_val)
1990 *inactive_val = control->hot_swap_inactive_val;
1991 if (req_act_val)
1992 *req_act_val = control->hot_swap_req_act_val;
1993 if (req_deact_val)
1994 *req_deact_val = control->hot_swap_req_deact_val;
1995 return 1;
1996 }
1997 return 0;
1998 }
1999
2000 void
ipmi_control_set_hot_swap_power(ipmi_control_t * control,int val)2001 ipmi_control_set_hot_swap_power(ipmi_control_t *control, int val)
2002 {
2003 control->hot_swap_power = val;
2004 }
2005
2006 int
ipmi_control_is_hot_swap_power(ipmi_control_t * control)2007 ipmi_control_is_hot_swap_power(ipmi_control_t *control)
2008 {
2009 CHECK_CONTROL_LOCK(control);
2010
2011 return control->hot_swap_power;
2012 }
2013
2014 int
ipmi_control_get_ignore_if_no_entity(ipmi_control_t * control)2015 ipmi_control_get_ignore_if_no_entity(ipmi_control_t *control)
2016 {
2017 CHECK_CONTROL_LOCK(control);
2018
2019 return control->ignore_if_no_entity;
2020 }
2021
2022 void
ipmi_control_set_ignore_if_no_entity(ipmi_control_t * control,int ignore_if_no_entity)2023 ipmi_control_set_ignore_if_no_entity(ipmi_control_t *control,
2024 int ignore_if_no_entity)
2025 {
2026 control->ignore_if_no_entity = ignore_if_no_entity;
2027 }
2028
2029 int
ipmi_control_get_ignore_for_presence(ipmi_control_t * control)2030 ipmi_control_get_ignore_for_presence(ipmi_control_t *control)
2031 {
2032 CHECK_CONTROL_LOCK(control);
2033
2034 return control->ignore_for_presence;
2035 }
2036
2037 void
ipmi_control_set_ignore_for_presence(ipmi_control_t * control,int ignore)2038 ipmi_control_set_ignore_for_presence(ipmi_control_t *control, int ignore)
2039 {
2040 control->ignore_for_presence = ignore;
2041 }
2042
2043 ipmi_domain_t *
ipmi_control_get_domain(ipmi_control_t * control)2044 ipmi_control_get_domain(ipmi_control_t *control)
2045 {
2046 return control->domain;
2047 }
2048
2049 #ifdef IPMI_CHECK_LOCKS
2050 void
i__ipmi_check_control_lock(const ipmi_control_t * control)2051 i__ipmi_check_control_lock(const ipmi_control_t *control)
2052 {
2053 if (!control)
2054 return;
2055
2056 if (!DEBUG_LOCKS)
2057 return;
2058
2059 CHECK_ENTITY_LOCK(control->entity);
2060 CHECK_MC_LOCK(control->mc);
2061
2062 if (control->usecount == 0)
2063 ipmi_report_lock_error(ipmi_domain_get_os_hnd(control->domain),
2064 "control not locked when it should have been");
2065 }
2066 #endif
2067
2068 /***********************************************************************
2069 *
2070 * Crufty backwards-compatible interfaces. Don't use these as they
2071 * are deprecated.
2072 *
2073 **********************************************************************/
2074
2075 int
ipmi_control_get_num_light_settings(ipmi_control_t * control,unsigned int light)2076 ipmi_control_get_num_light_settings(ipmi_control_t *control,
2077 unsigned int light)
2078 {
2079 return ipmi_control_get_num_light_values(control, light);
2080 }
2081
2082 int
ipmi_control_light_is_color_supported(ipmi_control_t * control,unsigned int color)2083 ipmi_control_light_is_color_supported(ipmi_control_t *control,
2084 unsigned int color)
2085 {
2086 return ipmi_control_light_is_color_sup(control, 0, color);
2087 }
2088
2089 int
ipmi_control_light_has_local_control(ipmi_control_t * control)2090 ipmi_control_light_has_local_control(ipmi_control_t *control)
2091 {
2092 return ipmi_control_light_has_loc_ctrl(control, 0);
2093 }
2094