summaryrefslogtreecommitdiff
path: root/lib/ipmi_gendev.c
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-07-23 15:03:01 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-07-23 15:03:01 +0200
commit777af8a8761d05c30588abec7444b143fe7393f0 (patch)
tree5a135c37eaa9ac94772819a28ce5beedd18e5c4a /lib/ipmi_gendev.c
parentc3445516ecd58e97de483cf4b7fafcc1104890d7 (diff)
parentb32d92e890caac903491116e9d817aa780c0323b (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.c640
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;
+}