1 /*****************************************************************************\
2 * $Id: ipmi-sdr-cache-create.c,v 1.42 2010-02-08 22:09:40 chu11 Exp $
3 *****************************************************************************
4 * Copyright (C) 2007-2015 Lawrence Livermore National Security, LLC.
5 * Copyright (C) 2006-2007 The Regents of the University of California.
6 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
7 * Written by Albert Chu <chu11@llnl.gov>
8 * UCRL-CODE-222073
9 *
10 * This file is part of Ipmimonitoring, an IPMI sensor monitoring
11 * library. For details, see http://www.llnl.gov/linux/.
12 *
13 * Ipmimonitoring is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 3 of the License, or (at your
16 * option) any later version.
17 *
18 * Ipmimonitoring is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with Ipmimonitoring. If not, see <http://www.gnu.org/licenses/>.
25 \*****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif /* HAVE_CONFIG_H */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #if STDC_HEADERS
34 #include <string.h>
35 #endif /* STDC_HEADERS */
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #if HAVE_FCNTL_H
39 #include <fcntl.h>
40 #endif /* HAVE_FCNTL_H */
41 #if HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif /* HAVE_UNISTD_H */
44 #include <assert.h>
45 #include <errno.h>
46
47 #include "freeipmi/sdr/ipmi-sdr.h"
48 #include "freeipmi/api/ipmi-sdr-repository-cmds-api.h"
49 #include "freeipmi/cmds/ipmi-sdr-repository-cmds.h"
50 #include "freeipmi/fiid/fiid.h"
51 #include "freeipmi/debug/ipmi-debug.h"
52 #include "freeipmi/record-format/ipmi-sdr-record-format.h"
53 #include "freeipmi/spec/ipmi-comp-code-spec.h"
54 #include "freeipmi/util/ipmi-util.h"
55
56 #include "ipmi-sdr-common.h"
57 #include "ipmi-sdr-defs.h"
58 #include "ipmi-sdr-trace.h"
59 #include "ipmi-sdr-util.h"
60
61 #include "libcommon/ipmi-fiid-util.h"
62
63 #include "freeipmi-portability.h"
64 #include "debug-util.h"
65 #include "fd.h"
66
67 #define IPMI_SDR_CACHE_MAX_RESERVATION_ID_RETRY 4
68
69 /* achu: bytes to read start = 16 specifically chosen to 16 because it
70 * appears most motherboards can handle 16. Many cannot handle larger
71 * numbers like 32.
72 */
73 #define IPMI_SDR_CACHE_BYTES_TO_READ_START 16
74 #define IPMI_SDR_CACHE_BYTES_TO_READ_DECREMENT 4
75
76 static int
_sdr_cache_header_write(ipmi_sdr_ctx_t ctx,ipmi_ctx_t ipmi_ctx,int fd,unsigned int * total_bytes_written,uint8_t sdr_version,uint16_t record_count,uint32_t most_recent_addition_timestamp,uint32_t most_recent_erase_timestamp)77 _sdr_cache_header_write (ipmi_sdr_ctx_t ctx,
78 ipmi_ctx_t ipmi_ctx,
79 int fd,
80 unsigned int *total_bytes_written,
81 uint8_t sdr_version,
82 uint16_t record_count,
83 uint32_t most_recent_addition_timestamp,
84 uint32_t most_recent_erase_timestamp)
85 {
86 char sdr_cache_magic_buf[4];
87 char sdr_cache_version_buf[4];
88 char record_count_buf[2];
89 char most_recent_addition_timestamp_buf[4];
90 char most_recent_erase_timestamp_buf[4];
91 uint8_t header_checksum_buf[512];
92 unsigned int header_checksum_buf_len = 0;
93 uint8_t header_checksum;
94 ssize_t n;
95
96 assert (ctx);
97 assert (ctx->magic == IPMI_SDR_CTX_MAGIC);
98 assert (ipmi_ctx);
99 assert (fd);
100 assert (total_bytes_written);
101
102 sdr_cache_magic_buf[0] = IPMI_SDR_CACHE_FILE_MAGIC_0;
103 sdr_cache_magic_buf[1] = IPMI_SDR_CACHE_FILE_MAGIC_1;
104 sdr_cache_magic_buf[2] = IPMI_SDR_CACHE_FILE_MAGIC_2;
105 sdr_cache_magic_buf[3] = IPMI_SDR_CACHE_FILE_MAGIC_3;
106
107 if ((n = fd_write_n (fd, sdr_cache_magic_buf, 4)) < 0)
108 {
109 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
110 return (-1);
111 }
112 if (n != 4)
113 {
114 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
115 return (-1);
116 }
117 (*total_bytes_written) += 4;
118
119 memcpy(&header_checksum_buf[header_checksum_buf_len], sdr_cache_magic_buf, 4);
120 header_checksum_buf_len += 4;
121
122 sdr_cache_version_buf[0] = IPMI_SDR_CACHE_FILE_VERSION_1_2_0;
123 sdr_cache_version_buf[1] = IPMI_SDR_CACHE_FILE_VERSION_1_2_1;
124 sdr_cache_version_buf[2] = IPMI_SDR_CACHE_FILE_VERSION_1_2_2;
125 sdr_cache_version_buf[3] = IPMI_SDR_CACHE_FILE_VERSION_1_2_3;
126
127 if ((n = fd_write_n (fd, sdr_cache_version_buf, 4)) < 0)
128 {
129 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
130 return (-1);
131 }
132 if (n != 4)
133 {
134 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
135 return (-1);
136 }
137 (*total_bytes_written) += 4;
138
139 memcpy(&header_checksum_buf[header_checksum_buf_len], sdr_cache_version_buf, 4);
140 header_checksum_buf_len += 4;
141
142 if ((n = fd_write_n (fd, (char *)&sdr_version, 1)) < 0)
143 {
144 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
145 return (-1);
146 }
147 if (n != 1)
148 {
149 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
150 return (-1);
151 }
152 (*total_bytes_written) += 1;
153
154 memcpy(&header_checksum_buf[header_checksum_buf_len], &sdr_version, 1);
155 header_checksum_buf_len += 1;
156
157 /* Store record count little-endian */
158 record_count_buf[0] = (record_count & 0x00FF);
159 record_count_buf[1] = (record_count & 0xFF00) >> 8;
160
161 if ((n = fd_write_n (fd, record_count_buf, 2)) < 0)
162 {
163 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
164 return (-1);
165 }
166 if (n != 2)
167 {
168 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
169 return (-1);
170 }
171 (*total_bytes_written) += 2;
172
173 memcpy(&header_checksum_buf[header_checksum_buf_len], record_count_buf, 2);
174 header_checksum_buf_len += 2;
175
176 /* Store most recent addition timestamp little-endian */
177 most_recent_addition_timestamp_buf[0] = (most_recent_addition_timestamp & 0x000000FF);
178 most_recent_addition_timestamp_buf[1] = (most_recent_addition_timestamp & 0x0000FF00) >> 8;
179 most_recent_addition_timestamp_buf[2] = (most_recent_addition_timestamp & 0x00FF0000) >> 16;
180 most_recent_addition_timestamp_buf[3] = (most_recent_addition_timestamp & 0xFF000000) >> 24;
181
182 if ((n = fd_write_n (fd, most_recent_addition_timestamp_buf, 4)) < 0)
183 {
184 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
185 return (-1);
186 }
187 if (n != 4)
188 {
189 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
190 return (-1);
191 }
192 (*total_bytes_written) += 4;
193
194 memcpy(&header_checksum_buf[header_checksum_buf_len], most_recent_addition_timestamp_buf, 4);
195 header_checksum_buf_len += 4;
196
197 /* Store most recent erase timestamp little-endian */
198 most_recent_erase_timestamp_buf[0] = (most_recent_erase_timestamp & 0x000000FF);
199 most_recent_erase_timestamp_buf[1] = (most_recent_erase_timestamp & 0x0000FF00) >> 8;
200 most_recent_erase_timestamp_buf[2] = (most_recent_erase_timestamp & 0x00FF0000) >> 16;
201 most_recent_erase_timestamp_buf[3] = (most_recent_erase_timestamp & 0xFF000000) >> 24;
202
203 if ((n = fd_write_n (fd, most_recent_erase_timestamp_buf, 4)) < 0)
204 {
205 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
206 return (-1);
207 }
208 if (n != 4)
209 {
210 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
211 return (-1);
212 }
213 (*total_bytes_written) += 4;
214
215 memcpy(&header_checksum_buf[header_checksum_buf_len], most_recent_erase_timestamp_buf, 4);
216 header_checksum_buf_len += 4;
217
218 header_checksum = ipmi_checksum (header_checksum_buf, header_checksum_buf_len);
219
220 if ((n = fd_write_n (fd, (char *)&header_checksum, 1)) < 0)
221 {
222 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
223 return (-1);
224 }
225 if (n != 1)
226 {
227 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
228 return (-1);
229 }
230 (*total_bytes_written) += 1;
231
232 return (0);
233 }
234
235 static int
_sdr_cache_trailer_write(ipmi_sdr_ctx_t ctx,ipmi_ctx_t ipmi_ctx,int fd,unsigned int total_bytes_written,uint8_t trailer_checksum)236 _sdr_cache_trailer_write (ipmi_sdr_ctx_t ctx,
237 ipmi_ctx_t ipmi_ctx,
238 int fd,
239 unsigned int total_bytes_written,
240 uint8_t trailer_checksum)
241 {
242 char total_bytes_written_buf[4];
243 ssize_t n;
244
245 assert (ctx);
246 assert (ctx->magic == IPMI_SDR_CTX_MAGIC);
247 assert (ipmi_ctx);
248 assert (fd);
249
250 /* + 4 for this value, + 1 for checksum at end */
251 total_bytes_written += 4;
252 total_bytes_written += 1;
253
254 total_bytes_written_buf[0] = (total_bytes_written & 0x000000FF);
255 total_bytes_written_buf[1] = (total_bytes_written & 0x0000FF00) >> 8;
256 total_bytes_written_buf[2] = (total_bytes_written & 0x00FF0000) >> 16;
257 total_bytes_written_buf[3] = (total_bytes_written & 0xFF000000) >> 24;
258
259 if ((n = fd_write_n (fd, total_bytes_written_buf, 4)) < 0)
260 {
261 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
262 return (-1);
263 }
264 if (n != 4)
265 {
266 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
267 return (-1);
268 }
269
270 trailer_checksum = ipmi_checksum_final (total_bytes_written_buf, 4, trailer_checksum);
271
272 if ((n = fd_write_n (fd, (char *)&trailer_checksum, 1)) < 0)
273 {
274 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
275 return (-1);
276 }
277 if (n != 1)
278 {
279 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
280 return (-1);
281 }
282
283 return (0);
284 }
285
286 static int
_sdr_cache_reservation_id(ipmi_sdr_ctx_t ctx,ipmi_ctx_t ipmi_ctx,uint16_t * reservation_id)287 _sdr_cache_reservation_id (ipmi_sdr_ctx_t ctx,
288 ipmi_ctx_t ipmi_ctx,
289 uint16_t *reservation_id)
290 {
291 fiid_obj_t obj_cmd_rs = NULL;
292 uint64_t val;
293 int rv = -1;
294
295 assert (ctx);
296 assert (ctx->magic == IPMI_SDR_CTX_MAGIC);
297 assert (ipmi_ctx);
298 assert (reservation_id);
299
300 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_reserve_sdr_repository_rs)))
301 {
302 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
303 goto cleanup;
304 }
305
306 if (ipmi_cmd_reserve_sdr_repository (ipmi_ctx, obj_cmd_rs) < 0)
307 {
308 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR);
309 goto cleanup;
310 }
311
312 *reservation_id = 0;
313 if (FIID_OBJ_GET (obj_cmd_rs,
314 "reservation_id",
315 &val) < 0)
316 {
317 SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
318 goto cleanup;
319 }
320 *reservation_id = val;
321
322 rv = 0;
323 cleanup:
324 fiid_obj_destroy (obj_cmd_rs);
325 return (rv);
326 }
327
328 static int
_sdr_cache_get_record(ipmi_sdr_ctx_t ctx,ipmi_ctx_t ipmi_ctx,uint16_t record_id,void * record_buf,unsigned int record_buf_len,uint16_t * reservation_id,uint16_t * next_record_id)329 _sdr_cache_get_record (ipmi_sdr_ctx_t ctx,
330 ipmi_ctx_t ipmi_ctx,
331 uint16_t record_id,
332 void *record_buf,
333 unsigned int record_buf_len,
334 uint16_t *reservation_id,
335 uint16_t *next_record_id)
336 {
337 fiid_obj_t obj_cmd_rs = NULL;
338 fiid_obj_t obj_sdr_record_header = NULL;
339 int sdr_record_header_length = 0;
340 int sdr_record_len = 0;
341 unsigned int record_length = 0;
342 int rv = -1;
343 unsigned int bytes_to_read = IPMI_SDR_CACHE_BYTES_TO_READ_START;
344 unsigned int offset_into_record = 0;
345 unsigned int reservation_id_retry_count = 0;
346 uint8_t temp_record_buf[IPMI_SDR_MAX_RECORD_LENGTH];
347 uint64_t val;
348
349 assert (ctx);
350 assert (ctx->magic == IPMI_SDR_CTX_MAGIC);
351 assert (ipmi_ctx);
352 assert (record_buf);
353 assert (record_buf_len);
354 assert (reservation_id);
355 assert (next_record_id);
356
357 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_sdr_rs)))
358 {
359 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
360 goto cleanup;
361 }
362
363 if (!(obj_sdr_record_header = fiid_obj_create (tmpl_sdr_record_header)))
364 {
365 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
366 goto cleanup;
367 }
368
369 if ((sdr_record_header_length = fiid_template_len_bytes (tmpl_sdr_record_header)) < 0)
370 {
371 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
372 goto cleanup;
373 }
374
375 /* achu:
376 *
377 * Many motherboards now allow you to read the full SDR record, try
378 * that first. If it fails for any reason, bail and try to read via
379 * partial reads.
380 */
381
382 reservation_id_retry_count = 0;
383 while (!offset_into_record)
384 {
385 if (ipmi_cmd_get_sdr (ipmi_ctx,
386 *reservation_id,
387 record_id,
388 0,
389 IPMI_SDR_READ_ENTIRE_RECORD_BYTES_TO_READ,
390 obj_cmd_rs) < 0)
391 {
392 if (ipmi_ctx_errnum (ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE)
393 {
394 uint8_t comp_code;
395
396 if (FIID_OBJ_GET (obj_cmd_rs,
397 "comp_code",
398 &val) < 0)
399 {
400 SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
401 goto cleanup;
402 }
403 comp_code = val;
404
405 if (comp_code == IPMI_COMP_CODE_RESERVATION_CANCELLED
406 && (reservation_id_retry_count < IPMI_SDR_CACHE_MAX_RESERVATION_ID_RETRY))
407 {
408 if (_sdr_cache_reservation_id (ctx,
409 ipmi_ctx,
410 reservation_id) < 0)
411 goto cleanup;
412 reservation_id_retry_count++;
413 continue;
414 }
415 }
416
417 goto partial_read;
418 }
419
420 if ((sdr_record_len = fiid_obj_get_data (obj_cmd_rs,
421 "record_data",
422 temp_record_buf,
423 IPMI_SDR_MAX_RECORD_LENGTH)) < 0)
424 {
425 SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
426 goto cleanup;
427 }
428
429 /* Assume this is an "IPMI Error", fall through to partial reads */
430 if (sdr_record_len < sdr_record_header_length)
431 goto partial_read;
432
433 /*
434 * IPMI Workaround (achu)
435 *
436 * Discovered on Xyratex HB-F8-SRAY
437 *
438 * For some reason reading the entire SDR record (with
439 * IPMI_SDR_READ_ENTIRE_RECORD_BYTES_TO_READ) the response
440 * returns fewer bytes than the actual length of the record.
441 * However, when reading with partial reads things ultimately
442 * succeed. If we notice the length is off, we fall out and do
443 * a partial read.
444 */
445 if ((((uint8_t)temp_record_buf[IPMI_SDR_RECORD_LENGTH_INDEX]) + IPMI_SDR_RECORD_HEADER_LENGTH) > sdr_record_len)
446 goto partial_read;
447
448 if (sdr_record_len > record_buf_len)
449 {
450 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
451 goto cleanup;
452 }
453
454 if (FIID_OBJ_GET (obj_cmd_rs,
455 "next_record_id",
456 &val) < 0)
457 {
458 SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
459 goto cleanup;
460 }
461 *next_record_id = val;
462
463 memcpy (record_buf, temp_record_buf, sdr_record_len);
464 offset_into_record += sdr_record_len;
465 goto out;
466 }
467
468 partial_read:
469
470 reservation_id_retry_count = 0;
471 while (!record_length)
472 {
473 uint8_t record_header_buf[IPMI_SDR_MAX_RECORD_LENGTH];
474 int sdr_record_header_len;
475
476 if (ipmi_cmd_get_sdr (ipmi_ctx,
477 *reservation_id,
478 record_id,
479 0,
480 sdr_record_header_length,
481 obj_cmd_rs) < 0)
482 {
483 if (ipmi_ctx_errnum (ipmi_ctx) != IPMI_ERR_BAD_COMPLETION_CODE)
484 {
485 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR);
486 goto cleanup;
487 }
488 else
489 {
490 uint8_t comp_code;
491
492 if (FIID_OBJ_GET (obj_cmd_rs,
493 "comp_code",
494 &val) < 0)
495 {
496 SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
497 goto cleanup;
498 }
499 comp_code = val;
500
501 if (comp_code == IPMI_COMP_CODE_RESERVATION_CANCELLED
502 && (reservation_id_retry_count < IPMI_SDR_CACHE_MAX_RESERVATION_ID_RETRY))
503 {
504 if (_sdr_cache_reservation_id (ctx,
505 ipmi_ctx,
506 reservation_id) < 0)
507 goto cleanup;
508 reservation_id_retry_count++;
509 continue;
510 }
511
512 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR);
513 goto cleanup;
514 }
515 }
516
517 if ((sdr_record_header_len = fiid_obj_get_data (obj_cmd_rs,
518 "record_data",
519 record_header_buf,
520 IPMI_SDR_MAX_RECORD_LENGTH)) < 0)
521 {
522 SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
523 goto cleanup;
524 }
525
526 if (sdr_record_header_len < sdr_record_header_length)
527 {
528 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR);
529 goto cleanup;
530 }
531
532 if (fiid_obj_set_all (obj_sdr_record_header,
533 record_header_buf,
534 sdr_record_header_len) < 0)
535 {
536 SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_sdr_record_header);
537 goto cleanup;
538 }
539
540 if (FIID_OBJ_GET (obj_sdr_record_header,
541 "record_length",
542 &val) < 0)
543 {
544 SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_sdr_record_header);
545 goto cleanup;
546 }
547
548 if (sdr_record_header_len > record_buf_len)
549 {
550 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
551 goto cleanup;
552 }
553
554 /* copy header into buf */
555 memcpy (record_buf, record_header_buf, sdr_record_header_len);
556 offset_into_record += sdr_record_header_len;
557 record_length = val + sdr_record_header_length;
558 }
559
560 if (record_length > record_buf_len)
561 {
562 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
563 goto cleanup;
564 }
565
566 if (FIID_OBJ_GET (obj_cmd_rs,
567 "next_record_id",
568 &val) < 0)
569 {
570 SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
571 goto cleanup;
572 }
573 *next_record_id = val;
574
575 reservation_id_retry_count = 0;
576 while (offset_into_record < record_length)
577 {
578 int record_data_len;
579
580 if ((record_length - offset_into_record) < bytes_to_read)
581 bytes_to_read = record_length - offset_into_record;
582
583 if (ipmi_cmd_get_sdr (ipmi_ctx,
584 *reservation_id,
585 record_id,
586 offset_into_record,
587 bytes_to_read,
588 obj_cmd_rs) < 0)
589 {
590 /* Workaround
591 *
592 * Dell Poweredge FC830
593 *
594 * Last SDR record can't be read, it always returns
595 * 0xC3. If this is the last record, just don't return
596 * a record back to the caller.
597 */
598 if (ipmi_ctx_errnum (ipmi_ctx) == IPMI_ERR_MESSAGE_TIMEOUT)
599 {
600 uint8_t comp_code;
601
602 if (FIID_OBJ_GET (obj_cmd_rs,
603 "comp_code",
604 &val) < 0)
605 {
606 SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
607 goto cleanup;
608 }
609 comp_code = val;
610
611 if (comp_code == IPMI_COMP_CODE_COMMAND_TIMEOUT
612 && (*next_record_id) == IPMI_SDR_RECORD_ID_LAST)
613 {
614 offset_into_record = 0;
615 goto out;
616 }
617 }
618
619 if (ipmi_ctx_errnum (ipmi_ctx) != IPMI_ERR_BAD_COMPLETION_CODE)
620 {
621 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR);
622 goto cleanup;
623 }
624 else
625 {
626 uint8_t comp_code;
627
628 if (FIID_OBJ_GET (obj_cmd_rs,
629 "comp_code",
630 &val) < 0)
631 {
632 SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
633 goto cleanup;
634 }
635 comp_code = val;
636
637 if (comp_code == IPMI_COMP_CODE_RESERVATION_CANCELLED
638 && (reservation_id_retry_count < IPMI_SDR_CACHE_MAX_RESERVATION_ID_RETRY))
639 {
640 if (_sdr_cache_reservation_id (ctx,
641 ipmi_ctx,
642 reservation_id) < 0)
643 goto cleanup;
644 reservation_id_retry_count++;
645 continue;
646 }
647 else if ((comp_code == IPMI_COMP_CODE_CANNOT_RETURN_REQUESTED_NUMBER_OF_BYTES
648 || comp_code == IPMI_COMP_CODE_UNSPECIFIED_ERROR)
649 && bytes_to_read > sdr_record_header_length)
650 {
651 bytes_to_read -= IPMI_SDR_CACHE_BYTES_TO_READ_DECREMENT;
652 if (bytes_to_read < sdr_record_header_length)
653 bytes_to_read = sdr_record_header_length;
654 continue;
655 }
656
657 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR);
658 goto cleanup;
659 }
660 }
661
662 if ((record_data_len = fiid_obj_get_data (obj_cmd_rs,
663 "record_data",
664 record_buf + offset_into_record,
665 record_buf_len - offset_into_record)) < 0)
666 {
667 SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
668 goto cleanup;
669 }
670
671 offset_into_record += record_data_len;
672 }
673
674 out:
675 rv = offset_into_record;
676 cleanup:
677 fiid_obj_destroy (obj_cmd_rs);
678 fiid_obj_destroy (obj_sdr_record_header);
679 return (rv);
680 }
681
682 static int
_sdr_cache_record_write(ipmi_sdr_ctx_t ctx,int fd,unsigned int * total_bytes_written,uint16_t * record_ids,unsigned int * record_ids_count,uint8_t * buf,unsigned int buflen,uint8_t * trailer_checksum)683 _sdr_cache_record_write (ipmi_sdr_ctx_t ctx,
684 int fd,
685 unsigned int *total_bytes_written,
686 uint16_t *record_ids,
687 unsigned int *record_ids_count,
688 uint8_t *buf,
689 unsigned int buflen,
690 uint8_t *trailer_checksum)
691 {
692 ssize_t n;
693
694 assert (ctx);
695 assert (ctx->magic == IPMI_SDR_CTX_MAGIC);
696 assert (fd);
697 assert (total_bytes_written);
698 assert (!record_ids || (record_ids && record_ids_count));
699 assert (buf);
700 assert (buflen);
701 assert (trailer_checksum);
702
703 /* Record header bytes are 5 bytes */
704 if (buflen < IPMI_SDR_RECORD_HEADER_LENGTH)
705 {
706 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_CREATE_INVALID_RECORD_LENGTH);
707 return (-1);
708 }
709
710 /* Record Length plus the header bytes should match buflen. */
711 if ((((uint8_t)buf[IPMI_SDR_RECORD_LENGTH_INDEX]) + IPMI_SDR_RECORD_HEADER_LENGTH) != buflen)
712 {
713 /*
714 * IPMI Workaround (achu)
715 *
716 * Discovered on HP Proliant DL585G7
717 *
718 * When reading an entire SDR record (using
719 * IPMI_SDR_READ_ENTIRE_RECORD_BYTES_TO_READ), sometimes records
720 * are returned with an excess of bytes. The following
721 * truncates the buffer length to the correct size.
722 */
723 if ((((uint8_t)buf[IPMI_SDR_RECORD_LENGTH_INDEX]) + IPMI_SDR_RECORD_HEADER_LENGTH) <= buflen)
724 buflen = ((uint8_t)buf[IPMI_SDR_RECORD_LENGTH_INDEX]) + IPMI_SDR_RECORD_HEADER_LENGTH;
725 else
726 {
727 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_CREATE_INVALID_RECORD_LENGTH);
728 return (-1);
729 }
730 }
731
732 if (record_ids)
733 {
734 uint16_t record_id;
735 unsigned int i;
736
737 /* Record ID stored little endian */
738 record_id = ((uint16_t)buf[IPMI_SDR_RECORD_ID_INDEX_LS] & 0xFF);
739 record_id |= ((uint16_t)buf[IPMI_SDR_RECORD_ID_INDEX_MS] & 0xFF) << 8;
740
741 for (i = 0; i < *record_ids_count; i++)
742 {
743 if (record_ids[i] == record_id)
744 {
745 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_CREATE_DUPLICATE_RECORD_ID);
746 return (-1);
747 }
748 }
749 record_ids[*record_ids_count] = record_id;
750 (*record_ids_count)++;
751 }
752
753 if ((n = fd_write_n (fd, buf, buflen)) < 0)
754 {
755 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
756 return (-1);
757 }
758
759 if (n != buflen)
760 {
761 /* Try to lseek back to our original spot */
762 lseek (fd, SEEK_SET, *total_bytes_written);
763 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
764 return (-1);
765 }
766 (*total_bytes_written) += buflen;
767
768 (*trailer_checksum) = ipmi_checksum_incremental (buf, buflen, (*trailer_checksum));
769
770 return (0);
771
772 }
773
774 int
ipmi_sdr_cache_create(ipmi_sdr_ctx_t ctx,ipmi_ctx_t ipmi_ctx,const char * filename,int cache_create_flags,Ipmi_Sdr_Cache_Create_Callback create_callback,void * create_callback_data)775 ipmi_sdr_cache_create (ipmi_sdr_ctx_t ctx,
776 ipmi_ctx_t ipmi_ctx,
777 const char *filename,
778 int cache_create_flags,
779 Ipmi_Sdr_Cache_Create_Callback create_callback,
780 void *create_callback_data)
781 {
782 int open_flags;
783 uint8_t sdr_version;
784 uint16_t record_count, reservation_id, record_id, next_record_id;
785 uint32_t most_recent_addition_timestamp, most_recent_erase_timestamp;
786 unsigned int record_count_written = 0;
787 unsigned int total_bytes_written = 0;
788 uint16_t *record_ids = NULL;
789 unsigned int record_ids_count = 0;
790 unsigned int cache_create_flags_mask = (IPMI_SDR_CACHE_CREATE_FLAGS_OVERWRITE
791 | IPMI_SDR_CACHE_CREATE_FLAGS_DUPLICATE_RECORD_ID
792 | IPMI_SDR_CACHE_CREATE_FLAGS_ASSUME_MAX_SDR_RECORD_COUNT);
793 uint8_t trailer_checksum = 0;
794 int fd = -1;
795 int rv = -1;
796
797 if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
798 {
799 ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
800 return (-1);
801 }
802
803 /* Version cannot be 0h according to the IPMI spec */
804 if (!ipmi_ctx
805 || !filename
806 || (strlen (filename) > MAXPATHLEN)
807 || (cache_create_flags & ~cache_create_flags_mask))
808 {
809 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
810 return (-1);
811 }
812
813 if (ctx->operation != IPMI_SDR_OPERATION_UNINITIALIZED)
814 {
815 if (ctx->operation == IPMI_SDR_OPERATION_READ_CACHE)
816 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CONTEXT_PERFORMING_OTHER_OPERATION);
817 else
818 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
819 return (-1);
820 }
821
822 ctx->operation = IPMI_SDR_OPERATION_CREATE_CACHE;
823
824 if (cache_create_flags & IPMI_SDR_CACHE_CREATE_FLAGS_OVERWRITE)
825 open_flags = O_CREAT | O_TRUNC | O_WRONLY;
826 else
827 open_flags = O_CREAT | O_EXCL | O_WRONLY;
828
829 if ((fd = open (filename, open_flags, 0644)) < 0)
830 {
831 if (!(cache_create_flags & IPMI_SDR_CACHE_CREATE_FLAGS_OVERWRITE)
832 && errno == EEXIST)
833 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_CREATE_CACHE_EXISTS);
834 else if (errno == EPERM
835 || errno == EACCES
836 || errno == EISDIR
837 || errno == EROFS)
838 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PERMISSION);
839 else if (errno == ENAMETOOLONG
840 || errno == ENOENT
841 || errno == ELOOP)
842 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_FILENAME_INVALID);
843 else if (errno == ENOSPC
844 || errno == EMFILE
845 || errno == ENFILE)
846 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_FILESYSTEM);
847 else
848 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
849 goto cleanup;
850 }
851
852 if (sdr_info (ctx,
853 ipmi_ctx,
854 &sdr_version,
855 &record_count,
856 &most_recent_addition_timestamp,
857 &most_recent_erase_timestamp) < 0)
858 goto cleanup;
859
860 if (!record_count)
861 {
862 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_CREATE_INVALID_RECORD_COUNT);
863 goto cleanup;
864 }
865
866 if (_sdr_cache_header_write (ctx,
867 ipmi_ctx,
868 fd,
869 &total_bytes_written,
870 sdr_version,
871 record_count,
872 most_recent_addition_timestamp,
873 most_recent_erase_timestamp) < 0)
874 goto cleanup;
875
876 /* Version cannot be 0h according to the IPMI spec, but we accept it regardless */
877 ctx->sdr_version = sdr_version;
878 ctx->record_count = record_count;
879 ctx->most_recent_addition_timestamp = most_recent_addition_timestamp;
880 ctx->most_recent_erase_timestamp = most_recent_erase_timestamp;
881
882 if (cache_create_flags & IPMI_SDR_CACHE_CREATE_FLAGS_DUPLICATE_RECORD_ID)
883 {
884 if (!(record_ids = (uint16_t *)malloc (ctx->record_count * sizeof (uint16_t))))
885 {
886 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_OUT_OF_MEMORY);
887 goto cleanup;
888 }
889 record_ids_count = 0;
890 }
891
892 if (_sdr_cache_reservation_id (ctx,
893 ipmi_ctx,
894 &reservation_id) < 0)
895 goto cleanup;
896
897 next_record_id = IPMI_SDR_RECORD_ID_FIRST;
898 while (next_record_id != IPMI_SDR_RECORD_ID_LAST)
899 {
900 uint8_t record_buf[IPMI_SDR_MAX_RECORD_LENGTH];
901 int record_len;
902
903 if (record_count_written >= ctx->record_count)
904 {
905 /* IPMI Workaround
906 *
907 * Discovered on unspecified Inspur motherboard
908 *
909 * SDR record reading is broken, the IPMI_SDR_RECORD_ID_LAST
910 * record id never occurs. So this workaround allows the
911 * user to not error out and avoids this loop from looping
912 * infinitely.
913 *
914 */
915
916 if (cache_create_flags & IPMI_SDR_CACHE_CREATE_FLAGS_ASSUME_MAX_SDR_RECORD_COUNT)
917 break;
918
919 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_CREATE_INVALID_RECORD_COUNT);
920 goto cleanup;
921 }
922
923 record_id = next_record_id;
924 if ((record_len = _sdr_cache_get_record (ctx,
925 ipmi_ctx,
926 record_id,
927 record_buf,
928 IPMI_SDR_MAX_RECORD_LENGTH,
929 &reservation_id,
930 &next_record_id)) < 0)
931 goto cleanup;
932
933 if (record_len)
934 {
935 if (ctx->flags & IPMI_SDR_FLAGS_DEBUG_DUMP)
936 {
937 const char *record_str;
938
939 if ((record_str = sdr_record_type_str (ctx,
940 record_buf,
941 record_len)))
942 {
943 char hdrbuf[IPMI_SDR_CACHE_DEBUG_BUFLEN + 1];
944
945 memset (hdrbuf, '\0', IPMI_SDR_CACHE_DEBUG_BUFLEN + 1);
946
947 debug_hdr_str (DEBUG_UTIL_TYPE_NONE,
948 DEBUG_UTIL_DIRECTION_NONE,
949 DEBUG_UTIL_FLAGS_DEFAULT,
950 record_str,
951 hdrbuf,
952 IPMI_SDR_CACHE_DEBUG_BUFLEN);
953
954 ipmi_dump_sdr_record (STDERR_FILENO,
955 ctx->debug_prefix,
956 hdrbuf,
957 NULL,
958 record_buf,
959 record_len);
960 }
961 }
962
963 if (_sdr_cache_record_write (ctx,
964 fd,
965 &total_bytes_written,
966 record_ids,
967 &record_ids_count,
968 record_buf,
969 record_len,
970 &trailer_checksum) < 0)
971 goto cleanup;
972
973 record_count_written++;
974
975 if (create_callback)
976 (*create_callback)(ctx->sdr_version,
977 ctx->record_count,
978 ctx->most_recent_addition_timestamp,
979 ctx->most_recent_erase_timestamp,
980 record_id,
981 create_callback_data);
982 }
983 }
984
985 if (record_count_written != ctx->record_count)
986 {
987 /*
988 * IPMI Workaround (achu)
989 *
990 * Discovered on Fujitsu RX 100
991 * Discovered on Fujitsu RX300/200-S8
992 *
993 * The record_count listed from the Get SDR Repository Info command
994 * is not consistent with the length of SDR records stored.
995 *
996 * We will assume that if we reached the end of the SDR record
997 * list (i.e. next_record_id == 0xFFFF), a non-zero number of
998 * records were written, it's ok and we can continue on.
999 */
1000 /* Note Dell Poweredge FC830 workaround above, this code is used
1001 * as a consequence of that workaround
1002 */
1003 if (next_record_id == IPMI_SDR_RECORD_ID_LAST
1004 && record_count_written)
1005 {
1006 unsigned int total_bytes_written_temp = 0;
1007
1008 ctx->record_count = record_count_written;
1009
1010 /* need to seek back to the beginning of the file and
1011 * re-write the header info with the correct number of
1012 * records
1013 */
1014
1015 if (lseek (fd, 0, SEEK_SET) < 0)
1016 {
1017 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
1018 goto cleanup;
1019 }
1020
1021 if (_sdr_cache_header_write (ctx,
1022 ipmi_ctx,
1023 fd,
1024 &total_bytes_written_temp,
1025 ctx->sdr_version,
1026 ctx->record_count,
1027 ctx->most_recent_addition_timestamp,
1028 ctx->most_recent_erase_timestamp) < 0)
1029 goto cleanup;
1030
1031 /* need to seek back to the end of the file to write the
1032 * trailer below
1033 */
1034 if (lseek (fd, 0, SEEK_END) < 0)
1035 {
1036 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
1037 goto cleanup;
1038 }
1039 }
1040 else
1041 {
1042 SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_CREATE_INVALID_RECORD_COUNT);
1043 goto cleanup;
1044 }
1045 }
1046
1047 if (_sdr_cache_trailer_write (ctx,
1048 ipmi_ctx,
1049 fd,
1050 total_bytes_written,
1051 trailer_checksum) < 0)
1052 goto cleanup;
1053
1054 if (fsync (fd) < 0)
1055 {
1056 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
1057 goto cleanup;
1058 }
1059
1060 if (close (fd) < 0)
1061 {
1062 SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
1063 goto cleanup;
1064 }
1065 fd = -1;
1066
1067 rv = 0;
1068 ctx->errnum = IPMI_SDR_ERR_SUCCESS;
1069 cleanup:
1070 ctx->operation = IPMI_SDR_OPERATION_UNINITIALIZED;
1071 if (fd >= 0)
1072 {
1073 /* If the cache create never completed, try to remove the file */
1074 /* ignore potential error, cleanup path */
1075 unlink (filename);
1076 /* ignore potential error, cleanup path */
1077 close (fd);
1078 }
1079 free (record_ids);
1080 sdr_init_ctx (ctx);
1081 return (rv);
1082 }
1083