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