1 /*
2 * bmc_storage.c
3 *
4 * MontaVista IPMI code for emulating a MC.
5 *
6 * Author: MontaVista Software, Inc.
7 * Corey Minyard <minyard@mvista.com>
8 * source@mvista.com
9 *
10 * Copyright 2003,2012 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 * Modified BSD Licence
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 *
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above
42 * copyright notice, this list of conditions and the following
43 * disclaimer in the documentation and/or other materials provided
44 * with the distribution.
45 * 3. The name of the author may not be used to endorse or promote
46 * products derived from this software without specific prior
47 * written permission.
48 */
49
50 #include "bmc.h"
51
52 #include <errno.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <fcntl.h>
59 #include <time.h>
60
61 #include <OpenIPMI/ipmi_err.h>
62 #include <OpenIPMI/ipmi_msgbits.h>
63 #include <OpenIPMI/persist.h>
64
65 /*
66 * SEL handling commands.
67 */
68
69 #define IPMI_SEL_SUPPORTS_DELETE (1 << 3)
70 #define IPMI_SEL_SUPPORTS_RESERVE (1 << 1)
71 #define IPMI_SEL_SUPPORTS_GET_ALLOC_INFO (1 << 0)
72
73 static sel_entry_t *
find_sel_event_by_recid(lmc_data_t * mc,uint16_t record_id,sel_entry_t ** prev)74 find_sel_event_by_recid(lmc_data_t *mc,
75 uint16_t record_id,
76 sel_entry_t **prev)
77 {
78 sel_entry_t *entry;
79 sel_entry_t *p_entry = NULL;
80
81 entry = mc->sel.entries;
82 while (entry) {
83 if (record_id == entry->record_id)
84 break;
85 p_entry = entry;
86 entry = entry->next;
87 }
88 if (prev)
89 *prev = p_entry;
90 return entry;
91 }
92
93 static int
handle_sel(const char * name,void * data,unsigned int len,void * cb_data)94 handle_sel(const char *name, void *data, unsigned int len, void *cb_data)
95 {
96 sel_entry_t *e, *n;
97 lmc_data_t *mc = cb_data;
98
99 if (len != 16) {
100 mc->sysinfo->log(mc->sysinfo, INFO, NULL,
101 "Got invalid SEL entry for %2.2x, name is %s",
102 ipmi_mc_get_ipmb(mc), name);
103 goto out;
104 }
105
106 n = malloc(sizeof(*n));
107 if (!n)
108 return ENOMEM;
109
110 memcpy(n->data, data, 16);
111 n->record_id = n->data[0] | (n->data[1] << 8);
112 n->next = NULL;
113
114 e = mc->sel.entries;
115 if (!e)
116 mc->sel.entries = n;
117 else {
118 while (e->next)
119 e = e->next;
120 e->next = n;
121 }
122 mc->sel.count++;
123
124 out:
125 return ITER_PERSIST_CONTINUE;
126 }
127
128 static int
handle_sel_time(const char * name,long val,void * cb_data)129 handle_sel_time(const char *name, long val, void *cb_data)
130 {
131 lmc_data_t *mc = cb_data;
132
133 if (strcmp(name, "last_add_time") == 0)
134 mc->sel.last_add_time = val;
135 else if (strcmp(name, "last_erase_time") == 0)
136 mc->sel.last_erase_time = val;
137 return ITER_PERSIST_CONTINUE;
138 }
139
140 int
ipmi_mc_enable_sel(lmc_data_t * mc,int max_entries,unsigned char flags)141 ipmi_mc_enable_sel(lmc_data_t *mc,
142 int max_entries,
143 unsigned char flags)
144 {
145 persist_t *p;
146
147 mc->sel.entries = NULL;
148 mc->sel.count = 0;
149 mc->sel.max_count = max_entries;
150 mc->sel.last_add_time = 0;
151 mc->sel.last_erase_time = 0;
152 mc->sel.flags = flags & 0xb;
153 mc->sel.reservation = 0;
154 mc->sel.next_entry = 1;
155
156 p = read_persist("sel.%2.2x", ipmi_mc_get_ipmb(mc));
157 if (!p)
158 return 0;
159
160 iterate_persist(p, mc, handle_sel, handle_sel_time);
161 free_persist(p);
162 return 0;
163 }
164
165 static void
rewrite_sels(lmc_data_t * mc)166 rewrite_sels(lmc_data_t *mc)
167 {
168 persist_t *p = NULL;
169 sel_entry_t *e;
170 int err;
171
172 p = alloc_persist("sel.%2.2x", ipmi_mc_get_ipmb(mc));
173 if (!p) {
174 err = ENOMEM;
175 goto out_err;
176 }
177
178 err = add_persist_int(p, mc->sel.last_add_time, "last_add_time");
179 if (err)
180 goto out_err;
181
182 err = add_persist_int(p, mc->sel.last_erase_time, "last_erase_time");
183 if (err)
184 goto out_err;
185
186 for (e = mc->sel.entries; e; e = e->next) {
187 err = add_persist_data(p, e->data, 16, "%d", e->record_id);
188 if (err)
189 goto out_err;
190 }
191
192 err = write_persist(p);
193 if (err)
194 goto out_err;
195 free_persist(p);
196 return;
197
198 out_err:
199 mc->sysinfo->log(mc->sysinfo, OS_ERROR, NULL,
200 "Unable to write persistent SELs for MC %d: %d",
201 ipmi_mc_get_ipmb(mc), err);
202 if (p)
203 free_persist(p);
204 }
205
206 int
ipmi_mc_add_to_sel(lmc_data_t * mc,unsigned char record_type,unsigned char event[13],unsigned int * recid)207 ipmi_mc_add_to_sel(lmc_data_t *mc,
208 unsigned char record_type,
209 unsigned char event[13],
210 unsigned int *recid)
211 {
212 sel_entry_t *e;
213 struct timeval t;
214 uint16_t start_record_id;
215
216 if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE))
217 return ENOTSUP;
218
219 if (mc->sel.count >= mc->sel.max_count) {
220 mc->sel.flags |= 0x80;
221 return EAGAIN;
222 }
223
224 e = malloc(sizeof(*e));
225 if (!e)
226 return ENOMEM;
227
228 /* FIXME - this is inefficient, but simple */
229 e->record_id = mc->sel.next_entry;
230 mc->sel.next_entry++;
231 start_record_id = e->record_id;
232 while ((mc->sel.next_entry == 0)
233 || find_sel_event_by_recid(mc, e->record_id, NULL))
234 {
235 e->record_id++;
236 if (e->record_id == start_record_id) {
237 free(e);
238 return EAGAIN;
239 }
240 mc->sel.next_entry++;
241 }
242
243 mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
244
245 ipmi_set_uint16(e->data, e->record_id);
246 e->data[2] = record_type;
247 if (record_type < 0xe0) {
248 ipmi_set_uint32(e->data+3, t.tv_sec + mc->sel.time_offset);
249 memcpy(e->data+7, event+4, 9);
250 } else {
251 memcpy(e->data+3, event, 13);
252 }
253
254 e->next = NULL;
255 if (!mc->sel.entries) {
256 mc->sel.entries = e;
257 } else {
258 sel_entry_t *f = mc->sel.entries;
259 while (f->next)
260 f = f->next;
261 f->next = e;
262 }
263
264 mc->sel.count++;
265
266 mc->sel.last_add_time = t.tv_sec + mc->sel.time_offset;
267
268 if (recid)
269 *recid = e->record_id;
270
271 rewrite_sels(mc);
272
273 return 0;
274 }
275
276 void
mc_new_event(lmc_data_t * mc,unsigned char record_type,unsigned char event[13])277 mc_new_event(lmc_data_t *mc,
278 unsigned char record_type,
279 unsigned char event[13])
280 {
281 unsigned int recid;
282 int rv;
283
284 if (IPMI_MC_EVENT_LOG_ENABLED(mc)) {
285 rv = ipmi_mc_add_to_sel(mc, record_type, event, &recid);
286 if (rv)
287 recid = 0xffff;
288 } else
289 recid = 0xffff;
290 if (!mc->ev_in_q && IPMI_MC_EVENT_MSG_BUF_ENABLED(mc)) {
291 channel_t *chan = mc->channels[15];
292 mc->ev_in_q = 1;
293 ipmi_set_uint16(mc->evq, recid);
294 mc->evq[2] = record_type;
295 memcpy(mc->evq + 3, event, 13);
296 mc->msg_flags |= IPMI_MC_MSG_FLAG_EVT_BUF_FULL;
297 if (chan->set_atn)
298 chan->set_atn(chan, 1, IPMI_MC_EVBUF_FULL_INT_ENABLED(mc));
299 }
300 }
301
302 static void
handle_get_sel_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)303 handle_get_sel_info(lmc_data_t *mc,
304 msg_t *msg,
305 unsigned char *rdata,
306 unsigned int *rdata_len,
307 void *cb_data)
308 {
309 if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
310 handle_invalid_cmd(mc, rdata, rdata_len);
311 return;
312 }
313
314 memset(rdata, 0, 15);
315 rdata[1] = 0x51;
316 ipmi_set_uint16(rdata+2, mc->sel.count);
317 ipmi_set_uint16(rdata+4, (mc->sel.max_count - mc->sel.count) * 16);
318 ipmi_set_uint32(rdata+6, mc->sel.last_add_time);
319 ipmi_set_uint32(rdata+10, mc->sel.last_erase_time);
320 rdata[14] = mc->sel.flags;
321
322 *rdata_len = 15;
323 }
324
325 static void
handle_get_sel_allocation_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)326 handle_get_sel_allocation_info(lmc_data_t *mc,
327 msg_t *msg,
328 unsigned char *rdata,
329 unsigned int *rdata_len,
330 void *cb_data)
331 {
332 if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
333 handle_invalid_cmd(mc, rdata, rdata_len);
334 return;
335 }
336
337 if (!(mc->sel.flags & IPMI_SEL_SUPPORTS_GET_ALLOC_INFO)) {
338 handle_invalid_cmd(mc, rdata, rdata_len);
339 return;
340 }
341
342 memset(rdata, 0, 10);
343 ipmi_set_uint16(rdata+1, mc->sel.max_count * 16);
344 ipmi_set_uint16(rdata+3, 16);
345 ipmi_set_uint32(rdata+5, (mc->sel.max_count - mc->sel.count) * 16);
346 ipmi_set_uint32(rdata+7, (mc->sel.max_count - mc->sel.count) * 16);
347 rdata[9] = 1;
348
349 *rdata_len = 10;
350 }
351
352 static void
handle_reserve_sel(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)353 handle_reserve_sel(lmc_data_t *mc,
354 msg_t *msg,
355 unsigned char *rdata,
356 unsigned int *rdata_len,
357 void *cb_data)
358 {
359 if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
360 handle_invalid_cmd(mc, rdata, rdata_len);
361 return;
362 }
363
364 if (!(mc->sel.flags & IPMI_SEL_SUPPORTS_RESERVE)) {
365 handle_invalid_cmd(mc, rdata, rdata_len);
366 return;
367 }
368
369 mc->sel.reservation++;
370 if (mc->sel.reservation == 0)
371 mc->sel.reservation++;
372 rdata[0] = 0;
373 ipmi_set_uint16(rdata+1, mc->sel.reservation);
374 *rdata_len = 3;
375 }
376
377 static void
handle_get_sel_entry(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)378 handle_get_sel_entry(lmc_data_t *mc,
379 msg_t *msg,
380 unsigned char *rdata,
381 unsigned int *rdata_len,
382 void *cb_data)
383 {
384 uint16_t record_id;
385 int offset;
386 int count;
387 sel_entry_t *entry;
388
389 if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
390 handle_invalid_cmd(mc, rdata, rdata_len);
391 return;
392 }
393
394 if (check_msg_length(msg, 6, rdata, rdata_len))
395 return;
396
397 if (mc->sel.flags & IPMI_SEL_SUPPORTS_RESERVE) {
398 uint16_t reservation = ipmi_get_uint16(msg->data+0);
399
400 if ((reservation != 0) && (reservation != mc->sel.reservation)) {
401 rdata[0] = IPMI_INVALID_RESERVATION_CC;
402 *rdata_len = 1;
403 return;
404 }
405 }
406
407 record_id = ipmi_get_uint16(msg->data+2);
408 offset = msg->data[4];
409 count = msg->data[5];
410
411 if (offset >= 16) {
412 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
413 *rdata_len = 1;
414 return;
415 }
416
417 if (record_id == 0) {
418 entry = mc->sel.entries;
419 } else if (record_id == 0xffff) {
420 entry = mc->sel.entries;
421 if (entry) {
422 while (entry->next) {
423 entry = entry->next;
424 }
425 }
426 } else {
427 entry = find_sel_event_by_recid(mc, record_id, NULL);
428 }
429
430 if (entry == NULL) {
431 rdata[0] = IPMI_NOT_PRESENT_CC;
432 *rdata_len = 1;
433 return;
434 }
435
436 rdata[0] = 0;
437 if (entry->next)
438 ipmi_set_uint16(rdata+1, entry->next->record_id);
439 else {
440 rdata[1] = 0xff;
441 rdata[2] = 0xff;
442 }
443
444 if ((offset+count) > 16)
445 count = 16 - offset;
446 memcpy(rdata+3, entry->data+offset, count);
447 *rdata_len = count + 3;
448 }
449
450 static void
handle_add_sel_entry(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)451 handle_add_sel_entry(lmc_data_t *mc,
452 msg_t *msg,
453 unsigned char *rdata,
454 unsigned int *rdata_len,
455 void *cb_data)
456 {
457 int rv;
458 unsigned int r;
459
460 if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
461 handle_invalid_cmd(mc, rdata, rdata_len);
462 return;
463 }
464
465 if (check_msg_length(msg, 16, rdata, rdata_len))
466 return;
467
468 rv = ipmi_mc_add_to_sel(mc, msg->data[2], msg->data+3, &r);
469 if (rv == EAGAIN) {
470 rdata[0] = IPMI_OUT_OF_SPACE_CC;
471 } else if (rv) {
472 rdata[0] = IPMI_UNKNOWN_ERR_CC;
473 } else {
474 rdata[0] = 0;
475 ipmi_set_uint16(rdata+1, r);
476 }
477 *rdata_len = 3;
478 }
479
480 static void
handle_delete_sel_entry(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)481 handle_delete_sel_entry(lmc_data_t *mc,
482 msg_t *msg,
483 unsigned char *rdata,
484 unsigned int *rdata_len,
485 void *cb_data)
486 {
487 uint16_t record_id;
488 sel_entry_t *entry, *p_entry;
489
490 if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
491 handle_invalid_cmd(mc, rdata, rdata_len);
492 return;
493 }
494
495 if (!(mc->sel.flags & IPMI_SEL_SUPPORTS_DELETE)) {
496 handle_invalid_cmd(mc, rdata, rdata_len);
497 return;
498 }
499
500 if (check_msg_length(msg, 4, rdata, rdata_len))
501 return;
502
503 if (mc->sel.flags & IPMI_SEL_SUPPORTS_RESERVE) {
504 uint16_t reservation = ipmi_get_uint16(msg->data+0);
505
506 if ((reservation != 0) && (reservation != mc->sel.reservation)) {
507 rdata[0] = IPMI_INVALID_RESERVATION_CC;
508 *rdata_len = 1;
509 return;
510 }
511 }
512
513 record_id = ipmi_get_uint16(msg->data+2);
514
515 if (record_id == 0) {
516 entry = mc->sel.entries;
517 p_entry = NULL;
518 } else if (record_id == 0xffff) {
519 entry = mc->sel.entries;
520 p_entry = NULL;
521 if (entry) {
522 while (entry->next) {
523 p_entry = entry;
524 entry = entry->next;
525 }
526 }
527 } else {
528 entry = find_sel_event_by_recid(mc, record_id, &p_entry);
529 }
530 if (!entry) {
531 rdata[0] = IPMI_NOT_PRESENT_CC;
532 *rdata_len = 1;
533 return;
534 }
535
536 if (p_entry)
537 p_entry->next = entry->next;
538 else
539 mc->sel.entries = entry->next;
540
541 /* Clear the overflow flag. */
542 mc->sel.flags &= ~0x80;
543
544 rdata[0] = 0;
545 ipmi_set_uint16(rdata+1, entry->record_id);
546 *rdata_len = 3;
547
548 mc->sel.count--;
549 free(entry);
550
551 rewrite_sels(mc);
552 }
553
554 static void
handle_clear_sel(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)555 handle_clear_sel(lmc_data_t *mc,
556 msg_t *msg,
557 unsigned char *rdata,
558 unsigned int *rdata_len,
559 void *cb_data)
560 {
561 sel_entry_t *entry, *n_entry;
562 unsigned char op;
563 struct timeval t;
564
565 if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
566 handle_invalid_cmd(mc, rdata, rdata_len);
567 return;
568 }
569
570 if (check_msg_length(msg, 6, rdata, rdata_len))
571 return;
572
573 if (mc->sel.flags & IPMI_SEL_SUPPORTS_RESERVE) {
574 uint16_t reservation = ipmi_get_uint16(msg->data+0);
575
576 if ((reservation != 0) && (reservation != mc->sel.reservation)) {
577 rdata[0] = IPMI_INVALID_RESERVATION_CC;
578 *rdata_len = 1;
579 return;
580 }
581 }
582
583 if ((msg->data[2] != 'C')
584 || (msg->data[3] != 'L')
585 || (msg->data[4] != 'R'))
586 {
587 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
588 *rdata_len = 1;
589 return;
590 }
591
592 op = msg->data[5];
593 if ((op != 0) && (op != 0xaa))
594 {
595 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
596 *rdata_len = 1;
597 return;
598 }
599
600 rdata[1] = 1;
601 if (op == 0xaa) {
602 entry = mc->sel.entries;
603 mc->sel.entries = NULL;
604 mc->sel.count = 0;
605 while (entry) {
606 n_entry = entry->next;
607 free(entry);
608 entry = n_entry;
609 }
610 }
611
612 mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
613 mc->sel.last_erase_time = t.tv_sec + mc->sel.time_offset;
614
615 rdata[0] = 0;
616 *rdata_len = 2;
617
618 /* Clear the overflow flag. */
619 mc->sel.flags &= ~0x80;
620
621 rewrite_sels(mc);
622 }
623
624 static void
handle_get_sel_time(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)625 handle_get_sel_time(lmc_data_t *mc,
626 msg_t *msg,
627 unsigned char *rdata,
628 unsigned int *rdata_len,
629 void *cb_data)
630 {
631 struct timeval t;
632
633 if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
634 handle_invalid_cmd(mc, rdata, rdata_len);
635 return;
636 }
637
638 mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
639 rdata[0] = 0;
640 ipmi_set_uint32(rdata+1, t.tv_sec + mc->sel.time_offset);
641 *rdata_len = 5;
642 }
643
644 static void
handle_set_sel_time(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)645 handle_set_sel_time(lmc_data_t *mc,
646 msg_t *msg,
647 unsigned char *rdata,
648 unsigned int *rdata_len,
649 void *cb_data)
650 {
651 struct timeval t;
652
653 if (!(mc->device_support & IPMI_DEVID_SEL_DEVICE)) {
654 handle_invalid_cmd(mc, rdata, rdata_len);
655 return;
656 }
657
658 if (check_msg_length(msg, 4, rdata, rdata_len))
659 return;
660
661 mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
662 mc->sel.time_offset = ipmi_get_uint32(msg->data) - t.tv_sec;
663
664 rdata[0] = 0;
665 *rdata_len = 1;
666 }
667
668 /*
669 * SDR handling commands
670 */
671
672 #define IPMI_SDR_OVERFLOW_FLAG (1 << 7)
673 #define IPMI_SDR_GET_MODAL(v) (((v) >> 5) & 0x3)
674 #define IPMI_SDR_MODAL_UNSPECIFIED 0
675 #define IPMI_SDR_NON_MODAL_ONLY 1
676 #define IPMI_SDR_MODAL_ONLY 2
677 #define IPMI_SDR_MODAL_BOTH 3
678
679 sdr_t *
find_sdr_by_recid(sdrs_t * sdrs,uint16_t record_id,sdr_t ** prev)680 find_sdr_by_recid(sdrs_t *sdrs,
681 uint16_t record_id,
682 sdr_t **prev)
683 {
684 sdr_t *entry;
685 sdr_t *p_entry = NULL;
686
687 entry = sdrs->sdrs;
688 while (entry) {
689 if (record_id == entry->record_id)
690 break;
691 p_entry = entry;
692 entry = entry->next;
693 }
694 if (prev)
695 *prev = p_entry;
696 return entry;
697 }
698
699 sdr_t *
new_sdr_entry(sdrs_t * sdrs,unsigned char length)700 new_sdr_entry(sdrs_t *sdrs, unsigned char length)
701 {
702 sdr_t *entry;
703 uint16_t start_recid;
704
705 start_recid = sdrs->next_entry;
706 while (find_sdr_by_recid(sdrs, sdrs->next_entry, NULL)) {
707 sdrs->next_entry++;
708 if (sdrs->next_entry == 0xffff)
709 sdrs->next_entry = 1;
710 if (sdrs->next_entry == start_recid)
711 return NULL;
712 }
713
714 entry = malloc(sizeof(*entry));
715 if (!entry)
716 return NULL;
717
718 entry->data = malloc(length + 6);
719 if (!entry->data) {
720 free(entry);
721 return NULL;
722 }
723
724 entry->record_id = sdrs->next_entry;
725
726 sdrs->next_entry++;
727
728 ipmi_set_uint16(entry->data, entry->record_id);
729
730 entry->length = length + 6;
731 entry->next = NULL;
732 return entry;
733 }
734
735 static void
rewrite_sdrs(lmc_data_t * mc,sdrs_t * sdrs)736 rewrite_sdrs(lmc_data_t *mc, sdrs_t *sdrs)
737 {
738 persist_t *p = NULL;
739 sdr_t *sdr;
740 int err;
741
742 p = alloc_persist("sdr.%2.2x.main", ipmi_mc_get_ipmb(mc));
743 if (!p) {
744 err = ENOMEM;
745 goto out_err;
746 }
747
748 err = add_persist_int(p, sdrs->last_add_time, "last_add_time");
749 if (err)
750 goto out_err;
751
752 err = add_persist_int(p, sdrs->last_erase_time, "last_erase_time");
753 if (err)
754 goto out_err;
755
756 for (sdr = sdrs->sdrs; sdr; sdr = sdr->next) {
757 unsigned int recid = ipmi_get_uint16(sdr->data);
758 err = add_persist_data(p, sdr->data, sdr->length, "%d", recid);
759 if (err)
760 goto out_err;
761 }
762
763 err = write_persist(p);
764 if (err)
765 goto out_err;
766 free_persist(p);
767 return;
768
769 out_err:
770 mc->sysinfo->log(mc->sysinfo, OS_ERROR, NULL,
771 "Unable to write persistent SDRs for MC %d: %d",
772 ipmi_mc_get_ipmb(mc), err);
773 if (p)
774 free_persist(p);
775 }
776
777 void
add_sdr_entry(lmc_data_t * mc,sdrs_t * sdrs,sdr_t * entry)778 add_sdr_entry(lmc_data_t *mc, sdrs_t *sdrs, sdr_t *entry)
779 {
780 sdr_t *p;
781 struct timeval t;
782
783 entry->next = NULL;
784 p = sdrs->sdrs;
785 if (!p)
786 sdrs->sdrs = entry;
787 else {
788 while (p->next)
789 p = p->next;
790 p->next = entry;
791 }
792
793 mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
794 sdrs->last_add_time = t.tv_sec + mc->main_sdrs.time_offset;
795 sdrs->sdr_count++;
796
797 rewrite_sdrs(mc, sdrs);
798 }
799
800 static void
free_sdr(sdr_t * sdr)801 free_sdr(sdr_t *sdr)
802 {
803 free(sdr->data);
804 free(sdr);
805 }
806
807 static int
handle_sdr(const char * name,void * data,unsigned int len,void * cb_data)808 handle_sdr(const char *name, void *data, unsigned int len, void *cb_data)
809 {
810 sdr_t *sdr, *p;
811 sdrs_t *sdrs = cb_data;
812
813 sdr = new_sdr_entry(sdrs, len);
814 if (!sdr)
815 return ENOMEM;
816 memcpy(sdr->data, data, len);
817
818 sdr->next = NULL;
819 p = sdrs->sdrs;
820 if (!p)
821 sdrs->sdrs = sdr;
822 else {
823 while (p->next)
824 p = p->next;
825 p->next = sdr;
826 }
827 sdrs->sdr_count++;
828
829 return ITER_PERSIST_CONTINUE;
830 }
831
832 static int
handle_sdr_time(const char * name,long val,void * cb_data)833 handle_sdr_time(const char *name, long val, void *cb_data)
834 {
835 sdrs_t *sdrs = cb_data;
836
837 if (strcmp(name, "last_add_time") == 0)
838 sdrs->last_add_time = val;
839 else if (strcmp(name, "last_erase_time") == 0)
840 sdrs->last_erase_time = val;
841 return ITER_PERSIST_CONTINUE;
842 }
843
844 void
read_mc_sdrs(lmc_data_t * mc,sdrs_t * sdrs,const char * sdrtype)845 read_mc_sdrs(lmc_data_t *mc, sdrs_t *sdrs, const char *sdrtype)
846 {
847 persist_t *p;
848
849 p = read_persist("sdr.%2.2x.%s", ipmi_mc_get_ipmb(mc), sdrtype);
850 if (!p)
851 return;
852
853 iterate_persist(p, sdrs, handle_sdr, handle_sdr_time);
854 free_persist(p);
855 }
856
857 int
ipmi_mc_add_main_sdr(lmc_data_t * mc,unsigned char * data,unsigned int data_len)858 ipmi_mc_add_main_sdr(lmc_data_t *mc,
859 unsigned char *data,
860 unsigned int data_len)
861 {
862 sdr_t *entry;
863
864 if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV))
865 return ENOSYS;
866
867 if ((data_len < 5) || (data_len != (((unsigned int) data[4]) + 5)))
868 return EINVAL;
869
870 entry = new_sdr_entry(&mc->main_sdrs, data_len);
871 if (!entry)
872 return ENOMEM;
873
874 memcpy(entry->data+2, data+2, data_len-2);
875
876 add_sdr_entry(mc, &mc->main_sdrs, entry);
877
878 return 0;
879 }
880
881 int
ipmi_mc_add_device_sdr(lmc_data_t * mc,unsigned char lun,unsigned char * data,unsigned int data_len)882 ipmi_mc_add_device_sdr(lmc_data_t *mc,
883 unsigned char lun,
884 unsigned char *data,
885 unsigned int data_len)
886 {
887 struct timeval t;
888 sdr_t *entry;
889
890 if (lun >= 4)
891 return EINVAL;
892
893 if (!(mc->has_device_sdrs)) {
894 return ENOSYS;
895 }
896
897 entry = new_sdr_entry(&mc->device_sdrs[lun], data_len);
898 if (!entry)
899 return ENOMEM;
900
901 add_sdr_entry(mc, &mc->device_sdrs[lun], entry);
902
903 memcpy(entry->data+2, data+2, data_len-2);
904
905 mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
906 mc->sensor_population_change_time = t.tv_sec + mc->main_sdrs.time_offset;
907 mc->lun_has_sensors[lun] = 1;
908 mc->num_sensors_per_lun[lun]++;
909 return 0;
910 }
911
912 static void
handle_get_sdr_repository_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)913 handle_get_sdr_repository_info(lmc_data_t *mc,
914 msg_t *msg,
915 unsigned char *rdata,
916 unsigned int *rdata_len,
917 void *cb_data)
918 {
919 unsigned int space;
920
921 if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
922 handle_invalid_cmd(mc, rdata, rdata_len);
923 return;
924 }
925
926 rdata[0] = 0;
927 rdata[1] = 0x51;
928 ipmi_set_uint16(rdata+2, mc->main_sdrs.sdr_count);
929 space = MAX_SDR_LENGTH * (MAX_NUM_SDRS - mc->main_sdrs.sdr_count);
930 if (space > 0xfffe)
931 space = 0xfffe;
932 ipmi_set_uint16(rdata+4, space);
933 ipmi_set_uint32(rdata+6, mc->main_sdrs.last_add_time);
934 ipmi_set_uint32(rdata+10, mc->main_sdrs.last_erase_time);
935 rdata[14] = mc->main_sdrs.flags;
936 *rdata_len = 15;
937 }
938
939 static void
handle_get_sdr_repository_alloc_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)940 handle_get_sdr_repository_alloc_info(lmc_data_t *mc,
941 msg_t *msg,
942 unsigned char *rdata,
943 unsigned int *rdata_len,
944 void *cb_data)
945 {
946 if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
947 handle_invalid_cmd(mc, rdata, rdata_len);
948 return;
949 }
950
951 if (!(mc->main_sdrs.flags & IPMI_SDR_GET_SDR_ALLOC_INFO_SDR_SUPPORTED)) {
952 handle_invalid_cmd(mc, rdata, rdata_len);
953 return;
954 }
955
956 rdata[0] = 0;
957 ipmi_set_uint16(rdata+1, MAX_NUM_SDRS);
958 ipmi_set_uint16(rdata+3, MAX_SDR_LENGTH);
959 ipmi_set_uint16(rdata+5, MAX_NUM_SDRS - mc->main_sdrs.sdr_count);
960 ipmi_set_uint16(rdata+7, MAX_NUM_SDRS - mc->main_sdrs.sdr_count);
961 rdata[9] = 1;
962 *rdata_len = 10;
963 }
964
965 static void
handle_reserve_sdr_repository(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)966 handle_reserve_sdr_repository(lmc_data_t *mc,
967 msg_t *msg,
968 unsigned char *rdata,
969 unsigned int *rdata_len,
970 void *cb_data)
971 {
972 if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
973 handle_invalid_cmd(mc, rdata, rdata_len);
974 return;
975 }
976
977 if (!(mc->main_sdrs.flags & IPMI_SDR_RESERVE_SDR_SUPPORTED)) {
978 handle_invalid_cmd(mc, rdata, rdata_len);
979 return;
980 }
981
982 mc->main_sdrs.reservation++;
983 if (mc->main_sdrs.reservation == 0)
984 mc->main_sdrs.reservation++;
985
986 rdata[0] = 0;
987 ipmi_set_uint16(rdata+1, mc->main_sdrs.reservation);
988 *rdata_len = 3;
989
990 /* If adding an SDR and the reservation changes, we have to
991 destroy the working SDR addition. */
992 if (mc->part_add_sdr) {
993 free_sdr(mc->part_add_sdr);
994 mc->part_add_sdr = NULL;
995 }
996 }
997
998 static void
handle_get_sdr(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)999 handle_get_sdr(lmc_data_t *mc,
1000 msg_t *msg,
1001 unsigned char *rdata,
1002 unsigned int *rdata_len,
1003 void *cb_data)
1004 {
1005 uint16_t record_id;
1006 unsigned int offset;
1007 unsigned int count;
1008 sdr_t *entry;
1009
1010 if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1011 handle_invalid_cmd(mc, rdata, rdata_len);
1012 return;
1013 }
1014
1015 if (check_msg_length(msg, 6, rdata, rdata_len))
1016 return;
1017
1018 if (mc->main_sdrs.flags & IPMI_SDR_RESERVE_SDR_SUPPORTED) {
1019 uint16_t reservation = ipmi_get_uint16(msg->data+0);
1020
1021 if ((reservation != 0) && (reservation != mc->main_sdrs.reservation)) {
1022 rdata[0] = IPMI_INVALID_RESERVATION_CC;
1023 *rdata_len = 1;
1024 return;
1025 }
1026 }
1027
1028 record_id = ipmi_get_uint16(msg->data+2);
1029 offset = msg->data[4];
1030 count = msg->data[5];
1031
1032 if (record_id == 0) {
1033 entry = mc->main_sdrs.sdrs;
1034 } else if (record_id == 0xffff) {
1035 entry = mc->main_sdrs.sdrs;
1036 if (entry) {
1037 while (entry->next) {
1038 entry = entry->next;
1039 }
1040 }
1041 } else {
1042 entry = find_sdr_by_recid(&mc->main_sdrs, record_id, NULL);
1043 }
1044
1045 if (entry == NULL) {
1046 rdata[0] = IPMI_NOT_PRESENT_CC;
1047 *rdata_len = 1;
1048 return;
1049 }
1050
1051 if (offset >= entry->length) {
1052 rdata[0] = IPMI_PARAMETER_OUT_OF_RANGE_CC;
1053 *rdata_len = 1;
1054 return;
1055 }
1056
1057 if ((offset+count) > entry->length)
1058 count = entry->length - offset;
1059 if (count+3 > *rdata_len) {
1060 /* Too much data to put into response. */
1061 rdata[0] = IPMI_CANNOT_RETURN_REQ_LENGTH_CC;
1062 *rdata_len = 1;
1063 return;
1064 }
1065
1066 rdata[0] = 0;
1067 if (entry->next)
1068 ipmi_set_uint16(rdata+1, entry->next->record_id);
1069 else {
1070 rdata[1] = 0xff;
1071 rdata[2] = 0xff;
1072 }
1073
1074 memcpy(rdata+3, entry->data+offset, count);
1075 *rdata_len = count + 3;
1076 }
1077
1078 static void
handle_add_sdr(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1079 handle_add_sdr(lmc_data_t *mc,
1080 msg_t *msg,
1081 unsigned char *rdata,
1082 unsigned int *rdata_len,
1083 void *cb_data)
1084 {
1085 int modal;
1086 sdr_t *entry;
1087
1088 if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1089 handle_invalid_cmd(mc, rdata, rdata_len);
1090 return;
1091 }
1092
1093 modal = IPMI_SDR_GET_MODAL(mc->main_sdrs.flags);
1094 if ((modal == IPMI_SDR_NON_MODAL_ONLY)
1095 && !mc->in_update_mode)
1096 {
1097 rdata[0] = IPMI_NOT_SUPPORTED_IN_PRESENT_STATE_CC;
1098 *rdata_len = 1;
1099 return;
1100 }
1101
1102 if (check_msg_length(msg, 6, rdata, rdata_len))
1103 return;
1104
1105 if (msg->len != (unsigned int) msg->data[5] + 6) {
1106 rdata[0] = 0x80; /* Length is invalid. */
1107 *rdata_len = 1;
1108 return;
1109 }
1110
1111 entry = new_sdr_entry(&mc->main_sdrs, msg->data[5]);
1112 if (!entry) {
1113 rdata[0] = IPMI_OUT_OF_SPACE_CC;
1114 *rdata_len = 1;
1115 return;
1116 }
1117 add_sdr_entry(mc, &mc->main_sdrs, entry);
1118
1119 memcpy(entry->data+2, msg->data+2, entry->length-2);
1120
1121 rdata[0] = 0;
1122 ipmi_set_uint16(rdata+1, entry->record_id);
1123 *rdata_len = 3;
1124 }
1125
1126 static void
handle_partial_add_sdr(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1127 handle_partial_add_sdr(lmc_data_t *mc,
1128 msg_t *msg,
1129 unsigned char *rdata,
1130 unsigned int *rdata_len,
1131 void *cb_data)
1132 {
1133 uint16_t record_id;
1134 unsigned int offset;
1135 int modal;
1136
1137 if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1138 handle_invalid_cmd(mc, rdata, rdata_len);
1139 return;
1140 }
1141
1142 if (!(mc->main_sdrs.flags & IPMI_SDR_PARTIAL_ADD_SDR_SUPPORTED)) {
1143 handle_invalid_cmd(mc, rdata, rdata_len);
1144 return;
1145 }
1146
1147 if (mc->main_sdrs.flags & IPMI_SDR_RESERVE_SDR_SUPPORTED) {
1148 uint16_t reservation = ipmi_get_uint16(msg->data+0);
1149
1150 if ((reservation != 0) && (reservation != mc->main_sdrs.reservation)) {
1151 rdata[0] = IPMI_INVALID_RESERVATION_CC;
1152 *rdata_len = 1;
1153 return;
1154 }
1155 }
1156
1157 modal = IPMI_SDR_GET_MODAL(mc->main_sdrs.flags);
1158 if ((modal == IPMI_SDR_NON_MODAL_ONLY)
1159 && !mc->in_update_mode)
1160 {
1161 rdata[0] = IPMI_NOT_SUPPORTED_IN_PRESENT_STATE_CC;
1162 *rdata_len = 1;
1163 return;
1164 }
1165
1166 offset = msg->data[4];
1167 record_id = ipmi_get_uint16(rdata+2);
1168 if (record_id == 0) {
1169 /* New add. */
1170 if (check_msg_length(msg, 12, rdata, rdata_len))
1171 return;
1172 if (offset != 0) {
1173 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1174 *rdata_len = 1;
1175 return;
1176 }
1177 if (msg->len > (unsigned int) msg->data[11] + 12) {
1178 rdata[0] = 0x80; /* Invalid data length */
1179 *rdata_len = 1;
1180 return;
1181 }
1182 if (mc->part_add_sdr) {
1183 /* Still working on a previous one, return an error and
1184 abort. */
1185 free_sdr(mc->part_add_sdr);
1186 mc->part_add_sdr = NULL;
1187 rdata[0] = IPMI_UNKNOWN_ERR_CC;
1188 *rdata_len = 1;
1189 return;
1190 }
1191 mc->part_add_sdr = new_sdr_entry(&mc->main_sdrs, msg->data[11]);
1192 memcpy(mc->part_add_sdr->data+2, msg->data+8, msg->len - 8);
1193 mc->part_add_next = msg->len - 8;
1194 } else {
1195 if (!mc->part_add_next) {
1196 rdata[0] = IPMI_UNKNOWN_ERR_CC;
1197 *rdata_len = 1;
1198 return;
1199 }
1200 if (offset != mc->part_add_next) {
1201 free_sdr(mc->part_add_sdr);
1202 mc->part_add_sdr = NULL;
1203 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1204 *rdata_len = 1;
1205 return;
1206 }
1207 if ((offset + msg->len - 6) > mc->part_add_sdr->length) {
1208 free_sdr(mc->part_add_sdr);
1209 mc->part_add_sdr = NULL;
1210 rdata[0] = 0x80; /* Invalid data length */
1211 *rdata_len = 1;
1212 return;
1213 }
1214 memcpy(mc->part_add_sdr->data+offset, msg->data+6, msg->len-6);
1215 mc->part_add_next += msg->len - 6;
1216 }
1217
1218 if ((msg->data[5] & 0xf) == 1) {
1219 /* End of the operation. */
1220 if (mc->part_add_next != mc->part_add_sdr->length) {
1221 free_sdr(mc->part_add_sdr);
1222 mc->part_add_sdr = NULL;
1223 rdata[0] = 0x80; /* Invalid data length */
1224 *rdata_len = 1;
1225 return;
1226 }
1227 add_sdr_entry(mc, &mc->main_sdrs, mc->part_add_sdr);
1228 mc->part_add_sdr = NULL;
1229 }
1230
1231 rdata[0] = 0;
1232 *rdata_len = 1;
1233 }
1234
1235 void
iterate_sdrs(lmc_data_t * mc,sdrs_t * sdrs,int (* func)(lmc_data_t * mc,unsigned char * sdr,unsigned int len,void * cb_data),void * cb_data)1236 iterate_sdrs(lmc_data_t *mc,
1237 sdrs_t *sdrs,
1238 int (*func)(lmc_data_t *mc, unsigned char *sdr,
1239 unsigned int len, void *cb_data),
1240 void *cb_data)
1241 {
1242 sdr_t *entry;
1243
1244 for (entry = sdrs->sdrs; entry; entry = entry->next)
1245 func(mc, entry->data, entry->length, cb_data);
1246 }
1247
1248 static void
handle_delete_sdr(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1249 handle_delete_sdr(lmc_data_t *mc,
1250 msg_t *msg,
1251 unsigned char *rdata,
1252 unsigned int *rdata_len,
1253 void *cb_data)
1254 {
1255 uint16_t record_id;
1256 sdr_t *entry, *p_entry;
1257 struct timeval t;
1258
1259 if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1260 handle_invalid_cmd(mc, rdata, rdata_len);
1261 return;
1262 }
1263
1264 if (check_msg_length(msg, 4, rdata, rdata_len))
1265 return;
1266
1267 if (mc->main_sdrs.flags & IPMI_SDR_RESERVE_SDR_SUPPORTED) {
1268 uint16_t reservation = ipmi_get_uint16(msg->data+0);
1269
1270 if ((reservation != 0) && (reservation != mc->main_sdrs.reservation)) {
1271 rdata[0] = IPMI_INVALID_RESERVATION_CC;
1272 *rdata_len = 1;
1273 return;
1274 }
1275 }
1276
1277 record_id = ipmi_get_uint16(rdata+2);
1278
1279 if (record_id == 0) {
1280 entry = mc->main_sdrs.sdrs;
1281 p_entry = NULL;
1282 } else if (record_id == 0xffff) {
1283 entry = mc->main_sdrs.sdrs;
1284 p_entry = NULL;
1285 if (entry) {
1286 while (entry->next) {
1287 p_entry = entry;
1288 entry = entry->next;
1289 }
1290 }
1291 } else {
1292 entry = find_sdr_by_recid(&mc->main_sdrs, record_id, &p_entry);
1293 }
1294 if (!entry) {
1295 rdata[0] = IPMI_NOT_PRESENT_CC;
1296 *rdata_len = 1;
1297 return;
1298 }
1299
1300 if (p_entry)
1301 p_entry->next = entry->next;
1302 else
1303 mc->main_sdrs.sdrs = entry->next;
1304
1305 rdata[0] = 0;
1306 ipmi_set_uint16(rdata+1, entry->record_id);
1307 *rdata_len = 3;
1308
1309 free_sdr(entry);
1310
1311 mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
1312 mc->main_sdrs.last_erase_time = t.tv_sec + mc->main_sdrs.time_offset;
1313 mc->main_sdrs.sdr_count--;
1314 rewrite_sdrs(mc, &mc->main_sdrs);
1315 }
1316
1317 static void
handle_clear_sdr_repository(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1318 handle_clear_sdr_repository(lmc_data_t *mc,
1319 msg_t *msg,
1320 unsigned char *rdata,
1321 unsigned int *rdata_len,
1322 void *cb_data)
1323 {
1324 sdr_t *entry, *n_entry;
1325 struct timeval t;
1326 unsigned char op;
1327
1328 if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1329 handle_invalid_cmd(mc, rdata, rdata_len);
1330 return;
1331 }
1332
1333 if (check_msg_length(msg, 6, rdata, rdata_len))
1334 return;
1335
1336 if (mc->main_sdrs.flags & IPMI_SDR_RESERVE_SDR_SUPPORTED) {
1337 uint16_t reservation = ipmi_get_uint16(msg->data+0);
1338
1339 if ((reservation != 0) && (reservation != mc->main_sdrs.reservation)) {
1340 rdata[0] = IPMI_INVALID_RESERVATION_CC;
1341 *rdata_len = 1;
1342 return;
1343 }
1344 }
1345
1346 if ((msg->data[2] != 'C')
1347 || (msg->data[3] != 'L')
1348 || (msg->data[4] != 'R'))
1349 {
1350 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1351 *rdata_len = 1;
1352 return;
1353 }
1354
1355 op = msg->data[5];
1356 if ((op != 0) && (op != 0xaa))
1357 {
1358 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1359 *rdata_len = 1;
1360 return;
1361 }
1362
1363 rdata[1] = 1;
1364 if (op == 0) {
1365 entry = mc->main_sdrs.sdrs;
1366 while (entry) {
1367 n_entry = entry->next;
1368 free_sdr(entry);
1369 entry = n_entry;
1370 }
1371 }
1372
1373 rdata[0] = 0;
1374 *rdata_len = 2;
1375
1376 mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
1377 mc->main_sdrs.last_erase_time = t.tv_sec + mc->main_sdrs.time_offset;
1378 rewrite_sdrs(mc, &mc->main_sdrs);
1379 }
1380
1381 static void
handle_get_sdr_repository_time(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1382 handle_get_sdr_repository_time(lmc_data_t *mc,
1383 msg_t *msg,
1384 unsigned char *rdata,
1385 unsigned int *rdata_len,
1386 void *cb_data)
1387 {
1388 struct timeval t;
1389
1390 if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1391 handle_invalid_cmd(mc, rdata, rdata_len);
1392 return;
1393 }
1394
1395 mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
1396 rdata[0] = 0;
1397 ipmi_set_uint32(rdata+1, t.tv_sec + mc->main_sdrs.time_offset);
1398 *rdata_len = 5;
1399 }
1400
1401 static void
handle_set_sdr_repository_time(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1402 handle_set_sdr_repository_time(lmc_data_t *mc,
1403 msg_t *msg,
1404 unsigned char *rdata,
1405 unsigned int *rdata_len,
1406 void *cb_data)
1407 {
1408 struct timeval t;
1409
1410 if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1411 handle_invalid_cmd(mc, rdata, rdata_len);
1412 return;
1413 }
1414
1415 if (check_msg_length(msg, 4, rdata, rdata_len))
1416 return;
1417
1418 mc->emu->sysinfo->get_monotonic_time(mc->emu->sysinfo, &t);
1419 mc->main_sdrs.time_offset = ipmi_get_uint32(msg->data) - t.tv_sec;
1420
1421 rdata[0] = 0;
1422 *rdata_len = 1;
1423 }
1424
1425 static void
handle_enter_sdr_repository_update(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1426 handle_enter_sdr_repository_update(lmc_data_t *mc,
1427 msg_t *msg,
1428 unsigned char *rdata,
1429 unsigned int *rdata_len,
1430 void *cb_data)
1431 {
1432 int modal;
1433
1434 if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1435 handle_invalid_cmd(mc, rdata, rdata_len);
1436 return;
1437 }
1438
1439 modal = IPMI_SDR_GET_MODAL(mc->main_sdrs.flags);
1440 if ((modal == IPMI_SDR_MODAL_UNSPECIFIED)
1441 || (modal == IPMI_SDR_NON_MODAL_ONLY))
1442 {
1443 handle_invalid_cmd(mc, rdata, rdata_len);
1444 return;
1445 }
1446
1447 mc->in_update_mode = 1;
1448
1449 rdata[0] = 0;
1450 *rdata_len = 1;
1451 }
1452
1453 static void
handle_exit_sdr_repository_update(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1454 handle_exit_sdr_repository_update(lmc_data_t *mc,
1455 msg_t *msg,
1456 unsigned char *rdata,
1457 unsigned int *rdata_len,
1458 void *cb_data)
1459 {
1460 int modal;
1461
1462 if (!(mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV)) {
1463 handle_invalid_cmd(mc, rdata, rdata_len);
1464 return;
1465 }
1466
1467 modal = IPMI_SDR_GET_MODAL(mc->main_sdrs.flags);
1468 if ((modal == IPMI_SDR_MODAL_UNSPECIFIED)
1469 || (modal == IPMI_SDR_NON_MODAL_ONLY))
1470 {
1471 handle_invalid_cmd(mc, rdata, rdata_len);
1472 return;
1473 }
1474
1475 mc->in_update_mode = 0;
1476
1477 rdata[0] = 0;
1478 *rdata_len = 1;
1479 }
1480
1481 /*
1482 * FRU Inventory handling
1483 */
1484
1485 fru_data_t *
find_fru(lmc_data_t * mc,unsigned int devid)1486 find_fru(lmc_data_t *mc, unsigned int devid)
1487 {
1488 fru_data_t *fru = mc->frulist;
1489
1490 while (fru && fru->devid != devid)
1491 fru = fru->next;
1492
1493 return fru;
1494 }
1495
1496 int
ipmi_mc_set_frudata_handler(lmc_data_t * mc,unsigned int devid,get_frudata_f handler,free_frudata_f freefunc)1497 ipmi_mc_set_frudata_handler(lmc_data_t *mc, unsigned int devid,
1498 get_frudata_f handler, free_frudata_f freefunc)
1499 {
1500 fru_data_t *fru = find_fru(mc, devid);
1501
1502 if (!fru)
1503 return EINVAL;
1504 fru->get = handler;
1505 fru->free = freefunc;
1506 return 0;
1507 }
1508
1509 static void
fru_session_closed(lmc_data_t * mc,uint32_t session_id,void * cb_data)1510 fru_session_closed(lmc_data_t *mc, uint32_t session_id, void *cb_data)
1511 {
1512 fru_session_t *ses = cb_data;
1513 fru_data_t *fru = ses->fru;
1514
1515 if (fru->sessions == ses) {
1516 fru->sessions = ses->next;
1517 } else {
1518 fru_session_t *p = fru->sessions;
1519 while (p && p->next != ses)
1520 p = p->next;
1521 if (p && p->next != ses)
1522 p->next = ses->next;
1523 }
1524 fru->free(mc, ses->data_to_free);
1525 free(ses);
1526 }
1527
1528 static void
handle_get_fru_inventory_area_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1529 handle_get_fru_inventory_area_info(lmc_data_t *mc,
1530 msg_t *msg,
1531 unsigned char *rdata,
1532 unsigned int *rdata_len,
1533 void *cb_data)
1534 {
1535 unsigned char devid;
1536 fru_data_t *fru;
1537 unsigned int size;
1538 unsigned char *data;
1539 int rv;
1540
1541 if (check_msg_length(msg, 1, rdata, rdata_len))
1542 return;
1543
1544 devid = msg->data[0];
1545
1546 fru = find_fru(mc, devid);
1547 if (!fru) {
1548 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1549 *rdata_len = 1;
1550 return;
1551 }
1552
1553 if (fru->get) {
1554 channel_t *channel;
1555 fru_session_t *ses;
1556 int link_in = 0;
1557
1558 ses = fru->sessions;
1559 while (ses) {
1560 if (ses->sid == msg->sid)
1561 break;
1562 ses = ses->next;
1563 }
1564 if (!ses) {
1565 ses = malloc(sizeof(*ses));
1566 if (!ses) {
1567 rdata[0] = IPMI_OUT_OF_SPACE_CC;
1568 *rdata_len = 1;
1569 return;
1570 }
1571 memset(ses, 0, sizeof(*ses));
1572 ses->sid = msg->sid;
1573 ses->fru = fru;
1574 link_in = 1;
1575 }
1576
1577 /* Set up to free the FRU data when the session closes. */
1578 channel = msg->orig_channel;
1579 rv = channel->set_associated_mc(channel, msg->sid, 0, mc,
1580 NULL, fru_session_closed, ses);
1581 if (rv == EBUSY) {
1582 rdata[0] = IPMI_NODE_BUSY_CC;
1583 *rdata_len = 1;
1584 return;
1585 } else if (rv) {
1586 rdata[0] = IPMI_UNKNOWN_ERR_CC;
1587 *rdata_len = 1;
1588 return;
1589 }
1590
1591 data = fru->get(mc, &size);
1592 if (!data) {
1593 channel->set_associated_mc(channel, msg->sid, 0, NULL,
1594 NULL, NULL, NULL);
1595 rdata[0] = IPMI_OUT_OF_SPACE_CC;
1596 *rdata_len = 1;
1597 return;
1598 }
1599
1600 if (ses->data_to_free)
1601 fru->free(mc, ses->data_to_free);
1602
1603 ses->data_to_free = data;
1604 if (size > 65535) {
1605 ses->data = data + (size - 65535);
1606 size = 65535;
1607 } else {
1608 ses->data = data;
1609 }
1610 ses->length = size;
1611
1612 if (link_in) {
1613 ses->next = fru->sessions;
1614 fru->sessions = ses;
1615 }
1616 } else {
1617 size = fru->length;
1618 data = fru->data;
1619 }
1620
1621 if (!data) {
1622 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1623 *rdata_len = 1;
1624 return;
1625 }
1626
1627 rdata[0] = 0;
1628 ipmi_set_uint16(rdata+1, size);
1629 rdata[3] = 0; /* We only support byte access for now. */
1630 *rdata_len = 4;
1631 }
1632
1633 static int
fru_sem_trywait(fru_data_t * fru)1634 fru_sem_trywait(fru_data_t *fru)
1635 {
1636 struct timespec ts;
1637 int rv;
1638
1639 /* Wait 250ms for the semaphore. */
1640 restart:
1641 rv = clock_gettime(CLOCK_REALTIME, &ts);
1642 if (rv == -1)
1643 return errno;
1644
1645 ts.tv_nsec += 250000000;
1646 if (ts.tv_nsec >= 1000000000) {
1647 ts.tv_nsec -= 1000000000;
1648 ts.tv_sec += 1;
1649 }
1650 rv = sem_timedwait(&fru->sem, &ts);
1651 if (rv) {
1652 if (rv == EINTR)
1653 goto restart;
1654 if (rv == ETIMEDOUT)
1655 rv = EAGAIN;
1656 else
1657 rv = errno;
1658 return rv;
1659 }
1660 return 0;
1661 }
1662
1663 static void
handle_read_fru_data(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1664 handle_read_fru_data(lmc_data_t *mc,
1665 msg_t *msg,
1666 unsigned char *rdata,
1667 unsigned int *rdata_len,
1668 void *cb_data)
1669 {
1670 unsigned char devid;
1671 unsigned int offset;
1672 unsigned int count;
1673 unsigned char *data = NULL;
1674 unsigned int size;
1675 fru_session_t *ses;
1676 fru_data_t *fru;
1677 int rv;
1678
1679 if (check_msg_length(msg, 4, rdata, rdata_len))
1680 return;
1681
1682 devid = msg->data[0];
1683 fru = find_fru(mc, devid);
1684 if (!fru) {
1685 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1686 *rdata_len = 1;
1687 return;
1688 }
1689
1690 rv = fru_sem_trywait(fru);
1691 if (rv) {
1692 if (rv == EAGAIN)
1693 rdata[0] = IPMI_NODE_BUSY_CC;
1694 else
1695 rdata[0] = IPMI_UNKNOWN_ERR_CC;
1696 *rdata_len = 1;
1697 return;
1698 }
1699
1700 offset = ipmi_get_uint16(msg->data+1);
1701 count = msg->data[3];
1702
1703 size = fru->length;
1704
1705 if (!fru->fru_io_cb) {
1706 data = fru->data;
1707 ses = fru->sessions;
1708 while (ses && (ses->sid != msg->sid))
1709 ses = ses->next;
1710 if (ses) {
1711 data = ses->data;
1712 size = ses->length;
1713 }
1714
1715 if (!data) {
1716 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1717 *rdata_len = 1;
1718 goto out_unlock;
1719 }
1720
1721 if (offset >= size) {
1722 rdata[0] = IPMI_PARAMETER_OUT_OF_RANGE_CC;
1723 *rdata_len = 1;
1724 goto out_unlock;
1725 }
1726 }
1727
1728 if ((offset+count) > size)
1729 count = size - offset;
1730 if (count+2 > *rdata_len) {
1731 /* Too much data to put into response. */
1732 rdata[0] = IPMI_REQUESTED_DATA_LENGTH_EXCEEDED_CC;
1733 *rdata_len = 1;
1734 goto out_unlock;
1735 }
1736
1737 if (fru->fru_io_cb) {
1738 int rv;
1739
1740 rv = fru->fru_io_cb(fru->data, FRU_IO_READ, rdata + 2, offset, count);
1741 if (rv) {
1742 rdata[0] = IPMI_UNKNOWN_ERR_CC;
1743 *rdata_len = 1;
1744 goto out_unlock;
1745 }
1746 } else {
1747 memcpy(rdata + 2, data + offset, count);
1748 }
1749
1750 rdata[0] = 0;
1751 rdata[1] = count;
1752 *rdata_len = 2 + count;
1753
1754 out_unlock:
1755 sem_post(&fru->sem);
1756 }
1757
1758 static void
handle_write_fru_data(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1759 handle_write_fru_data(lmc_data_t *mc,
1760 msg_t *msg,
1761 unsigned char *rdata,
1762 unsigned int *rdata_len,
1763 void *cb_data)
1764 {
1765 unsigned char device_id;
1766 unsigned int offset;
1767 unsigned int count;
1768 fru_data_t *fru;
1769 int rv;
1770
1771 if (check_msg_length(msg, 3, rdata, rdata_len))
1772 return;
1773
1774 device_id = msg->data[0];
1775 fru = find_fru(mc, device_id);
1776 if (!fru) {
1777 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
1778 *rdata_len = 1;
1779 return;
1780 }
1781
1782 rv = fru_sem_trywait(fru);
1783 if (rv) {
1784 if (rv == EAGAIN)
1785 rdata[0] = IPMI_NODE_BUSY_CC;
1786 else
1787 rdata[0] = IPMI_UNKNOWN_ERR_CC;
1788 *rdata_len = 1;
1789 return;
1790 }
1791
1792 offset = ipmi_get_uint16(msg->data+1);
1793 count = msg->len - 3;
1794
1795 if (offset >= fru->length) {
1796 rdata[0] = IPMI_PARAMETER_OUT_OF_RANGE_CC;
1797 *rdata_len = 1;
1798 goto out_unlock;
1799 }
1800
1801 if ((offset+count) > fru->length) {
1802 /* Too much data to put into FRU. */
1803 rdata[0] = IPMI_REQUESTED_DATA_LENGTH_EXCEEDED_CC;
1804 *rdata_len = 1;
1805 goto out_unlock;
1806 }
1807
1808 if (fru->fru_io_cb) {
1809 int rv;
1810
1811 rv = fru->fru_io_cb(fru->data, FRU_IO_WRITE, msg->data + 3, offset,
1812 count);
1813 if (rv) {
1814 rdata[0] = IPMI_UNKNOWN_ERR_CC;
1815 *rdata_len = 1;
1816 goto out_unlock;
1817 }
1818 } else {
1819 memcpy(fru->data+offset, msg->data+3, count);
1820 }
1821 rdata[0] = 0;
1822 rdata[1] = count;
1823 *rdata_len = 2;
1824
1825 out_unlock:
1826 sem_post(&fru->sem);
1827 }
1828
1829 int
ipmi_mc_get_fru_data_len(lmc_data_t * mc,unsigned char device_id,unsigned int * length)1830 ipmi_mc_get_fru_data_len(lmc_data_t *mc,
1831 unsigned char device_id,
1832 unsigned int *length)
1833 {
1834 fru_data_t *fru;
1835
1836 if (!(mc->device_support & IPMI_DEVID_FRU_INVENTORY_DEV))
1837 return ENOSYS;
1838
1839 if (device_id >= 255)
1840 return EINVAL;
1841
1842 fru = find_fru(mc, device_id);
1843 if (!fru || !fru->data)
1844 return EINVAL;
1845
1846 *length = fru->length;
1847
1848 return 0;
1849 }
1850
1851 int
ipmi_mc_get_fru_data(lmc_data_t * mc,unsigned char device_id,unsigned int length,unsigned char * data)1852 ipmi_mc_get_fru_data(lmc_data_t *mc,
1853 unsigned char device_id,
1854 unsigned int length,
1855 unsigned char *data)
1856 {
1857 fru_data_t *fru;
1858 int rv;
1859
1860 if (!(mc->device_support & IPMI_DEVID_FRU_INVENTORY_DEV))
1861 return ENOSYS;
1862
1863 fru = find_fru(mc, device_id);
1864 if (!fru)
1865 return EINVAL;
1866
1867 if (length > fru->length)
1868 return EINVAL;
1869
1870 rv = fru_sem_trywait(fru);
1871 if (rv)
1872 return errno;
1873
1874 if (fru->fru_io_cb) {
1875 rv = fru->fru_io_cb(fru->data, FRU_IO_READ, data, 0, length);
1876 } else {
1877 memcpy(data, fru->data, length);
1878 }
1879
1880 sem_post(&fru->sem);
1881 return rv;
1882 }
1883
1884 int
ipmi_mc_add_fru_data(lmc_data_t * mc,unsigned char device_id,unsigned int length,fru_io_cb fru_io_cb,void * data)1885 ipmi_mc_add_fru_data(lmc_data_t *mc,
1886 unsigned char device_id,
1887 unsigned int length,
1888 fru_io_cb fru_io_cb,
1889 void *data)
1890 {
1891 fru_data_t *fru;
1892
1893 if (device_id > 255)
1894 return EINVAL;
1895
1896 fru = find_fru(mc, device_id);
1897 if (!fru) {
1898 int rv;
1899 fru = malloc(sizeof(*fru));
1900 memset(fru, 0, sizeof(*fru));
1901 rv = sem_init(&fru->sem, 0, 1);
1902 if (rv) {
1903 rv = errno;
1904 free(fru);
1905 return rv;
1906 }
1907 fru->devid = device_id;
1908 fru->next = mc->frulist;
1909 mc->frulist = fru;
1910 }
1911
1912 if (fru->data) {
1913 free(fru->data);
1914 fru->length = 0;
1915 }
1916
1917 if (fru_io_cb) {
1918 fru->fru_io_cb = fru_io_cb;
1919 fru->data = data;
1920 } else if (length) {
1921 fru->data = malloc(length);
1922 if (!fru->data)
1923 return ENOMEM;
1924 memcpy(fru->data, data, length);
1925 } else
1926 fru->data = NULL;
1927
1928 fru->length = length;
1929
1930 return 0;
1931 }
1932
1933 int
ipmi_mc_fru_sem_wait(lmc_data_t * mc,unsigned char device_id)1934 ipmi_mc_fru_sem_wait(lmc_data_t *mc, unsigned char device_id)
1935 {
1936 int rv;
1937 fru_data_t *fru = find_fru(mc, device_id);
1938 if (!fru)
1939 return EINVAL;
1940 rv = sem_wait(&fru->sem);
1941 if (rv)
1942 return errno;
1943 return 0;
1944 }
1945
1946 int
ipmi_mc_fru_sem_trywait(lmc_data_t * mc,unsigned char device_id)1947 ipmi_mc_fru_sem_trywait(lmc_data_t *mc, unsigned char device_id)
1948 {
1949 int rv;
1950 fru_data_t *fru = find_fru(mc, device_id);
1951 if (!fru)
1952 return EINVAL;
1953 rv = fru_sem_trywait(fru);
1954 if (rv)
1955 return errno;
1956 return 0;
1957 }
1958
1959 int
ipmi_mc_fru_sem_post(lmc_data_t * mc,unsigned char device_id)1960 ipmi_mc_fru_sem_post(lmc_data_t *mc, unsigned char device_id)
1961 {
1962 int rv;
1963 fru_data_t *fru = find_fru(mc, device_id);
1964 if (!fru)
1965 return EINVAL;
1966 rv = sem_post(&fru->sem);
1967 if (rv)
1968 return errno;
1969 return 0;
1970 }
1971
1972 struct fru_file_io_info {
1973 lmc_data_t *mc;
1974 char *filename;
1975 unsigned int file_offset;
1976 unsigned int length;
1977 };
1978
fru_file_io_cb(void * cb_data,enum fru_io_cb_op op,unsigned char * data,unsigned int offset,unsigned int length)1979 static int fru_file_io_cb(void *cb_data,
1980 enum fru_io_cb_op op,
1981 unsigned char *data,
1982 unsigned int offset,
1983 unsigned int length)
1984 {
1985 struct fru_file_io_info *info = cb_data;
1986 int fd;
1987 int rv = 0;
1988 int l;
1989
1990 if (offset + length > info->length)
1991 return EINVAL;
1992
1993 switch (op) {
1994 case FRU_IO_READ:
1995 fd = open(info->filename, O_RDONLY);
1996 if (fd == -1) {
1997 rv = errno;
1998 info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
1999 "fru_io: (read) error on open of %s: %s",
2000 info->filename, strerror(rv));
2001 return rv;
2002 }
2003 if (lseek(fd, info->file_offset + offset, SEEK_SET) == -1) {
2004 rv = errno;
2005 close(fd);
2006 info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2007 "fru_io: (read) error on lseek"
2008 " of %s to %u: %s",
2009 info->filename, info->file_offset + offset,
2010 strerror(rv));
2011 return rv;
2012 }
2013 restart_read:
2014 l = read(fd, data, length);
2015 if (l == -1) {
2016 if (errno == EINTR)
2017 goto restart_read;
2018 rv = errno;
2019 info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2020 "fru_io: error on read of %u bytes of %s"
2021 " at %u: %s",
2022 length, info->filename,
2023 info->file_offset + offset,
2024 strerror(rv));
2025 } else if (l == 0) {
2026 rv = EIO;
2027 info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2028 "fru_io: end of file read of %u bytes of %s"
2029 " at %u: %s",
2030 length, info->filename,
2031 info->file_offset + offset,
2032 strerror(rv));
2033 } else if (((unsigned int) l) != length) {
2034 length -= l;
2035 data += l;
2036 goto restart_read;
2037 }
2038 close(fd);
2039 break;
2040
2041 case FRU_IO_WRITE:
2042 fd = open(info->filename, O_WRONLY);
2043 if (fd == -1) {
2044 rv = errno;
2045 info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2046 "fru_io: (write) error on open of %s: %s",
2047 info->filename, strerror(rv));
2048 return rv;
2049 }
2050 if (lseek(fd, info->file_offset + offset, SEEK_SET) == -1) {
2051 rv = errno;
2052 close(fd);
2053 info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2054 "fru_io: (write) error on lseek"
2055 " of %s to %u: %s",
2056 info->filename, info->file_offset + offset,
2057 strerror(rv));
2058 return rv;
2059 }
2060 restart_write:
2061 l = write(fd, data, length);
2062 if (l == -1) {
2063 if (errno == EINTR)
2064 goto restart_write;
2065 rv = errno;
2066 info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2067 "fru_io: error on write of %u bytes of %s"
2068 " at %u: %s",
2069 length, info->filename,
2070 info->file_offset + offset,
2071 strerror(rv));
2072 } else if (l == 0) {
2073 rv = EIO;
2074 info->mc->sysinfo->log(info->mc->sysinfo, OS_ERROR, NULL,
2075 "fru_io: end of file write of %u bytes of %s"
2076 " at %u: %s",
2077 length, info->filename,
2078 info->file_offset + offset,
2079 strerror(rv));
2080 } else if (((unsigned int) l) != length) {
2081 length -= l;
2082 data += l;
2083 goto restart_write;
2084 }
2085 close(fd);
2086 break;
2087
2088 default:
2089 return EINVAL;
2090 }
2091
2092 return rv;
2093 }
2094
ipmi_mc_add_fru_file(lmc_data_t * mc,unsigned char device_id,unsigned int length,unsigned int file_offset,const char * filename)2095 int ipmi_mc_add_fru_file(lmc_data_t *mc,
2096 unsigned char device_id,
2097 unsigned int length,
2098 unsigned int file_offset,
2099 const char *filename)
2100 {
2101 struct fru_file_io_info *info;
2102 int rv;
2103
2104 info = malloc(sizeof(*info));
2105 if (!info)
2106 return ENOMEM;
2107 info->filename = strdup(filename);
2108 if (!info->filename) {
2109 free(info);
2110 return ENOMEM;
2111 }
2112 info->mc = mc;
2113 info->length = length;
2114 info->file_offset = file_offset;
2115
2116 rv = ipmi_mc_add_fru_data(mc, device_id, length, fru_file_io_cb, info);
2117 if (rv) {
2118 free(info->filename);
2119 free(info);
2120 }
2121
2122 return rv;
2123 }
2124
2125 /* We don't currently care about partial sel adds, since they are
2126 pretty stupid. */
2127 cmd_handler_f storage_netfn_handlers[256] = {
2128 [IPMI_GET_SEL_INFO_CMD] = handle_get_sel_info,
2129 [IPMI_GET_SEL_ALLOCATION_INFO_CMD] = handle_get_sel_allocation_info,
2130 [IPMI_RESERVE_SEL_CMD] = handle_reserve_sel,
2131 [IPMI_GET_SEL_ENTRY_CMD] = handle_get_sel_entry,
2132 [IPMI_ADD_SEL_ENTRY_CMD] = handle_add_sel_entry,
2133 [IPMI_DELETE_SEL_ENTRY_CMD] = handle_delete_sel_entry,
2134 [IPMI_CLEAR_SEL_CMD] = handle_clear_sel,
2135 [IPMI_GET_SEL_TIME_CMD] = handle_get_sel_time,
2136 [IPMI_SET_SEL_TIME_CMD] = handle_set_sel_time,
2137 [IPMI_GET_SDR_REPOSITORY_INFO_CMD] = handle_get_sdr_repository_info,
2138 [IPMI_GET_SDR_REPOSITORY_ALLOC_INFO_CMD] = handle_get_sdr_repository_alloc_info,
2139 [IPMI_RESERVE_SDR_REPOSITORY_CMD] = handle_reserve_sdr_repository,
2140 [IPMI_GET_SDR_CMD] = handle_get_sdr,
2141 [IPMI_ADD_SDR_CMD] = handle_add_sdr,
2142 [IPMI_PARTIAL_ADD_SDR_CMD] = handle_partial_add_sdr,
2143 [IPMI_DELETE_SDR_CMD] = handle_delete_sdr,
2144 [IPMI_CLEAR_SDR_REPOSITORY_CMD] = handle_clear_sdr_repository,
2145 [IPMI_GET_SDR_REPOSITORY_TIME_CMD] = handle_get_sdr_repository_time,
2146 [IPMI_SET_SDR_REPOSITORY_TIME_CMD] = handle_set_sdr_repository_time,
2147 [IPMI_ENTER_SDR_REPOSITORY_UPDATE_CMD] = handle_enter_sdr_repository_update,
2148 [IPMI_EXIT_SDR_REPOSITORY_UPDATE_CMD] = handle_exit_sdr_repository_update,
2149 [IPMI_GET_FRU_INVENTORY_AREA_INFO_CMD] = handle_get_fru_inventory_area_info,
2150 [IPMI_READ_FRU_DATA_CMD] = handle_read_fru_data,
2151 [IPMI_WRITE_FRU_DATA_CMD] = handle_write_fru_data
2152 };
2153