1 /*
2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that the following conditions
4 * are met:
5 *
6 * Redistribution of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 *
9 * Redistribution in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * Neither the name of Sun Microsystems, Inc. or the names of
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * This software is provided "AS IS," without a warranty of any kind.
18 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
19 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
20 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
21 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
22 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
23 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
24 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
25 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
26 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
27 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
28 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
29 */
30
31 /*
32 * Functions to program the SDR repository, from built-in sensors or
33 * from sensors dumped in a binary file.
34 */
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <time.h>
40 #include <fcntl.h>
41
42 #include <ipmitool/helper.h>
43 #include <ipmitool/log.h>
44 #include <ipmitool/bswap.h>
45 #include <ipmitool/ipmi.h>
46 #include <ipmitool/ipmi_intf.h>
47 #include <ipmitool/ipmi_mc.h>
48 #include <ipmitool/ipmi_strings.h>
49
50 #include <ipmitool/ipmi_sdr.h>
51
52
53 #define ADD_PARTIAL_SDR 0x25
54
55 #ifdef HAVE_PRAGMA_PACK
56 #pragma pack(1)
57 #endif
58 struct sdr_add_rq {
59 uint16_t reserve_id; /* reservation ID */
60 uint16_t id; /* record ID */
61 uint8_t offset; /* offset into SDR */
62 uint8_t in_progress; /* 0=partial, 1=last */
63 #define PARTIAL_ADD (0)
64 #define LAST_RECORD (1)
65 uint8_t data[1]; /* SDR record data */
66 } ATTRIBUTE_PACKING;
67 #ifdef HAVE_PRAGMA_PACK
68 #pragma pack(0)
69 #endif
70
71 /* This was formerly initialized to 24, reduced this to 19 so the overall
72 message fits into the recommended 32-byte limit */
73 static int sdr_max_write_len = 19;
74 int ipmi_parse_range_list(const char *rangeList, unsigned char *pHexList);
75 int ipmi_hex_to_dec( char * rangeList, unsigned char * pDecValue);
76
77 static int
partial_send(struct ipmi_intf * intf,struct ipmi_rq * req,uint16_t * id)78 partial_send(struct ipmi_intf *intf, struct ipmi_rq *req, uint16_t *id)
79 {
80 struct ipmi_rs *rsp;
81 rsp = intf->sendrecv(intf, req);
82 if (rsp == NULL) {
83 return -1;
84 }
85
86 if (rsp->ccode || rsp->data_len < 2) {
87 return -1;
88 }
89
90 *id = rsp->data[0] + (rsp->data[1] << 8);
91 return 0;
92 }
93
94 int
ipmi_sdr_add_record(struct ipmi_intf * intf,struct sdr_record_list * sdrr)95 ipmi_sdr_add_record(struct ipmi_intf *intf, struct sdr_record_list *sdrr)
96 {
97 struct ipmi_rq req;
98 struct sdr_add_rq *sdr_rq;
99 uint16_t reserve_id;
100 uint16_t id;
101 int i;
102 int len = sdrr->length;
103 int rc = 0;
104
105 /* actually no SDR to program */
106 if (len < 1 || !sdrr->raw) {
107 lprintf(LOG_ERR, "ipmitool: bad record , skipped");
108 return 0;
109 }
110
111 if (ipmi_sdr_get_reservation(intf, 0, &reserve_id)) {
112 lprintf(LOG_ERR, "ipmitool: reservation failed");
113 return -1;
114 }
115
116 sdr_rq = (struct sdr_add_rq *)malloc(sizeof(*sdr_rq) + sdr_max_write_len);
117 if (sdr_rq == NULL) {
118 lprintf(LOG_ERR, "ipmitool: malloc failure");
119 return -1;
120 }
121 sdr_rq->reserve_id = reserve_id;
122 sdr_rq->in_progress = PARTIAL_ADD;
123
124 memset(&req, 0, sizeof(req));
125 req.msg.netfn = IPMI_NETFN_STORAGE;
126 req.msg.cmd = ADD_PARTIAL_SDR;
127 req.msg.data = (uint8_t *) sdr_rq;
128
129 /* header first */
130 sdr_rq->id = 0;
131 sdr_rq->offset = 0;
132 sdr_rq->data[0] = sdrr->id & 0xFF;
133 sdr_rq->data[1] = (sdrr->id >> 8) & 0xFF;
134 sdr_rq->data[2] = sdrr->version;
135 sdr_rq->data[3] = sdrr->type;
136 sdr_rq->data[4] = sdrr->length;
137 req.msg.data_len = 5 + sizeof(*sdr_rq) - 1;
138
139 if (partial_send(intf, &req, &id)) {
140 lprintf(LOG_ERR, "ipmitool: partial send error");
141 free(sdr_rq);
142 sdr_rq = NULL;
143 return -1;
144 }
145
146 i = 0;
147
148 /* sdr entry */
149 while (i < len) {
150 int data_len = 0;
151 if ( (len - i) <= sdr_max_write_len) {
152 /* last crunch */
153 data_len = len - i;
154 sdr_rq->in_progress = LAST_RECORD;
155 } else {
156 data_len = sdr_max_write_len;
157 }
158
159 sdr_rq->id = id;
160 sdr_rq->offset = i + 5;
161 memcpy(sdr_rq->data, sdrr->raw + i, data_len);
162 req.msg.data_len = data_len + sizeof(*sdr_rq) - 1;
163
164 if ((rc = partial_send(intf, &req, &id)) != 0) {
165 lprintf(LOG_ERR, "ipmitool: partial add failed");
166 break;
167 }
168
169 i += data_len;
170 }
171
172 free(sdr_rq);
173 sdr_rq = NULL;
174 return rc;
175 }
176
177 static int
ipmi_sdr_repo_clear(struct ipmi_intf * intf)178 ipmi_sdr_repo_clear(struct ipmi_intf *intf)
179 {
180 struct ipmi_rs * rsp;
181 struct ipmi_rq req;
182 uint8_t msg_data[8];
183 uint16_t reserve_id;
184 int try;
185
186 if (ipmi_sdr_get_reservation(intf, 0, &reserve_id))
187 return -1;
188
189 memset(&req, 0, sizeof(req));
190 req.msg.netfn = IPMI_NETFN_STORAGE;
191 req.msg.cmd = 0x27; // FIXME
192 req.msg.data = msg_data;
193 req.msg.data_len = 6;
194
195 msg_data[0] = reserve_id & 0xFF;
196 msg_data[1] = reserve_id >> 8;
197 msg_data[2] = 'C';
198 msg_data[3] = 'L';
199 msg_data[4] = 'R';
200 msg_data[5] = 0xAA;
201
202 for (try = 0; try < 5; try++) {
203 rsp = intf->sendrecv(intf, &req);
204 if (rsp == NULL) {
205 lprintf(LOG_ERR, "Unable to clear SDRR");
206 return -1;
207 }
208 if (rsp->ccode > 0) {
209 lprintf(LOG_ERR, "Unable to clear SDRR: %s",
210 val2str(rsp->ccode, completion_code_vals));
211 return -1;
212 }
213 if ((rsp->data[0] & 1) == 1) {
214 printf("SDRR successfully erased\n");
215 return 0;
216 }
217 printf("Wait for SDRR erasure completed...\n");
218 msg_data[5] = 0;
219 sleep(1);
220 }
221
222 /* if we are here we fed up trying erase */
223 return -1;
224 }
225
226
227 struct sdrr_queue {
228 struct sdr_record_list *head;
229 struct sdr_record_list *tail;
230 };
231
232
233 /*
234 * Fill the SDR repository from built-in sensors
235 *
236 */
237
238 /*
239 * Get all the SDR records stored in <queue>
240 */
241 static int
sdrr_get_records(struct ipmi_intf * intf,struct ipmi_sdr_iterator * itr,struct sdrr_queue * queue)242 sdrr_get_records(struct ipmi_intf *intf, struct ipmi_sdr_iterator *itr,
243 struct sdrr_queue *queue)
244 {
245 struct sdr_get_rs *header;
246
247 queue->head = NULL;
248 queue->tail = NULL;
249
250 while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) {
251 struct sdr_record_list *sdrr;
252
253 sdrr = malloc(sizeof (struct sdr_record_list));
254 if (sdrr == NULL) {
255 lprintf(LOG_ERR, "ipmitool: malloc failure");
256 return -1;
257 }
258 memset(sdrr, 0, sizeof (struct sdr_record_list));
259
260 sdrr->id = header->id;
261 sdrr->version = header->version;
262 sdrr->type = header->type;
263 sdrr->length = header->length;
264 sdrr->raw = ipmi_sdr_get_record(intf, header, itr);
265 (void)ipmi_sdr_print_name_from_rawentry(intf, sdrr->id, sdrr->type,sdrr->raw);
266
267 /* put in the record queue */
268 if (queue->head == NULL)
269 queue->head = sdrr;
270 else
271 queue->tail->next = sdrr;
272 queue->tail = sdrr;
273 }
274 return 0;
275 }
276
277 static int
sdr_copy_to_sdrr(struct ipmi_intf * intf,int use_builtin,int from_addr,int to_addr)278 sdr_copy_to_sdrr(struct ipmi_intf *intf, int use_builtin,
279 int from_addr, int to_addr)
280 {
281 int rc;
282 struct sdrr_queue sdrr_queue;
283 struct ipmi_sdr_iterator *itr;
284 struct sdr_record_list *sdrr;
285 struct sdr_record_list *sdrr_next;
286
287 /* generate list of records for this target */
288 intf->target_addr = from_addr;
289
290 /* initialize iterator */
291 itr = ipmi_sdr_start(intf, use_builtin);
292 if (itr == 0)
293 return 0;
294
295 printf("Load SDRs from 0x%x\n", from_addr);
296 rc = sdrr_get_records(intf, itr, &sdrr_queue);
297 ipmi_sdr_end(intf, itr);
298 /* ... */
299
300 /* write the SDRs to the destination SDR Repository */
301 intf->target_addr = to_addr;
302 for (sdrr = sdrr_queue.head; sdrr != NULL; sdrr = sdrr_next) {
303 sdrr_next = sdrr->next;
304 rc = ipmi_sdr_add_record(intf, sdrr);
305 if(rc < 0){
306 lprintf(LOG_ERR, "Cannot add SDR ID 0x%04x to repository...", sdrr->id);
307 }
308 free(sdrr);
309 sdrr = NULL;
310 }
311 return rc;
312 }
313
314 int
ipmi_sdr_add_from_sensors(struct ipmi_intf * intf,int maxslot)315 ipmi_sdr_add_from_sensors(struct ipmi_intf *intf, int maxslot)
316 {
317 int i;
318 int rc = 0;
319 int slave_addr;
320 int myaddr = intf->target_addr;
321
322 if (ipmi_sdr_repo_clear(intf)) {
323 lprintf(LOG_ERR, "Cannot erase SDRR. Give up.");
324 return -1;
325 }
326
327 /* First fill the SDRR from local built-in sensors */
328 rc = sdr_copy_to_sdrr(intf, 1, myaddr, myaddr);
329
330 /* Now fill the SDRR with remote sensors */
331 if( maxslot != 0 ) {
332 for (i = 0, slave_addr = 0xB0; i < maxslot; i++, slave_addr += 2) {
333 /* Hole in the PICMG 2.9 mapping */
334 if (slave_addr == 0xC2) slave_addr += 2;
335 if(sdr_copy_to_sdrr(intf, 0, slave_addr, myaddr) < 0)
336 {
337 rc = -1;
338 }
339 }
340 }
341 return rc;
342 }
343
ipmi_hex_to_dec(char * strchar,unsigned char * pDecValue)344 int ipmi_hex_to_dec( char * strchar, unsigned char * pDecValue)
345 {
346 int rc = -1;
347 unsigned char retValue = 0;
348
349 if(
350 (strlen(strchar) == 4)
351 &&
352 (strchar[0] == '0')
353 &&
354 (strchar[1] == 'x')
355 )
356 {
357 rc = 0;
358
359 if((strchar[2] >= '0') && (strchar[2] <= '9'))
360 {
361 retValue += ((strchar[2]-'0') * 16);
362 }
363 else if((strchar[2] >= 'a') && (strchar[2] <= 'f'))
364 {
365 retValue += (((strchar[2]-'a') + 10) * 16);
366 }
367 else if((strchar[2] >= 'A') && (strchar[2] <= 'F'))
368 {
369 retValue += (((strchar[2]-'A') + 10) * 16);
370 }
371 else
372 {
373 rc = -1;
374 }
375
376 if((strchar[3] >= '0') && (strchar[3] <= '9'))
377 {
378 retValue += ((strchar[3]-'0'));
379 }
380 else if((strchar[3] >= 'a') && (strchar[3] <= 'f'))
381 {
382 retValue += (((strchar[3]-'a') + 10));
383 }
384 else if((strchar[3] >= 'A') && (strchar[3] <= 'F'))
385 {
386 retValue += (((strchar[3]-'A') + 10));
387 }
388 else
389 {
390 rc = -1;
391 }
392 }
393
394 if(rc == 0)
395 {
396 * pDecValue = retValue;
397 }
398 else
399 {
400 lprintf(LOG_ERR, "Must be Hex value of 4 characters (Ex.: 0x24)");
401 }
402
403 return rc;
404 }
405
406
407
408 #define MAX_NUM_SLOT 128
ipmi_parse_range_list(const char * rangeList,unsigned char * pHexList)409 int ipmi_parse_range_list(const char *rangeList, unsigned char * pHexList)
410 {
411 int rc = -1;
412
413 unsigned char listOffset = 0;
414 char * nextString;
415 char * rangeString;
416 char * inProcessString = (char *) rangeList;
417
418 /* Discard empty string */
419 if(strlen(rangeList) == 0)
420 {
421 return rc;
422 }
423
424 /* First, cut to comma separated string */
425 nextString = strstr( rangeList, "," );
426
427 if(nextString != rangeList)
428 {
429 unsigned char isLast;
430 /* We get a valid string so far */
431 rc = 0;
432
433 do
434 {
435 if(nextString != NULL)
436 {
437 (*nextString)= 0;
438 nextString ++;
439 isLast = 0;
440 }
441 else
442 {
443 isLast = 1;
444 }
445
446 /* At this point, it is a single entry or a range */
447 rangeString = strstr( inProcessString, "-" );
448 if(rangeString == NULL)
449 {
450 unsigned char decValue = 0;
451
452 /* Single entry */
453 rc = ipmi_hex_to_dec( inProcessString, &decValue);
454
455 if(rc == 0)
456 {
457 if((decValue % 2) == 0)
458 {
459 pHexList[listOffset++] = decValue;
460 }
461 else
462 {
463 lprintf(LOG_ERR, "I2C address provided value must be even.");
464 }
465 }
466 }
467 else
468 {
469 unsigned char startValue = 0;
470 unsigned char endValue = 0;
471
472
473 (*rangeString)= 0; /* Cut string*/
474 rangeString ++;
475
476 /* Range */
477 rc = ipmi_hex_to_dec( inProcessString, &startValue);
478 if(rc == 0)
479 rc = ipmi_hex_to_dec( rangeString, &endValue);
480
481 if(rc == 0)
482 {
483 if(((startValue % 2) == 0) && ((endValue % 2) == 0))
484 {
485 do
486 {
487 pHexList[listOffset++] = startValue;
488 startValue += 2;
489 }
490 while(startValue != endValue);
491 pHexList[listOffset++] = endValue;
492 }
493 else
494 {
495 lprintf(LOG_ERR, "I2C address provided value must be even.");
496 }
497 }
498 }
499
500 if(isLast == 0)
501 {
502 /* Setup for next string */
503 inProcessString = nextString;
504 nextString = strstr( rangeList, "," );
505 }
506 }while ((isLast == 0) && (rc == 0));
507 }
508
509 return rc;
510 }
511
512 int
ipmi_sdr_add_from_list(struct ipmi_intf * intf,const char * rangeList)513 ipmi_sdr_add_from_list(struct ipmi_intf *intf, const char *rangeList)
514 {
515 int rc = 0;
516 int slave_addr;
517 int myaddr = intf->target_addr;
518 unsigned char listValue[MAX_NUM_SLOT];
519
520 memset( listValue, 0, MAX_NUM_SLOT );
521
522 /* Build list from string */
523 if(ipmi_parse_range_list(rangeList, listValue) != 0)
524 {
525 lprintf(LOG_ERR, "Range - List invalid, cannot be parsed.");
526 return -1;
527 }
528
529 {
530 unsigned char counter = 0;
531 printf("List to scan: (Built-in) ");
532 while(listValue[counter] != 0)
533 {
534 printf("%02x ", listValue[counter]);
535 counter++;
536 }
537 printf("\n");
538 }
539
540 printf("Clearing SDR Repository\n");
541 if (ipmi_sdr_repo_clear(intf)) {
542 lprintf(LOG_ERR, "Cannot erase SDRR. Give up.");
543 return -1;
544 }
545
546 /* First fill the SDRR from local built-in sensors */
547 printf("Sanning built-in sensors..\n");
548 rc = sdr_copy_to_sdrr(intf, 1, myaddr, myaddr);
549
550 /* Now fill the SDRR with provided sensors list */
551 {
552 unsigned char counter = 0;
553 while((rc == 0) && (listValue[counter] != 0))
554 {
555 slave_addr = listValue[counter];
556 printf("Scanning %02Xh..\n", slave_addr);
557 if(sdr_copy_to_sdrr(intf, 0, slave_addr, myaddr) < 0)
558 {
559 rc = -1;
560 }
561 counter++;
562 }
563 }
564
565 return rc;
566 }
567
568
569 /*
570 * Fill the SDR repository from records stored in a binary file
571 *
572 */
573
574 static int
ipmi_sdr_read_records(const char * filename,struct sdrr_queue * queue)575 ipmi_sdr_read_records(const char *filename, struct sdrr_queue *queue)
576 {
577 int rc = 0;
578 int fd;
579 uint8_t binHdr[5];
580
581 queue->head = NULL;
582 queue->tail = NULL;
583
584 if ((fd = open(filename, O_RDONLY)) < 0) {
585 return -1;
586 }
587
588 while (read(fd, binHdr, 5) == 5) {
589
590 struct sdr_record_list *sdrr;
591
592 lprintf(LOG_DEBUG, "binHdr[0] (id[MSB]) = 0x%02x", binHdr[0]);
593 lprintf(LOG_DEBUG, "binHdr[1] (id[LSB]) = 0x%02x", binHdr[1]);
594 lprintf(LOG_DEBUG, "binHdr[2] (version) = 0x%02x", binHdr[2]);
595 lprintf(LOG_DEBUG, "binHdr[3] (type) = 0x%02x", binHdr[3]);
596 lprintf(LOG_DEBUG, "binHdr[4] (length) = 0x%02x", binHdr[4]);
597
598 sdrr = malloc(sizeof(*sdrr));
599 if (sdrr == NULL) {
600 lprintf(LOG_ERR, "ipmitool: malloc failure");
601 rc = -1;
602 break;
603 }
604 sdrr->id = (binHdr[1] << 8) | binHdr[0]; // LS Byte first
605 sdrr->version = binHdr[2];
606 sdrr->type = binHdr[3];
607 sdrr->length = binHdr[4];
608
609 if ((sdrr->raw = malloc(sdrr->length)) == NULL) {
610 lprintf(LOG_ERR, "ipmitool: malloc failure");
611 free(sdrr);
612 sdrr = NULL;
613 rc = -1;
614 break;
615 }
616
617 if (read(fd, sdrr->raw, sdrr->length) != sdrr->length) {
618 lprintf(LOG_ERR, "SDR from '%s' truncated", filename);
619 free(sdrr->raw);
620 sdrr->raw = NULL;
621 free(sdrr);
622 sdrr = NULL;
623 rc = -1;
624 break;
625 }
626
627 /* put in the record queue */
628 if (queue->head == NULL)
629 queue->head = sdrr;
630 else
631 queue->tail->next = sdrr;
632 queue->tail = sdrr;
633 }
634 close(fd);
635 return rc;
636 }
637
638 int
ipmi_sdr_add_from_file(struct ipmi_intf * intf,const char * ifile)639 ipmi_sdr_add_from_file(struct ipmi_intf *intf, const char *ifile)
640 {
641 int rc;
642 struct sdrr_queue sdrr_queue;
643 struct sdr_record_list *sdrr;
644 struct sdr_record_list *sdrr_next;
645
646 /* read the SDR records from file */
647 rc = ipmi_sdr_read_records(ifile, &sdrr_queue);
648
649 if (ipmi_sdr_repo_clear(intf)) {
650 lprintf(LOG_ERR, "Cannot erase SDRR. Giving up.");
651 /* FIXME: free sdr list */
652 return -1;
653 }
654
655 /* write the SDRs to the SDR Repository */
656 for (sdrr = sdrr_queue.head; sdrr != NULL; sdrr = sdrr_next) {
657 sdrr_next = sdrr->next;
658 rc = ipmi_sdr_add_record(intf, sdrr);
659 if(rc < 0){
660 lprintf(LOG_ERR, "Cannot add SDR ID 0x%04x to repository...", sdrr->id);
661 }
662 free(sdrr);
663 sdrr = NULL;
664 }
665 return rc;
666 }
667
668