summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvishwa <vishwanath@in.ibm.com>2015-11-10 12:10:38 -0600
committervishwa <vishwanath@in.ibm.com>2015-11-24 10:20:04 -0600
commit13555bd0db6c5436b8630ff368537adce11f9968 (patch)
treeaaa89e6bb863f6541d9421932f9368076f7b6a08
parent1c779b8570849a52dac828538c36a59798f4583a (diff)
downloadipmi-fru-parser-13555bd0db6c5436b8630ff368537adce11f9968.tar.gz
ipmi-fru-parser-13555bd0db6c5436b8630ff368537adce11f9968.zip
eeprom read CLI
-rw-r--r--Makefile33
-rw-r--r--argument.C62
-rw-r--r--argument.H27
-rw-r--r--readeeprom.C71
-rw-r--r--strgfnhandler.C102
-rw-r--r--writefrudata.C120
-rw-r--r--writefrudata.H3
7 files changed, 303 insertions, 115 deletions
diff --git a/Makefile b/Makefile
index f56eba3..07bbf5a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,23 +1,33 @@
-LIBS += libwritefrudata.so
-libwritefrudata.so_OBJS += frup.o writefrudata.o
-libwritefrudata.so_NEEDED += libsystemd
+LIBS += libwritefrudata.so
+HOST_LIBS += libstrgfnhandler.so
+libwritefrudata.so_OBJS += frup.o writefrudata.o
+libstrgfnhandler.so_OBJS += strgfnhandler.o
+
+EXES += phosphor-read-eeprom
+
+phosphor-read-eeprom_OBJS += readeeprom.o argument.o
+phosphor-read-eeprom_EXTRA_LIBS += writefrudata
+libstrgfnhandler.so_EXTRA_LIBS += writefrudata
+libwritefrudata.so_NEEDED += libsystemd
+phosphor-read-eeprom_NEEDED += libsystemd
#### -----------------------------------------------------------------------####
# #
## Compilare Regulas Sequi ##
# #
#### -----------------------------------------------------------------------####
-OPTFLAGS ?= -O3 -g -pipe
+OPTFLAGS ?= -O3 -g -pipe -G -K
CFLAGS ?= $(OPTFLAGS)
CXXFLAGS ?= $(OPTFLAGS)
CFLAGS += -Wall -flto -fPIC
CXXFLAGS += --std=gnu++14 -Wall -flto -fPIC
__PKG_CONFIG = $(if $1,$(shell pkg-config $2 $1))
+__EXTRA_LIB_RESOLV = $(if $1,$1)
define __BUILD_EXE
-$1 : $$($1_OBJS) $$(LIBS)
- $$(LINK.cpp) -o $$@ $$^ $(call __PKG_CONFIG,$($1_NEEDED),--libs)
+$1 : $$($1_OBJS) | $$(LIBS) $$(HOST_LIBS)
+ $$(LINK.cpp) -o $$@ $$^ $(call __EXTRA_LIB_RESOLV,$(addprefix -l,$($1_EXTRA_LIBS))) -L. $(call __PKG_CONFIG,$($1_NEEDED),--libs)
$(eval CXXFLAGS += $(call __PKG_CONFIG,$($1_NEEDED),--cflags))
@@ -27,8 +37,8 @@ endef
$(foreach exe,$(EXES),$(eval $(call __BUILD_EXE,$(exe))))
define __BUILD_LIB
-$1 : $$($1_OBJS)
- $$(LINK.cpp) -shared -o $$@ $$^ $(call __PKG_CONFIG,$($1_NEEDED),--libs)
+$1 : $$($1_OBJS) | $$(addsuffix .so,$$(addprefix lib,$$($1_EXTRA_LIBS)))
+ $$(LINK.cpp) -fPIC -shared -o $$@ $$^ $(call __EXTRA_LIB_RESOLV,$(addprefix -l,$($1_EXTRA_LIBS))) -L. $(call __PKG_CONFIG,$($1_NEEDED),--libs)
$(eval CXXFLAGS += $(call __PKG_CONFIG,$($1_NEEDED),--cflags))
@@ -36,11 +46,13 @@ $(eval CXXFLAGS += $(call __PKG_CONFIG,$($1_NEEDED),--cflags))
endef
$(foreach lib,$(LIBS),$(eval $(call __BUILD_LIB,$(lib))))
+$(foreach lib,$(HOST_LIBS),$(eval $(call __BUILD_LIB,$(lib))))
.PHONY: clean
clean:
$(RM) $(foreach exe,$(EXES),$(exe) $($(exe)_OBJS)) \
- $(foreach lib,$(LIBS),$(lib) $($(lib)_OBJS))
+ $(foreach lib,$(LIBS),$(lib) $($(lib)_OBJS)) \
+ $(foreach lib,$(HOST_LIBS),$(lib) $($(lib)_OBJS))
DESTDIR ?= /
BINDIR ?= /usr/bin
@@ -54,7 +66,8 @@ install:
)
$(if $(LIBS),\
install -m 0755 -d $(DESTDIR)$(LIBDIR)/host-ipmid && \
- install -m 0755 $(LIBS) $(DESTDIR)$(LIBDIR)/host-ipmid \
+ install -m 0755 $(HOST_LIBS) $(DESTDIR)$(LIBDIR)/host-ipmid \
+ install -m 0755 $(LIBS) $(DESTDIR)$(LIBDIR) \
)
.DEFAULT_GOAL: all
diff --git a/argument.C b/argument.C
new file mode 100644
index 0000000..a7e0a94
--- /dev/null
+++ b/argument.C
@@ -0,0 +1,62 @@
+#include <iostream>
+#include <iterator>
+#include <algorithm>
+#include <cassert>
+#include "argument.H"
+
+ArgumentParser::ArgumentParser(int argc, char** argv)
+{
+ int option = 0;
+ while(-1 != (option = getopt_long(argc, argv, optionstr, options, NULL)))
+ {
+ if ((option == '?') || (option == 'h'))
+ {
+ usage(argv);
+ exit(-1);
+ }
+
+ auto i = &options[0];
+ while ((i->val != option) && (i->val != 0)) ++i;
+
+ if (i->val)
+ arguments[i->name] = (i->has_arg ? optarg : true_string);
+ }
+}
+
+const std::string& ArgumentParser::operator[](const std::string& opt)
+{
+ auto i = arguments.find(opt);
+ if (i == arguments.end())
+ {
+ return empty_string;
+ }
+ else
+ {
+ return i->second;
+ }
+}
+
+void ArgumentParser::usage(char** argv)
+{
+ std::cerr << "Usage: " << argv[0] << " [options]" << std::endl;
+ std::cerr << "Options:" << std::endl;
+ std::cerr << " --eeprom=<eeprom file path> Absolute file name of eeprom"
+ << std::endl;
+ std::cerr << " --fruid=<FRU ID> valid fru id in integer"
+ << std::endl;
+ std::cerr << " --help display help"
+ << std::endl;
+}
+
+const option ArgumentParser::options[] =
+{
+ { "eeprom", required_argument, NULL, 'e' },
+ { "fruid", required_argument, NULL, 'f' },
+ { "help", no_argument, NULL, 'h' },
+ { 0, 0, 0, 0},
+};
+
+const char* ArgumentParser::optionstr = "e:f:?h";
+
+const std::string ArgumentParser::true_string = "true";
+const std::string ArgumentParser::empty_string = "";
diff --git a/argument.H b/argument.H
new file mode 100644
index 0000000..bd3b0b2
--- /dev/null
+++ b/argument.H
@@ -0,0 +1,27 @@
+#ifndef __ARGUMENT_H
+#define __ARGUMENT_H
+#include <getopt.h>
+#include <map>
+#include <string>
+class ArgumentParser
+{
+ public:
+ ArgumentParser(int argc, char** argv);
+ const std::string& operator[](const std::string& opt);
+
+ static void usage(char** argv);
+
+ static const std::string true_string;
+ static const std::string empty_string;
+
+ private:
+ std::map<const std::string, std::string> arguments;
+
+ static const option options[];
+ static const char* optionstr;
+
+ private:
+ ArgumentParser() {};
+};
+
+#endif
diff --git a/readeeprom.C b/readeeprom.C
new file mode 100644
index 0000000..b9c6f69
--- /dev/null
+++ b/readeeprom.C
@@ -0,0 +1,71 @@
+#include <iostream>
+#include <memory>
+#include "argument.H"
+#include "writefrudata.H"
+
+static void exit_with_error(const char* err, char** argv)
+{
+ ArgumentParser::usage(argv);
+ std::cerr << std::endl;
+ std::cerr << "ERROR: " << err << std::endl;
+ exit(-1);
+}
+
+//--------------------------------------------------------------------------
+// This gets called by udev monitor soon after seeing hog plugs for EEPROMS.
+//--------------------------------------------------------------------------
+int main(int argc, char **argv)
+{
+ int rc = 0;
+ uint8_t fruid = 0;
+
+ // Handle to per process system bus
+ sd_bus *bus_type = NULL;
+
+ // Read the arguments.
+ auto cli_options = std::make_unique<ArgumentParser>(argc, argv);
+
+ // Parse out each argument.
+ auto eeprom_file = (*cli_options)["eeprom"];
+ if (eeprom_file == ArgumentParser::empty_string)
+ {
+ // User has not passed in the appropriate argument value
+ exit_with_error("eeprom data not found.", argv);
+ }
+
+ auto fruid_str = (*cli_options)["fruid"];
+ if (eeprom_file == ArgumentParser::empty_string)
+ {
+ // User has not passed in the appropriate argument value
+ exit_with_error("fruid data not found.", argv);
+ }
+
+ // Extract the fruid
+ fruid = strtol(fruid_str.c_str(), NULL, 16);
+ if(fruid == 0)
+ {
+ // User has not passed in the appropriate argument value
+ exit_with_error("Invalid fruid.", argv);
+ }
+
+ // Finished getting options out, so release the parser.
+ cli_options.release();
+
+ // Get a handle to System Bus
+ rc = sd_bus_open_system(&bus_type);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Failed to connect to system bus: %s\n",strerror(-rc));
+ }
+ else
+ {
+ // Now that we have the file that contains the eeprom data, go read it and
+ // update the Inventory DB.
+ rc = ipmi_validate_fru_area(fruid, eeprom_file.c_str(), bus_type);
+ }
+
+ // Cleanup
+ sd_bus_unref(bus_type);
+
+ return (rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
+}
diff --git a/strgfnhandler.C b/strgfnhandler.C
new file mode 100644
index 0000000..28406de
--- /dev/null
+++ b/strgfnhandler.C
@@ -0,0 +1,102 @@
+#include <host-ipmid/ipmid-api.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "writefrudata.H"
+
+void register_netfn_storage_write_fru() __attribute__((constructor));
+
+sd_bus* ipmid_get_sd_bus_connection(void);
+
+///-------------------------------------------------------
+// Called by IPMI netfn router for write fru data command
+//--------------------------------------------------------
+ipmi_ret_t ipmi_storage_write_fru_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ FILE *fp = NULL;
+ char fru_file_name[16] = {0};
+ uint8_t offset = 0;
+ uint16_t len = 0;
+ ipmi_ret_t rc = IPMI_CC_INVALID;
+ const char *mode = NULL;
+
+ // From the payload, extract the header that has fruid and the offsets
+ write_fru_data_t *reqptr = (write_fru_data_t*)request;
+
+ // Maintaining a temporary file to pump the data
+ sprintf(fru_file_name, "%s%02x", "/tmp/ipmifru", reqptr->frunum);
+
+ offset = ((uint16_t)reqptr->offsetms) << 8 | reqptr->offsetls;
+
+ // Length is the number of request bytes minus the header itself.
+ // The header contains an extra byte to indicate the start of
+ // the data (so didn't need to worry about word/byte boundaries)
+ // hence the -1...
+ len = ((uint16_t)*data_len) - (sizeof(write_fru_data_t)-1);
+
+ // On error there is no response data for this command.
+ *data_len = 0;
+
+#ifdef __IPMI__DEBUG__
+ printf("IPMI WRITE-FRU-DATA for [%s] Offset = [%d] Length = [%d]\n",
+ fru_file_name, offset, len);
+#endif
+
+
+ if( access( fru_file_name, F_OK ) == -1 ) {
+ mode = "wb";
+ } else {
+ mode = "rb+";
+ }
+
+ if ((fp = fopen(fru_file_name, mode)) != NULL)
+ {
+ if(fseek(fp, offset, SEEK_SET))
+ {
+ perror("Error:");
+ fclose(fp);
+ return rc;
+ }
+
+ if(fwrite(&reqptr->data, len, 1, fp) != 1)
+ {
+ perror("Error:");
+ fclose(fp);
+ return rc;
+ }
+
+ fclose(fp);
+ }
+ else
+ {
+ fprintf(stderr, "Error trying to write to fru file %s\n",fru_file_name);
+ return rc;
+ }
+
+
+ // If we got here then set the resonse byte
+ // to the number of bytes written
+ memcpy(response, &len, 1);
+ *data_len = 1;
+ rc = IPMI_CC_OK;
+
+ // Get the reference to global sd_bus object
+ sd_bus *bus_type = ipmid_get_sd_bus_connection();
+
+ // We received some bytes. It may be full or partial. Send a valid
+ // FRU file to the inventory controller on DBus for the correct number
+ ipmi_validate_fru_area(reqptr->frunum, fru_file_name, bus_type);
+
+ return rc;
+}
+
+//-------------------------------------------------------
+// Registering WRITE FRU DATA command handler with daemon
+//-------------------------------------------------------
+void register_netfn_storage_write_fru()
+{
+ printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_WRITE_FRU_DATA);
+ ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WRITE_FRU_DATA, NULL, ipmi_storage_write_fru_data);
+}
diff --git a/writefrudata.C b/writefrudata.C
index 91aef45..ae0d1eb 100644
--- a/writefrudata.C
+++ b/writefrudata.C
@@ -1,4 +1,3 @@
-#include <host-ipmid/ipmid-api.h>
#include <vector>
#include <stdlib.h>
#include <dlfcn.h>
@@ -8,17 +7,15 @@
#include "writefrudata.H"
#include <systemd/sd-bus.h>
#include <unistd.h>
-
-
-void register_netfn_storage_write_fru() __attribute__((constructor));
+#include <host-ipmid/ipmid-api.h>
// Needed to be passed into fru parser alorithm
typedef std::vector<fru_area_t> fru_area_vec_t;
// OpenBMC System Manager dbus framework
-const char *bus_name = "org.openbmc.managers.System";
-const char *object_name = "/org/openbmc/managers/System";
-const char *intf_name = "org.openbmc.managers.System";
+const char *sys_bus_name = "org.openbmc.managers.System";
+const char *sys_object_name = "/org/openbmc/managers/System";
+const char *sys_intf_name = "org.openbmc.managers.System";
//------------------------------------------------
// Takes the pointer to stream of bytes and length
@@ -78,7 +75,7 @@ uint8_t get_fru_area_type(uint8_t area_offset)
// Inventory
//------------------------------------------------------------------------
int ipmi_update_inventory(const uint8_t fruid, const uint8_t *fru_data,
- fru_area_vec_t & area_vec)
+ fru_area_vec_t & area_vec, sd_bus *bus_type)
{
// Now, use this fru dictionary object and connect with FRU Inventory Dbus
// and update the data for this FRU ID.
@@ -90,9 +87,6 @@ int ipmi_update_inventory(const uint8_t fruid, const uint8_t *fru_data,
// SD Bus error report mechanism.
sd_bus_error bus_error = SD_BUS_ERROR_NULL;
- // Gets a hook onto either a SYSTEM or SESSION bus
- sd_bus *bus_type = ipmid_get_sd_bus_connection();
-
// Req message contains the specifics about which method etc that we want to
// access on which bus, object
sd_bus_message *response = NULL;
@@ -145,9 +139,9 @@ int ipmi_update_inventory(const uint8_t fruid, const uint8_t *fru_data,
// We want to call a method "getObjectFromId" on System Bus that is
// made available over OpenBmc system services.
rc = sd_bus_call_method(bus_type, // On the System Bus
- bus_name, // Service to contact
- object_name, // Object path
- intf_name, // Interface name
+ sys_bus_name, // Service to contact
+ sys_object_name, // Object path
+ sys_intf_name, // Interface name
"getObjectFromId", // Method to be called
&bus_error, // object to return error
&response, // Response message on success
@@ -240,7 +234,8 @@ int ipmi_update_inventory(const uint8_t fruid, const uint8_t *fru_data,
// Validates the CRC and if found good, calls fru areas parser and calls
// Inventory Dbus with the dictionary of Name:Value for updating.
//-------------------------------------------------------------------------
-int ipmi_validate_and_update_inventory(const uint8_t fruid, const uint8_t *fru_data)
+int ipmi_validate_and_update_inventory(const uint8_t fruid, const uint8_t *fru_data,
+ sd_bus *bus_type)
{
// Used for generic checksum calculation
uint8_t checksum = 0;
@@ -249,7 +244,7 @@ int ipmi_validate_and_update_inventory(const uint8_t fruid, const uint8_t *fru_d
uint8_t fru_entry;
// A generic offset locator for any FRU record.
- uint8_t area_offset = 0;
+ size_t area_offset = 0;
// First 2 bytes in the record.
uint8_t fru_area_hdr[2] = {0};
@@ -389,7 +384,7 @@ int ipmi_validate_and_update_inventory(const uint8_t fruid, const uint8_t *fru_d
if(!(fru_area_vec.empty()))
{
- rc = ipmi_update_inventory(fruid, fru_data, fru_area_vec);
+ rc = ipmi_update_inventory(fruid, fru_data, fru_area_vec, bus_type);
}
// We are done with this FRU write packet.
@@ -401,7 +396,8 @@ int ipmi_validate_and_update_inventory(const uint8_t fruid, const uint8_t *fru_d
///-----------------------------------------------------
// Accepts the filename and validates per IPMI FRU spec
//----------------------------------------------------
-int ipmi_validate_fru_area(const uint8_t fruid, const char *fru_file_name)
+int ipmi_validate_fru_area(const uint8_t fruid, const char *fru_file_name,
+ sd_bus *bus_type)
{
int file_size = 0;
uint8_t *fru_data = NULL;
@@ -445,7 +441,7 @@ int ipmi_validate_fru_area(const uint8_t fruid, const char *fru_file_name)
}
fclose(fru_file);
- rc = ipmi_validate_and_update_inventory(fruid, fru_data);
+ rc = ipmi_validate_and_update_inventory(fruid, fru_data, bus_type);
if(rc == -1)
{
printf("ERROR: Validation failed for:[%d]\n",fruid);
@@ -464,89 +460,3 @@ int ipmi_validate_fru_area(const uint8_t fruid, const char *fru_file_name)
return rc;
}
-///-------------------------------------------------------
-// Called by IPMI netfn router for write fru data command
-//--------------------------------------------------------
-ipmi_ret_t ipmi_storage_write_fru_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
- ipmi_request_t request, ipmi_response_t response,
- ipmi_data_len_t data_len, ipmi_context_t context)
-{
- FILE *fp = NULL;
- char fru_file_name[16] = {0};
- uint8_t offset = 0;
- uint16_t len = 0;
- ipmi_ret_t rc = IPMI_CC_INVALID;
- const char *mode = NULL;
-
- // From the payload, extract the header that has fruid and the offsets
- write_fru_data_t *reqptr = (write_fru_data_t*)request;
-
- // Maintaining a temporary file to pump the data
- sprintf(fru_file_name, "%s%02x", "/tmp/ipmifru", reqptr->frunum);
-
- offset = ((uint16_t)reqptr->offsetms) << 8 | reqptr->offsetls;
-
- // Length is the number of request bytes minus the header itself.
- // The header contains an extra byte to indicate the start of
- // the data (so didn't need to worry about word/byte boundaries)
- // hence the -1...
- len = ((uint16_t)*data_len) - (sizeof(write_fru_data_t)-1);
-
- // On error there is no response data for this command.
- *data_len = 0;
-
-#ifdef __IPMI__DEBUG__
- printf("IPMI WRITE-FRU-DATA for [%s] Offset = [%d] Length = [%d]\n",
- fru_file_name, offset, len);
-#endif
-
-
- if( access( fru_file_name, F_OK ) == -1 ) {
- mode = "wb";
- } else {
- mode = "rb+";
- }
-
- if ((fp = fopen(fru_file_name, mode)) != NULL)
- {
- if(fseek(fp, offset, SEEK_SET))
- {
- perror("Error:");
- fclose(fp);
- return rc;
- }
-
- if(fwrite(&reqptr->data, len, 1, fp) != 1)
- {
- perror("Error:");
- fclose(fp);
- return rc;
- }
-
- fclose(fp);
- }
- else
- {
- fprintf(stderr, "Error trying to write to fru file %s\n",fru_file_name);
- return rc;
- }
-
-
- // If we got here then set the resonse byte
- // to the number of bytes written
- memcpy(response, &len, 1);
- *data_len = 1;
- rc = IPMI_CC_OK;
-
- // We received some bytes. It may be full or partial. Send a valid
- // FRU file to the inventory controller on DBus for the correct number
- ipmi_validate_fru_area(reqptr->frunum, fru_file_name);
-
- return rc;
-}
-
-void register_netfn_storage_write_fru()
-{
- printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_WRITE_FRU_DATA);
- ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WRITE_FRU_DATA, NULL, ipmi_storage_write_fru_data);
-}
diff --git a/writefrudata.H b/writefrudata.H
index 42924a3..89c20ac 100644
--- a/writefrudata.H
+++ b/writefrudata.H
@@ -3,6 +3,7 @@
#include <stdint.h>
#include <stddef.h>
+#include <systemd/sd-bus.h>
// IPMI commands for Storage net functions.
enum ipmi_netfn_storage_cmds
@@ -50,4 +51,6 @@ typedef struct
#define IPMI_FRU_HDR_CRC_OFFSET offsetof(struct common_header, crc)
#define IPMI_EIGHT_BYTES 8
+extern "C" int ipmi_validate_fru_area(const uint8_t, const char *, sd_bus *);
+
#endif
OpenPOWER on IntegriCloud