1 /*
2 * pef.c
3 *
4 * OpenIPMI code for handling Platform Event Filters
5 *
6 * Author: Intel Corporation
7 * Jeff Zheng <Jeff.Zheng@Intel.com>
8 *
9 * Copyright 2002,2003 Intel Corporation.
10 *
11 * Mostly rewritten by: MontaVista Software, Inc.
12 * Corey Minyard <minyard@mvista.com>
13 * source@mvista.com
14 *
15 * Copyright 2004 MontaVista Software Inc.
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public License
19 * as published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
21 *
22 *
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
31 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
32 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 * You should have received a copy of the GNU Lesser General Public
35 * License along with this program; if not, write to the Free
36 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37 */
38
39 /* I rewrote this because I needed access to individual data items,
40 not just a full configuration. -Corey */
41
42 #include <string.h>
43 #include <math.h>
44 #include <stdio.h>
45
46 #include <OpenIPMI/ipmiif.h>
47 #include <OpenIPMI/ipmi_pef.h>
48 #include <OpenIPMI/ipmi_msgbits.h>
49 #include <OpenIPMI/ipmi_err.h>
50
51 #include <OpenIPMI/internal/opq.h>
52 #include <OpenIPMI/internal/locked_list.h>
53 #include <OpenIPMI/internal/ipmi_int.h>
54 #include <OpenIPMI/internal/ipmi_domain.h>
55 #include <OpenIPMI/internal/ipmi_mc.h>
56
57 #define IPMI_PEF_ATTR_NAME "ipmi_pef"
58
59 struct ipmi_pef_s
60 {
61 ipmi_mcid_t mc;
62 ipmi_domain_id_t domain;
63
64 int refcount;
65
66 char name[IPMI_PEF_NAME_LEN];
67
68 /* Is the PEF ready (the capabilities have been checked)? */
69 unsigned int ready : 1;
70
71 /* Does the MC have a usable PEF? */
72 unsigned int valid : 1;
73
74 unsigned int in_list : 1;
75
76 /* Information from the get PEF capability command. */
77 unsigned int can_diagnostic_interrupt : 1;
78 unsigned int can_oem_action : 1;
79 unsigned int can_power_cycle : 1;
80 unsigned int can_reset : 1;
81 unsigned int can_power_down : 1;
82 unsigned int can_alert : 1;
83 unsigned int major_version : 4;
84 unsigned int minor_version : 4;
85
86 unsigned char num_eft_entries;
87
88 /* Used to inform the user when the PEF is ready. */
89 ipmi_pef_done_cb ready_cb;
90 void *ready_cb_data;
91
92 unsigned int destroyed : 1;
93 unsigned int in_destroy : 1;
94
95 /* Something to call when the destroy is complete. */
96 ipmi_pef_done_cb destroy_handler;
97 void *destroy_cb_data;
98
99 os_hnd_lock_t *pef_lock;
100
101 os_handler_t *os_hnd;
102
103 /* We serialize operations through here, since we are dealing with
104 a locked resource. */
105 opq_t *opq;
106 };
107
108 static int
pef_attr_init(ipmi_domain_t * domain,void * cb_data,void ** data)109 pef_attr_init(ipmi_domain_t *domain, void *cb_data, void **data)
110 {
111 locked_list_t *pefl;
112
113 pefl = locked_list_alloc(ipmi_domain_get_os_hnd(domain));
114 if (!pefl)
115 return ENOMEM;
116
117 *data = pefl;
118 return 0;
119 }
120
121 static void
pef_lock(ipmi_pef_t * pef)122 pef_lock(ipmi_pef_t *pef)
123 {
124 if (pef->os_hnd->lock)
125 pef->os_hnd->lock(pef->os_hnd, pef->pef_lock);
126 }
127
128 static void
pef_unlock(ipmi_pef_t * pef)129 pef_unlock(ipmi_pef_t *pef)
130 {
131 if (pef->os_hnd->lock)
132 pef->os_hnd->unlock(pef->os_hnd, pef->pef_lock);
133 }
134
135 static void
pef_get(ipmi_pef_t * pef)136 pef_get(ipmi_pef_t *pef)
137 {
138 pef_lock(pef);
139 pef->refcount++;
140 pef_unlock(pef);
141 }
142
143 static void internal_destroy_pef(ipmi_pef_t *pef);
144
145 static void
pef_put(ipmi_pef_t * pef)146 pef_put(ipmi_pef_t *pef)
147 {
148 pef_lock(pef);
149 pef->refcount--;
150 if (pef->refcount == 0) {
151 internal_destroy_pef(pef);
152 return;
153 }
154 pef_unlock(pef);
155 }
156
157 void
ipmi_pef_ref(ipmi_pef_t * pef)158 ipmi_pef_ref(ipmi_pef_t *pef)
159 {
160 pef_get(pef);
161 }
162
163 void
ipmi_pef_deref(ipmi_pef_t * pef)164 ipmi_pef_deref(ipmi_pef_t *pef)
165 {
166 pef_put(pef);
167 }
168
169 static int
destroy_pef(void * cb_data,void * item1,void * item2)170 destroy_pef(void *cb_data, void *item1, void *item2)
171 {
172 ipmi_pef_t *pef = item1;
173 pef_lock(pef);
174 pef->in_list = 0;
175 pef_unlock(pef);
176 return LOCKED_LIST_ITER_CONTINUE;
177 }
178
179 static void
pef_attr_destroy(void * cb_data,void * data)180 pef_attr_destroy(void *cb_data, void *data)
181 {
182 locked_list_t *pefl = data;
183
184 locked_list_iterate(pefl, destroy_pef, NULL);
185 locked_list_destroy(pefl);
186 }
187
188 typedef struct iterate_pefs_info_s
189 {
190 ipmi_pef_ptr_cb handler;
191 void *cb_data;
192 } iterate_pefs_info_t;
193
194 static int
pefs_handler(void * cb_data,void * item1,void * item2)195 pefs_handler(void *cb_data, void *item1, void *item2)
196 {
197 iterate_pefs_info_t *info = cb_data;
198 info->handler(item1, info->cb_data);
199 pef_put(item1);
200 return LOCKED_LIST_ITER_CONTINUE;
201 }
202
203 static int
pefs_prefunc(void * cb_data,void * item1,void * item2)204 pefs_prefunc(void *cb_data, void *item1, void *item2)
205 {
206 pef_get(item1);
207 return LOCKED_LIST_ITER_CONTINUE;
208 }
209
210 void
ipmi_pef_iterate_pefs(ipmi_domain_t * domain,ipmi_pef_ptr_cb handler,void * cb_data)211 ipmi_pef_iterate_pefs(ipmi_domain_t *domain,
212 ipmi_pef_ptr_cb handler,
213 void *cb_data)
214 {
215 iterate_pefs_info_t info;
216 ipmi_domain_attr_t *attr;
217 locked_list_t *pefs;
218 int rv;
219
220 rv = ipmi_domain_find_attribute(domain, IPMI_PEF_ATTR_NAME,
221 &attr);
222 if (rv)
223 return;
224 pefs = ipmi_domain_attr_get_data(attr);
225
226 info.handler = handler;
227 info.cb_data = cb_data;
228 locked_list_iterate_prefunc(pefs, pefs_prefunc, pefs_handler, &info);
229 ipmi_domain_attr_put(attr);
230 }
231
232 ipmi_mcid_t
ipmi_pef_get_mc_id(ipmi_pef_t * pef)233 ipmi_pef_get_mc_id(ipmi_pef_t *pef)
234 {
235 return pef->mc;
236 }
237
238 int
ipmi_pef_get_name(ipmi_pef_t * pef,char * name,int length)239 ipmi_pef_get_name(ipmi_pef_t *pef, char *name, int length)
240 {
241 int slen;
242
243 if (length <= 0)
244 return 0;
245
246 /* Never changes, no lock needed. */
247 slen = strlen(pef->name);
248 if (slen == 0) {
249 if (name)
250 *name = '\0';
251 goto out;
252 }
253
254 if (name) {
255 memcpy(name, pef->name, slen);
256 name[slen] = '\0';
257 }
258 out:
259 return slen;
260 }
261
262 static int
check_pef_response_param(ipmi_pef_t * pef,ipmi_mc_t * mc,ipmi_msg_t * rsp,int len,char * func_name)263 check_pef_response_param(ipmi_pef_t *pef,
264 ipmi_mc_t *mc,
265 ipmi_msg_t *rsp,
266 int len,
267 char *func_name)
268 {
269 if (pef->destroyed) {
270 ipmi_log(IPMI_LOG_ERR_INFO,
271 "%s: "
272 "PEF was destroyed while an operation was in progress",
273 func_name);
274 return ECANCELED;
275 }
276
277 if (!mc) {
278 ipmi_log(IPMI_LOG_ERR_INFO,
279 "%s: MC went away while PEF op was in progress",
280 func_name);
281 return ECANCELED;
282 }
283
284 if (rsp->data[0] != 0) {
285 /* Allow optional parameters to return errors without complaining. */
286 if ((rsp->data[0] != 0x80) && (rsp->data[0] != 0xcc)
287 && (rsp->data[0] != 0x81))
288 {
289 ipmi_log(IPMI_LOG_ERR_INFO,
290 "%s: IPMI error from PEF capabilities fetch: %x",
291 func_name,
292 rsp->data[0]);
293 }
294 return IPMI_IPMI_ERR_VAL(rsp->data[0]);
295 }
296
297 if (rsp->data_len < len) {
298 ipmi_log(IPMI_LOG_ERR_INFO,
299 "%s: PEF capabilities too short",
300 func_name);
301 return EINVAL;
302 }
303 return 0;
304 }
305
306 static void
handle_pef_capabilities(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)307 handle_pef_capabilities(ipmi_mc_t *mc,
308 ipmi_msg_t *rsp,
309 void *rsp_data)
310 {
311 ipmi_pef_t *pef = rsp_data;
312 int rv;
313
314 rv = check_pef_response_param(pef, mc, rsp, 4, "handle_pef_capabilities");
315 if (rv)
316 goto out;
317
318 pef_lock(pef);
319
320 pef->valid = 1;
321
322 /* Pull pertinant info from the response. */
323 pef->major_version = rsp->data[1] & 0xf;
324 pef->minor_version = (rsp->data[1] >> 4) & 0xf;
325 pef->can_alert = (rsp->data[2] & 0x01) == 0x01;
326 pef->can_power_down = (rsp->data[2] & 0x02) == 0x02;
327 pef->can_reset = (rsp->data[2] & 0x04) == 0x04;
328 pef->can_power_cycle = (rsp->data[2] & 0x08) == 0x08;
329 pef->can_oem_action = (rsp->data[2] & 0x10) == 0x10;
330 pef->can_diagnostic_interrupt = (rsp->data[2] & 0x20) == 0x20;
331 pef->num_eft_entries = rsp->data[3];
332
333 pef_unlock(pef);
334
335 out:
336 pef->ready = 1;
337
338 if (pef->ready_cb)
339 pef->ready_cb(pef, rv, pef->ready_cb_data);
340
341 pef_put(pef);
342 }
343
344 static int
pef_start_capability_fetch(ipmi_pef_t * pef,ipmi_mc_t * mc)345 pef_start_capability_fetch(ipmi_pef_t *pef, ipmi_mc_t *mc)
346 {
347 ipmi_msg_t msg;
348 int rv;
349
350 msg.netfn = IPMI_SENSOR_EVENT_NETFN;
351 msg.cmd = IPMI_GET_PEF_CAPABILITIES_CMD;
352 msg.data_len = 0;
353 msg.data = NULL;
354 pef_get(pef);
355 rv = ipmi_mc_send_command(mc, 0,
356 &msg, handle_pef_capabilities, pef);
357 if (rv) {
358 ipmi_log(IPMI_LOG_ERR_INFO,
359 "pef_start_capability_fetch: could not send cmd: %x",
360 rv);
361 pef_put(pef);
362 }
363
364 return rv;
365 }
366
367 int
ipmi_pef_alloc(ipmi_mc_t * mc,ipmi_pef_done_cb done,void * cb_data,ipmi_pef_t ** new_pef)368 ipmi_pef_alloc(ipmi_mc_t *mc,
369 ipmi_pef_done_cb done,
370 void *cb_data,
371 ipmi_pef_t **new_pef)
372 {
373 ipmi_pef_t *pef = NULL;
374 int rv = 0;
375 ipmi_domain_t *domain = ipmi_mc_get_domain(mc);
376 locked_list_t *pefl;
377 ipmi_domain_attr_t *attr;
378 int len, p;
379
380 CHECK_MC_LOCK(mc);
381
382 rv = ipmi_domain_register_attribute(domain, IPMI_PEF_ATTR_NAME,
383 pef_attr_init,
384 pef_attr_destroy,
385 NULL,
386 &attr);
387 if (rv)
388 return rv;
389 pefl = ipmi_domain_attr_get_data(attr);
390
391 pef = ipmi_mem_alloc(sizeof(*pef));
392 if (!pef) {
393 rv = ENOMEM;
394 goto out;
395 }
396 memset(pef, 0, sizeof(*pef));
397
398 pef->refcount = 1;
399 pef->in_list = 1;
400 pef->mc = ipmi_mc_convert_to_id(mc);
401 pef->domain = ipmi_domain_convert_to_id(domain);
402 len = sizeof(pef->name);
403 p = ipmi_domain_get_name(domain, pef->name, len);
404 len -= p;
405 snprintf(pef->name+p, len, ".%d", ipmi_domain_get_unique_num(domain));
406 pef->os_hnd = ipmi_domain_get_os_hnd(domain);
407 pef->pef_lock = NULL;
408 pef->ready_cb = done;
409 pef->ready_cb_data = cb_data;
410
411 pef->opq = opq_alloc(pef->os_hnd);
412 if (!pef->opq) {
413 rv = ENOMEM;
414 goto out;
415 }
416
417 if (pef->os_hnd->create_lock) {
418 rv = pef->os_hnd->create_lock(pef->os_hnd, &pef->pef_lock);
419 if (rv)
420 goto out;
421 }
422
423 if (! locked_list_add(pefl, pef, NULL)) {
424 rv = ENOMEM;
425 goto out;
426 }
427
428 out:
429 ipmi_domain_attr_put(attr);
430 if (!rv)
431 rv = pef_start_capability_fetch(pef, mc);
432
433 if (rv) {
434 if (pef) {
435 if (pef->opq)
436 opq_destroy(pef->opq);
437 if (pef->pef_lock)
438 pef->os_hnd->destroy_lock(pef->os_hnd, pef->pef_lock);
439 ipmi_mem_free(pef);
440 }
441 } else {
442 if (new_pef)
443 *new_pef = pef;
444 }
445 return rv;
446 }
447
448 static void
internal_destroy_pef(ipmi_pef_t * pef)449 internal_destroy_pef(ipmi_pef_t *pef)
450 {
451 pef->in_destroy = 1;
452
453 if (pef->in_list) {
454 ipmi_domain_attr_t *attr;
455 locked_list_t *pefs;
456 int rv;
457 rv = ipmi_domain_id_find_attribute(pef->domain,
458 IPMI_PEF_ATTR_NAME, &attr);
459 if (!rv) {
460 pef->in_list = 0;
461 pef->refcount++;
462 pef_unlock(pef);
463
464 pefs = ipmi_domain_attr_get_data(attr);
465
466 locked_list_remove(pefs, pef, NULL);
467 ipmi_domain_attr_put(attr);
468 pef_lock(pef);
469 /* While we were unlocked, someone may have come in and
470 grabbed the PEF by iterating the list of PEFs. That's
471 ok, we just let them handle the destruction since this
472 code will not be entered again. */
473 if (pef->refcount != 1) {
474 pef->refcount--;
475 pef_unlock(pef);
476 return;
477 }
478 }
479 }
480
481 pef_unlock(pef);
482
483 if (pef->opq)
484 opq_destroy(pef->opq);
485
486 if (pef->pef_lock)
487 pef->os_hnd->destroy_lock(pef->os_hnd, pef->pef_lock);
488
489 /* Do this after we have gotten rid of all external dependencies,
490 but before it is free. */
491 if (pef->destroy_handler)
492 pef->destroy_handler(pef, 0, pef->destroy_cb_data);
493
494 ipmi_mem_free(pef);
495 }
496
497 int
ipmi_pef_destroy(ipmi_pef_t * pef,ipmi_pef_done_cb done,void * cb_data)498 ipmi_pef_destroy(ipmi_pef_t *pef,
499 ipmi_pef_done_cb done,
500 void *cb_data)
501 {
502 int rv;
503 ipmi_domain_attr_t *attr;
504 locked_list_t *pefl;
505
506 pef_lock(pef);
507 if (pef->in_list) {
508 pef->in_list = 0;
509 rv = ipmi_domain_id_find_attribute(pef->domain, IPMI_PEF_ATTR_NAME,
510 &attr);
511 if (!rv) {
512 pef_unlock(pef);
513 pefl = ipmi_domain_attr_get_data(attr);
514
515 locked_list_remove(pefl, pef, NULL);
516 ipmi_domain_attr_put(attr);
517 pef_lock(pef);
518 }
519 }
520
521 if (pef->destroyed) {
522 pef_unlock(pef);
523 return EINVAL;
524 }
525 pef->destroyed = 1;
526 pef_unlock(pef);
527 pef->destroy_handler = done;
528 pef->destroy_cb_data = cb_data;
529 pef_put(pef);
530 return 0;
531 }
532
533 typedef struct pef_fetch_handler_s
534 {
535 ipmi_pef_t *pef;
536 unsigned char parm;
537 unsigned char set;
538 unsigned char block;
539 ipmi_pef_get_cb handler;
540 void *cb_data;
541 unsigned char *data;
542 unsigned int data_len;
543 int rv;
544 } pef_fetch_handler_t;
545
546 /* This should be called with the pef locked. It will unlock the pef
547 before returning. */
548 static void
fetch_complete(ipmi_pef_t * pef,int err,pef_fetch_handler_t * elem)549 fetch_complete(ipmi_pef_t *pef, int err, pef_fetch_handler_t *elem)
550 {
551 if (pef->in_destroy)
552 goto out;
553
554 pef_unlock(pef);
555
556 if (elem->handler)
557 elem->handler(pef, err, elem->data, elem->data_len, elem->cb_data);
558
559 ipmi_mem_free(elem);
560
561 if (!pef->destroyed)
562 opq_op_done(pef->opq);
563
564 pef_put(pef);
565 return;
566
567 out:
568 pef_unlock(pef);
569 pef_put(pef);
570 }
571
572
573 static void
pef_config_fetched(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)574 pef_config_fetched(ipmi_mc_t *mc,
575 ipmi_msg_t *rsp,
576 void *rsp_data)
577 {
578 pef_fetch_handler_t *elem = rsp_data;
579 ipmi_pef_t *pef = elem->pef;
580 int rv;
581
582 rv = check_pef_response_param(pef, mc, rsp, 2, "pef_config_fetched");
583
584 /* Skip the revision number. */
585 elem->data = rsp->data + 1;
586 elem->data_len = rsp->data_len - 1;
587
588 pef_lock(pef);
589 fetch_complete(pef, rv, elem);
590 }
591
592 static void
start_config_fetch_cb(ipmi_mc_t * mc,void * cb_data)593 start_config_fetch_cb(ipmi_mc_t *mc, void *cb_data)
594 {
595 pef_fetch_handler_t *elem = cb_data;
596 ipmi_pef_t *pef = elem->pef;
597 unsigned char data[3];
598 ipmi_msg_t msg;
599 int rv;
600
601 pef_lock(pef);
602 if (pef->destroyed) {
603 ipmi_log(IPMI_LOG_ERR_INFO,
604 "start_fetch: "
605 "PEF was destroyed while an operation was in progress");
606 fetch_complete(pef, ECANCELED, elem);
607 goto out;
608 }
609
610 msg.data = data;
611 msg.netfn = IPMI_SENSOR_EVENT_NETFN;
612 msg.cmd = IPMI_GET_PEF_CONFIG_PARMS_CMD;
613 data[0] = elem->parm;
614 data[1] = elem->set;
615 data[2] = elem->block;
616 msg.data_len = 3;
617 rv = ipmi_mc_send_command(mc, 0, &msg, pef_config_fetched, elem);
618
619 if (rv) {
620 ipmi_log(IPMI_LOG_ERR_INFO,
621 "PEF start_config_fetch: could not send cmd: %x",
622 rv);
623 fetch_complete(pef, ECANCELED, elem);
624 goto out;
625 }
626
627 pef_unlock(pef);
628 out:
629 return;
630 }
631
632 static int
start_config_fetch(void * cb_data,int shutdown)633 start_config_fetch(void *cb_data, int shutdown)
634 {
635 pef_fetch_handler_t *elem = cb_data;
636 int rv;
637
638 if (shutdown) {
639 ipmi_log(IPMI_LOG_ERR_INFO,
640 "start_fetch: "
641 "PEF was destroyed while an operation was in progress");
642 pef_lock(elem->pef);
643 fetch_complete(elem->pef, ECANCELED, elem);
644 return OPQ_HANDLER_STARTED;
645 }
646
647 /* The read lock must be claimed before the pef lock to avoid
648 deadlock. */
649 rv = ipmi_mc_pointer_cb(elem->pef->mc, start_config_fetch_cb, elem);
650 if (rv) {
651 ipmi_log(IPMI_LOG_ERR_INFO, "start_fetch: PEF's MC is not valid");
652 pef_lock(elem->pef);
653 fetch_complete(elem->pef, rv, elem);
654 }
655 return OPQ_HANDLER_STARTED;
656 }
657
658 int
ipmi_pef_get_parm(ipmi_pef_t * pef,unsigned int parm,unsigned int set,unsigned int block,ipmi_pef_get_cb done,void * cb_data)659 ipmi_pef_get_parm(ipmi_pef_t *pef,
660 unsigned int parm,
661 unsigned int set,
662 unsigned int block,
663 ipmi_pef_get_cb done,
664 void *cb_data)
665 {
666 pef_fetch_handler_t *elem;
667 int rv = 0;
668
669 if (pef->destroyed)
670 return EINVAL;
671
672 if (!pef->valid)
673 return EINVAL;
674
675 elem = ipmi_mem_alloc(sizeof(*elem));
676 if (!elem) {
677 ipmi_log(IPMI_LOG_ERR_INFO,
678 "ipmi_pef_get: could not allocate the pef element");
679 return ENOMEM;
680 }
681
682 elem->handler = done;
683 elem->cb_data = cb_data;
684 elem->pef = pef;
685 elem->parm = parm;
686 elem->set = set;
687 elem->block = block;
688 elem->rv = 0;
689
690 pef_get(pef);
691 if (!opq_new_op(pef->opq, start_config_fetch, elem, 0)) {
692 pef_put(pef);
693 rv = ENOMEM;
694 }
695
696 if (rv)
697 ipmi_mem_free(elem);
698
699 return rv;
700 }
701
702 typedef struct pef_set_handler_s
703 {
704 ipmi_pef_t *pef;
705 ipmi_pef_done_cb handler;
706 void *cb_data;
707 unsigned char data[MAX_IPMI_DATA_SIZE];
708 unsigned int data_len;
709 int rv;
710 } pef_set_handler_t;
711
712 /* This should be called with the pef locked. It will unlock the pef
713 before returning. */
714 static void
set_complete(ipmi_pef_t * pef,int err,pef_set_handler_t * elem)715 set_complete(ipmi_pef_t *pef, int err, pef_set_handler_t *elem)
716 {
717 if (pef->in_destroy)
718 goto out;
719
720 pef_unlock(pef);
721
722 if (elem->handler)
723 elem->handler(pef, err, elem->cb_data);
724
725 ipmi_mem_free(elem);
726
727 pef_lock(pef);
728 if (!pef->destroyed) {
729 pef_unlock(pef);
730 opq_op_done(pef->opq);
731 } else {
732 pef_unlock(pef);
733 }
734
735 pef_put(pef);
736 return;
737
738 out:
739 pef_unlock(pef);
740 pef_put(pef);
741 }
742
743 static void
pef_config_set(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)744 pef_config_set(ipmi_mc_t *mc,
745 ipmi_msg_t *rsp,
746 void *rsp_data)
747 {
748 pef_set_handler_t *elem = rsp_data;
749 ipmi_pef_t *pef = elem->pef;
750 int rv;
751
752 rv = check_pef_response_param(pef, mc, rsp, 1, "pef_config_set");
753
754 pef_lock(pef);
755 set_complete(pef, rv, elem);
756 }
757
758 static void
start_config_set_cb(ipmi_mc_t * mc,void * cb_data)759 start_config_set_cb(ipmi_mc_t *mc, void *cb_data)
760 {
761 pef_set_handler_t *elem = cb_data;
762 ipmi_pef_t *pef = elem->pef;
763 ipmi_msg_t msg;
764 int rv;
765
766 pef_lock(pef);
767 if (pef->destroyed) {
768 ipmi_log(IPMI_LOG_ERR_INFO,
769 "start_set: "
770 "PEF was destroyed while an operation was in progress");
771 set_complete(pef, ECANCELED, elem);
772 goto out;
773 }
774
775 msg.netfn = IPMI_SENSOR_EVENT_NETFN;
776 msg.cmd = IPMI_SET_PEF_CONFIG_PARMS_CMD;
777 msg.data = elem->data;
778 msg.data_len = elem->data_len;
779 rv = ipmi_mc_send_command(mc, 0, &msg, pef_config_set, elem);
780
781 if (rv) {
782 ipmi_log(IPMI_LOG_ERR_INFO,
783 "PEF start_config_set: could not send cmd: %x",
784 rv);
785 set_complete(pef, ECANCELED, elem);
786 goto out;
787 }
788
789 pef_unlock(pef);
790 out:
791 return;
792 }
793
794 static int
start_config_set(void * cb_data,int shutdown)795 start_config_set(void *cb_data, int shutdown)
796 {
797 pef_set_handler_t *elem = cb_data;
798 int rv;
799
800 if (shutdown) {
801 ipmi_log(IPMI_LOG_ERR_INFO,
802 "start_config_set: "
803 "PEF was destroyed while an operation was in progress");
804 pef_lock(elem->pef);
805 set_complete(elem->pef, ECANCELED, elem);
806 return OPQ_HANDLER_STARTED;
807 }
808
809 /* The read lock must be claimed before the pef lock to avoid
810 deadlock. */
811 rv = ipmi_mc_pointer_cb(elem->pef->mc, start_config_set_cb, elem);
812 if (rv) {
813 ipmi_log(IPMI_LOG_ERR_INFO, "start_config_set: PEF's MC is not valid");
814 pef_lock(elem->pef);
815 set_complete(elem->pef, rv, elem);
816 }
817 return OPQ_HANDLER_STARTED;
818 }
819
820 int
ipmi_pef_set_parm(ipmi_pef_t * pef,unsigned int parm,unsigned char * data,unsigned int data_len,ipmi_pef_done_cb done,void * cb_data)821 ipmi_pef_set_parm(ipmi_pef_t *pef,
822 unsigned int parm,
823 unsigned char *data,
824 unsigned int data_len,
825 ipmi_pef_done_cb done,
826 void *cb_data)
827 {
828 pef_set_handler_t *elem;
829 int rv = 0;
830
831 if (pef->destroyed)
832 return EINVAL;
833
834 if (!pef->valid)
835 return EINVAL;
836
837 if (data_len > MAX_IPMI_DATA_SIZE-1)
838 return EINVAL;
839
840 elem = ipmi_mem_alloc(sizeof(*elem));
841 if (!elem) {
842 ipmi_log(IPMI_LOG_ERR_INFO,
843 "ipmi_pef_get: could not allocate the pef element");
844 return ENOMEM;
845 }
846
847 elem->handler = done;
848 elem->cb_data = cb_data;
849 elem->pef = pef;
850 elem->data[0] = parm;
851 memcpy(elem->data+1, data, data_len);
852 elem->data_len = data_len + 1;
853 elem->rv = 0;
854
855
856 pef_get(pef);
857 if (!opq_new_op(pef->opq, start_config_set, elem, 0)) {
858 pef_put(pef);
859 rv = ENOMEM;
860 }
861
862 if (rv)
863 ipmi_mem_free(elem);
864
865 return rv;
866 }
867
868 int
ipmi_pef_valid(ipmi_pef_t * pef)869 ipmi_pef_valid(ipmi_pef_t *pef)
870 {
871 return pef->valid;
872 }
873
874 int
ipmi_pef_supports_diagnostic_interrupt(ipmi_pef_t * pef)875 ipmi_pef_supports_diagnostic_interrupt(ipmi_pef_t *pef)
876 {
877 return pef->can_diagnostic_interrupt;
878 }
879
880 int
ipmi_pef_supports_oem_action(ipmi_pef_t * pef)881 ipmi_pef_supports_oem_action(ipmi_pef_t *pef)
882 {
883 return pef->can_oem_action;
884 }
885
886 int
ipmi_pef_supports_power_cycle(ipmi_pef_t * pef)887 ipmi_pef_supports_power_cycle(ipmi_pef_t *pef)
888 {
889 return pef->can_power_cycle;
890 }
891
892 int
ipmi_pef_supports_reset(ipmi_pef_t * pef)893 ipmi_pef_supports_reset(ipmi_pef_t *pef)
894 {
895 return pef->can_reset;
896 }
897
898 int
ipmi_pef_supports_power_down(ipmi_pef_t * pef)899 ipmi_pef_supports_power_down(ipmi_pef_t *pef)
900 {
901 return pef->can_power_down;
902 }
903
904 int
ipmi_pef_supports_alert(ipmi_pef_t * pef)905 ipmi_pef_supports_alert(ipmi_pef_t *pef)
906 {
907 return pef->can_alert;
908 }
909
910 unsigned int
ipmi_pef_major_version(ipmi_pef_t * pef)911 ipmi_pef_major_version(ipmi_pef_t *pef)
912 {
913 return pef->major_version;
914 }
915
916 unsigned int
ipmi_pef_minor_version(ipmi_pef_t * pef)917 ipmi_pef_minor_version(ipmi_pef_t *pef)
918 {
919 return pef->minor_version;
920 }
921
922 unsigned int
num_event_filter_table_entries(ipmi_pef_t * pef)923 num_event_filter_table_entries(ipmi_pef_t *pef)
924 {
925 return pef->num_eft_entries;
926 }
927
928 ipmi_mcid_t
ipmi_pef_get_mc(ipmi_pef_t * pef)929 ipmi_pef_get_mc(ipmi_pef_t *pef)
930 {
931 return pef->mc;
932 }
933
934 typedef struct ipmi_eft_s
935 {
936 unsigned int enable_filter : 1;
937 unsigned int filter_type : 2;
938
939 /* Byte 2: Event Filter Action */
940 unsigned int diagnostic_interrupt : 1;
941 unsigned int oem_action : 1;
942 unsigned int power_cycle : 1;
943 unsigned int reset : 1;
944 unsigned int power_down : 1;
945 unsigned int alert : 1;
946
947 /* Byte 3: Alert Policy Number */
948 unsigned char alert_policy_number;
949
950 /* Byte 4: Event Severity */
951 unsigned char event_severity;
952
953 /* Byte 5 : Generator ID Byte 1 */
954 unsigned char generator_id_addr;
955
956 /* Byte 6 : Generator ID Byte 2 */
957 unsigned char generator_id_channel_lun;
958
959 /* Byte 7 : Sensor Type */
960 unsigned char sensor_type;
961
962 /* Byte 8 : Sensor Number */
963 unsigned char sensor_number;
964
965 /* Byte 9 : Event trigger (Event/Reading Type) */
966 unsigned char event_trigger;
967
968 /* Byte 10 - 20 : Event data process */
969 unsigned short data1_offset_mask; /* byte 10, 11 */
970 unsigned char data1_mask;
971 unsigned char data1_compare1;
972 unsigned char data1_compare2;
973 unsigned char data2_mask;
974 unsigned char data2_compare1;
975 unsigned char data2_compare2;
976 unsigned char data3_mask;
977 unsigned char data3_compare1;
978 unsigned char data3_compare2;
979 } ipmi_eft_t;
980
981 typedef struct ipmi_apt_s
982 {
983 unsigned int policy_num : 4;
984 unsigned int enabled : 1;
985 unsigned int policy : 3;
986 unsigned int channel : 4;
987 unsigned int destination_selector : 4;
988 unsigned int alert_string_event_specific : 1;
989 unsigned int alert_string_selector : 7;
990 } ipmi_apt_t;
991
992 typedef struct ipmi_ask_s
993 {
994 unsigned int event_filter : 4;
995 unsigned int alert_string_set : 4;
996 } ipmi_ask_t;
997
998 struct ipmi_pef_config_s
999 {
1000 int curr_parm;
1001 int curr_sel;
1002 int curr_block;
1003
1004 /* Not used for access, just for checking validity. */
1005 ipmi_pef_t *my_pef;
1006
1007 /* Does this config hold the external PEF "set in progress" lock? */
1008 int pef_locked;
1009
1010 /* Does the PEF support locking? */
1011 int lock_supported;
1012
1013 /* Used for deferred errors. */
1014 int err;
1015
1016 ipmi_pef_done_cb set_done;
1017 ipmi_pef_get_config_cb done;
1018 void *cb_data;
1019
1020 /* PEF Control */
1021 unsigned int alert_startup_delay_enabled : 1;
1022 unsigned int startup_delay_enabled : 1;
1023 unsigned int event_messages_enabled : 1;
1024 unsigned int pef_enabled : 1;
1025
1026 /* PEF Action global control */
1027 unsigned char diagnostic_interrupt_enabled : 1;
1028 unsigned char oem_action_enabled : 1;
1029 unsigned char power_cycle_enabled : 1;
1030 unsigned char reset_enabled : 1;
1031 unsigned char power_down_enabled : 1;
1032 unsigned char alert_enabled : 1;
1033
1034 unsigned char startup_delay; /* PEF Startup Delay */
1035 unsigned char startup_delay_supported;
1036
1037 unsigned char alert_startup_delay; /* PEF Alert Startup Delay */
1038 unsigned char alert_startup_delay_supported;
1039
1040 unsigned char guid[16]; /* System GUID */
1041 unsigned char guid_enabled;
1042
1043 unsigned char num_event_filters; /* Number of Event Filters */
1044 ipmi_eft_t *efts; /* Event Filter Table */
1045
1046 unsigned char num_alert_policies; /* Number of alert policy entries */
1047 ipmi_apt_t *apts; /* Alert Policy Table */
1048
1049 unsigned char num_alert_strings; /* Number of alert strings */
1050 ipmi_ask_t *asks; /* Alert String Key Table */
1051 char **alert_strings; /* Alert strings */
1052 };
1053
1054
1055 typedef struct pefparms_s pefparms_t;
1056 struct pefparms_s
1057 {
1058 unsigned int valid : 1;
1059 unsigned int optional_offset : 8;
1060 unsigned int offset : 8;
1061 unsigned int length : 8;
1062 /* Returns err. */
1063 int (*get_handler)(ipmi_pef_config_t *pefc, pefparms_t *lp, int err,
1064 unsigned char *data, unsigned int data_len);
1065 /* NULL if parameter is read-only */
1066 void (*set_handler)(ipmi_pef_config_t *pefc, pefparms_t *lp,
1067 unsigned char *data, unsigned int *data_len);
1068 };
1069
1070 /* Control */
gctl(ipmi_pef_config_t * pefc,pefparms_t * lp,int err,unsigned char * data,unsigned int data_len)1071 static int gctl(ipmi_pef_config_t *pefc, pefparms_t *lp, int err,
1072 unsigned char *data, unsigned int data_len)
1073 {
1074 if (err)
1075 return err;
1076
1077 data++; /* Skip the revision byte. */
1078
1079 pefc->alert_startup_delay_enabled = (data[0] >> 3) & 1;
1080 pefc->startup_delay_enabled = (data[0] >> 2) & 1;
1081 pefc->event_messages_enabled = (data[0] >> 1) & 1;
1082 pefc->pef_enabled = (data[0] >> 0) & 1;
1083
1084 return 0;
1085 }
1086
sctl(ipmi_pef_config_t * pefc,pefparms_t * lp,unsigned char * data,unsigned int * data_len)1087 static void sctl(ipmi_pef_config_t *pefc, pefparms_t *lp, unsigned char *data,
1088 unsigned int *data_len)
1089 {
1090 data[0] = ((pefc->alert_startup_delay_enabled << 3)
1091 | (pefc->startup_delay_enabled << 2)
1092 | (pefc->event_messages_enabled << 1)
1093 | pefc->pef_enabled);
1094 }
1095
1096 /* Action Global Control */
gagc(ipmi_pef_config_t * pefc,pefparms_t * lp,int err,unsigned char * data,unsigned int data_len)1097 static int gagc(ipmi_pef_config_t *pefc, pefparms_t *lp, int err,
1098 unsigned char *data, unsigned int data_len)
1099 {
1100 if (err)
1101 return err;
1102
1103 data++; /* Skip the revision byte. */
1104
1105 pefc->diagnostic_interrupt_enabled = (data[0] >> 5) & 1;
1106 pefc->oem_action_enabled = (data[0] >> 4) & 1;
1107 pefc->power_cycle_enabled = (data[0] >> 3) & 1;
1108 pefc->reset_enabled = (data[0] >> 2) & 1;
1109 pefc->power_down_enabled = (data[0] >> 1) & 1;
1110 pefc->alert_enabled = (data[0] >> 0) & 1;
1111
1112 return 0;
1113 }
1114
sagc(ipmi_pef_config_t * pefc,pefparms_t * lp,unsigned char * data,unsigned int * data_len)1115 static void sagc(ipmi_pef_config_t *pefc, pefparms_t *lp, unsigned char *data,
1116 unsigned int *data_len)
1117 {
1118 data[0] = ((pefc->diagnostic_interrupt_enabled << 5)
1119 | (pefc->oem_action_enabled << 4)
1120 | (pefc->power_cycle_enabled << 3)
1121 | (pefc->reset_enabled << 2)
1122 | (pefc->power_down_enabled << 1)
1123 | (pefc->alert_enabled << 0));
1124 }
1125
1126 /* Startup Delay */
gsd(ipmi_pef_config_t * pefc,pefparms_t * lp,int err,unsigned char * data,unsigned int data_len)1127 static int gsd(ipmi_pef_config_t *pefc, pefparms_t *lp, int err,
1128 unsigned char *data, unsigned int data_len)
1129 {
1130 if (err) {
1131 pefc->startup_delay_supported = 0;
1132 return 0;
1133 }
1134
1135 data++; /* Skip the revision byte. */
1136
1137 pefc->startup_delay_supported = 1;
1138 pefc->startup_delay = data[0] & 0x7f;
1139
1140 return 0;
1141 }
1142
ssd(ipmi_pef_config_t * pefc,pefparms_t * lp,unsigned char * data,unsigned int * data_len)1143 static void ssd(ipmi_pef_config_t *pefc, pefparms_t *lp, unsigned char *data,
1144 unsigned int *data_len)
1145 {
1146 data[0] = pefc->startup_delay;
1147 }
1148
1149 /* Alert Startup Delay */
gasd(ipmi_pef_config_t * pefc,pefparms_t * lp,int err,unsigned char * data,unsigned int data_len)1150 static int gasd(ipmi_pef_config_t *pefc, pefparms_t *lp, int err,
1151 unsigned char *data, unsigned int data_len)
1152 {
1153 if (err) {
1154 pefc->alert_startup_delay_supported = 0;
1155 return 0;
1156 }
1157
1158 data++; /* Skip the revision byte. */
1159
1160 pefc->alert_startup_delay_supported = 1;
1161 pefc->alert_startup_delay = data[0] & 0x7f;
1162
1163 return 0;
1164 }
1165
sasd(ipmi_pef_config_t * pefc,pefparms_t * lp,unsigned char * data,unsigned int * data_len)1166 static void sasd(ipmi_pef_config_t *pefc, pefparms_t *lp, unsigned char *data,
1167 unsigned int *data_len)
1168 {
1169 data[0] = pefc->alert_startup_delay;
1170 }
1171
1172 /* Number of Event Filters */
gnef(ipmi_pef_config_t * pefc,pefparms_t * lp,int err,unsigned char * data,unsigned int data_len)1173 static int gnef(ipmi_pef_config_t *pefc, pefparms_t *lp, int err,
1174 unsigned char *data, unsigned int data_len)
1175 {
1176 int num;
1177
1178 if (err)
1179 return err;
1180
1181 data++; /* Skip the revision byte. */
1182
1183 pefc->num_event_filters = 0;
1184 num = data[0] & 0x7f;
1185 if (pefc->efts)
1186 ipmi_mem_free(pefc->efts);
1187 pefc->efts = NULL;
1188
1189 if (num == 0)
1190 return 0;
1191
1192 pefc->efts = ipmi_mem_alloc(sizeof(ipmi_eft_t) * num);
1193 if (!pefc->efts)
1194 return ENOMEM;
1195
1196 pefc->num_event_filters = num;
1197
1198 return 0;
1199 }
1200
1201 /* Event Filter Table */
geft(ipmi_pef_config_t * pefc,pefparms_t * lp,int err,unsigned char * data,unsigned int data_len)1202 static int geft(ipmi_pef_config_t *pefc, pefparms_t *lp, int err,
1203 unsigned char *data, unsigned int data_len)
1204 {
1205 int pos;
1206 ipmi_eft_t *t;
1207
1208 data++; /* Skip the revision byte. */
1209 pos = data[0] & 0x7f;
1210
1211 if (err)
1212 return err;
1213 if (pos > pefc->num_event_filters)
1214 return 0; /* Another error check will get this later. */
1215
1216 pos--; /* Make it zero-based. */
1217
1218 t = &(pefc->efts[pos]);
1219 t->enable_filter = (data[1] >> 7) & 0x1;
1220 t->filter_type = (data[1] >> 5) & 0x3;
1221 t->diagnostic_interrupt = (data[2] >> 5) & 1;
1222 t->oem_action = (data[2] >> 4) & 1;
1223 t->power_cycle = (data[2] >> 3) & 1;
1224 t->reset = (data[2] >> 2) & 1;
1225 t->power_down = (data[2] >> 1) & 1;
1226 t->alert = (data[2] >> 0) & 1;
1227 t->alert_policy_number = data[3] & 0xf;
1228 t->event_severity = data[4];
1229 t->generator_id_addr = data[5];
1230 t->generator_id_channel_lun = data[6];
1231 t->sensor_type = data[7];
1232 t->sensor_number = data[8];
1233 t->event_trigger = data[9];
1234 t->data1_offset_mask = data[10] | (data[11] << 8);
1235 t->data1_mask = data[12];
1236 t->data1_compare1 = data[13];
1237 t->data1_compare2 = data[14];
1238 t->data2_mask = data[15];
1239 t->data2_compare1 = data[16];
1240 t->data2_compare2 = data[17];
1241 t->data3_mask = data[18];
1242 t->data3_compare1 = data[19];
1243 t->data3_compare2 = data[20];
1244
1245 return 0;
1246 }
1247
1248 /* Comes in with position in data[0]. */
seft(ipmi_pef_config_t * pefc,pefparms_t * lp,unsigned char * data,unsigned int * data_len)1249 static void seft(ipmi_pef_config_t *pefc, pefparms_t *lp, unsigned char *data,
1250 unsigned int *data_len)
1251 {
1252 int pos = data[0] & 0x7f;
1253 ipmi_eft_t *t;
1254
1255 pos--; /* Make it zero-based. */
1256
1257 t = &(pefc->efts[pos]);
1258
1259 data[1] = (t->enable_filter << 7) | (t->filter_type << 5);
1260 data[2] = ((t->diagnostic_interrupt << 5)
1261 | (t->oem_action << 4)
1262 | (t->power_cycle << 3)
1263 | (t->reset << 2)
1264 | (t->power_down << 1)
1265 | t->alert);
1266 data[3] = t->alert_policy_number;
1267 data[4] = t->event_severity;
1268 data[5] = t->generator_id_addr;
1269 data[6] = t->generator_id_channel_lun;
1270 data[7] = t->sensor_type;
1271 data[8] = t->sensor_number;
1272 data[9] = t->event_trigger;
1273 data[10] = t->data1_offset_mask & 0xff;
1274 data[11] = (t->data1_offset_mask >> 8) & 0xff;
1275 data[12] = t->data1_mask;
1276 data[13] = t->data1_compare1;
1277 data[14] = t->data1_compare2;
1278 data[15] = t->data2_mask;
1279 data[16] = t->data2_compare1;
1280 data[17] = t->data2_compare2;
1281 data[18] = t->data3_mask;
1282 data[19] = t->data3_compare1;
1283 data[20] = t->data3_compare2;
1284 }
1285
1286 /* Number of Alert Policies */
gnap(ipmi_pef_config_t * pefc,pefparms_t * lp,int err,unsigned char * data,unsigned int data_len)1287 static int gnap(ipmi_pef_config_t *pefc, pefparms_t *lp, int err,
1288 unsigned char *data, unsigned int data_len)
1289 {
1290 int num;
1291
1292 if (err)
1293 return err;
1294
1295 data++; /* Skip the revision byte. */
1296
1297 pefc->num_alert_policies = 0;
1298 num = data[0] & 0x7f;
1299 if (pefc->apts)
1300 ipmi_mem_free(pefc->apts);
1301 pefc->apts = NULL;
1302
1303 if (num == 0)
1304 return 0;
1305
1306 pefc->apts = ipmi_mem_alloc(sizeof(ipmi_apt_t) * num);
1307 if (!pefc->apts)
1308 return ENOMEM;
1309
1310 pefc->num_alert_policies = num;
1311
1312 return 0;
1313 }
1314
1315 /* Alert Policy Table */
gapt(ipmi_pef_config_t * pefc,pefparms_t * lp,int err,unsigned char * data,unsigned int data_len)1316 static int gapt(ipmi_pef_config_t *pefc, pefparms_t *lp, int err,
1317 unsigned char *data, unsigned int data_len)
1318 {
1319 int pos;
1320 ipmi_apt_t *t;
1321
1322 data++; /* Skip the revision byte. */
1323 pos = data[0] & 0x7f;
1324
1325 if (err)
1326 return err;
1327 if (pos > pefc->num_alert_policies)
1328 return 0; /* Another error check will get this later. */
1329
1330 pos--; /* Make it zero-based. */
1331
1332 t = &(pefc->apts[pos]);
1333 t->policy_num = (data[1] >> 4) & 0xf;
1334 t->enabled = (data[1] >> 3) & 0x1;
1335 t->policy = (data[1] >> 0) & 0x7;
1336 t->channel = (data[2] >> 4) & 0xf;
1337 t->destination_selector = data[2] & 0xf;
1338 t->alert_string_event_specific = (data[3] >> 7) & 1;
1339 t->alert_string_selector = data[3] & 0x7f;
1340
1341 return 0;
1342 }
1343
1344 /* Comes in with position in data[0]. */
sapt(ipmi_pef_config_t * pefc,pefparms_t * lp,unsigned char * data,unsigned int * data_len)1345 static void sapt(ipmi_pef_config_t *pefc, pefparms_t *lp, unsigned char *data,
1346 unsigned int *data_len)
1347 {
1348 int pos = data[0] & 0x7f;
1349 ipmi_apt_t *t;
1350
1351 pos--; /* Make it zero-based. */
1352
1353 t = &(pefc->apts[pos]);
1354
1355 data[1] = ((t->policy_num << 4)
1356 | (t->enabled << 3)
1357 | t->policy);
1358 data[2] = (t->channel << 4) | t->destination_selector;
1359 data[3] = (t->alert_string_event_specific << 7) | t->alert_string_selector;
1360 }
1361
1362 /* System GUID */
gsg(ipmi_pef_config_t * pefc,pefparms_t * lp,int err,unsigned char * data,unsigned int data_len)1363 static int gsg(ipmi_pef_config_t *pefc, pefparms_t *lp, int err,
1364 unsigned char *data, unsigned int data_len)
1365 {
1366 if (err)
1367 return err;
1368
1369 data++; /* Skip the revision byte. */
1370
1371 pefc->guid_enabled = data[0] & 1;
1372 memcpy(pefc->guid, data+1, 16);
1373
1374 return 0;
1375 }
1376
ssg(ipmi_pef_config_t * pefc,pefparms_t * lp,unsigned char * data,unsigned int * data_len)1377 static void ssg(ipmi_pef_config_t *pefc, pefparms_t *lp, unsigned char *data,
1378 unsigned int *data_len)
1379 {
1380 data[0] = pefc->guid_enabled;
1381 memcpy(data+1, pefc->guid, 16);
1382 }
1383
1384 /* Number of Alert Strings */
gnas(ipmi_pef_config_t * pefc,pefparms_t * lp,int err,unsigned char * data,unsigned int data_len)1385 static int gnas(ipmi_pef_config_t *pefc, pefparms_t *lp, int err,
1386 unsigned char *data, unsigned int data_len)
1387 {
1388 int num = pefc->num_alert_strings;
1389 int i;
1390 unsigned char ddata[1];
1391
1392 data++; /* Skip the revision byte. */
1393
1394 if (err == IPMI_IPMI_ERR_VAL(0x80)) {
1395 /* If it's unsupported, then just set it to zero. */
1396 data = ddata;
1397 data[0] = 0;
1398 } else if (err)
1399 return err;
1400
1401 if (pefc->asks)
1402 ipmi_mem_free(pefc->asks);
1403 if (pefc->alert_strings) {
1404 for (i=0; i<num; i++) {
1405 if (pefc->alert_strings[i])
1406 ipmi_mem_free(pefc->alert_strings[i]);
1407 }
1408 ipmi_mem_free(pefc->alert_strings);
1409 }
1410 pefc->asks = NULL;
1411 pefc->alert_strings = NULL;
1412
1413 pefc->num_alert_strings = 0;
1414 num = data[0] & 0x7f;
1415
1416 if (num == 0)
1417 return 0;
1418
1419 num++;
1420 pefc->asks = ipmi_mem_alloc(sizeof(ipmi_ask_t) * num);
1421 if (!pefc->asks)
1422 return ENOMEM;
1423
1424 pefc->alert_strings = ipmi_mem_alloc(sizeof(unsigned char *) * num);
1425 if (!pefc->alert_strings) {
1426 ipmi_mem_free(pefc->asks);
1427 pefc->asks = NULL;
1428 return ENOMEM;
1429 }
1430
1431 memset(pefc->alert_strings, 0, sizeof(unsigned char *) * num);
1432 pefc->num_alert_strings = num;
1433
1434 return 0;
1435 }
1436
1437 /* Alert String Keys */
gask(ipmi_pef_config_t * pefc,pefparms_t * lp,int err,unsigned char * data,unsigned int data_len)1438 static int gask(ipmi_pef_config_t *pefc, pefparms_t *lp, int err,
1439 unsigned char *data, unsigned int data_len)
1440 {
1441 int pos;
1442 ipmi_ask_t *t;
1443
1444 data++; /* Skip the revision byte. */
1445 pos = data[0] & 0x7f;
1446
1447 if (err)
1448 return err;
1449 if (pos >= pefc->num_alert_strings)
1450 return 0; /* Another error check will get this later. */
1451
1452 t = &(pefc->asks[pos]);
1453
1454 t->event_filter = data[1] & 0x7f;
1455 t->alert_string_set = data[2] & 0x7f;
1456
1457 return 0;
1458 }
1459
1460 /* Comes in with position in data[0]. */
sask(ipmi_pef_config_t * pefc,pefparms_t * lp,unsigned char * data,unsigned int * data_len)1461 static void sask(ipmi_pef_config_t *pefc, pefparms_t *lp, unsigned char *data,
1462 unsigned int *data_len)
1463 {
1464 int pos = data[0] & 0x7f;
1465 ipmi_ask_t *t = &(pefc->asks[pos]);
1466
1467 data[1] = t->event_filter;
1468 data[2] = t->alert_string_set;
1469 }
1470
1471 /* Alert Strings */
gas(ipmi_pef_config_t * pefc,pefparms_t * lp,int err,unsigned char * data,unsigned int data_len)1472 static int gas(ipmi_pef_config_t *pefc, pefparms_t *lp, int err,
1473 unsigned char *data, unsigned int data_len)
1474 {
1475 int pos;
1476 char **t;
1477 char *s1, *s2;
1478 int len;
1479
1480 data++; /* Skip the revision byte. */
1481 data_len--;
1482 pos = data[0] & 0x7f;
1483 t = &(pefc->alert_strings[pos]);
1484
1485 if (err)
1486 return err;
1487 if (pos >= pefc->num_alert_strings)
1488 return 0; /* Another error check will get this later. */
1489 if (data_len-3 == 0)
1490 return 0;
1491
1492 data += 2;
1493 data_len -= 2;
1494
1495 /* We fetch the blocks successively, so just appending is all that
1496 is necessary. The actual block check is done later. The
1497 string in nil terminated (per the spec), so no worries about
1498 zeros, either. */
1499 s1 = *t;
1500 if (s1)
1501 len = strlen((char *) s1);
1502 else
1503 len = 0;
1504 s2 = ipmi_mem_alloc(len + data_len + 1);
1505 if (!s2)
1506 return ENOMEM;
1507
1508 if (s1)
1509 memcpy(s2, s1, len);
1510 memcpy(s2+len, data, data_len);
1511 s2[len+data_len] = '\0';
1512
1513 *t = s2;
1514 if (s1)
1515 ipmi_mem_free(s1);
1516
1517 return 0;
1518 }
1519
1520 /* Comes in with position in data[0], block in data[1]. */
sas(ipmi_pef_config_t * pefc,pefparms_t * lp,unsigned char * data,unsigned int * data_len)1521 static void sas(ipmi_pef_config_t *pefc, pefparms_t *lp, unsigned char *data,
1522 unsigned int *data_len)
1523 {
1524 int pos = data[0] & 0x7f;
1525 int block = data[1];
1526 char *t = pefc->alert_strings[pos];
1527 int len;
1528
1529 if (!t) {
1530 data[2] = '\0';
1531 *data_len = 3;
1532 return;
1533 }
1534
1535 t += ((block-1) * 16);
1536 len = strlen(t);
1537 if (len >= 16) {
1538 memcpy(data+2, t, 16);
1539 *data_len = 18;
1540 } else {
1541 memcpy(data+2, t, len+1); /* Make sure to include the nil */
1542 *data_len = len + 2 + 1;
1543 }
1544 }
1545
1546 #define OFFSET_OF(x) (((unsigned char *) &(((ipmi_pef_config_t *) NULL)->x)) \
1547 - ((unsigned char *) NULL))
1548
1549 #define NUM_PEFPARMS 20
1550 static pefparms_t pefparms[NUM_PEFPARMS] =
1551 {
1552 { 0, 0, 0, 0, NULL, NULL }, /* IPMI_PEFPARM_SET_IN_PROGRESS */
1553 { 1, 0, 0, 1, gctl, sctl }, /* IPMI_PERPARM_CONTROL */
1554 { 1, 0, 0, 1, gagc, sagc }, /* IPMI_PEFPARM_ACTION_GLOBAL_CONTROL */
1555 #undef S
1556 #define S OFFSET_OF(startup_delay_supported)
1557 { 1, S, 0, 1, gsd, ssd }, /* IPMI_PEFPARM_STARTUP_DELAY */
1558 #undef S
1559 #define S OFFSET_OF(alert_startup_delay_supported)
1560 { 1, S, 0, 1, gasd, sasd }, /* IPMI_PEFPARM_ALERT_STARTUP_DELAY */
1561 { 1, 0, 0, 1, gnef, NULL }, /* IPMI_PEFPARM_NUM_EVENT_FILTERS */
1562 { 1, 0, 0, 21, geft, seft }, /* IPMI_PEFPARM_EVENT_FILTER_TABLE */
1563 { 0, 0, 0, 0, NULL, NULL }, /* IPMI_PEFPARM_EVENT_FILTER_TABLE_DATA1 */
1564 { 1, 0, 0, 1, gnap, NULL }, /* IPMI_PEFPARM_NUM_ALERT_POLICIES */
1565 { 1, 0, 0, 4, gapt, sapt }, /* IPMI_PEFPARM_ALERT_POLICY_TABLE */
1566 { 1, 0, 0, 17, gsg, ssg }, /* IPMI_PEFPARM_SYSTEM_GUID */
1567 { 1, 0, 0, 1, gnas, NULL }, /* IPMI_PEFPARM_NUM_ALERT_STRINGS */
1568 { 1, 0, 0, 3, gask, sask }, /* IPMI_PEFPARM_ALERT_STRING_KEY */
1569 { 1, 0, 0, 18, gas, sas }, /* IPMI_PEFPARM_ALERT_STRING */
1570 };
1571
1572 static void
err_lock_cleared(ipmi_pef_t * pef,int err,void * cb_data)1573 err_lock_cleared(ipmi_pef_t *pef,
1574 int err,
1575 void *cb_data)
1576 {
1577 ipmi_pef_config_t *pefc = cb_data;
1578
1579 pefc->done(pef, pefc->err, NULL, pefc->cb_data);
1580 ipmi_pef_free_config(pefc);
1581 pef_put(pef);
1582 }
1583
1584 static void
got_parm(ipmi_pef_t * pef,int err,unsigned char * data,unsigned int data_len,void * cb_data)1585 got_parm(ipmi_pef_t *pef,
1586 int err,
1587 unsigned char *data,
1588 unsigned int data_len,
1589 void *cb_data)
1590 {
1591 ipmi_pef_config_t *pefc = cb_data;
1592 pefparms_t *lp = &(pefparms[pefc->curr_parm]);
1593
1594 /* Check the length, and don't forget the revision byte must be added. */
1595 if ((!err) && (data_len < (unsigned int) (lp->length+1))) {
1596 ipmi_log(IPMI_LOG_ERR_INFO,
1597 "ipmi_pefparm_got_parm:"
1598 " Invalid data length on parm %d was %d, should have been %d",
1599 pefc->curr_parm, data_len, lp->length+1);
1600 err = EINVAL;
1601 goto done;
1602 }
1603
1604 err = lp->get_handler(pefc, lp, err, data, data_len);
1605 if (err) {
1606 ipmi_log(IPMI_LOG_ERR_INFO,
1607 "ipmi_pefparm_got_parm: Error fetching parm %d: %x",
1608 pefc->curr_parm, err);
1609 goto done;
1610 }
1611
1612 next_parm:
1613 switch (pefc->curr_parm) {
1614 case IPMI_PEFPARM_NUM_EVENT_FILTERS:
1615 pefc->curr_parm++;
1616 if (pefc->num_event_filters == 0)
1617 pefc->curr_parm = IPMI_PEFPARM_NUM_ALERT_POLICIES;
1618 else
1619 pefc->curr_sel = 1;
1620 break;
1621
1622 case IPMI_PEFPARM_EVENT_FILTER_TABLE:
1623 if ((data[1] & 0x7f) != pefc->curr_sel) {
1624 /* Yikes, wrong selector came back! */
1625 ipmi_log(IPMI_LOG_ERR_INFO,
1626 "ipmi_pefparm_got_parm: Error fetching eft %d,"
1627 " wrong selector came back, expecting %d, was %d",
1628 pefc->curr_parm, pefc->curr_sel, data[1] & 0x7f);
1629 err = EINVAL;
1630 goto done;
1631 }
1632 pefc->curr_sel++;
1633 if (pefc->curr_sel > pefc->num_event_filters) {
1634 pefc->curr_parm++;
1635 pefc->curr_sel = 0;
1636 }
1637 break;
1638
1639 case IPMI_PEFPARM_NUM_ALERT_POLICIES:
1640 pefc->curr_parm++;
1641 if (pefc->num_alert_policies == 0)
1642 pefc->curr_parm = IPMI_PEFPARM_NUM_ALERT_STRINGS;
1643 else
1644 pefc->curr_sel = 1;
1645 break;
1646
1647 case IPMI_PEFPARM_ALERT_POLICY_TABLE:
1648 if ((data[1] & 0x7f) != pefc->curr_sel) {
1649 /* Yikes, wrong selector came back! */
1650 ipmi_log(IPMI_LOG_ERR_INFO,
1651 "ipmi_pefparm_got_parm: Error fetching apt %d,"
1652 " wrong selector came back, expecting %d, was %d",
1653 pefc->curr_parm, pefc->curr_sel, data[1] & 0x7f);
1654 err = EINVAL;
1655 goto done;
1656 }
1657 pefc->curr_sel++;
1658 if (pefc->curr_sel > pefc->num_alert_policies) {
1659 pefc->curr_parm++;
1660 pefc->curr_sel = 0;
1661 }
1662 break;
1663
1664 case IPMI_PEFPARM_NUM_ALERT_STRINGS:
1665 pefc->curr_parm++;
1666 if (pefc->num_alert_strings == 0)
1667 goto done;
1668 pefc->curr_sel = 0;
1669 break;
1670
1671 case IPMI_PEFPARM_ALERT_STRING_KEY:
1672 if ((data[1] & 0x7f) != pefc->curr_sel) {
1673 /* Yikes, wrong selector came back! */
1674 ipmi_log(IPMI_LOG_ERR_INFO,
1675 "ipmi_pefparm_got_parm: Error fetching ask %d,"
1676 " wrong selector came back, expecting %d, was %d",
1677 pefc->curr_parm, pefc->curr_sel, data[1] & 0x7f);
1678 err = EINVAL;
1679 goto done;
1680 }
1681 pefc->curr_sel++;
1682 if (pefc->curr_sel >= pefc->num_alert_strings) {
1683 pefc->curr_parm++;
1684 pefc->curr_sel = 0;
1685 pefc->curr_block = 1;
1686 }
1687 break;
1688
1689 case IPMI_PEFPARM_ALERT_STRING:
1690 if ((data[1] & 0x7f) != pefc->curr_sel) {
1691 /* Yikes, wrong selector came back! */
1692 ipmi_log(IPMI_LOG_ERR_INFO,
1693 "ipmi_pefparm_got_parm: Error fetching ask %d,"
1694 " wrong selector came back, expecting %d, was %d",
1695 pefc->curr_parm, pefc->curr_sel, data[1] & 0x7f);
1696 err = EINVAL;
1697 goto done;
1698 }
1699 if (data[2] != pefc->curr_block) {
1700 /* Yikes, wrong block came back! */
1701 ipmi_log(IPMI_LOG_ERR_INFO,
1702 "ipmi_pefparm_got_parm: Error fetching ask %d,"
1703 " wrong block came back, expecting %d, was %d",
1704 pefc->curr_parm, pefc->curr_block, data[2]);
1705 err = EINVAL;
1706 goto done;
1707 }
1708 if ((data_len < 19) ||
1709 (memchr(data+3, '\0', data_len-3)))
1710 {
1711 /* End of string, either a subsize-block or a nil
1712 character in the data. */
1713 pefc->curr_sel++;
1714 pefc->curr_block = 1;
1715 if (pefc->curr_sel >= pefc->num_alert_strings)
1716 goto done;
1717 } else {
1718 /* Not at the end yet. */
1719 pefc->curr_block++;
1720 }
1721 break;
1722
1723 default:
1724 pefc->curr_parm++;
1725 }
1726
1727 lp = &(pefparms[pefc->curr_parm]);
1728 if (!lp->valid)
1729 goto next_parm;
1730
1731 err = ipmi_pef_get_parm(pef, pefc->curr_parm, pefc->curr_sel,
1732 pefc->curr_block, got_parm, pefc);
1733 if (err)
1734 goto done;
1735
1736 return;
1737
1738 done:
1739 if (err) {
1740 unsigned char data[1];
1741
1742 ipmi_log(IPMI_LOG_ERR_INFO,
1743 "pef.c(got_parm): Error trying to get parm %d: %x",
1744 pefc->curr_parm, err);
1745 pefc->err = err;
1746 /* Clear the lock */
1747 data[0] = 0;
1748 err = ipmi_pef_set_parm(pef, 0, data, 1, err_lock_cleared, pefc);
1749 if (err) {
1750 ipmi_log(IPMI_LOG_ERR_INFO,
1751 "pef.c(got_parm): Error trying to clear lock: %x",
1752 err);
1753 pefc->done(pef, pefc->err, NULL, pefc->cb_data);
1754 ipmi_pef_free_config(pefc);
1755 pef_put(pef);
1756 }
1757 } else {
1758 pefc->done(pef, 0, pefc, pefc->cb_data);
1759 pef_put(pef);
1760 }
1761 }
1762
1763 static void
lock_done(ipmi_pef_t * pef,int err,void * cb_data)1764 lock_done(ipmi_pef_t *pef,
1765 int err,
1766 void *cb_data)
1767 {
1768 ipmi_pef_config_t *pefc = cb_data;
1769 int rv;
1770
1771 if (err == IPMI_IPMI_ERR_VAL(0x80)) {
1772 /* Lock is not supported, just mark it and go on. */
1773 pefc->lock_supported = 0;
1774 } else if (err == IPMI_IPMI_ERR_VAL(0x81)) {
1775 /* Someone else has the lock, return EAGAIN. */
1776 pefc->done(pef, EAGAIN, NULL, pefc->cb_data);
1777 ipmi_pef_free_config(pefc);
1778 pef_put(pef);
1779 return;
1780 } else if (err) {
1781 ipmi_log(IPMI_LOG_ERR_INFO,
1782 "pef.c(lock_done): Error trying to lock the PEF"
1783 " parms: %x",
1784 err);
1785 pefc->done(pef, err, NULL, pefc->cb_data);
1786 ipmi_pef_free_config(pefc);
1787 pef_put(pef);
1788 return;
1789 }
1790
1791 pefc->pef_locked = 1;
1792
1793 rv = ipmi_pef_get_parm(pef, pefc->curr_parm, pefc->curr_sel, 0,
1794 got_parm, pefc);
1795 if (rv) {
1796 unsigned char data[1];
1797
1798 ipmi_log(IPMI_LOG_ERR_INFO,
1799 "pef.c(lock_done): Error trying to get parm %d: %x",
1800 pefc->curr_parm, rv);
1801 pefc->err = rv;
1802 /* Clear the lock */
1803 data[0] = 0;
1804 rv = ipmi_pef_set_parm(pef, 0, data, 1, err_lock_cleared, pefc);
1805 if (rv) {
1806 ipmi_log(IPMI_LOG_ERR_INFO,
1807 "pef.c(lock_done): Error trying to clear lock: %x",
1808 err);
1809 pefc->done(pef, pefc->err, NULL, pefc->cb_data);
1810 ipmi_pef_free_config(pefc);
1811 pef_put(pef);
1812 }
1813 }
1814 }
1815
ipmi_pef_get_config(ipmi_pef_t * pef,ipmi_pef_get_config_cb done,void * cb_data)1816 int ipmi_pef_get_config(ipmi_pef_t *pef,
1817 ipmi_pef_get_config_cb done,
1818 void *cb_data)
1819 {
1820 ipmi_pef_config_t *pefc;
1821 int rv;
1822 unsigned char data[1];
1823
1824 pefc = ipmi_mem_alloc(sizeof(*pefc));
1825 if (!pefc)
1826 return ENOMEM;
1827 memset(pefc, 0, sizeof(*pefc));
1828
1829 pefc->curr_parm = 1;
1830 pefc->curr_sel = 0;
1831 pefc->done = done;
1832 pefc->cb_data = cb_data;
1833 pefc->my_pef = pef;
1834 pefc->lock_supported = 1; /* Assume it works. */
1835
1836 /* First grab the lock */
1837 data[0] = 1; /* Set in progress. */
1838 pef_get(pef);
1839 rv = ipmi_pef_set_parm(pef, 0, data, 1, lock_done, pefc);
1840 if (rv) {
1841 ipmi_pef_free_config(pefc);
1842 pef_put(pef);
1843 }
1844
1845 return rv;
1846 }
1847
1848 static void
set_clear(ipmi_pef_t * pef,int err,void * cb_data)1849 set_clear(ipmi_pef_t *pef,
1850 int err,
1851 void *cb_data)
1852 {
1853 ipmi_pef_config_t *pefc = cb_data;
1854
1855 if (pefc->err)
1856 err = pefc->err;
1857 if (pefc->set_done)
1858 pefc->set_done(pef, err, pefc->cb_data);
1859 ipmi_pef_free_config(pefc);
1860 pef_put(pef);
1861 }
1862
1863 static void
commit_done(ipmi_pef_t * pef,int err,void * cb_data)1864 commit_done(ipmi_pef_t *pef,
1865 int err,
1866 void *cb_data)
1867 {
1868 ipmi_pef_config_t *pefc = cb_data;
1869 unsigned char data[1];
1870 int rv;
1871
1872 /* Note that we ignore the error. The commit done is optional,
1873 and must return an error if it is optional, so we just ignore
1874 the error and clear the field here. */
1875
1876 /* Commit is done. The IPMI spec says that it goes into the
1877 set-in-progress state after this, so we need to clear it. */
1878
1879 data[0] = 0;
1880 rv = ipmi_pef_set_parm(pef, 0, data, 1, set_clear, pefc);
1881 if (rv) {
1882 ipmi_log(IPMI_LOG_WARNING,
1883 "pef.c(commit_done): Error trying to clear the set in"
1884 " progress: %x",
1885 rv);
1886 set_clear(pef, rv, pefc);
1887 }
1888 }
1889
1890 static void
set_done(ipmi_pef_t * pef,int err,void * cb_data)1891 set_done(ipmi_pef_t *pef,
1892 int err,
1893 void *cb_data)
1894 {
1895 ipmi_pef_config_t *pefc = cb_data;
1896 unsigned char data[MAX_IPMI_DATA_SIZE] = { 0, 0 };
1897 pefparms_t *lp = &(pefparms[pefc->curr_parm]);
1898 unsigned int length;
1899
1900 if (err) {
1901 ipmi_log(IPMI_LOG_ERR_INFO,
1902 "Error setting PEF parm %d: %x", pefc->curr_parm, err);
1903 goto done;
1904 }
1905
1906 next_parm:
1907 switch (pefc->curr_parm) {
1908 case IPMI_PEFPARM_NUM_EVENT_FILTERS:
1909 pefc->curr_parm++;
1910 if (pefc->num_event_filters == 0)
1911 pefc->curr_parm = IPMI_PEFPARM_NUM_ALERT_POLICIES;
1912 else {
1913 pefc->curr_sel = 1;
1914 data[0] = pefc->curr_sel;
1915 }
1916 break;
1917
1918 case IPMI_PEFPARM_EVENT_FILTER_TABLE:
1919 pefc->curr_sel++;
1920 if (pefc->curr_sel > pefc->num_event_filters) {
1921 pefc->curr_parm++;
1922 pefc->curr_sel = 1;
1923 }
1924 data[0] = pefc->curr_sel;
1925 break;
1926
1927 case IPMI_PEFPARM_NUM_ALERT_POLICIES:
1928 pefc->curr_parm++;
1929 if (pefc->num_event_filters == 0)
1930 pefc->curr_parm = IPMI_PEFPARM_NUM_ALERT_STRINGS;
1931 else {
1932 pefc->curr_sel = 1;
1933 data[0] = pefc->curr_sel;
1934 }
1935 break;
1936
1937 case IPMI_PEFPARM_ALERT_POLICY_TABLE:
1938 pefc->curr_sel++;
1939 if (pefc->curr_sel > pefc->num_alert_policies) {
1940 pefc->curr_parm++;
1941 pefc->curr_sel = 0;
1942 }
1943 data[0] = pefc->curr_sel;
1944 break;
1945
1946 case IPMI_PEFPARM_NUM_ALERT_STRINGS:
1947 pefc->curr_parm++;
1948 if (pefc->num_alert_strings == 0)
1949 goto done;
1950 pefc->curr_sel = 0;
1951 data[0] = pefc->curr_sel;
1952 break;
1953
1954 case IPMI_PEFPARM_ALERT_STRING_KEY:
1955 pefc->curr_sel++;
1956 if (pefc->curr_sel >= pefc->num_alert_strings) {
1957 pefc->curr_parm++;
1958 pefc->curr_sel = 0;
1959 pefc->curr_block = 1;
1960 data[1] = pefc->curr_block;
1961 }
1962 data[0] = pefc->curr_sel;
1963 break;
1964
1965 case IPMI_PEFPARM_ALERT_STRING:
1966 /* curr_sel increment is done right after the send formatting,
1967 because we don't know until there if it's the end of the
1968 string. */
1969 if (pefc->curr_sel >= pefc->num_alert_strings)
1970 goto done;
1971 data[0] = pefc->curr_sel;
1972 data[1] = pefc->curr_block;
1973 break;
1974
1975 default:
1976 pefc->curr_parm++;
1977 }
1978
1979 lp = &(pefparms[pefc->curr_parm]);
1980 if ((!lp->valid) || (lp->set_handler == NULL)
1981 || (lp->optional_offset
1982 && !(((unsigned char *) pefc)[lp->optional_offset])))
1983 {
1984 /* The parameter is read-only or not supported, just go on. */
1985 goto next_parm;
1986 }
1987
1988 length = lp->length;
1989 lp->set_handler(pefc, lp, data, &length);
1990 err = ipmi_pef_set_parm(pef, pefc->curr_parm,
1991 data, length, set_done, pefc);
1992 if (err)
1993 goto done;
1994
1995 if (pefc->curr_parm == IPMI_PEFPARM_ALERT_STRING) {
1996 /* Special handling for blocks of an alert string */
1997 if ((length < 18) ||
1998 (memchr(data+2, '\0', length-2)))
1999 {
2000 /* End of string, either a subsize-block or a nil
2001 character in the data. */
2002 pefc->curr_sel++;
2003 pefc->curr_block = 1;
2004 } else {
2005 pefc->curr_block++;
2006 }
2007 }
2008 return;
2009
2010 done:
2011 if (!pefc->lock_supported) {
2012 /* No lock support, just finish the operation. */
2013 set_clear(pef, err, pefc);
2014 return;
2015 } else if (err) {
2016 data[0] = 0; /* Don't commit the parameters. */
2017 pefc->err = err;
2018 err = ipmi_pef_set_parm(pef, 0, data, 1, set_clear, pefc);
2019 } else {
2020 data[0] = 2; /* Commit the parameters. */
2021 err = ipmi_pef_set_parm(pef, 0, data, 1, commit_done, pefc);
2022 }
2023 if (err) {
2024 ipmi_log(IPMI_LOG_WARNING,
2025 "pef.c(got_parm): Error trying to clear the set in"
2026 " progress: %x",
2027 err);
2028 set_clear(pef, err, pefc);
2029 }
2030 }
2031
2032 int
ipmi_pef_set_config(ipmi_pef_t * pef,ipmi_pef_config_t * opefc,ipmi_pef_done_cb done,void * cb_data)2033 ipmi_pef_set_config(ipmi_pef_t *pef,
2034 ipmi_pef_config_t *opefc,
2035 ipmi_pef_done_cb done,
2036 void *cb_data)
2037 {
2038 ipmi_pef_config_t *pefc;
2039 unsigned char data[MAX_IPMI_DATA_SIZE];
2040 int rv;
2041 int i;
2042 pefparms_t *lp;
2043 unsigned int length;
2044
2045 if (opefc->my_pef != pef)
2046 return EINVAL;
2047
2048 if (!opefc->pef_locked)
2049 return EINVAL;
2050
2051 pefc = ipmi_mem_alloc(sizeof(*pefc));
2052 if (!pefc)
2053 return ENOMEM;
2054
2055 *pefc = *opefc;
2056 pefc->efts = NULL;
2057 pefc->apts = NULL;
2058 pefc->asks = NULL;
2059 pefc->alert_strings = NULL;
2060 pefc->err = 0;
2061 pefc->pef_locked = 0; /* Set this here, since we will unlock it,
2062 but we don't want the free operation to
2063 attempt an unlock */
2064
2065 if (pefc->num_event_filters) {
2066 pefc->efts = ipmi_mem_alloc(sizeof(ipmi_eft_t)
2067 * pefc->num_event_filters);
2068 if (!pefc->efts) {
2069 rv = ENOMEM;
2070 goto out;
2071 }
2072 memcpy(pefc->efts, opefc->efts,
2073 sizeof(ipmi_eft_t) * pefc->num_event_filters);
2074 }
2075
2076 if (pefc->num_alert_policies) {
2077 pefc->apts = ipmi_mem_alloc(sizeof(ipmi_apt_t)
2078 * pefc->num_alert_policies);
2079 if (!pefc->apts) {
2080 rv = ENOMEM;
2081 goto out;
2082 }
2083 memcpy(pefc->apts, opefc->apts,
2084 sizeof(ipmi_apt_t) * pefc->num_alert_policies);
2085 }
2086
2087 if (pefc->num_alert_strings) {
2088 pefc->asks = ipmi_mem_alloc(sizeof(ipmi_ask_t)
2089 * pefc->num_alert_strings);
2090 if (!pefc->asks) {
2091 rv = ENOMEM;
2092 goto out;
2093 }
2094 memcpy(pefc->asks, opefc->asks,
2095 sizeof(ipmi_ask_t) * pefc->num_alert_strings);
2096
2097 pefc->alert_strings = ipmi_mem_alloc(sizeof(unsigned char *)
2098 * pefc->num_alert_strings);
2099 if (!pefc->alert_strings) {
2100 rv = ENOMEM;
2101 goto out;
2102 }
2103 memset(pefc->alert_strings, 0,
2104 sizeof(unsigned char *) * pefc->num_alert_strings);
2105
2106 for (i=0; i<pefc->num_alert_strings; i++) {
2107 if (!opefc->alert_strings[i])
2108 continue;
2109 pefc->alert_strings[i] = ipmi_strdup(opefc->alert_strings[i]);
2110 if (!pefc->alert_strings[i]) {
2111 rv = ENOMEM;
2112 goto out;
2113 }
2114 }
2115 }
2116
2117 /* We know that parm 1 is valid an non-optional, so we just set it. */
2118 pefc->curr_parm = 1;
2119 pefc->curr_sel = 0;
2120 pefc->curr_block = 0;
2121 pefc->set_done = done;
2122 pefc->cb_data = cb_data;
2123
2124 lp = &(pefparms[pefc->curr_parm]);
2125 length = lp->length;
2126 lp->set_handler(pefc, lp, data, &length);
2127 pef_get(pef);
2128 rv = ipmi_pef_set_parm(pef, pefc->curr_parm, data, length, set_done, pefc);
2129 if (rv)
2130 pef_put(pef);
2131 out:
2132 if (rv) {
2133 ipmi_pef_free_config(pefc);
2134 } else {
2135 /* The old config no longer holds the lock. */
2136 opefc->pef_locked = 0;
2137 }
2138 return rv;
2139 }
2140
2141 typedef struct clear_lock_s
2142 {
2143 ipmi_pef_done_cb done;
2144 void *cb_data;
2145
2146 } clear_lock_t;
2147
2148 static void
lock_cleared(ipmi_pef_t * pef,int err,void * cb_data)2149 lock_cleared(ipmi_pef_t *pef,
2150 int err,
2151 void *cb_data)
2152 {
2153 clear_lock_t *cl = cb_data;
2154
2155 if (cl->done)
2156 cl->done(pef, err, cl->cb_data);
2157
2158 ipmi_mem_free(cl);
2159 pef_put(pef);
2160 }
2161
2162 int
ipmi_pef_clear_lock(ipmi_pef_t * pef,ipmi_pef_config_t * pefc,ipmi_pef_done_cb done,void * cb_data)2163 ipmi_pef_clear_lock(ipmi_pef_t *pef,
2164 ipmi_pef_config_t *pefc,
2165 ipmi_pef_done_cb done,
2166 void *cb_data)
2167 {
2168 unsigned char data[1];
2169 int rv;
2170 clear_lock_t *cl;
2171
2172 if (pefc) {
2173 if (pefc->my_pef != pef)
2174 return EINVAL;
2175
2176 if (!pefc->pef_locked)
2177 return EINVAL;
2178 }
2179
2180 cl = ipmi_mem_alloc(sizeof(*cl));
2181 if (!cl)
2182 return ENOMEM;
2183 cl->done = done;
2184 cl->cb_data = cb_data;
2185
2186 data[0] = 0; /* Clear the lock. */
2187 pef_get(pef);
2188 rv = ipmi_pef_set_parm(pef, 0, data, 1, lock_cleared, cl);
2189 if (rv) {
2190 pef_put(pef);
2191 ipmi_mem_free(cl);
2192 } else if (pefc) {
2193 pefc->pef_locked = 0;
2194 }
2195
2196 return rv;
2197 }
2198
2199 void
ipmi_pef_free_config(ipmi_pef_config_t * pefc)2200 ipmi_pef_free_config(ipmi_pef_config_t *pefc)
2201 {
2202 int i;
2203
2204 if (pefc->efts)
2205 ipmi_mem_free(pefc->efts);
2206 if (pefc->apts)
2207 ipmi_mem_free(pefc->apts);
2208 if (pefc->asks)
2209 ipmi_mem_free(pefc->asks);
2210 if (pefc->alert_strings) {
2211 for (i=0; i<pefc->num_alert_strings; i++) {
2212 if (pefc->alert_strings[i])
2213 ipmi_mem_free(pefc->alert_strings[i]);
2214 }
2215 ipmi_mem_free(pefc->alert_strings);
2216 }
2217 ipmi_mem_free(pefc);
2218 }
2219
2220 #define PEF_BIT(n) \
2221 unsigned int \
2222 ipmi_pefconfig_get_ ## n(ipmi_pef_config_t *pefc) \
2223 { \
2224 return pefc->n; \
2225 } \
2226 int \
2227 ipmi_pefconfig_set_ ## n(ipmi_pef_config_t *pefc, unsigned int val) \
2228 { \
2229 pefc->n = (val != 0); \
2230 return 0; \
2231 }
2232
2233 PEF_BIT(alert_startup_delay_enabled)
2234 PEF_BIT(startup_delay_enabled)
2235 PEF_BIT(event_messages_enabled)
2236 PEF_BIT(pef_enabled)
2237 PEF_BIT(diagnostic_interrupt_enabled)
2238 PEF_BIT(oem_action_enabled)
2239 PEF_BIT(power_cycle_enabled)
2240 PEF_BIT(reset_enabled)
2241 PEF_BIT(power_down_enabled)
2242 PEF_BIT(alert_enabled)
2243
2244 #define PEF_BYTE_SUPPORT(n) \
2245 int \
2246 ipmi_pefconfig_get_ ## n(ipmi_pef_config_t *pefc, unsigned int *val) \
2247 { \
2248 if (!pefc->n ## _supported) \
2249 return ENOSYS; \
2250 *val = pefc->n; \
2251 return 0; \
2252 } \
2253 int \
2254 ipmi_pefconfig_set_ ## n(ipmi_pef_config_t *pefc, unsigned int val) \
2255 { \
2256 if (!pefc->n ## _supported) \
2257 return ENOSYS; \
2258 pefc->n = val; \
2259 return 0; \
2260 }
2261
2262 PEF_BYTE_SUPPORT(startup_delay);
2263 PEF_BYTE_SUPPORT(alert_startup_delay);
2264
2265 PEF_BIT(guid_enabled);
2266
2267 int
ipmi_pefconfig_get_guid_val(ipmi_pef_config_t * pefc,unsigned char * data,unsigned int * data_len)2268 ipmi_pefconfig_get_guid_val(ipmi_pef_config_t *pefc,
2269 unsigned char *data,
2270 unsigned int *data_len)
2271 {
2272 if (*data_len < 16) {
2273 *data_len = 16;
2274 return EBADF;
2275 }
2276 memcpy(data, pefc->guid, 16);
2277 *data_len = 16;
2278 return 0;
2279 }
2280
2281 int
ipmi_pefconfig_set_guid_val(ipmi_pef_config_t * pefc,unsigned char * data,unsigned int data_len)2282 ipmi_pefconfig_set_guid_val(ipmi_pef_config_t *pefc,
2283 unsigned char *data,
2284 unsigned int data_len)
2285 {
2286 if (data_len != 16)
2287 return EINVAL;
2288 memcpy(pefc->guid, data, 16);
2289 return 0;
2290 }
2291
2292 int
ipmi_pefconfig_get_guid(ipmi_pef_config_t * pefc,unsigned int * enabled,unsigned char * data,unsigned int * data_len)2293 ipmi_pefconfig_get_guid(ipmi_pef_config_t *pefc,
2294 unsigned int *enabled,
2295 unsigned char *data,
2296 unsigned int *data_len)
2297 {
2298 if (*data_len <= 16)
2299 return EINVAL;
2300 memcpy(data, pefc->guid, 16);
2301 *enabled = pefc->guid_enabled;
2302 *data_len = 16;
2303 return 0;
2304 }
2305
2306 int
ipmi_pefconfig_set_guid(ipmi_pef_config_t * pefc,unsigned int enabled,unsigned char * data,unsigned int data_len)2307 ipmi_pefconfig_set_guid(ipmi_pef_config_t *pefc, unsigned int enabled,
2308 unsigned char *data, unsigned int data_len)
2309 {
2310 if (data_len != 16)
2311 return EINVAL;
2312 pefc->guid_enabled = enabled;
2313 memcpy(pefc->guid, data, 16);
2314 return 0;
2315 }
2316
2317 unsigned int
ipmi_pefconfig_get_num_event_filters(ipmi_pef_config_t * pefc)2318 ipmi_pefconfig_get_num_event_filters(ipmi_pef_config_t *pefc)
2319 {
2320 return pefc->num_event_filters;
2321 }
2322 unsigned int
ipmi_pefconfig_get_num_alert_policies(ipmi_pef_config_t * pefc)2323 ipmi_pefconfig_get_num_alert_policies(ipmi_pef_config_t *pefc)
2324 {
2325 return pefc->num_alert_policies;
2326 }
2327 unsigned int
ipmi_pefconfig_get_num_alert_strings(ipmi_pef_config_t * pefc)2328 ipmi_pefconfig_get_num_alert_strings(ipmi_pef_config_t *pefc)
2329 {
2330 return pefc->num_alert_strings;
2331 }
2332
2333 #define PEF_SUB_BIT(t, c, n) \
2334 int \
2335 ipmi_pefconfig_get_ ## n(ipmi_pef_config_t *pefc, unsigned int sel, \
2336 unsigned int *val) \
2337 { \
2338 if (sel >= pefc->c) \
2339 return EINVAL; \
2340 *val = pefc->t[sel].n; \
2341 return 0; \
2342 } \
2343 int \
2344 ipmi_pefconfig_set_ ## n(ipmi_pef_config_t *pefc, unsigned int sel, \
2345 unsigned int val) \
2346 { \
2347 if (sel >= pefc->c) \
2348 return EINVAL; \
2349 pefc->t[sel].n = (val != 0); \
2350 return 0; \
2351 }
2352
2353 #define PEF_SUB_BYTE(t, c, n) \
2354 int \
2355 ipmi_pefconfig_get_ ## n(ipmi_pef_config_t *pefc, unsigned int sel, \
2356 unsigned int *val) \
2357 { \
2358 if (sel >= pefc->c) \
2359 return EINVAL; \
2360 *val = pefc->t[sel].n; \
2361 return 0; \
2362 } \
2363 int \
2364 ipmi_pefconfig_set_ ## n(ipmi_pef_config_t *pefc, unsigned int sel, \
2365 unsigned int val) \
2366 { \
2367 if (sel >= pefc->c) \
2368 return EINVAL; \
2369 pefc->t[sel].n = val; \
2370 return 0; \
2371 }
2372
2373 PEF_SUB_BIT(efts, num_event_filters, enable_filter);
2374 PEF_SUB_BYTE(efts, num_event_filters, filter_type);
2375 PEF_SUB_BIT(efts, num_event_filters, diagnostic_interrupt);
2376 PEF_SUB_BIT(efts, num_event_filters, oem_action);
2377 PEF_SUB_BIT(efts, num_event_filters, power_cycle);
2378 PEF_SUB_BIT(efts, num_event_filters, reset);
2379 PEF_SUB_BIT(efts, num_event_filters, power_down);
2380 PEF_SUB_BIT(efts, num_event_filters, alert);
2381 PEF_SUB_BYTE(efts, num_event_filters, alert_policy_number);
2382 PEF_SUB_BYTE(efts, num_event_filters, event_severity);
2383 PEF_SUB_BYTE(efts, num_event_filters, generator_id_addr);
2384 PEF_SUB_BYTE(efts, num_event_filters, generator_id_channel_lun);
2385 PEF_SUB_BYTE(efts, num_event_filters, sensor_type);
2386 PEF_SUB_BYTE(efts, num_event_filters, sensor_number);
2387 PEF_SUB_BYTE(efts, num_event_filters, event_trigger);
2388 PEF_SUB_BYTE(efts, num_event_filters, data1_offset_mask);
2389 PEF_SUB_BYTE(efts, num_event_filters, data1_mask);
2390 PEF_SUB_BYTE(efts, num_event_filters, data1_compare1);
2391 PEF_SUB_BYTE(efts, num_event_filters, data1_compare2);
2392 PEF_SUB_BYTE(efts, num_event_filters, data2_mask);
2393 PEF_SUB_BYTE(efts, num_event_filters, data2_compare1);
2394 PEF_SUB_BYTE(efts, num_event_filters, data2_compare2);
2395 PEF_SUB_BYTE(efts, num_event_filters, data3_mask);
2396 PEF_SUB_BYTE(efts, num_event_filters, data3_compare1);
2397 PEF_SUB_BYTE(efts, num_event_filters, data3_compare2);
2398
2399 PEF_SUB_BYTE(apts, num_alert_policies, policy_num);
2400 PEF_SUB_BIT(apts, num_alert_policies, enabled);
2401 PEF_SUB_BYTE(apts, num_alert_policies, policy);
2402 PEF_SUB_BYTE(apts, num_alert_policies, channel);
2403 PEF_SUB_BYTE(apts, num_alert_policies, destination_selector);
2404 PEF_SUB_BIT(apts, num_alert_policies, alert_string_event_specific);
2405 PEF_SUB_BYTE(apts, num_alert_policies, alert_string_selector);
2406
2407 PEF_SUB_BYTE(asks, num_alert_strings, event_filter);
2408 PEF_SUB_BYTE(asks, num_alert_strings, alert_string_set);
2409
2410 int
ipmi_pefconfig_get_alert_string(ipmi_pef_config_t * pefc,unsigned int sel,unsigned char * val,unsigned int * len)2411 ipmi_pefconfig_get_alert_string(ipmi_pef_config_t *pefc, unsigned int sel,
2412 unsigned char *val, unsigned int *len)
2413 {
2414 unsigned int olen = *len;
2415 unsigned int rlen;
2416
2417 if (sel >= pefc->num_alert_strings)
2418 return EINVAL;
2419 if (! pefc->alert_strings[sel]) {
2420 *len = 1;
2421 if (olen == 0)
2422 return EBADF;
2423 *val = '\0';
2424 return 0;
2425 }
2426 rlen = strlen((char *) pefc->alert_strings[sel]) + 1;
2427 *len = rlen;
2428 if (rlen > olen)
2429 return EBADF;
2430 strcpy((char *) val, pefc->alert_strings[sel]);
2431 return 0;
2432 }
2433
2434 int
ipmi_pefconfig_set_alert_string(ipmi_pef_config_t * pefc,unsigned int sel,unsigned char * val)2435 ipmi_pefconfig_set_alert_string(ipmi_pef_config_t *pefc, unsigned int sel,
2436 unsigned char *val)
2437 {
2438 unsigned char *s;
2439
2440 if (sel >= pefc->num_alert_strings)
2441 return EINVAL;
2442 s = (unsigned char *) pefc->alert_strings[sel];
2443 pefc->alert_strings[sel] = ipmi_strdup((char *) val);
2444 if (! pefc->alert_strings[sel]) {
2445 pefc->alert_strings[sel] = (char *) s;
2446 return ENOMEM;
2447 }
2448 if (s)
2449 ipmi_mem_free(s);
2450 return 0;
2451 }
2452
2453
2454 typedef struct pefparm_gendata_s
2455 {
2456 enum ipmi_pefconf_val_type_e datatype;
2457 char *fname;
2458
2459 union {
2460 struct {
2461 unsigned int (*gval)(ipmi_pef_config_t *pefc);
2462 int (*gval_v)(ipmi_pef_config_t *pefc, unsigned int *val);
2463 int (*gval_iv)(ipmi_pef_config_t *pefc, unsigned int idx,
2464 unsigned int *val);
2465 int (*sval)(ipmi_pef_config_t *pefc, unsigned int val);
2466 int (*sval_v)(ipmi_pef_config_t *pefc, unsigned int val);
2467 int (*sval_iv)(ipmi_pef_config_t *pefc, unsigned int idx,
2468 unsigned int val);
2469 } ival;
2470 struct {
2471 int (*gval_v)(ipmi_pef_config_t *pefc, unsigned char *data,
2472 unsigned int *data_len);
2473 int (*gval_iv)(ipmi_pef_config_t *pefc, unsigned int idx,
2474 unsigned char *data, unsigned int *data_len);
2475 int (*sval_v)(ipmi_pef_config_t *pefc, unsigned char *data,
2476 unsigned int data_len);
2477 int (*sval_iv)(ipmi_pef_config_t *pefc, unsigned int idx,
2478 unsigned char *data, unsigned int data_len);
2479 } dval;
2480 struct {
2481 int (*gval_v)(ipmi_pef_config_t *pefc, unsigned char *data,
2482 unsigned int *data_len);
2483 int (*gval_iv)(ipmi_pef_config_t *pefc, unsigned int idx,
2484 unsigned char *data, unsigned int *data_len);
2485 int (*sval_v)(ipmi_pef_config_t *pefc, unsigned char *data);
2486 int (*sval_iv)(ipmi_pef_config_t *pefc, unsigned int idx,
2487 unsigned char *data);
2488 } sval;
2489 } u;
2490 unsigned int (*iv_cnt)(ipmi_pef_config_t *pefc);
2491 } pefparm_gendata_t;
2492
2493 #define F_BOOLR(name) \
2494 { .datatype = IPMI_PEFCONFIG_BOOL, .fname = #name, \
2495 .u = { .ival = { .gval = ipmi_pefconfig_get_ ## name }}}
2496 #define F_BOOL(name) \
2497 { .datatype = IPMI_PEFCONFIG_BOOL, .fname = #name, \
2498 .u = { .ival = { .gval = ipmi_pefconfig_get_ ## name, \
2499 .sval = ipmi_pefconfig_set_ ## name }}}
2500 #define F_INTR(name) \
2501 { .datatype = IPMI_PEFCONFIG_INT, .fname = #name, \
2502 .u = { .ival = { .gval = ipmi_pefconfig_get_ ## name }}}
2503 #define F_INT(name) \
2504 { .datatype = IPMI_PEFCONFIG_INT, .fname = #name, \
2505 .u = { .ival = { .gval = ipmi_pefconfig_get_ ## name, \
2506 .sval = ipmi_pefconfig_set_ ## name }}}
2507 #define F_INTV(name) \
2508 { .datatype = IPMI_PEFCONFIG_INT, .fname = #name, \
2509 .u = { .ival = { .gval_v = ipmi_pefconfig_get_ ## name, \
2510 .sval_v = ipmi_pefconfig_set_ ## name }}}
2511 #define F_INTIV(name, gcnt) \
2512 { .datatype = IPMI_PEFCONFIG_INT, .fname = #name, \
2513 .u = { .ival = { .gval_iv = ipmi_pefconfig_get_ ## name, \
2514 .sval_iv = ipmi_pefconfig_set_ ## name }}, \
2515 .iv_cnt = gcnt }
2516 #define F_BOOLV(name) \
2517 { .datatype = IPMI_PEFCONFIG_BOOL, .fname = #name, \
2518 .u = { .ival = { .gval_v = ipmi_pefconfig_get_ ## name, \
2519 .sval_v = ipmi_pefconfig_set_ ## name }}}
2520 #define F_BOOLIV(name, gcnt) \
2521 { .datatype = IPMI_PEFCONFIG_BOOL, .fname = #name, \
2522 .u = { .ival = { .gval_iv = ipmi_pefconfig_get_ ## name, \
2523 .sval_iv = ipmi_pefconfig_set_ ## name }}, \
2524 .iv_cnt = gcnt }
2525 #define F_DATA(name) \
2526 { .datatype = IPMI_PEFCONFIG_DATA, .fname = #name, \
2527 .u = { .dval = { .gval_v = ipmi_pefconfig_get_ ## name, \
2528 .sval_v = ipmi_pefconfig_set_ ## name }}}
2529 #define F_STRIV(name, gcnt) \
2530 { .datatype = IPMI_PEFCONFIG_STR, .fname = #name, \
2531 .u = { .sval = { .gval_iv = ipmi_pefconfig_get_ ## name, \
2532 .sval_iv = ipmi_pefconfig_set_ ## name }}, \
2533 .iv_cnt = gcnt }
2534
2535 static pefparm_gendata_t gdata[] =
2536 {
2537 F_BOOL(alert_startup_delay_enabled), /* 0 */
2538 F_BOOL(startup_delay_enabled),
2539 F_BOOL(event_messages_enabled),
2540 F_BOOL(pef_enabled),
2541 F_BOOL(diagnostic_interrupt_enabled),
2542 F_BOOL(oem_action_enabled), /* 5 */
2543 F_BOOL(power_cycle_enabled),
2544 F_BOOL(reset_enabled),
2545 F_BOOL(power_down_enabled),
2546 F_BOOL(alert_enabled),
2547 F_INTV(startup_delay), /* 10 */
2548 F_INTV(alert_startup_delay),
2549 F_BOOL(guid_enabled),
2550 F_DATA(guid_val),
2551 F_INTR(num_event_filters),
2552 F_BOOLIV(enable_filter, ipmi_pefconfig_get_num_event_filters), /* 15 */
2553 F_INTIV(filter_type, ipmi_pefconfig_get_num_event_filters),
2554 F_BOOLIV(diagnostic_interrupt, ipmi_pefconfig_get_num_event_filters),
2555 F_BOOLIV(oem_action, ipmi_pefconfig_get_num_event_filters),
2556 F_BOOLIV(power_cycle, ipmi_pefconfig_get_num_event_filters),
2557 F_BOOLIV(reset, ipmi_pefconfig_get_num_event_filters), /* 20 */
2558 F_BOOLIV(power_down, ipmi_pefconfig_get_num_event_filters),
2559 F_BOOLIV(alert, ipmi_pefconfig_get_num_event_filters),
2560 F_INTIV(alert_policy_number, ipmi_pefconfig_get_num_event_filters),
2561 F_INTIV(event_severity, ipmi_pefconfig_get_num_event_filters),
2562 F_INTIV(generator_id_addr, ipmi_pefconfig_get_num_event_filters), /* 25 */
2563 F_INTIV(generator_id_channel_lun, ipmi_pefconfig_get_num_event_filters),
2564 F_INTIV(sensor_type, ipmi_pefconfig_get_num_event_filters),
2565 F_INTIV(sensor_number, ipmi_pefconfig_get_num_event_filters),
2566 F_INTIV(event_trigger, ipmi_pefconfig_get_num_event_filters),
2567 F_INTIV(data1_offset_mask, ipmi_pefconfig_get_num_event_filters), /* 30 */
2568 F_INTIV(data1_mask, ipmi_pefconfig_get_num_event_filters),
2569 F_INTIV(data1_compare1, ipmi_pefconfig_get_num_event_filters),
2570 F_INTIV(data1_compare2, ipmi_pefconfig_get_num_event_filters),
2571 F_INTIV(data2_mask, ipmi_pefconfig_get_num_event_filters),
2572 F_INTIV(data2_compare1, ipmi_pefconfig_get_num_event_filters), /* 35 */
2573 F_INTIV(data2_compare2, ipmi_pefconfig_get_num_event_filters),
2574 F_INTIV(data3_mask, ipmi_pefconfig_get_num_event_filters),
2575 F_INTIV(data3_compare1, ipmi_pefconfig_get_num_event_filters),
2576 F_INTIV(data3_compare2, ipmi_pefconfig_get_num_event_filters),
2577 F_INTR(num_alert_policies), /* 40 */
2578 F_INTIV(policy_num, ipmi_pefconfig_get_num_alert_policies),
2579 F_BOOLIV(enabled, ipmi_pefconfig_get_num_alert_policies),
2580 F_INTIV(policy, ipmi_pefconfig_get_num_alert_policies),
2581 F_INTIV(channel, ipmi_pefconfig_get_num_alert_policies),
2582 F_INTIV(destination_selector, ipmi_pefconfig_get_num_alert_policies), /* 45 */
2583 F_BOOLIV(alert_string_event_specific, ipmi_pefconfig_get_num_alert_policies),
2584 F_INTIV(alert_string_selector, ipmi_pefconfig_get_num_alert_policies),
2585 F_INTR(num_alert_strings),
2586 F_INTIV(event_filter, ipmi_pefconfig_get_num_alert_strings),
2587 F_INTIV(alert_string_set, ipmi_pefconfig_get_num_alert_strings), /* 50 */
2588 F_STRIV(alert_string, ipmi_pefconfig_get_num_alert_strings),
2589 };
2590 #define NUM_GDATA_ENTRIES (sizeof(gdata) / sizeof(pefparm_gendata_t))
2591
2592 int
ipmi_pefconfig_enum_val(unsigned int parm,int val,int * nval,const char ** sval)2593 ipmi_pefconfig_enum_val(unsigned int parm, int val, int *nval,
2594 const char **sval)
2595 {
2596 return ENOSYS;
2597 }
2598
2599 int
ipmi_pefconfig_enum_idx(unsigned int parm,int idx,const char ** sval)2600 ipmi_pefconfig_enum_idx(unsigned int parm, int idx, const char **sval)
2601 {
2602 return ENOSYS;
2603 }
2604
2605 int
ipmi_pefconfig_get_val(ipmi_pef_config_t * pefc,unsigned int parm,const char ** name,int * index,enum ipmi_pefconf_val_type_e * valtype,unsigned int * ival,unsigned char ** dval,unsigned int * dval_len)2606 ipmi_pefconfig_get_val(ipmi_pef_config_t *pefc,
2607 unsigned int parm,
2608 const char **name,
2609 int *index,
2610 enum ipmi_pefconf_val_type_e *valtype,
2611 unsigned int *ival,
2612 unsigned char **dval,
2613 unsigned int *dval_len)
2614 {
2615 unsigned int curr = *index;
2616 unsigned int count;
2617 int rv = 0;
2618 unsigned char *data;
2619 unsigned int data_len;
2620
2621 if (parm >= NUM_GDATA_ENTRIES)
2622 return EINVAL;
2623 if (valtype)
2624 *valtype = gdata[parm].datatype;
2625 if (name)
2626 *name = gdata[parm].fname;
2627
2628 if (gdata[parm].iv_cnt) {
2629 count = gdata[parm].iv_cnt(pefc);
2630 if (curr >= count) {
2631 *index = -1;
2632 return E2BIG;
2633 }
2634
2635 if (curr+1 == count)
2636 *index = -1;
2637 else
2638 *index = curr+1;
2639 }
2640
2641 switch (gdata[parm].datatype) {
2642 case IPMI_PEFCONFIG_INT:
2643 case IPMI_PEFCONFIG_BOOL:
2644 if (!ival)
2645 break;
2646 if (gdata[parm].u.ival.gval)
2647 *ival = gdata[parm].u.ival.gval(pefc);
2648 else if (gdata[parm].u.ival.gval_v)
2649 rv = gdata[parm].u.ival.gval_v(pefc, ival);
2650 else if (gdata[parm].u.ival.gval_iv)
2651 rv = gdata[parm].u.ival.gval_iv(pefc, curr, ival);
2652 else
2653 rv = ENOSYS;
2654 break;
2655
2656 case IPMI_PEFCONFIG_DATA:
2657 data_len = 0;
2658 if (gdata[parm].u.dval.gval_v)
2659 rv = gdata[parm].u.dval.gval_v(pefc, NULL, &data_len);
2660 else if (gdata[parm].u.dval.gval_iv)
2661 rv = gdata[parm].u.dval.gval_iv(pefc, curr, NULL, &data_len);
2662 else
2663 rv = ENOSYS;
2664 if (rv && (rv != EBADF))
2665 break;
2666 if (data_len == 0)
2667 data = ipmi_mem_alloc(1);
2668 else
2669 data = ipmi_mem_alloc(data_len);
2670 if (gdata[parm].u.dval.gval_v)
2671 rv = gdata[parm].u.dval.gval_v(pefc, data, &data_len);
2672 else if (gdata[parm].u.dval.gval_iv)
2673 rv = gdata[parm].u.dval.gval_iv(pefc, curr, data, &data_len);
2674 if (rv) {
2675 ipmi_mem_free(data);
2676 break;
2677 }
2678 if (dval)
2679 *dval = data;
2680 if (dval_len)
2681 *dval_len = data_len;
2682 break;
2683
2684 case IPMI_PEFCONFIG_STR:
2685 data_len = 0;
2686 if (gdata[parm].u.sval.gval_v)
2687 rv = gdata[parm].u.sval.gval_v(pefc, NULL, &data_len);
2688 else if (gdata[parm].u.sval.gval_iv)
2689 rv = gdata[parm].u.sval.gval_iv(pefc, curr, NULL, &data_len);
2690 else
2691 rv = ENOSYS;
2692 if (rv && (rv != EBADF))
2693 break;
2694 if (data_len == 0)
2695 data = ipmi_mem_alloc(1);
2696 else
2697 data = ipmi_mem_alloc(data_len);
2698 if (gdata[parm].u.sval.gval_v)
2699 rv = gdata[parm].u.sval.gval_v(pefc, data, &data_len);
2700 else if (gdata[parm].u.sval.gval_iv)
2701 rv = gdata[parm].u.sval.gval_iv(pefc, curr, data, &data_len);
2702 if (rv) {
2703 ipmi_mem_free(data);
2704 break;
2705 }
2706 if (dval)
2707 *dval = data;
2708 if (dval_len)
2709 *dval_len = data_len;
2710 }
2711
2712 return rv;
2713 }
2714
2715 int
ipmi_pefconfig_set_val(ipmi_pef_config_t * pefc,unsigned int parm,int index,unsigned int ival,unsigned char * dval,unsigned int dval_len)2716 ipmi_pefconfig_set_val(ipmi_pef_config_t *pefc,
2717 unsigned int parm,
2718 int index,
2719 unsigned int ival,
2720 unsigned char *dval,
2721 unsigned int dval_len)
2722 {
2723 unsigned int count;
2724 int rv = 0;
2725
2726 if (parm >= NUM_GDATA_ENTRIES)
2727 return EINVAL;
2728
2729 if (gdata[parm].iv_cnt) {
2730 count = gdata[parm].iv_cnt(pefc);
2731 if (index >= (int) count)
2732 return E2BIG;
2733 }
2734
2735 switch (gdata[parm].datatype) {
2736 case IPMI_PEFCONFIG_INT:
2737 case IPMI_PEFCONFIG_BOOL:
2738 if (!ival)
2739 break;
2740 if (gdata[parm].u.ival.sval)
2741 rv = gdata[parm].u.ival.sval(pefc, ival);
2742 else if (gdata[parm].u.ival.sval_v)
2743 rv = gdata[parm].u.ival.sval_v(pefc, ival);
2744 else if (gdata[parm].u.ival.sval_iv)
2745 rv = gdata[parm].u.ival.sval_iv(pefc, index, ival);
2746 else
2747 rv = ENOSYS;
2748 break;
2749
2750 case IPMI_PEFCONFIG_DATA:
2751 if (gdata[parm].u.dval.sval_v)
2752 rv = gdata[parm].u.dval.sval_v(pefc, dval, dval_len);
2753 else if (gdata[parm].u.dval.sval_iv)
2754 rv = gdata[parm].u.dval.sval_iv(pefc, index, dval, dval_len);
2755 else
2756 rv = ENOSYS;
2757 break;
2758
2759 case IPMI_PEFCONFIG_STR:
2760 if (gdata[parm].u.sval.sval_v)
2761 rv = gdata[parm].u.sval.sval_v(pefc, dval);
2762 else if (gdata[parm].u.sval.sval_iv)
2763 rv = gdata[parm].u.sval.sval_iv(pefc, index, dval);
2764 else
2765 rv = ENOSYS;
2766 break;
2767 }
2768
2769 return rv;
2770 }
2771
2772
2773 void
ipmi_pefconfig_data_free(void * data)2774 ipmi_pefconfig_data_free(void *data)
2775 {
2776 ipmi_mem_free(data);
2777 }
2778
2779 unsigned int
ipmi_pefconfig_str_to_parm(char * name)2780 ipmi_pefconfig_str_to_parm(char *name)
2781 {
2782 unsigned int i;
2783 for (i=0; i<NUM_GDATA_ENTRIES; i++) {
2784 if (strcmp(name, gdata[i].fname) == 0)
2785 return i;
2786 }
2787 return -1;
2788 }
2789
2790 const char *
ipmi_pefconfig_parm_to_str(unsigned int parm)2791 ipmi_pefconfig_parm_to_str(unsigned int parm)
2792 {
2793 if (parm >= NUM_GDATA_ENTRIES)
2794 return NULL;
2795 return gdata[parm].fname;
2796 }
2797
2798 int
ipmi_pefconfig_parm_to_type(unsigned int parm,enum ipmi_pefconf_val_type_e * valtype)2799 ipmi_pefconfig_parm_to_type(unsigned int parm,
2800 enum ipmi_pefconf_val_type_e *valtype)
2801 {
2802 if (parm >= NUM_GDATA_ENTRIES)
2803 return EINVAL;
2804 *valtype = gdata[parm].datatype;
2805 return 0;
2806 }
2807