1 /*
2 * solparm.c
3 *
4 * MontaVista IPMI code for configuring SoL data
5 *
6 * Author: MontaVista Software, Inc.
7 * Corey Minyard <minyard@mvista.com>
8 * source@mvista.com
9 *
10 * Copyright 2006 MontaVista Software Inc.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this program; if not, write to the Free
31 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 */
33
34 #include <string.h>
35 #include <math.h>
36 #include <stdio.h>
37
38 #include <OpenIPMI/ipmiif.h>
39 #include <OpenIPMI/ipmi_solparm.h>
40 #include <OpenIPMI/ipmi_msgbits.h>
41 #include <OpenIPMI/ipmi_err.h>
42
43 #include <OpenIPMI/internal/opq.h>
44 #include <OpenIPMI/internal/locked_list.h>
45 #include <OpenIPMI/internal/ipmi_domain.h>
46 #include <OpenIPMI/internal/ipmi_mc.h>
47 #include <OpenIPMI/internal/ipmi_int.h>
48
49 #define IPMI_SOLPARM_ATTR_NAME "ipmi_solparm"
50
51 struct ipmi_solparm_s
52 {
53 ipmi_mcid_t mc;
54 ipmi_domain_id_t domain;
55 unsigned char channel;
56
57 int refcount;
58
59 char name[IPMI_SOLPARM_NAME_LEN];
60
61 unsigned int destroyed : 1;
62 unsigned int in_destroy : 1;
63 unsigned int locked : 1;
64 unsigned int in_list : 1;
65
66 /* Something to call when the destroy is complete. */
67 ipmi_solparm_done_cb destroy_handler;
68 void *destroy_cb_data;
69
70 os_hnd_lock_t *solparm_lock;
71
72 os_handler_t *os_hnd;
73
74 /* We serialize operations through here, since we are dealing with
75 a locked resource. */
76 opq_t *opq;
77 };
78
79 static int
solparm_attr_init(ipmi_domain_t * domain,void * cb_data,void ** data)80 solparm_attr_init(ipmi_domain_t *domain, void *cb_data, void **data)
81 {
82 locked_list_t *solparml;
83
84 solparml = locked_list_alloc(ipmi_domain_get_os_hnd(domain));
85 if (!solparml)
86 return ENOMEM;
87
88 *data = solparml;
89 return 0;
90 }
91
92 static void
solparm_lock(ipmi_solparm_t * solparm)93 solparm_lock(ipmi_solparm_t *solparm)
94 {
95 if (solparm->os_hnd->lock)
96 solparm->os_hnd->lock(solparm->os_hnd, solparm->solparm_lock);
97 }
98
99 static void
solparm_unlock(ipmi_solparm_t * solparm)100 solparm_unlock(ipmi_solparm_t *solparm)
101 {
102 if (solparm->os_hnd->lock)
103 solparm->os_hnd->unlock(solparm->os_hnd, solparm->solparm_lock);
104 }
105
106 static void
solparm_get(ipmi_solparm_t * solparm)107 solparm_get(ipmi_solparm_t *solparm)
108 {
109 solparm_lock(solparm);
110 solparm->refcount++;
111 solparm_unlock(solparm);
112 }
113
114 static void internal_destroy_solparm(ipmi_solparm_t *solparm);
115
116 static void
solparm_put(ipmi_solparm_t * solparm)117 solparm_put(ipmi_solparm_t *solparm)
118 {
119 solparm_lock(solparm);
120 solparm->refcount--;
121 if (solparm->refcount == 0) {
122 internal_destroy_solparm(solparm);
123 return;
124 }
125 solparm_unlock(solparm);
126 }
127
128 void
ipmi_solparm_ref(ipmi_solparm_t * solparm)129 ipmi_solparm_ref(ipmi_solparm_t *solparm)
130 {
131 solparm_get(solparm);
132 }
133
134 void
ipmi_solparm_deref(ipmi_solparm_t * solparm)135 ipmi_solparm_deref(ipmi_solparm_t *solparm)
136 {
137 solparm_put(solparm);
138 }
139
140 static int
destroy_solparm(void * cb_data,void * item1,void * item2)141 destroy_solparm(void *cb_data, void *item1, void *item2)
142 {
143 ipmi_solparm_t *solparm = item1;
144
145 solparm_lock(solparm);
146 solparm->in_list = 1;
147 solparm_unlock(solparm);
148 return LOCKED_LIST_ITER_CONTINUE;
149 }
150
151 static void
solparm_attr_destroy(void * cb_data,void * data)152 solparm_attr_destroy(void *cb_data, void *data)
153 {
154 locked_list_t *solparml = data;
155
156 locked_list_iterate(solparml, destroy_solparm, NULL);
157 locked_list_destroy(solparml);
158 }
159
160 typedef struct iterate_solparms_info_s
161 {
162 ipmi_solparm_ptr_cb handler;
163 void *cb_data;
164 } iterate_solparms_info_t;
165
166 static int
solparms_handler(void * cb_data,void * item1,void * item2)167 solparms_handler(void *cb_data, void *item1, void *item2)
168 {
169 iterate_solparms_info_t *info = cb_data;
170 info->handler(item1, info->cb_data);
171 solparm_put(item1);
172 return LOCKED_LIST_ITER_CONTINUE;
173 }
174
175 static int
solparms_prefunc(void * cb_data,void * item1,void * item2)176 solparms_prefunc(void *cb_data, void *item1, void *item2)
177 {
178 ipmi_solparm_t *solparm = item1;
179 solparm_get(solparm);
180 return LOCKED_LIST_ITER_CONTINUE;
181 }
182
183 void
ipmi_solparm_iterate_solparms(ipmi_domain_t * domain,ipmi_solparm_ptr_cb handler,void * cb_data)184 ipmi_solparm_iterate_solparms(ipmi_domain_t *domain,
185 ipmi_solparm_ptr_cb handler,
186 void *cb_data)
187 {
188 iterate_solparms_info_t info;
189 ipmi_domain_attr_t *attr;
190 locked_list_t *solparms;
191 int rv;
192
193 rv = ipmi_domain_find_attribute(domain, IPMI_SOLPARM_ATTR_NAME,
194 &attr);
195 if (rv)
196 return;
197 solparms = ipmi_domain_attr_get_data(attr);
198
199 info.handler = handler;
200 info.cb_data = cb_data;
201 locked_list_iterate_prefunc(solparms, solparms_prefunc,
202 solparms_handler, &info);
203 ipmi_domain_attr_put(attr);
204 }
205
206 ipmi_mcid_t
ipmi_solparm_get_mc_id(ipmi_solparm_t * solparm)207 ipmi_solparm_get_mc_id(ipmi_solparm_t *solparm)
208 {
209 return solparm->mc;
210 }
211
212 unsigned int
ipmi_solparm_get_channel(ipmi_solparm_t * solparm)213 ipmi_solparm_get_channel(ipmi_solparm_t *solparm)
214 {
215 return solparm->channel;
216 }
217
218 int
ipmi_solparm_get_name(ipmi_solparm_t * solparm,char * name,int length)219 ipmi_solparm_get_name(ipmi_solparm_t *solparm, char *name, int length)
220 {
221 int slen;
222
223 if (length <= 0)
224 return 0;
225
226 /* Never changes, no lock needed. */
227 slen = strlen(solparm->name);
228 if (slen == 0) {
229 if (name)
230 *name = '\0';
231 goto out;
232 }
233
234 if (name) {
235 memcpy(name, solparm->name, slen);
236 name[slen] = '\0';
237 }
238 out:
239 return slen;
240 }
241
242 static int
check_solparm_response_param(ipmi_solparm_t * solparm,ipmi_mc_t * mc,ipmi_msg_t * rsp,int len,char * func_name)243 check_solparm_response_param(ipmi_solparm_t *solparm,
244 ipmi_mc_t *mc,
245 ipmi_msg_t *rsp,
246 int len,
247 char *func_name)
248 {
249 if (solparm->destroyed) {
250 ipmi_log(IPMI_LOG_ERR_INFO,
251 "%ssolparm.c(%s): "
252 "SOLPARM was destroyed while an operation was in progress",
253 MC_NAME(mc), func_name);
254 return ECANCELED;
255 }
256
257 if (!mc) {
258 ipmi_log(IPMI_LOG_ERR_INFO,
259 "%ssolparm.c(%s): "
260 "MC went away while SOLPARM op was in progress",
261 MC_NAME(mc), func_name);
262 return ECANCELED;
263 }
264
265 if (rsp->data[0] != 0) {
266 #if 0
267 /* Sometimes this comes in and is valid (like when writing
268 parm 0 to value 2), just ignore it. */
269 /* We ignore 0x80, since that may be a valid error return for an
270 unsupported parameter. We also ignore 0x82, just to avoid
271 extraneous errors. */
272 if ((rsp->data[0] != 0x80) && (rsp->data[0] != 0x82))
273 ipmi_log(IPMI_LOG_ERR_INFO,
274 "%ssolparm.c(%s): "
275 "IPMI error from SOLPARM capabilities fetch: %x",
276 MC_NAME(mc), func_name, rsp->data[0]);
277 #endif
278 return IPMI_IPMI_ERR_VAL(rsp->data[0]);
279 }
280
281 if (rsp->data_len < len) {
282 ipmi_log(IPMI_LOG_ERR_INFO,
283 "%ssolparm.c(%s): SOLPARM capabilities too short",
284 MC_NAME(mc), func_name);
285 return EINVAL;
286 }
287 return 0;
288 }
289
290 int
ipmi_solparm_alloc(ipmi_mc_t * mc,unsigned int channel,ipmi_solparm_t ** new_solparm)291 ipmi_solparm_alloc(ipmi_mc_t *mc,
292 unsigned int channel,
293 ipmi_solparm_t **new_solparm)
294 {
295 ipmi_solparm_t *solparm = NULL;
296 int rv = 0;
297 ipmi_domain_t *domain = ipmi_mc_get_domain(mc);
298 int p, len;
299 locked_list_t *solparml;
300 ipmi_domain_attr_t *attr;
301
302 CHECK_MC_LOCK(mc);
303
304 rv = ipmi_domain_register_attribute(domain, IPMI_SOLPARM_ATTR_NAME,
305 solparm_attr_init,
306 solparm_attr_destroy,
307 NULL,
308 &attr);
309 if (rv)
310 return rv;
311 solparml = ipmi_domain_attr_get_data(attr);
312
313 solparm = ipmi_mem_alloc(sizeof(*solparm));
314 if (!solparm) {
315 rv = ENOMEM;
316 goto out;
317 }
318 memset(solparm, 0, sizeof(*solparm));
319
320 solparm->refcount = 1;
321 solparm->in_list = 1;
322 solparm->mc = ipmi_mc_convert_to_id(mc);
323 solparm->domain = ipmi_domain_convert_to_id(domain);
324 len = sizeof(solparm->name);
325 p = ipmi_domain_get_name(domain, solparm->name, len);
326 len -= p;
327 snprintf(solparm->name+p, len, ".%d", ipmi_domain_get_unique_num(domain));
328 solparm->os_hnd = ipmi_domain_get_os_hnd(domain);
329 solparm->solparm_lock = NULL;
330 solparm->channel = channel & 0xf;
331
332 solparm->opq = opq_alloc(solparm->os_hnd);
333 if (!solparm->opq) {
334 rv = ENOMEM;
335 goto out;
336 }
337
338 if (solparm->os_hnd->create_lock) {
339 rv = solparm->os_hnd->create_lock(solparm->os_hnd,
340 &solparm->solparm_lock);
341 if (rv)
342 goto out;
343 }
344
345 if (! locked_list_add(solparml, solparm, NULL)) {
346 rv = ENOMEM;
347 goto out;
348 }
349
350 out:
351 if (rv) {
352 if (solparm) {
353 if (solparm->opq)
354 opq_destroy(solparm->opq);
355 if (solparm->solparm_lock)
356 solparm->os_hnd->destroy_lock(solparm->os_hnd,
357 solparm->solparm_lock);
358 ipmi_mem_free(solparm);
359 }
360 } else {
361 *new_solparm = solparm;
362 }
363 ipmi_domain_attr_put(attr);
364 return rv;
365 }
366
367 static void
internal_destroy_solparm(ipmi_solparm_t * solparm)368 internal_destroy_solparm(ipmi_solparm_t *solparm)
369 {
370 solparm->in_destroy = 1;
371
372 /* We don't have to have a valid ipmi to destroy a solparm, they
373 are designed to live after the ipmi has been destroyed. */
374
375 if (solparm->in_list) {
376 int rv;
377 ipmi_domain_attr_t *attr;
378 locked_list_t *solparml;
379
380 rv = ipmi_domain_id_find_attribute(solparm->domain,
381 IPMI_SOLPARM_ATTR_NAME,
382 &attr);
383 if (!rv) {
384 solparm->refcount++;
385 solparm->in_list = 0;
386 solparm_unlock(solparm);
387 solparml = ipmi_domain_attr_get_data(attr);
388
389 locked_list_remove(solparml, solparm, NULL);
390 ipmi_domain_attr_put(attr);
391 solparm_lock(solparm);
392 /* While we were unlocked, someone may have come in and
393 grabbed the solparm by iterating the list of solparms.
394 That's ok, we just let them handle the destruction
395 since this code will not be entered again. */
396 if (solparm->refcount != 1) {
397 solparm->refcount--;
398 solparm_unlock(solparm);
399 return;
400 }
401 }
402 }
403 solparm_unlock(solparm);
404
405 if (solparm->opq)
406 opq_destroy(solparm->opq);
407
408 if (solparm->solparm_lock)
409 solparm->os_hnd->destroy_lock(solparm->os_hnd, solparm->solparm_lock);
410
411 /* Do this after we have gotten rid of all external dependencies,
412 but before it is free. */
413 if (solparm->destroy_handler)
414 solparm->destroy_handler(solparm, 0, solparm->destroy_cb_data);
415
416 ipmi_mem_free(solparm);
417 }
418
419 int
ipmi_solparm_destroy(ipmi_solparm_t * solparm,ipmi_solparm_done_cb done,void * cb_data)420 ipmi_solparm_destroy(ipmi_solparm_t *solparm,
421 ipmi_solparm_done_cb done,
422 void *cb_data)
423
424 {
425 solparm_lock(solparm);
426 if (solparm->in_list) {
427 int rv;
428 ipmi_domain_attr_t *attr;
429 locked_list_t *solparml;
430
431 solparm->in_list = 0;
432 rv = ipmi_domain_id_find_attribute(solparm->domain,
433 IPMI_SOLPARM_ATTR_NAME,
434 &attr);
435 if (!rv) {
436 solparm_unlock(solparm);
437 solparml = ipmi_domain_attr_get_data(attr);
438
439 locked_list_remove(solparml, solparm, NULL);
440 ipmi_domain_attr_put(attr);
441 solparm_lock(solparm);
442 }
443 }
444
445 if (solparm->destroyed) {
446 solparm_unlock(solparm);
447 return EINVAL;
448 }
449 solparm->destroyed = 1;
450 solparm_unlock(solparm);
451 solparm->destroy_handler = done;
452 solparm->destroy_cb_data = cb_data;
453
454 solparm_put(solparm);
455 return 0;
456 }
457
458 typedef struct solparm_fetch_handler_s
459 {
460 ipmi_solparm_t *solparm;
461 unsigned char parm;
462 unsigned char set;
463 unsigned char block;
464 ipmi_solparm_get_cb handler;
465 void *cb_data;
466 unsigned char *data;
467 unsigned int data_len;
468 int rv;
469 } solparm_fetch_handler_t;
470
471 /* This should be called with the solparm locked. It will unlock the solparm
472 before returning. */
473 static void
fetch_complete(ipmi_solparm_t * solparm,int err,solparm_fetch_handler_t * elem)474 fetch_complete(ipmi_solparm_t *solparm, int err, solparm_fetch_handler_t *elem)
475 {
476 if (solparm->in_destroy)
477 goto out;
478
479 solparm_unlock(solparm);
480
481 if (elem->handler)
482 elem->handler(solparm, err, elem->data, elem->data_len, elem->cb_data);
483
484 ipmi_mem_free(elem);
485
486 if (!solparm->destroyed)
487 opq_op_done(solparm->opq);
488
489 solparm_put(solparm);
490 return;
491
492 out:
493 solparm_unlock(solparm);
494 solparm_put(solparm);
495 }
496
497
498 static void
solparm_config_fetched(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)499 solparm_config_fetched(ipmi_mc_t *mc,
500 ipmi_msg_t *rsp,
501 void *rsp_data)
502 {
503 solparm_fetch_handler_t *elem = rsp_data;
504 ipmi_solparm_t *solparm = elem->solparm;
505 int rv;
506
507 rv = check_solparm_response_param(solparm, mc, rsp, 2,
508 "solparm_config_fetched");
509
510 /* Skip over the completion code. */
511 elem->data = rsp->data + 1;
512 elem->data_len = rsp->data_len - 1;
513
514 solparm_lock(solparm);
515 fetch_complete(solparm, rv, elem);
516 }
517
518 static void
start_config_fetch_cb(ipmi_mc_t * mc,void * cb_data)519 start_config_fetch_cb(ipmi_mc_t *mc, void *cb_data)
520 {
521 solparm_fetch_handler_t *elem = cb_data;
522 ipmi_solparm_t *solparm = elem->solparm;
523 unsigned char data[4];
524 ipmi_msg_t msg;
525 int rv;
526
527 solparm_lock(solparm);
528 if (solparm->destroyed) {
529 ipmi_log(IPMI_LOG_ERR_INFO,
530 "%ssolparm.c(start_config_fetch_cb): "
531 "SOLPARM was destroyed while an operation was in progress",
532 MC_NAME(mc));
533 fetch_complete(solparm, ECANCELED, elem);
534 goto out;
535 }
536
537 msg.data = data;
538 msg.netfn = IPMI_TRANSPORT_NETFN;
539 msg.cmd = IPMI_GET_SOL_CONFIGURATION_PARAMETERS;
540 data[0] = solparm->channel;
541 data[1] = elem->parm;
542 data[2] = elem->set;
543 data[3] = elem->block;
544 msg.data_len = 4;
545 rv = ipmi_mc_send_command(mc, 0, &msg, solparm_config_fetched, elem);
546
547 if (rv) {
548 ipmi_log(IPMI_LOG_ERR_INFO,
549 "%ssolparm.c(start_config_fetch_cb): "
550 "SOLPARM start_config_fetch: could not send cmd: %x",
551 MC_NAME(mc), rv);
552 fetch_complete(solparm, ECANCELED, elem);
553 goto out;
554 }
555
556 solparm_unlock(solparm);
557 out:
558 return;
559 }
560
561 static int
start_config_fetch(void * cb_data,int shutdown)562 start_config_fetch(void *cb_data, int shutdown)
563 {
564 solparm_fetch_handler_t *elem = cb_data;
565 int rv;
566
567 if (shutdown) {
568 ipmi_log(IPMI_LOG_ERR_INFO,
569 "solparm.c(start_config_fetch): "
570 "SOLPARM was destroyed while an operation was in progress");
571 solparm_lock(elem->solparm);
572 fetch_complete(elem->solparm, ECANCELED, elem);
573 return OPQ_HANDLER_STARTED;
574 }
575
576 /* The read lock must be claimed before the solparm lock to avoid
577 deadlock. */
578 rv = ipmi_mc_pointer_cb(elem->solparm->mc, start_config_fetch_cb, elem);
579 if (rv) {
580 ipmi_log(IPMI_LOG_ERR_INFO,
581 "solparm.c(start_config_fetch): "
582 "SOLPARM's MC is not valid");
583 solparm_lock(elem->solparm);
584 fetch_complete(elem->solparm, rv, elem);
585 }
586 return OPQ_HANDLER_STARTED;
587 }
588
589 int
ipmi_solparm_get_parm(ipmi_solparm_t * solparm,unsigned int parm,unsigned int set,unsigned int block,ipmi_solparm_get_cb done,void * cb_data)590 ipmi_solparm_get_parm(ipmi_solparm_t *solparm,
591 unsigned int parm,
592 unsigned int set,
593 unsigned int block,
594 ipmi_solparm_get_cb done,
595 void *cb_data)
596 {
597 solparm_fetch_handler_t *elem;
598 int rv = 0;
599
600 if (solparm->destroyed)
601 return EINVAL;
602
603 elem = ipmi_mem_alloc(sizeof(*elem));
604 if (!elem) {
605 ipmi_log(IPMI_LOG_ERR_INFO,
606 "solparm.c(ipmi_solparm_get_parm): "
607 "could not allocate the solparm element");
608 return ENOMEM;
609 }
610
611 elem->handler = done;
612 elem->cb_data = cb_data;
613 elem->solparm = solparm;
614 elem->parm = parm;
615 elem->set = set;
616 elem->block = block;
617 elem->rv = 0;
618
619 if (!opq_new_op(solparm->opq, start_config_fetch, elem, 0))
620 rv = ENOMEM;
621
622 if (rv)
623 ipmi_mem_free(elem);
624 else
625 solparm_get(solparm);
626
627 return rv;
628 }
629
630 typedef struct solparm_set_handler_s
631 {
632 ipmi_solparm_t *solparm;
633 ipmi_solparm_done_cb handler;
634 void *cb_data;
635 unsigned char data[MAX_IPMI_DATA_SIZE];
636 unsigned int data_len;
637 int rv;
638 } solparm_set_handler_t;
639
640 /* This should be called with the solparm locked. It will unlock the solparm
641 before returning. */
642 static void
set_complete(ipmi_solparm_t * solparm,int err,solparm_set_handler_t * elem)643 set_complete(ipmi_solparm_t *solparm, int err, solparm_set_handler_t *elem)
644 {
645 if (solparm->in_destroy)
646 goto out;
647
648 solparm_unlock(solparm);
649
650 if (elem->handler)
651 elem->handler(solparm, err, elem->cb_data);
652
653 ipmi_mem_free(elem);
654
655 solparm_lock(solparm);
656 if (!solparm->destroyed) {
657 solparm_unlock(solparm);
658 opq_op_done(solparm->opq);
659 } else {
660 solparm_unlock(solparm);
661 }
662
663 solparm_put(solparm);
664 return;
665
666 out:
667 solparm_unlock(solparm);
668 solparm_put(solparm);
669 }
670
671 static void
solparm_config_set(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)672 solparm_config_set(ipmi_mc_t *mc,
673 ipmi_msg_t *rsp,
674 void *rsp_data)
675 {
676 solparm_set_handler_t *elem = rsp_data;
677 ipmi_solparm_t *solparm = elem->solparm;
678 int rv;
679
680 rv = check_solparm_response_param(solparm, mc, rsp, 1,
681 "solparm_config_set");
682
683 solparm_lock(solparm);
684 set_complete(solparm, rv, elem);
685 }
686
687 static void
start_config_set_cb(ipmi_mc_t * mc,void * cb_data)688 start_config_set_cb(ipmi_mc_t *mc, void *cb_data)
689 {
690 solparm_set_handler_t *elem = cb_data;
691 ipmi_solparm_t *solparm = elem->solparm;
692 ipmi_msg_t msg;
693 int rv;
694
695 solparm_lock(solparm);
696 if (solparm->destroyed) {
697 ipmi_log(IPMI_LOG_ERR_INFO,
698 "%ssolparm.c(start_config_set_cb): "
699 "SOLPARM was destroyed while an operation was in progress",
700 MC_NAME(mc));
701 set_complete(solparm, ECANCELED, elem);
702 goto out;
703 }
704
705 msg.netfn = IPMI_TRANSPORT_NETFN;
706 msg.cmd = IPMI_SET_SOL_CONFIGURATION_PARAMETERS;
707 msg.data = elem->data;
708 msg.data_len = elem->data_len;
709 rv = ipmi_mc_send_command(mc, 0, &msg, solparm_config_set, elem);
710
711 if (rv) {
712 ipmi_log(IPMI_LOG_ERR_INFO,
713 "%ssolparm.c(start_config_set_cb): "
714 "SOLPARM start_config_set: could not send cmd: %x",
715 MC_NAME(mc), rv);
716 set_complete(solparm, ECANCELED, elem);
717 goto out;
718 }
719
720 solparm_unlock(solparm);
721 out:
722 return;
723 }
724
725 static int
start_config_set(void * cb_data,int shutdown)726 start_config_set(void *cb_data, int shutdown)
727 {
728 solparm_set_handler_t *elem = cb_data;
729 int rv;
730
731 if (shutdown) {
732 ipmi_log(IPMI_LOG_ERR_INFO,
733 "solparm.c(start_config_set): "
734 "SOLPARM was destroyed while an operation was in progress");
735 solparm_lock(elem->solparm);
736 set_complete(elem->solparm, ECANCELED, elem);
737 return OPQ_HANDLER_STARTED;
738 }
739
740 /* The read lock must be claimed before the solparm lock to avoid
741 deadlock. */
742 rv = ipmi_mc_pointer_cb(elem->solparm->mc, start_config_set_cb, elem);
743 if (rv) {
744 ipmi_log(IPMI_LOG_ERR_INFO,
745 "solparm.c(start_config_set): "
746 "SOLPARM's MC is not valid");
747 solparm_lock(elem->solparm);
748 set_complete(elem->solparm, rv, elem);
749 }
750 return OPQ_HANDLER_STARTED;
751 }
752
753 int
ipmi_solparm_set_parm(ipmi_solparm_t * solparm,unsigned int parm,unsigned char * data,unsigned int data_len,ipmi_solparm_done_cb done,void * cb_data)754 ipmi_solparm_set_parm(ipmi_solparm_t *solparm,
755 unsigned int parm,
756 unsigned char *data,
757 unsigned int data_len,
758 ipmi_solparm_done_cb done,
759 void *cb_data)
760 {
761 solparm_set_handler_t *elem;
762 int rv = 0;
763
764 if (solparm->destroyed)
765 return EINVAL;
766
767 if (data_len > MAX_IPMI_DATA_SIZE-2)
768 return EINVAL;
769
770 elem = ipmi_mem_alloc(sizeof(*elem));
771 if (!elem) {
772 ipmi_log(IPMI_LOG_ERR_INFO,
773 "solparm.c(ipmi_solparm_set_parm): "
774 "could not allocate the solparm element");
775 return ENOMEM;
776 }
777
778 elem->handler = done;
779 elem->cb_data = cb_data;
780 elem->solparm = solparm;
781 elem->data[0] = solparm->channel;
782 elem->data[1] = parm;
783 memcpy(elem->data+2, data, data_len);
784 elem->data_len = data_len + 2;
785 elem->rv = 0;
786
787 if (!opq_new_op(solparm->opq, start_config_set, elem, 0))
788 rv = ENOMEM;
789
790 if (rv)
791 ipmi_mem_free(elem);
792 else
793 solparm_get(solparm);
794
795 return rv;
796 }
797
798 struct ipmi_sol_config_s
799 {
800 /* Stuff for getting/setting the values. */
801 int curr_parm;
802 int curr_sel;
803
804 /* Not used for access, just for checking validity. */
805 ipmi_solparm_t *my_sol;
806
807 /* Does this config hold the external SOL "set in progress" lock? */
808 int sol_locked;
809
810 /* Does the SOL config support locking? */
811 int lock_supported;
812
813 /* Used for deferred errors. */
814 int err;
815
816 ipmi_solparm_done_cb set_done;
817 ipmi_sol_get_config_cb done;
818 void *cb_data;
819
820 unsigned int enable : 1;
821 unsigned int force_payload_encryption : 1;
822 unsigned int force_payload_authentication : 1;
823 unsigned int privilege_level : 4;
824 unsigned int retry_count : 3;
825 unsigned char payload_channel_supported;
826 unsigned char payload_channel;
827 unsigned char char_accumulation_interval;
828 unsigned char char_send_threshold;
829 unsigned char non_volatile_bitrate;
830 unsigned char volatile_bitrate;
831 unsigned char retry_interval;
832 unsigned char port_number_supported;
833 unsigned int port_number;
834 };
835
836 typedef struct solparms_s solparms_t;
837 struct solparms_s
838 {
839 unsigned int valid : 1;
840 unsigned int optional_offset : 8;
841 unsigned int length : 8;
842 unsigned int offset : 8;
843 /* Returns err. */
844 int (*get_handler)(ipmi_sol_config_t *solc, solparms_t *lp, int err,
845 unsigned char *data);
846 /* NULL if parameter is read-only */
847 void (*set_handler)(ipmi_sol_config_t *solc, solparms_t *lp,
848 unsigned char *data);
849 };
850
851 /* SoL Enable */
gse(ipmi_sol_config_t * solc,solparms_t * lp,int err,unsigned char * data)852 static int gse(ipmi_sol_config_t *solc, solparms_t *lp, int err,
853 unsigned char *data)
854 {
855 if (err)
856 return err;
857
858 data++; /* Skip over the revision byte. */
859 solc->enable = data[0] & 0x1;
860 return 0;
861 }
862
sse(ipmi_sol_config_t * solc,solparms_t * lp,unsigned char * data)863 static void sse(ipmi_sol_config_t *solc, solparms_t *lp, unsigned char *data)
864 {
865 data[0] = solc->enable;
866 }
867
868 /* Authentication */
gsa(ipmi_sol_config_t * solc,solparms_t * lp,int err,unsigned char * data)869 static int gsa(ipmi_sol_config_t *solc, solparms_t *lp, int err,
870 unsigned char *data)
871 {
872 if (err)
873 return err;
874
875 data++; /* Skip over the revision byte. */
876 solc->force_payload_encryption = (data[0] >> 7) & 0x1;
877 solc->force_payload_authentication = (data[0] >> 6) & 0x1;
878 solc->privilege_level = data[0] & 0xf;
879 return 0;
880 }
881
ssa(ipmi_sol_config_t * solc,solparms_t * lp,unsigned char * data)882 static void ssa(ipmi_sol_config_t *solc, solparms_t *lp, unsigned char *data)
883 {
884 data[0] = ((solc->force_payload_encryption << 7)
885 | (solc->force_payload_authentication << 6)
886 | solc->privilege_level);
887 }
888
889 /* char settings */
gcs(ipmi_sol_config_t * solc,solparms_t * lp,int err,unsigned char * data)890 static int gcs(ipmi_sol_config_t *solc, solparms_t *lp, int err,
891 unsigned char *data)
892 {
893 if (err)
894 return err;
895
896 data++; /* Skip over the revision byte. */
897 solc->char_accumulation_interval = data[0];
898 solc->char_send_threshold = data[1];
899 return 0;
900 }
901
scs(ipmi_sol_config_t * solc,solparms_t * lp,unsigned char * data)902 static void scs(ipmi_sol_config_t *solc, solparms_t *lp, unsigned char *data)
903 {
904 data[0] = solc->char_accumulation_interval;
905 data[1] = solc->char_send_threshold;
906 }
907
908 /* retry */
gsr(ipmi_sol_config_t * solc,solparms_t * lp,int err,unsigned char * data)909 static int gsr(ipmi_sol_config_t *solc, solparms_t *lp, int err,
910 unsigned char *data)
911 {
912 if (err)
913 return err;
914
915 data++; /* Skip over the revision byte. */
916 solc->retry_count = data[0] & 0x7;
917 solc->retry_interval = data[1];
918 return 0;
919 }
920
ssr(ipmi_sol_config_t * solc,solparms_t * lp,unsigned char * data)921 static void ssr(ipmi_sol_config_t *solc, solparms_t *lp, unsigned char *data)
922 {
923 data[0] = solc->retry_count;
924 data[1] = solc->retry_interval;
925 }
926
927 /* bitrate */
gbr(ipmi_sol_config_t * solc,solparms_t * lp,int err,unsigned char * data)928 static int gbr(ipmi_sol_config_t *solc, solparms_t *lp, int err,
929 unsigned char *data)
930 {
931 unsigned char *ptr;
932
933 if (err)
934 return err;
935
936 ptr = ((unsigned char *) solc) + lp->offset;
937
938 data++; /* Skip over the revision byte. */
939 *ptr = data[0] & 0xf;
940 return 0;
941 }
942
sbr(ipmi_sol_config_t * solc,solparms_t * lp,unsigned char * data)943 static void sbr(ipmi_sol_config_t *solc, solparms_t *lp, unsigned char *data)
944 {
945 unsigned char *ptr = ((unsigned char *) solc) + lp->offset;
946 data[0] = *ptr & 0xf;
947 }
948
949 /* payload channel */
gpc(ipmi_sol_config_t * solc,solparms_t * lp,int err,unsigned char * data)950 static int gpc(ipmi_sol_config_t *solc, solparms_t *lp, int err,
951 unsigned char *data)
952 {
953 if (err) {
954 if (err == IPMI_IPMI_ERR_VAL(0x80)) {
955 solc->payload_channel_supported = 0;
956 return 0;
957 }
958 return err;
959 }
960
961 data++; /* Skip over the revision byte. */
962 solc->payload_channel_supported = 1;
963 solc->payload_channel = data[0] & 0xf;
964 return 0;
965 }
966
967 /* port number */
gpn(ipmi_sol_config_t * solc,solparms_t * lp,int err,unsigned char * data)968 static int gpn(ipmi_sol_config_t *solc, solparms_t *lp, int err,
969 unsigned char *data)
970 {
971 if (err) {
972 if (err == IPMI_IPMI_ERR_VAL(0x80)) {
973 solc->port_number_supported = 0;
974 return 0;
975 }
976 return err;
977 }
978
979 data++; /* Skip over the revision byte. */
980 solc->port_number = ipmi_get_uint16(data);
981 return 0;
982 }
983
spn(ipmi_sol_config_t * solc,solparms_t * lp,unsigned char * data)984 static void spn(ipmi_sol_config_t *solc, solparms_t *lp, unsigned char *data)
985 {
986 ipmi_set_uint16(data, solc->port_number);
987 }
988
989
990 #define OFFSET_OF(x) (((unsigned char *) &(((ipmi_sol_config_t *) NULL)->x)) \
991 - ((unsigned char *) NULL))
992
993 #define NUM_SOLPARMS 26
994 static solparms_t solparms[NUM_SOLPARMS] =
995 {
996 { 0, 0, 0, 0, NULL, NULL }, /* IPMI_SOLPARM_SET_IN_PROGRESS */
997 { 1, 0, 1, 0, gse, sse }, /* IPMI_SOLPARM_ENABLE */
998 { 1, 0, 1, 0, gsa, ssa }, /* IPMI_SOLPARM_AUTHENTICATION */
999 { 1, 0, 2, 0, gcs, scs }, /* IPMI_SOLPARM_CHAR_SETTINGS */
1000 { 1, 0, 2, 0, gsr, ssr }, /* IPMI_SOLPARM_RETRY */
1001 #define F OFFSET_OF(non_volatile_bitrate)
1002 { 1, 0, 1, F, gbr, sbr }, /* IPMI_SOLPARM_NONVOLATILE_BITRATE */
1003 #undef F
1004 #define F OFFSET_OF(volatile_bitrate)
1005 { 1, 0, 1, F, gbr, sbr }, /* IPMI_SOLPARM_VOLATILE_BITRATE */
1006 #undef F
1007 #define S OFFSET_OF(payload_channel_supported)
1008 { 1, S, 1, 0, gpc, NULL }, /* IPMI_SOLPARM_PAYLOAD_CHANNEL */
1009 #undef S
1010 #define S OFFSET_OF(port_number_supported)
1011 { 1, S, 2, 0, gpn, spn }, /* IPMI_SOLPARM_PORT_NUMBER */
1012 #undef S
1013 };
1014
1015 static void
err_lock_cleared(ipmi_solparm_t * solparm,int err,void * cb_data)1016 err_lock_cleared(ipmi_solparm_t *solparm,
1017 int err,
1018 void *cb_data)
1019 {
1020 ipmi_sol_config_t *solc = cb_data;
1021
1022 if (solc->done)
1023 solc->done(solparm, solc->err, NULL, solc->cb_data);
1024 ipmi_sol_free_config(solc);
1025 solparm->locked = 0;
1026 solparm_put(solparm);
1027 }
1028
1029 static void
got_parm(ipmi_solparm_t * solparm,int err,unsigned char * data,unsigned int data_len,void * cb_data)1030 got_parm(ipmi_solparm_t *solparm,
1031 int err,
1032 unsigned char *data,
1033 unsigned int data_len,
1034 void *cb_data)
1035 {
1036 ipmi_sol_config_t *solc = cb_data;
1037 solparms_t *lp = &(solparms[solc->curr_parm]);
1038
1039 /* Check the length, and don't forget the revision byte must be added. */
1040 if ((!err) && (data_len < (unsigned int) (lp->length+1))) {
1041 if ((data_len == 1) && (lp->optional_offset)) {
1042 /* Some systems return zero-length data for optional parms. */
1043 unsigned char *opt = ((unsigned char *)solc) + lp->optional_offset;
1044 *opt = 0;
1045 goto next_parm;
1046 }
1047 ipmi_log(IPMI_LOG_ERR_INFO,
1048 "solparm.c(got_parm): "
1049 " Invalid data length on parm %d was %d, should have been %d",
1050 solc->curr_parm, data_len, lp->length+1);
1051 err = EINVAL;
1052 goto done;
1053 }
1054
1055 err = lp->get_handler(solc, lp, err, data);
1056 if (err) {
1057 ipmi_log(IPMI_LOG_ERR_INFO,
1058 "solparm.c(got_parm): "
1059 "Error fetching parm %d: %x",
1060 solc->curr_parm, err);
1061 goto done;
1062 }
1063
1064 next_parm:
1065 switch (solc->curr_parm) {
1066 case IPMI_SOLPARM_PAYLOAD_PORT_NUMBER:
1067 goto done;
1068 default:
1069 solc->curr_parm++;
1070 }
1071
1072 lp = &(solparms[solc->curr_parm]);
1073 if (!lp->valid)
1074 goto next_parm;
1075
1076 err = ipmi_solparm_get_parm(solparm, solc->curr_parm, solc->curr_sel, 0,
1077 got_parm, solc);
1078 if (err)
1079 goto done;
1080
1081 return;
1082
1083 done:
1084 if (err) {
1085 unsigned char data[1];
1086
1087 ipmi_log(IPMI_LOG_ERR_INFO,
1088 "solparm.c(got_parm): Error trying to get parm %d: %x",
1089 solc->curr_parm, err);
1090 solc->err = err;
1091 /* Clear the lock */
1092 data[0] = 0;
1093 err = ipmi_solparm_set_parm(solparm, 0, data, 1,
1094 err_lock_cleared, solc);
1095 if (err) {
1096 ipmi_sol_free_config(solc);
1097 ipmi_log(IPMI_LOG_ERR_INFO,
1098 "solparm.c(got_parm): Error trying to clear lock: %x",
1099 err);
1100 solc->done(solparm, solc->err, NULL, solc->cb_data);
1101 ipmi_sol_free_config(solc);
1102 solparm->locked = 0;
1103 solparm_put(solparm);
1104 }
1105 } else {
1106 solc->done(solparm, 0, solc, solc->cb_data);
1107 solparm_put(solparm);
1108 }
1109 }
1110
1111 static void
lock_done(ipmi_solparm_t * solparm,int err,void * cb_data)1112 lock_done(ipmi_solparm_t *solparm,
1113 int err,
1114 void *cb_data)
1115 {
1116 ipmi_sol_config_t *solc = cb_data;
1117 int rv;
1118
1119 if (err == IPMI_IPMI_ERR_VAL(0x80)) {
1120 /* Lock is not supported, just mark it and go on. */
1121 solc->lock_supported = 0;
1122 } else if (err == IPMI_IPMI_ERR_VAL(0x81)) {
1123 /* Someone else has the lock, return EAGAIN. */
1124 solc->done(solparm, EAGAIN, NULL, solc->cb_data);
1125 ipmi_sol_free_config(solc);
1126 solparm_put(solparm);
1127 return;
1128 } else if (err) {
1129 ipmi_log(IPMI_LOG_ERR_INFO,
1130 "solparm.c(lock_done): Error trying to lock the SOL"
1131 " parms: %x",
1132 err);
1133 solc->done(solparm, err, NULL, solc->cb_data);
1134 ipmi_sol_free_config(solc);
1135 solparm_put(solparm);
1136 return;
1137 } else {
1138 solc->sol_locked = 1;
1139 solparm->locked = 1;
1140 }
1141
1142 rv = ipmi_solparm_get_parm(solparm, solc->curr_parm, solc->curr_sel, 0,
1143 got_parm, solc);
1144 if (rv) {
1145 unsigned char data[1];
1146 ipmi_log(IPMI_LOG_ERR_INFO,
1147 "solparm.c(lock_done): Error trying to get parms: %x",
1148 err);
1149
1150 solc->err = rv;
1151 /* Clear the lock */
1152 data[0] = 0;
1153 rv = ipmi_solparm_set_parm(solparm, 0, data, 1,
1154 err_lock_cleared, solc);
1155 if (rv) {
1156 ipmi_log(IPMI_LOG_ERR_INFO,
1157 "solparm.c(lock_done): Error trying to clear lock: %x",
1158 err);
1159 solc->done(solparm, solc->err, NULL, solc->cb_data);
1160 ipmi_sol_free_config(solc);
1161 solparm->locked = 0;
1162 solparm_put(solparm);
1163 }
1164 }
1165 }
1166
ipmi_sol_get_config(ipmi_solparm_t * solparm,ipmi_sol_get_config_cb done,void * cb_data)1167 int ipmi_sol_get_config(ipmi_solparm_t *solparm,
1168 ipmi_sol_get_config_cb done,
1169 void *cb_data)
1170 {
1171 ipmi_sol_config_t *solc;
1172 int rv;
1173 unsigned char data[1];
1174
1175 solc = ipmi_mem_alloc(sizeof(*solc));
1176 if (!solc)
1177 return ENOMEM;
1178 memset(solc, 0, sizeof(*solc));
1179
1180 solc->curr_parm = 1;
1181 solc->curr_sel = 0;
1182 solc->done = done;
1183 solc->cb_data = cb_data;
1184 solc->my_sol = solparm;
1185 solc->lock_supported = 1; /* Assume it works */
1186
1187 solparm_get(solparm);
1188
1189 /* First grab the lock */
1190 data[0] = 1; /* Set in progress. */
1191 rv = ipmi_solparm_set_parm(solparm, 0, data, 1, lock_done, solc);
1192 if (rv) {
1193 ipmi_sol_free_config(solc);
1194 solparm_put(solparm);
1195 }
1196
1197 return rv;
1198 }
1199
1200 static void
set_clear(ipmi_solparm_t * solparm,int err,void * cb_data)1201 set_clear(ipmi_solparm_t *solparm,
1202 int err,
1203 void *cb_data)
1204 {
1205 ipmi_sol_config_t *solc = cb_data;
1206
1207 if (solc->err)
1208 err = solc->err;
1209 if (solc->set_done)
1210 solc->set_done(solparm, err, solc->cb_data);
1211 ipmi_sol_free_config(solc);
1212 solparm->locked = 0;
1213 solparm_put(solparm);
1214 }
1215
1216 static void
commit_done(ipmi_solparm_t * solparm,int err,void * cb_data)1217 commit_done(ipmi_solparm_t *solparm,
1218 int err,
1219 void *cb_data)
1220 {
1221 ipmi_sol_config_t *solc = cb_data;
1222 unsigned char data[1];
1223 int rv;
1224
1225 /* Note that we ignore the error. The commit done is optional,
1226 and must return an error if it is optional, so we just ignore
1227 the error and clear the field here. */
1228
1229 /* Commit is done. The IPMI spec says that it goes into the
1230 set-in-progress state after this, so we need to clear it. */
1231
1232 data[0] = 0;
1233 rv = ipmi_solparm_set_parm(solparm, 0, data, 1, set_clear, solc);
1234 if (rv) {
1235 ipmi_log(IPMI_LOG_WARNING,
1236 "solparm.c(commit_done): Error trying to clear the set in"
1237 " progress: %x",
1238 rv);
1239 set_clear(solparm, err, solc);
1240 }
1241 }
1242
1243 static void
set_done(ipmi_solparm_t * solparm,int err,void * cb_data)1244 set_done(ipmi_solparm_t *solparm,
1245 int err,
1246 void *cb_data)
1247 {
1248 ipmi_sol_config_t *solc = cb_data;
1249 unsigned char data[MAX_IPMI_DATA_SIZE];
1250 solparms_t *lp = &(solparms[solc->curr_parm]);
1251
1252 if (err == IPMI_IPMI_ERR_VAL(0x82)) {
1253 /* We attempted to write a read-only parameter that is not
1254 marked by the spec as read-only. Just ignore it. */
1255 err = 0;
1256 }
1257
1258 if (err) {
1259 ipmi_log(IPMI_LOG_ERR_INFO,
1260 "solparm.c(set_done): Error setting sol parm %d sel %d: %x",
1261 solc->curr_parm, solc->curr_sel, err);
1262 goto done;
1263 }
1264
1265 next_parm:
1266 switch (solc->curr_parm) {
1267 case IPMI_SOLPARM_PAYLOAD_PORT_NUMBER:
1268 goto done;
1269 default:
1270 solc->curr_parm++;
1271 }
1272
1273 lp = &(solparms[solc->curr_parm]);
1274 if ((!lp->valid) || (!lp->set_handler)
1275 || (lp->optional_offset
1276 && !(((unsigned char *) solc)[lp->optional_offset])))
1277 {
1278 /* The parameter is read-only or not supported, just go on. */
1279 goto next_parm;
1280 }
1281
1282 lp->set_handler(solc, lp, data);
1283 err = ipmi_solparm_set_parm(solparm, solc->curr_parm,
1284 data, lp->length, set_done, solc);
1285 if (err)
1286 goto done;
1287
1288 return;
1289
1290 done:
1291 if (!solc->lock_supported) {
1292 /* No lock support, just finish the operation. */
1293 set_clear(solparm, err, solc);
1294 return;
1295 }
1296 else if (err) {
1297 data[0] = 0; /* Don't commit the parameters. */
1298 solc->err = err;
1299 err = ipmi_solparm_set_parm(solparm, 0, data, 1, set_clear, solc);
1300 } else {
1301 data[0] = 2; /* Commit the parameters. */
1302 err = ipmi_solparm_set_parm(solparm, 0, data, 1, commit_done, solc);
1303 }
1304 if (err) {
1305 ipmi_log(IPMI_LOG_WARNING,
1306 "solparm.c(set_done): Error trying to clear the set in"
1307 " progress: %x",
1308 err);
1309 set_clear(solparm, err, solc);
1310 }
1311 }
1312
1313 int
ipmi_sol_set_config(ipmi_solparm_t * solparm,ipmi_sol_config_t * osolc,ipmi_solparm_done_cb done,void * cb_data)1314 ipmi_sol_set_config(ipmi_solparm_t *solparm,
1315 ipmi_sol_config_t *osolc,
1316 ipmi_solparm_done_cb done,
1317 void *cb_data)
1318 {
1319 ipmi_sol_config_t *solc;
1320 unsigned char data[MAX_IPMI_DATA_SIZE];
1321 solparms_t *lp;
1322 int rv;
1323
1324 if (osolc->my_sol != solparm)
1325 return EINVAL;
1326
1327 if (!osolc->sol_locked)
1328 return EINVAL;
1329
1330 solc = ipmi_mem_alloc(sizeof(*solc));
1331 if (!solc)
1332 return ENOMEM;
1333
1334 *solc = *osolc;
1335 solc->err = 0;
1336 solc->sol_locked = 0; /* Set this here, since we will unlock it,
1337 but we don't want the free operation to
1338 attempt an unlock */
1339
1340 solc->curr_parm = 1;
1341 solc->curr_sel = 0;
1342 solc->set_done = done;
1343 solc->cb_data = cb_data;
1344
1345 /* Parm 1 is known good for writing. */
1346 lp = &(solparms[solc->curr_parm]);
1347 lp->set_handler(solc, lp, data);
1348 rv = ipmi_solparm_set_parm(solparm, solc->curr_parm,
1349 data, lp->length, set_done, solc);
1350 if (rv) {
1351 ipmi_sol_free_config(solc);
1352 } else {
1353 /* The old config no longer holds the lock. */
1354 osolc->sol_locked = 0;
1355 solparm_get(solparm);
1356 }
1357 return rv;
1358 }
1359
1360 typedef struct clear_lock_s
1361 {
1362 ipmi_solparm_done_cb done;
1363 void *cb_data;
1364
1365 } clear_lock_t;
1366
1367 static void
lock_cleared(ipmi_solparm_t * solparm,int err,void * cb_data)1368 lock_cleared(ipmi_solparm_t *solparm,
1369 int err,
1370 void *cb_data)
1371 {
1372 clear_lock_t *cl = cb_data;
1373
1374 cl->done(solparm, err, cl->cb_data);
1375
1376 ipmi_mem_free(cl);
1377 solparm->locked = 0;
1378 solparm_put(solparm);
1379 }
1380
1381 int
ipmi_sol_clear_lock(ipmi_solparm_t * solparm,ipmi_sol_config_t * solc,ipmi_solparm_done_cb done,void * cb_data)1382 ipmi_sol_clear_lock(ipmi_solparm_t *solparm,
1383 ipmi_sol_config_t *solc,
1384 ipmi_solparm_done_cb done,
1385 void *cb_data)
1386 {
1387 unsigned char data[1];
1388 int rv;
1389 clear_lock_t *cl;
1390
1391 if (solc) {
1392 if (solc->my_sol != solparm)
1393 return EINVAL;
1394
1395 if (!solc->sol_locked)
1396 return EINVAL;
1397 }
1398
1399 cl = ipmi_mem_alloc(sizeof(*cl));
1400 if (!cl)
1401 return ENOMEM;
1402 cl->done = done;
1403 cl->cb_data = cb_data;
1404
1405 data[0] = 0; /* Clear the lock. */
1406 rv = ipmi_solparm_set_parm(solparm, 0, data, 1, lock_cleared, cl);
1407 if (rv) {
1408 ipmi_mem_free(cl);
1409 } else {
1410 if (solc)
1411 solc->sol_locked = 0;
1412 solparm_get(solparm);
1413 }
1414
1415 return rv;
1416 }
1417
1418 void
ipmi_sol_free_config(ipmi_sol_config_t * solc)1419 ipmi_sol_free_config(ipmi_sol_config_t *solc)
1420 {
1421 ipmi_mem_free(solc);
1422 }
1423
1424
1425 #define LP_INT_PARM(n) \
1426 unsigned int \
1427 ipmi_solconfig_get_ ## n(ipmi_sol_config_t *solc) \
1428 { \
1429 return solc->n; \
1430 } \
1431 int \
1432 ipmi_solconfig_set_ ## n(ipmi_sol_config_t *solc, \
1433 unsigned int val) \
1434 { \
1435 solc->n = val; \
1436 return 0; \
1437 }
1438
1439
1440 LP_INT_PARM(enable)
1441 LP_INT_PARM(force_payload_encryption)
1442 LP_INT_PARM(force_payload_authentication)
1443 LP_INT_PARM(privilege_level)
1444 LP_INT_PARM(char_accumulation_interval)
1445 LP_INT_PARM(char_send_threshold)
1446 LP_INT_PARM(retry_count)
1447 LP_INT_PARM(retry_interval)
1448 LP_INT_PARM(non_volatile_bitrate)
1449 LP_INT_PARM(volatile_bitrate)
1450
1451
1452 #define LP_INT_PARM_SUP(n, s) \
1453 int \
1454 ipmi_solconfig_get_ ## n(ipmi_sol_config_t *solc, \
1455 unsigned int *data) \
1456 { \
1457 if (! solc->s) \
1458 return ENOSYS; \
1459 *data = solc->n; \
1460 return 0; \
1461 } \
1462 int \
1463 ipmi_solconfig_set_ ## n(ipmi_sol_config_t *solc, \
1464 unsigned int data) \
1465 { \
1466 if (! solc->s) \
1467 return ENOSYS; \
1468 solc->n = data; \
1469 return 0; \
1470 }
1471
1472 LP_INT_PARM_SUP(payload_channel, payload_channel_supported);
1473 LP_INT_PARM_SUP(port_number, port_number_supported)
1474
1475
1476 typedef struct solparm_gendata_s
1477 {
1478 enum ipmi_solconf_val_type_e datatype;
1479 char *fname;
1480
1481 union {
1482 struct {
1483 unsigned int (*gval)(ipmi_sol_config_t *solc);
1484 int (*gval_v)(ipmi_sol_config_t *solc, unsigned int *val);
1485 int (*gval_iv)(ipmi_sol_config_t *solc, unsigned int idx,
1486 unsigned int *val);
1487 int (*sval)(ipmi_sol_config_t *solc, unsigned int val);
1488 int (*sval_v)(ipmi_sol_config_t *solc, unsigned int val);
1489 int (*sval_iv)(ipmi_sol_config_t *solc, unsigned int idx,
1490 unsigned int val);
1491 } ival;
1492 struct {
1493 int (*gval_v)(ipmi_sol_config_t *solc, unsigned char *data,
1494 unsigned int *data_len);
1495 int (*gval_iv)(ipmi_sol_config_t *solc, unsigned int idx,
1496 unsigned char *data, unsigned int *data_len);
1497 int (*sval_v)(ipmi_sol_config_t *solc, unsigned char *data,
1498 unsigned int data_len);
1499 int (*sval_iv)(ipmi_sol_config_t *solc, unsigned int idx,
1500 unsigned char *data, unsigned int data_len);
1501 } dval;
1502 } u;
1503 unsigned int (*iv_cnt)(ipmi_sol_config_t *solc);
1504 } solparm_gendata_t;
1505
1506 #define F_BOOL(name) \
1507 { .datatype = IPMI_SOLCONFIG_BOOL, .fname = #name, \
1508 .u = { .ival = { .gval = ipmi_solconfig_get_ ## name, \
1509 .sval = ipmi_solconfig_set_ ## name }}}
1510 #define F_INT(name) \
1511 { .datatype = IPMI_SOLCONFIG_INT, .fname = #name, \
1512 .u = { .ival = { .gval = ipmi_solconfig_get_ ## name, \
1513 .sval = ipmi_solconfig_set_ ## name }}}
1514 #define F_INTV(name) \
1515 { .datatype = IPMI_SOLCONFIG_INT, .fname = #name, \
1516 .u = { .ival = { .gval_v = ipmi_solconfig_get_ ## name, \
1517 .sval_v = ipmi_solconfig_set_ ## name }}}
1518
1519 static solparm_gendata_t gdata[] =
1520 {
1521 F_BOOL(enable), /* 0 */
1522 F_BOOL(force_payload_encryption),
1523 F_BOOL(force_payload_authentication),
1524 F_INT(privilege_level),
1525 F_INT(retry_count),
1526 F_INT(retry_interval), /* 5 */
1527 F_INT(char_accumulation_interval),
1528 F_INT(char_send_threshold),
1529 F_INT(non_volatile_bitrate),
1530 F_INT(volatile_bitrate),
1531 F_INTV(payload_channel), /* 10 */
1532 F_INTV(port_number),
1533 };
1534 #define NUM_GDATA_ENTRIES (sizeof(gdata) / sizeof(solparm_gendata_t))
1535
1536 int
ipmi_solconfig_enum_val(unsigned int parm,int val,int * nval,const char ** sval)1537 ipmi_solconfig_enum_val(unsigned int parm, int val, int *nval,
1538 const char **sval)
1539 {
1540 char *rval;
1541 int rnval;
1542
1543 switch (parm) {
1544 case 3: /* privilege level */
1545 if (val < 2) {
1546 if (nval)
1547 *nval = 2;
1548 return EINVAL;
1549 }
1550
1551 switch (val) {
1552 case 2:
1553 rval = "user";
1554 rnval = 3;
1555 break;
1556 case 3:
1557 rval = "operator";
1558 rnval = 4;
1559 break;
1560 case 4:
1561 rval = "admin";
1562 rnval = 5;
1563 break;
1564 case 5:
1565 rval = "oem";
1566 rnval = -1;
1567 break;
1568 default:
1569 if (*nval)
1570 *nval = -1;
1571 return EINVAL;
1572 }
1573 break;
1574
1575 case 8: case 9:
1576 if (val < 6) {
1577 if (nval)
1578 *nval = 6;
1579 return EINVAL;
1580 }
1581
1582 switch (val) {
1583 case 6:
1584 rval = "9600";
1585 rnval = 7;
1586 break;
1587 case 7:
1588 rval = "19.2K";
1589 rnval = 8;
1590 break;
1591 case 8:
1592 rval = "38.4K";
1593 rnval = 9;
1594 break;
1595 case 9:
1596 rval = "57.6K";
1597 rnval = 10;
1598 break;
1599 case 10:
1600 rval = "115.2K";
1601 rnval = -1;
1602 break;
1603 default:
1604 if (*nval)
1605 *nval = -1;
1606 return EINVAL;
1607 }
1608 break;
1609
1610 default:
1611 return ENOSYS;
1612 }
1613
1614
1615 if (sval)
1616 *sval = rval;
1617 if (nval)
1618 *nval = rnval;
1619 return 0;
1620 }
1621
1622 int
ipmi_solconfig_enum_idx(unsigned int parm,int idx,const char ** sval)1623 ipmi_solconfig_enum_idx(unsigned int parm, int idx, const char **sval)
1624 {
1625 return ENOSYS;
1626 }
1627
1628 int
ipmi_solconfig_get_val(ipmi_sol_config_t * solc,unsigned int parm,const char ** name,int * index,enum ipmi_solconf_val_type_e * valtype,unsigned int * ival,unsigned char ** dval,unsigned int * dval_len)1629 ipmi_solconfig_get_val(ipmi_sol_config_t *solc,
1630 unsigned int parm,
1631 const char **name,
1632 int *index,
1633 enum ipmi_solconf_val_type_e *valtype,
1634 unsigned int *ival,
1635 unsigned char **dval,
1636 unsigned int *dval_len)
1637 {
1638 unsigned int curr = *index;
1639 unsigned int count;
1640 int rv = 0;
1641 unsigned char *data;
1642 unsigned int data_len;
1643
1644 if (parm >= NUM_GDATA_ENTRIES)
1645 return EINVAL;
1646 if (valtype)
1647 *valtype = gdata[parm].datatype;
1648 if (name)
1649 *name = gdata[parm].fname;
1650
1651 if (gdata[parm].iv_cnt) {
1652 count = gdata[parm].iv_cnt(solc);
1653 if (curr >= count) {
1654 *index = -1;
1655 return E2BIG;
1656 }
1657
1658 if (curr+1 == count)
1659 *index = -1;
1660 else
1661 *index = curr+1;
1662 }
1663
1664 switch (gdata[parm].datatype) {
1665 case IPMI_SOLCONFIG_INT:
1666 case IPMI_SOLCONFIG_BOOL:
1667 if (!ival)
1668 break;
1669 if (gdata[parm].u.ival.gval)
1670 *ival = gdata[parm].u.ival.gval(solc);
1671 else if (gdata[parm].u.ival.gval_v)
1672 rv = gdata[parm].u.ival.gval_v(solc, ival);
1673 else if (gdata[parm].u.ival.gval_iv)
1674 rv = gdata[parm].u.ival.gval_iv(solc, curr, ival);
1675 else
1676 rv = ENOSYS;
1677 break;
1678
1679 case IPMI_SOLCONFIG_DATA:
1680 case IPMI_SOLCONFIG_IP:
1681 case IPMI_SOLCONFIG_MAC:
1682 data_len = 0;
1683 if (gdata[parm].u.dval.gval_v)
1684 rv = gdata[parm].u.dval.gval_v(solc, NULL, &data_len);
1685 else if (gdata[parm].u.dval.gval_iv)
1686 rv = gdata[parm].u.dval.gval_iv(solc, curr, NULL, &data_len);
1687 else
1688 rv = ENOSYS;
1689 if (rv && (rv != EBADF))
1690 break;
1691 if (data_len == 0)
1692 data = ipmi_mem_alloc(1);
1693 else
1694 data = ipmi_mem_alloc(data_len);
1695 if (gdata[parm].u.dval.gval_v)
1696 rv = gdata[parm].u.dval.gval_v(solc, data, &data_len);
1697 else if (gdata[parm].u.dval.gval_iv)
1698 rv = gdata[parm].u.dval.gval_iv(solc, curr, data, &data_len);
1699 if (rv) {
1700 ipmi_mem_free(data);
1701 break;
1702 }
1703 if (dval)
1704 *dval = data;
1705 if (dval_len)
1706 *dval_len = data_len;
1707 break;
1708 }
1709
1710 return rv;
1711 }
1712
1713 int
ipmi_solconfig_set_val(ipmi_sol_config_t * solc,unsigned int parm,int index,unsigned int ival,unsigned char * dval,unsigned int dval_len)1714 ipmi_solconfig_set_val(ipmi_sol_config_t *solc,
1715 unsigned int parm,
1716 int index,
1717 unsigned int ival,
1718 unsigned char *dval,
1719 unsigned int dval_len)
1720 {
1721 unsigned int count;
1722 int rv = 0;
1723
1724 if (parm >= NUM_GDATA_ENTRIES)
1725 return EINVAL;
1726
1727 if (gdata[parm].iv_cnt) {
1728 count = gdata[parm].iv_cnt(solc);
1729 if (index >= (int) count)
1730 return E2BIG;
1731 }
1732
1733 switch (gdata[parm].datatype) {
1734 case IPMI_SOLCONFIG_INT:
1735 case IPMI_SOLCONFIG_BOOL:
1736 if (gdata[parm].u.ival.sval)
1737
1738 rv = gdata[parm].u.ival.sval(solc, ival);
1739 else if (gdata[parm].u.ival.sval_v)
1740 rv = gdata[parm].u.ival.sval_v(solc, ival);
1741 else if (gdata[parm].u.ival.sval_iv)
1742 rv = gdata[parm].u.ival.sval_iv(solc, index, ival);
1743 else
1744 rv = ENOSYS;
1745 break;
1746
1747 case IPMI_SOLCONFIG_DATA:
1748 case IPMI_SOLCONFIG_IP:
1749 case IPMI_SOLCONFIG_MAC:
1750 if (gdata[parm].u.dval.sval_v)
1751 rv = gdata[parm].u.dval.sval_v(solc, dval, dval_len);
1752 else if (gdata[parm].u.dval.sval_iv)
1753 rv = gdata[parm].u.dval.sval_iv(solc, index, dval, dval_len);
1754 else
1755 rv = ENOSYS;
1756 break;
1757 }
1758
1759 return rv;
1760 }
1761
1762
1763 void
ipmi_solconfig_data_free(void * data)1764 ipmi_solconfig_data_free(void *data)
1765 {
1766 ipmi_mem_free(data);
1767 }
1768
1769 unsigned int
ipmi_solconfig_str_to_parm(char * name)1770 ipmi_solconfig_str_to_parm(char *name)
1771 {
1772 unsigned int i;
1773 for (i=0; i<NUM_GDATA_ENTRIES; i++) {
1774 if (strcmp(name, gdata[i].fname) == 0)
1775 return i;
1776 }
1777 return -1;
1778 }
1779
1780 const char *
ipmi_solconfig_parm_to_str(unsigned int parm)1781 ipmi_solconfig_parm_to_str(unsigned int parm)
1782 {
1783 if (parm >= NUM_GDATA_ENTRIES)
1784 return NULL;
1785 return gdata[parm].fname;
1786 }
1787
1788 int
ipmi_solconfig_parm_to_type(unsigned int parm,enum ipmi_solconf_val_type_e * valtype)1789 ipmi_solconfig_parm_to_type(unsigned int parm,
1790 enum ipmi_solconf_val_type_e *valtype)
1791 {
1792 if (parm >= NUM_GDATA_ENTRIES)
1793 return EINVAL;
1794 *valtype = gdata[parm].datatype;
1795 return 0;
1796 }
1797