diff options
| author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-23 15:03:01 +0200 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-23 15:03:01 +0200 | 
| commit | 777af8a8761d05c30588abec7444b143fe7393f0 (patch) | |
| tree | 5a135c37eaa9ac94772819a28ce5beedd18e5c4a /lib/ipmi_gendev.c | |
| parent | c3445516ecd58e97de483cf4b7fafcc1104890d7 (diff) | |
| parent | b32d92e890caac903491116e9d817aa780c0323b (diff) | |
Merge tag 'upstream/1.8.14'
Upstream version 1.8.14
Diffstat (limited to 'lib/ipmi_gendev.c')
| -rw-r--r-- | lib/ipmi_gendev.c | 640 | 
1 files changed, 640 insertions, 0 deletions
| diff --git a/lib/ipmi_gendev.c b/lib/ipmi_gendev.c new file mode 100644 index 0000000..7a4cf08 --- /dev/null +++ b/lib/ipmi_gendev.c @@ -0,0 +1,640 @@ +/* + * Copyright (c) 2003 Kontron Canada, Inc.  All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include <string.h> + +#include <math.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <time.h> + +#include <ipmitool/ipmi.h> +#include <ipmitool/log.h> +#include <ipmitool/ipmi_mc.h> +#include <ipmitool/ipmi_sdr.h> +#include <ipmitool/ipmi_gendev.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/ipmi_sel.h> +#include <ipmitool/ipmi_entity.h> +#include <ipmitool/ipmi_constants.h> +#include <ipmitool/ipmi_strings.h> +#include <ipmitool/ipmi_raw.h> + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +extern int verbose; + + +#define GENDEV_RETRY_COUNT    5 +#define GENDEV_MAX_SIZE       16 + +typedef struct gendev_eeprom_info +{ +   uint32_t size; +   uint16_t page_size; +   uint8_t  address_span; +   uint8_t  address_length; +}t_gendev_eeprom_info; + + +static int +ipmi_gendev_get_eeprom_size( +                        struct ipmi_intf *intf,  +                        struct sdr_record_generic_locator *dev, +                        t_gendev_eeprom_info *info +                     ) +{ +   int eeprom_size = 0; +   /* +   lprintf(LOG_ERR, "Gen Device : %s", dev->id_string); +   lprintf(LOG_ERR, "Access Addr: %x", dev->dev_access_addr); +   lprintf(LOG_ERR, "Slave Addr : %x", dev->dev_slave_addr); +   lprintf(LOG_ERR, "Channel Num: %x", dev->channel_num); +   lprintf(LOG_ERR, "Lun        : %x", dev->lun); +   lprintf(LOG_ERR, "Bus        : %x", dev->bus); +   lprintf(LOG_ERR, "Addr Span  : %x", dev->addr_span); +   lprintf(LOG_ERR, "DevType    : %x", dev->dev_type); +   lprintf(LOG_ERR, "DevType Mod: %x", dev->dev_type_modifier); +   */ +   if( info != NULL) +   { +      switch(dev->dev_type) +      { +         case 0x08:  // 24C01 +            info->size = 128; +            info->page_size = 8; +            info->address_span = dev->addr_span; +            info->address_length = 1; +         break;    +         case 0x09:  // 24C02 +            info->size = 256; +            info->page_size = 8; +            info->address_span = dev->addr_span; +            info->address_length = 1; +         break;    +         case 0x0A:  // 24C04 +            info->size = 512; +            info->page_size = 8; +            info->address_span = dev->addr_span; +            info->address_length = 2; +         break;    +         case 0x0B:  // 24C08 +            info->size = 1024; +            info->page_size = 8; +            info->address_span = dev->addr_span; +            info->address_length = 2; +         break;    +         case 0x0C:  // 24C16 +            info->size = 2048; +            info->page_size = 256; +            info->address_span = dev->addr_span; +            info->address_length = 2; +         break;    +         case 0x0D:  // 24C17 +            info->size = 2048; +            info->page_size = 256; +            info->address_span = dev->addr_span; +            info->address_length = 2; +         break;    +         case 0x0E:  // 24C32 +            info->size = 4096; +            info->page_size = 8; +            info->address_span = dev->addr_span; +            info->address_length = 2; +         break;    +         case 0x0F:  // 24C64 +            info->size = 8192; +            info->page_size = 32; +            info->address_span = dev->addr_span; +            info->address_length = 2; +         break;    +         case 0xC0:  // Proposed OEM Code for 24C128 +            info->size = 16384; +            info->page_size = 64; +            info->address_span = dev->addr_span; +            info->address_length = 2; +         break;    +         case 0xC1:  // Proposed OEM Code for 24C256 +            info->size = 32748; +            info->page_size = 64; +            info->address_span = dev->addr_span; +            info->address_length = 2; +         break;    +         case 0xC2:  // Proposed OEM Code for 24C512 +            info->size = 65536; +            info->page_size = 128; +            info->address_span = dev->addr_span; +            info->address_length = 2; +         break; +         case 0xC3:  // Proposed OEM Code for 24C1024 +            info->size = 131072; +            info->page_size = 128; +            info->address_span = dev->addr_span; +            info->address_length = 2; +         break; +         /* Please reserved up to CFh for future update */     +         default:   // Not a eeprom, return size = 0; +            info->size = 0; +            info->page_size = 0; +            info->address_span = 0; +            info->address_length = 0; +         break; +      } +       +      eeprom_size = info->size; +   } + +   return eeprom_size; +} + + + +static int +ipmi_gendev_read_file( +                        struct ipmi_intf *intf,  +                        struct sdr_record_generic_locator *dev,  +                        const char *ofile +                     ) +{ +   int rc = 0; +   int eeprom_size; +   t_gendev_eeprom_info eeprom_info; + +   eeprom_size = ipmi_gendev_get_eeprom_size(intf, dev, &eeprom_info); + +   if(eeprom_size > 0) +   { +      FILE *fp; +    +      /* now write to file */ +      fp = ipmi_open_file_write(ofile); + +      if(fp) +      { +         struct ipmi_rs *rsp; +         int numWrite; +         uint32_t counter; +         uint8_t msize; +         uint8_t channel = dev->channel_num; +         uint8_t i2cbus = dev->bus; +         uint8_t i2caddr = dev->dev_slave_addr; +         uint8_t privatebus = 1; +         uint32_t address_span_size; +         uint8_t percentCompleted = 0; + + +         /* Handle Address Span */ +         if( eeprom_info.address_span != 0) +         { +            address_span_size =  +               (eeprom_info.size / (eeprom_info.address_span+1)); +         } +         else +         { +            address_span_size = eeprom_info.size; +         } + +         /* Setup read/write size */ +         if( eeprom_info.page_size < GENDEV_MAX_SIZE) +         { +            msize = eeprom_info.page_size; +         } +         else +         { +            msize = GENDEV_MAX_SIZE;   +               // All eeprom with page higher than 32 is on the  +               // 16 bytes boundary +         } + +         /* Setup i2c bus byte */ +         i2cbus = ((channel & 0xF) << 4) | ((i2cbus & 7) << 1) | privatebus; + +/*    +         lprintf(LOG_ERR, "Generic device: %s", dev->id_string); +         lprintf(LOG_ERR, "I2C Chnl: %x", channel); +         lprintf(LOG_ERR, "I2C Bus : %x", i2cbus); +         lprintf(LOG_ERR, "I2C Addr: %x", i2caddr);    */ + +         for ( +               counter = 0;  +               (counter < (eeprom_info.size)) && (rc == 0);  +               counter+= msize +             )  +         { +            uint8_t retryCounter; + +            for( +                  retryCounter = 0;  +                  retryCounter<GENDEV_RETRY_COUNT;  +                  retryCounter ++ +               ) +            { +               uint8_t wrByte[GENDEV_MAX_SIZE+2]; + +               wrByte[0] =  (uint8_t) (counter>>0); +               if(eeprom_info.address_length > 1) +               { +                  wrByte[1] =  (uint8_t) (counter>>8); +               } +             +               i2caddr+= (((eeprom_info.size) % address_span_size) * 2); +                                            +               rsp = ipmi_master_write_read( +                           intf, +                           i2cbus, +                           i2caddr, +                           (uint8_t *) wrByte, +                           eeprom_info.address_length, +                           msize +                           ); + +               if (rsp != NULL)  +               { +                  retryCounter = GENDEV_RETRY_COUNT; +                  rc = 0; +               } +               else if(retryCounter < GENDEV_RETRY_COUNT) +               { +                  retryCounter ++; +                  lprintf(LOG_ERR, "Retry"); +                  sleep(1); +                  rc = -1; +               } +               else +               { +                  lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read"); +                  rc = -1; +               } +            } + +            if( rc == 0 ) +            { +               static uint8_t previousCompleted = 101; +               numWrite = fwrite(rsp->data, 1, msize, fp); +               if (numWrite != msize)  +               { +                  lprintf(LOG_ERR, "Error writing file %s", ofile); +                  rc = -1; +                  break; +               } + +               percentCompleted = ((counter * 100) / eeprom_info.size ); +                +               if(percentCompleted != previousCompleted) +               { +                  printf("\r%i percent completed", percentCompleted); +                  previousCompleted = percentCompleted; +               } + + +            } +         } +         if(counter == (eeprom_info.size)) +         { +            printf("\r%%100 percent completed\n"); +         } +         else +         { +            printf("\rError: %i percent completed, read not completed \n", percentCompleted); +         } + +         fclose(fp); +      } +   } +   else +   { +      lprintf(LOG_ERR, "The selected generic device is not an eeprom"); +   } + +   return rc; +} + + +/* ipmi_gendev_write_file  -  Read raw SDR from binary file + * + * used for writing generic locator device Eeprom type + * + * @intf:	ipmi interface + * @dev:		generic device to read + * @ofile:	output filename + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_gendev_write_file( +                        struct ipmi_intf *intf,  +                        struct sdr_record_generic_locator *dev,  +                        const char *ofile +                     ) +{ +   int rc = 0; +   int eeprom_size; +   t_gendev_eeprom_info eeprom_info; + +   eeprom_size = ipmi_gendev_get_eeprom_size(intf, dev, &eeprom_info); + +   if(eeprom_size > 0) +   { +      FILE *fp; +      uint32_t fileLength = 0; +    +      /* now write to file */ +      fp = ipmi_open_file_read(ofile); +       +      if(fp) +      { +         /* Retreive file length, check if it's fits the Eeprom Size */ +         fseek(fp, 0 ,SEEK_END); +         fileLength = ftell(fp); + +         lprintf(LOG_ERR, "File   Size: %i", fileLength); +         lprintf(LOG_ERR, "Eeprom Size: %i", eeprom_size); +         if(fileLength != eeprom_size) +         { +            lprintf(LOG_ERR, "File size does not fit Eeprom Size"); +            fclose(fp); +            fp = NULL; +         } +         else +         { +            fseek(fp, 0 ,SEEK_SET); +         } +      } +       +      if(fp) +      { +         struct ipmi_rs *rsp; +         int numRead; +         uint32_t counter; +         uint8_t msize; +         uint8_t channel = dev->channel_num; +         uint8_t i2cbus = dev->bus; +         uint8_t i2caddr = dev->dev_slave_addr; +         uint8_t privatebus = 1; +         uint32_t address_span_size; +         uint8_t percentCompleted = 0; + + +         /* Handle Address Span */ +         if( eeprom_info.address_span != 0) +         { +            address_span_size =  +               (eeprom_info.size / (eeprom_info.address_span+1)); +         } +         else +         { +            address_span_size = eeprom_info.size; +         } + +         /* Setup read/write size */ +         if( eeprom_info.page_size < GENDEV_MAX_SIZE) +         { +            msize = eeprom_info.page_size; +         } +         else +         { +            msize = GENDEV_MAX_SIZE;   +                     // All eeprom with page higher than 32 is on the  +                     // 16 bytes boundary +         } + +         /* Setup i2c bus byte */ +         i2cbus = ((channel & 0xF) << 4) | ((i2cbus & 7) << 1) | privatebus; + +/*    +         lprintf(LOG_ERR, "Generic device: %s", dev->id_string); +         lprintf(LOG_ERR, "I2C Chnl: %x", channel); +         lprintf(LOG_ERR, "I2C Bus : %x", i2cbus); +         lprintf(LOG_ERR, "I2C Addr: %x", i2caddr);    */ + +         for ( +               counter = 0;  +               (counter < (eeprom_info.size)) && (rc == 0);  +               counter+= msize +             )  +         { +            uint8_t retryCounter; +            uint8_t readByte[GENDEV_MAX_SIZE]; + +            numRead = fread(readByte, 1, msize, fp); +            if (numRead != msize)  +            { +               lprintf(LOG_ERR, "Error reading file %s", ofile); +               rc = -1; +               break; +            } + + + +            for( +                  retryCounter = 0;  +                  retryCounter<GENDEV_RETRY_COUNT;  +                  retryCounter ++ +               ) +            { +               uint8_t wrByte[GENDEV_MAX_SIZE+2]; +               wrByte[0] =  (uint8_t) (counter>>0); +               if(eeprom_info.address_length > 1) +               { +                  wrByte[1] =  (uint8_t) (counter>>8); +               } +               memcpy(&wrByte[eeprom_info.address_length], readByte, msize); + +               i2caddr+= (((eeprom_info.size) % address_span_size) * 2); + +               rsp = ipmi_master_write_read(intf, i2cbus, i2caddr, (uint8_t *) wrByte, eeprom_info.address_length+msize, 0); +               if (rsp != NULL)  +               { +                  retryCounter = GENDEV_RETRY_COUNT; +                  rc = 0; +               } +               else if(retryCounter < GENDEV_RETRY_COUNT) +               { +                  retryCounter ++; +                  lprintf(LOG_ERR, "Retry"); +                  sleep(1); +                  rc = -1; +               } +               else +               { +                  lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read"); +                  rc = -1; +               } +            } + +            if( rc == 0 ) +            { +               static uint8_t previousCompleted = 101; +               percentCompleted = ((counter * 100) / eeprom_info.size ); + +               if(percentCompleted != previousCompleted) +               { +                  printf("\r%i percent completed", percentCompleted); +                  previousCompleted = percentCompleted; +               } + +            } +         } +         if(counter == (eeprom_info.size)) +         { +            printf("\r%%100 percent completed\n"); +         } +         else +         { +            printf("\rError: %i percent completed, read not completed \n", percentCompleted); +         } + +         fclose(fp); +      } +   } +   else +   { +      lprintf(LOG_ERR, "The selected generic device is not an eeprom"); +   } + +   return rc; +} + + +/* ipmi_gendev_main  -  top-level handler for generic device + * + * @intf:	ipmi interface + * @argc:	number of arguments + * @argv:	argument list + * + * returns 0 on success + * returns -1 on error + */ +int +ipmi_gendev_main(struct ipmi_intf *intf, int argc, char **argv) +{ +   int rc = 0; + +   /* initialize random numbers used later */ +   srand(time(NULL)); + +   lprintf(LOG_ERR, "Rx gendev command: %s", argv[0]); + +   if ( +         (argc == 0) +         || +         (strncmp(argv[0], "help", 4) == 0)  +      ) +   { +      lprintf(LOG_ERR, +         "SDR Commands:  list read write"); +      lprintf(LOG_ERR, +         "                     list                     List All Generic Device Locators"); +      lprintf(LOG_ERR, +         "                     read <sdr name> <file>   Read to file eeprom specify by Generic Device Locators"); +      lprintf(LOG_ERR, +         "                     write <sdr name> <file>  Write from file eeprom specify by Generic Device Locators"); +   }  +   else if ( strncmp(argv[0], "list", 4) == 0) +   { +      rc = ipmi_sdr_print_sdr(intf, +                  SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR); +   } +   else if (strncmp(argv[0], "read", 4) == 0)  +   { +      if (argc < 3) +         lprintf(LOG_ERR, "usage: gendev read <gendev> <filename>"); +      else +      { +         struct sdr_record_list *sdr; + +         lprintf(LOG_ERR, "Gendev read sdr name : %s", argv[1]); + +         printf("Locating sensor record '%s'...\n", argv[1]); + +         /* lookup by sensor name */ +         sdr = ipmi_sdr_find_sdr_byid(intf, argv[1]); +         if (sdr == NULL)  +         { +            lprintf(LOG_ERR, "Sensor data record not found!"); +            return -1; +         } + +         if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)  +         { +            lprintf(LOG_ERR, "Target SDR is not a generic device locator"); +            return -1; +         } + +         lprintf(LOG_ERR, "Gendev read file name: %s", argv[2]); +         ipmi_gendev_read_file(intf, sdr->record.genloc, argv[2]); + +      } +   }  +   else if (strncmp(argv[0], "write", 5) == 0)  +   { +      if (argc < 3) +         lprintf(LOG_ERR, "usage: gendev write <gendev> <filename>"); +      else +      { +         struct sdr_record_list *sdr; + +         lprintf(LOG_ERR, "Gendev write sdr name : %s", argv[1]); + +         printf("Locating sensor record '%s'...\n", argv[1]); + +         /* lookup by sensor name */ +         sdr = ipmi_sdr_find_sdr_byid(intf, argv[1]); +         if (sdr == NULL)  +         { +            lprintf(LOG_ERR, "Sensor data record not found!"); +            return -1; +         } + +         if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)  +         { +            lprintf(LOG_ERR, "Target SDR is not a generic device locator"); +            return -1; +         } + +         lprintf(LOG_ERR, "Gendev write file name: %s", argv[2]); +         ipmi_gendev_write_file(intf, sdr->record.genloc, argv[2]); + +      } +   }  +   else  +   { +      lprintf(LOG_ERR, "Invalid gendev command: %s", argv[0]); +      rc = -1; +   } + +   return rc; +} | 
