1 /*
2 * Copyright (c) 2003 Kontron Canada, Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * Redistribution of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * Redistribution in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * Neither the name of Sun Microsystems, Inc. or the names of
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * This software is provided "AS IS," without a warranty of any kind.
20 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
26 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31 */
32
33 #include <string.h>
34
35 #include <math.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <time.h>
40
41 #include <ipmitool/ipmi.h>
42 #include <ipmitool/log.h>
43 #include <ipmitool/ipmi_mc.h>
44 #include <ipmitool/ipmi_sdr.h>
45 #include <ipmitool/ipmi_gendev.h>
46 #include <ipmitool/ipmi_intf.h>
47 #include <ipmitool/ipmi_sel.h>
48 #include <ipmitool/ipmi_entity.h>
49 #include <ipmitool/ipmi_constants.h>
50 #include <ipmitool/ipmi_strings.h>
51 #include <ipmitool/ipmi_raw.h>
52
53 #if HAVE_CONFIG_H
54 # include <config.h>
55 #endif
56
57 extern int verbose;
58
59
60 #define GENDEV_RETRY_COUNT 5
61 #define GENDEV_MAX_SIZE 16
62
63 typedef struct gendev_eeprom_info
64 {
65 uint32_t size;
66 uint16_t page_size;
67 uint8_t address_span;
68 uint8_t address_length;
69 }t_gendev_eeprom_info;
70
71
72 static int
ipmi_gendev_get_eeprom_size(struct ipmi_intf * intf,struct sdr_record_generic_locator * dev,t_gendev_eeprom_info * info)73 ipmi_gendev_get_eeprom_size(
74 struct ipmi_intf *intf,
75 struct sdr_record_generic_locator *dev,
76 t_gendev_eeprom_info *info
77 )
78 {
79 int eeprom_size = 0;
80 /*
81 lprintf(LOG_ERR, "Gen Device : %s", dev->id_string);
82 lprintf(LOG_ERR, "Access Addr: %x", dev->dev_access_addr);
83 lprintf(LOG_ERR, "Slave Addr : %x", dev->dev_slave_addr);
84 lprintf(LOG_ERR, "Channel Num: %x", dev->channel_num);
85 lprintf(LOG_ERR, "Lun : %x", dev->lun);
86 lprintf(LOG_ERR, "Bus : %x", dev->bus);
87 lprintf(LOG_ERR, "Addr Span : %x", dev->addr_span);
88 lprintf(LOG_ERR, "DevType : %x", dev->dev_type);
89 lprintf(LOG_ERR, "DevType Mod: %x", dev->dev_type_modifier);
90 */
91 if( info != NULL)
92 {
93 switch(dev->dev_type)
94 {
95 case 0x08: // 24C01
96 info->size = 128;
97 info->page_size = 8;
98 info->address_span = dev->addr_span;
99 info->address_length = 1;
100 break;
101 case 0x09: // 24C02
102 info->size = 256;
103 info->page_size = 8;
104 info->address_span = dev->addr_span;
105 info->address_length = 1;
106 break;
107 case 0x0A: // 24C04
108 info->size = 512;
109 info->page_size = 8;
110 info->address_span = dev->addr_span;
111 info->address_length = 2;
112 break;
113 case 0x0B: // 24C08
114 info->size = 1024;
115 info->page_size = 8;
116 info->address_span = dev->addr_span;
117 info->address_length = 2;
118 break;
119 case 0x0C: // 24C16
120 info->size = 2048;
121 info->page_size = 256;
122 info->address_span = dev->addr_span;
123 info->address_length = 2;
124 break;
125 case 0x0D: // 24C17
126 info->size = 2048;
127 info->page_size = 256;
128 info->address_span = dev->addr_span;
129 info->address_length = 2;
130 break;
131 case 0x0E: // 24C32
132 info->size = 4096;
133 info->page_size = 8;
134 info->address_span = dev->addr_span;
135 info->address_length = 2;
136 break;
137 case 0x0F: // 24C64
138 info->size = 8192;
139 info->page_size = 32;
140 info->address_span = dev->addr_span;
141 info->address_length = 2;
142 break;
143 case 0xC0: // Proposed OEM Code for 24C128
144 info->size = 16384;
145 info->page_size = 64;
146 info->address_span = dev->addr_span;
147 info->address_length = 2;
148 break;
149 case 0xC1: // Proposed OEM Code for 24C256
150 info->size = 32748;
151 info->page_size = 64;
152 info->address_span = dev->addr_span;
153 info->address_length = 2;
154 break;
155 case 0xC2: // Proposed OEM Code for 24C512
156 info->size = 65536;
157 info->page_size = 128;
158 info->address_span = dev->addr_span;
159 info->address_length = 2;
160 break;
161 case 0xC3: // Proposed OEM Code for 24C1024
162 info->size = 131072;
163 info->page_size = 128;
164 info->address_span = dev->addr_span;
165 info->address_length = 2;
166 break;
167 /* Please reserved up to CFh for future update */
168 default: // Not a eeprom, return size = 0;
169 info->size = 0;
170 info->page_size = 0;
171 info->address_span = 0;
172 info->address_length = 0;
173 break;
174 }
175
176 eeprom_size = info->size;
177 }
178
179 return eeprom_size;
180 }
181
182
183
184 static int
ipmi_gendev_read_file(struct ipmi_intf * intf,struct sdr_record_generic_locator * dev,const char * ofile)185 ipmi_gendev_read_file(
186 struct ipmi_intf *intf,
187 struct sdr_record_generic_locator *dev,
188 const char *ofile
189 )
190 {
191 int rc = 0;
192 int eeprom_size;
193 t_gendev_eeprom_info eeprom_info;
194
195 eeprom_size = ipmi_gendev_get_eeprom_size(intf, dev, &eeprom_info);
196
197 if(eeprom_size > 0)
198 {
199 FILE *fp;
200
201 /* now write to file */
202 fp = ipmi_open_file_write(ofile);
203
204 if(fp)
205 {
206 struct ipmi_rs *rsp;
207 int numWrite;
208 uint32_t counter;
209 uint8_t msize;
210 uint8_t channel = dev->channel_num;
211 uint8_t i2cbus = dev->bus;
212 uint8_t i2caddr = dev->dev_slave_addr;
213 uint8_t privatebus = 1;
214 uint32_t address_span_size;
215 uint8_t percentCompleted = 0;
216
217
218 /* Handle Address Span */
219 if( eeprom_info.address_span != 0)
220 {
221 address_span_size =
222 (eeprom_info.size / (eeprom_info.address_span+1));
223 }
224 else
225 {
226 address_span_size = eeprom_info.size;
227 }
228
229 /* Setup read/write size */
230 if( eeprom_info.page_size < GENDEV_MAX_SIZE)
231 {
232 msize = eeprom_info.page_size;
233 }
234 else
235 {
236 msize = GENDEV_MAX_SIZE;
237 // All eeprom with page higher than 32 is on the
238 // 16 bytes boundary
239 }
240
241 /* Setup i2c bus byte */
242 i2cbus = ((channel & 0xF) << 4) | ((i2cbus & 7) << 1) | privatebus;
243
244 /*
245 lprintf(LOG_ERR, "Generic device: %s", dev->id_string);
246 lprintf(LOG_ERR, "I2C Chnl: %x", channel);
247 lprintf(LOG_ERR, "I2C Bus : %x", i2cbus);
248 lprintf(LOG_ERR, "I2C Addr: %x", i2caddr); */
249
250 for (
251 counter = 0;
252 (counter < (eeprom_info.size)) && (rc == 0);
253 counter+= msize
254 )
255 {
256 uint8_t retryCounter;
257
258 for(
259 retryCounter = 0;
260 retryCounter<GENDEV_RETRY_COUNT;
261 retryCounter ++
262 )
263 {
264 uint8_t wrByte[GENDEV_MAX_SIZE+2];
265
266 wrByte[0] = (uint8_t) (counter>>0);
267 if(eeprom_info.address_length > 1)
268 {
269 wrByte[1] = (uint8_t) (counter>>8);
270 }
271
272 i2caddr+= (((eeprom_info.size) % address_span_size) * 2);
273
274 rsp = ipmi_master_write_read(
275 intf,
276 i2cbus,
277 i2caddr,
278 (uint8_t *) wrByte,
279 eeprom_info.address_length,
280 msize
281 );
282
283 if (rsp != NULL)
284 {
285 retryCounter = GENDEV_RETRY_COUNT;
286 rc = 0;
287 }
288 else if(retryCounter < GENDEV_RETRY_COUNT)
289 {
290 retryCounter ++;
291 lprintf(LOG_ERR, "Retry");
292 sleep(1);
293 rc = -1;
294 }
295 else
296 {
297 lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read");
298 rc = -1;
299 }
300 }
301
302 if( rc == 0 )
303 {
304 static uint8_t previousCompleted = 101;
305 numWrite = fwrite(rsp->data, 1, msize, fp);
306 if (numWrite != msize)
307 {
308 lprintf(LOG_ERR, "Error writing file %s", ofile);
309 rc = -1;
310 break;
311 }
312
313 percentCompleted = ((counter * 100) / eeprom_info.size );
314
315 if(percentCompleted != previousCompleted)
316 {
317 printf("\r%i percent completed", percentCompleted);
318 previousCompleted = percentCompleted;
319 }
320
321
322 }
323 }
324 if(counter == (eeprom_info.size))
325 {
326 printf("\r%%100 percent completed\n");
327 }
328 else
329 {
330 printf("\rError: %i percent completed, read not completed \n", percentCompleted);
331 }
332
333 fclose(fp);
334 }
335 }
336 else
337 {
338 lprintf(LOG_ERR, "The selected generic device is not an eeprom");
339 }
340
341 return rc;
342 }
343
344
345 /* ipmi_gendev_write_file - Read raw SDR from binary file
346 *
347 * used for writing generic locator device Eeprom type
348 *
349 * @intf: ipmi interface
350 * @dev: generic device to read
351 * @ofile: output filename
352 *
353 * returns 0 on success
354 * returns -1 on error
355 */
356 static int
ipmi_gendev_write_file(struct ipmi_intf * intf,struct sdr_record_generic_locator * dev,const char * ofile)357 ipmi_gendev_write_file(
358 struct ipmi_intf *intf,
359 struct sdr_record_generic_locator *dev,
360 const char *ofile
361 )
362 {
363 int rc = 0;
364 int eeprom_size;
365 t_gendev_eeprom_info eeprom_info;
366
367 eeprom_size = ipmi_gendev_get_eeprom_size(intf, dev, &eeprom_info);
368
369 if(eeprom_size > 0)
370 {
371 FILE *fp;
372 uint32_t fileLength = 0;
373
374 /* now write to file */
375 fp = ipmi_open_file_read(ofile);
376
377 if(fp)
378 {
379 /* Retreive file length, check if it's fits the Eeprom Size */
380 fseek(fp, 0 ,SEEK_END);
381 fileLength = ftell(fp);
382
383 lprintf(LOG_ERR, "File Size: %i", fileLength);
384 lprintf(LOG_ERR, "Eeprom Size: %i", eeprom_size);
385 if(fileLength != eeprom_size)
386 {
387 lprintf(LOG_ERR, "File size does not fit Eeprom Size");
388 fclose(fp);
389 fp = NULL;
390 }
391 else
392 {
393 fseek(fp, 0 ,SEEK_SET);
394 }
395 }
396
397 if(fp)
398 {
399 struct ipmi_rs *rsp;
400 int numRead;
401 uint32_t counter;
402 uint8_t msize;
403 uint8_t channel = dev->channel_num;
404 uint8_t i2cbus = dev->bus;
405 uint8_t i2caddr = dev->dev_slave_addr;
406 uint8_t privatebus = 1;
407 uint32_t address_span_size;
408 uint8_t percentCompleted = 0;
409
410
411 /* Handle Address Span */
412 if( eeprom_info.address_span != 0)
413 {
414 address_span_size =
415 (eeprom_info.size / (eeprom_info.address_span+1));
416 }
417 else
418 {
419 address_span_size = eeprom_info.size;
420 }
421
422 /* Setup read/write size */
423 if( eeprom_info.page_size < GENDEV_MAX_SIZE)
424 {
425 msize = eeprom_info.page_size;
426 }
427 else
428 {
429 msize = GENDEV_MAX_SIZE;
430 // All eeprom with page higher than 32 is on the
431 // 16 bytes boundary
432 }
433
434 /* Setup i2c bus byte */
435 i2cbus = ((channel & 0xF) << 4) | ((i2cbus & 7) << 1) | privatebus;
436
437 /*
438 lprintf(LOG_ERR, "Generic device: %s", dev->id_string);
439 lprintf(LOG_ERR, "I2C Chnl: %x", channel);
440 lprintf(LOG_ERR, "I2C Bus : %x", i2cbus);
441 lprintf(LOG_ERR, "I2C Addr: %x", i2caddr); */
442
443 for (
444 counter = 0;
445 (counter < (eeprom_info.size)) && (rc == 0);
446 counter+= msize
447 )
448 {
449 uint8_t retryCounter;
450 uint8_t readByte[GENDEV_MAX_SIZE];
451
452 numRead = fread(readByte, 1, msize, fp);
453 if (numRead != msize)
454 {
455 lprintf(LOG_ERR, "Error reading file %s", ofile);
456 rc = -1;
457 break;
458 }
459
460
461
462 for(
463 retryCounter = 0;
464 retryCounter<GENDEV_RETRY_COUNT;
465 retryCounter ++
466 )
467 {
468 uint8_t wrByte[GENDEV_MAX_SIZE+2];
469 wrByte[0] = (uint8_t) (counter>>0);
470 if(eeprom_info.address_length > 1)
471 {
472 wrByte[1] = (uint8_t) (counter>>8);
473 }
474 memcpy(&wrByte[eeprom_info.address_length], readByte, msize);
475
476 i2caddr+= (((eeprom_info.size) % address_span_size) * 2);
477
478 rsp = ipmi_master_write_read(intf, i2cbus, i2caddr, (uint8_t *) wrByte, eeprom_info.address_length+msize, 0);
479 if (rsp != NULL)
480 {
481 retryCounter = GENDEV_RETRY_COUNT;
482 rc = 0;
483 }
484 else if(retryCounter < GENDEV_RETRY_COUNT)
485 {
486 retryCounter ++;
487 lprintf(LOG_ERR, "Retry");
488 sleep(1);
489 rc = -1;
490 }
491 else
492 {
493 lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read");
494 rc = -1;
495 }
496 }
497
498 if( rc == 0 )
499 {
500 static uint8_t previousCompleted = 101;
501 percentCompleted = ((counter * 100) / eeprom_info.size );
502
503 if(percentCompleted != previousCompleted)
504 {
505 printf("\r%i percent completed", percentCompleted);
506 previousCompleted = percentCompleted;
507 }
508
509 }
510 }
511 if(counter == (eeprom_info.size))
512 {
513 printf("\r%%100 percent completed\n");
514 }
515 else
516 {
517 printf("\rError: %i percent completed, read not completed \n", percentCompleted);
518 }
519
520 fclose(fp);
521 }
522 }
523 else
524 {
525 lprintf(LOG_ERR, "The selected generic device is not an eeprom");
526 }
527
528 return rc;
529 }
530
531
532 /* ipmi_gendev_main - top-level handler for generic device
533 *
534 * @intf: ipmi interface
535 * @argc: number of arguments
536 * @argv: argument list
537 *
538 * returns 0 on success
539 * returns -1 on error
540 */
541 int
ipmi_gendev_main(struct ipmi_intf * intf,int argc,char ** argv)542 ipmi_gendev_main(struct ipmi_intf *intf, int argc, char **argv)
543 {
544 int rc = 0;
545
546 /* initialize random numbers used later */
547 srand(time(NULL));
548
549 lprintf(LOG_ERR, "Rx gendev command: %s", argv[0]);
550
551 if (
552 (argc == 0)
553 ||
554 (strncmp(argv[0], "help", 4) == 0)
555 )
556 {
557 lprintf(LOG_ERR,
558 "SDR Commands: list read write");
559 lprintf(LOG_ERR,
560 " list List All Generic Device Locators");
561 lprintf(LOG_ERR,
562 " read <sdr name> <file> Read to file eeprom specify by Generic Device Locators");
563 lprintf(LOG_ERR,
564 " write <sdr name> <file> Write from file eeprom specify by Generic Device Locators");
565 }
566 else if ( strncmp(argv[0], "list", 4) == 0)
567 {
568 rc = ipmi_sdr_print_sdr(intf,
569 SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR);
570 }
571 else if (strncmp(argv[0], "read", 4) == 0)
572 {
573 if (argc < 3)
574 lprintf(LOG_ERR, "usage: gendev read <gendev> <filename>");
575 else
576 {
577 struct sdr_record_list *sdr;
578
579 lprintf(LOG_ERR, "Gendev read sdr name : %s", argv[1]);
580
581 printf("Locating sensor record '%s'...\n", argv[1]);
582
583 /* lookup by sensor name */
584 sdr = ipmi_sdr_find_sdr_byid(intf, argv[1]);
585 if (sdr == NULL)
586 {
587 lprintf(LOG_ERR, "Sensor data record not found!");
588 return -1;
589 }
590
591 if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
592 {
593 lprintf(LOG_ERR, "Target SDR is not a generic device locator");
594 return -1;
595 }
596
597 lprintf(LOG_ERR, "Gendev read file name: %s", argv[2]);
598 ipmi_gendev_read_file(intf, sdr->record.genloc, argv[2]);
599
600 }
601 }
602 else if (strncmp(argv[0], "write", 5) == 0)
603 {
604 if (argc < 3)
605 lprintf(LOG_ERR, "usage: gendev write <gendev> <filename>");
606 else
607 {
608 struct sdr_record_list *sdr;
609
610 lprintf(LOG_ERR, "Gendev write sdr name : %s", argv[1]);
611
612 printf("Locating sensor record '%s'...\n", argv[1]);
613
614 /* lookup by sensor name */
615 sdr = ipmi_sdr_find_sdr_byid(intf, argv[1]);
616 if (sdr == NULL)
617 {
618 lprintf(LOG_ERR, "Sensor data record not found!");
619 return -1;
620 }
621
622 if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
623 {
624 lprintf(LOG_ERR, "Target SDR is not a generic device locator");
625 return -1;
626 }
627
628 lprintf(LOG_ERR, "Gendev write file name: %s", argv[2]);
629 ipmi_gendev_write_file(intf, sdr->record.genloc, argv[2]);
630
631 }
632 }
633 else
634 {
635 lprintf(LOG_ERR, "Invalid gendev command: %s", argv[0]);
636 rc = -1;
637 }
638
639 return rc;
640 }
641