diff options
author | vishwa <vishwanath@in.ibm.com> | 2015-11-10 12:10:38 -0600 |
---|---|---|
committer | vishwa <vishwanath@in.ibm.com> | 2015-11-24 10:20:04 -0600 |
commit | 13555bd0db6c5436b8630ff368537adce11f9968 (patch) | |
tree | aaa89e6bb863f6541d9421932f9368076f7b6a08 | |
parent | 1c779b8570849a52dac828538c36a59798f4583a (diff) | |
download | ipmi-fru-parser-13555bd0db6c5436b8630ff368537adce11f9968.tar.gz ipmi-fru-parser-13555bd0db6c5436b8630ff368537adce11f9968.zip |
eeprom read CLI
-rw-r--r-- | Makefile | 33 | ||||
-rw-r--r-- | argument.C | 62 | ||||
-rw-r--r-- | argument.H | 27 | ||||
-rw-r--r-- | readeeprom.C | 71 | ||||
-rw-r--r-- | strgfnhandler.C | 102 | ||||
-rw-r--r-- | writefrudata.C | 120 | ||||
-rw-r--r-- | writefrudata.H | 3 |
7 files changed, 303 insertions, 115 deletions
@@ -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 |