diff options
author | Bill Hoffa <wghoffa@us.ibm.com> | 2014-12-01 11:48:01 -0600 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2014-12-14 17:34:09 -0600 |
commit | 8f0edf314a9c9198d95b0c7598e269cf8b7f232a (patch) | |
tree | b6e09d66845e500bbaf036a40874aea461691044 /src | |
parent | 9b53fb2a9083e62380f7bf2fb041378ef4de96ee (diff) | |
download | talos-hostboot-8f0edf314a9c9198d95b0c7598e269cf8b7f232a.tar.gz talos-hostboot-8f0edf314a9c9198d95b0c7598e269cf8b7f232a.zip |
IPMI Fru Inventory Record Creation
Change-Id: I9339e267ff7d2e2edbf4305d8c2d57f73f0c5eeb
RTC:108829
Depends-on:I3c0c4c7c14521f1b64af37d62e57a5947602ed11
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/14666
Tested-by: Jenkins Server
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/include/usr/ipmi/ipmifruinv.H | 41 | ||||
-rw-r--r-- | src/include/usr/vpd/cvpdenums.H | 2 | ||||
-rw-r--r-- | src/usr/hwas/hostbootIstep.C | 7 | ||||
-rw-r--r-- | src/usr/hwpf/plat/fapiPlatMBvpdAccess.C | 2 | ||||
-rw-r--r-- | src/usr/ipmi/ipmifruinv.C | 864 | ||||
-rw-r--r-- | src/usr/ipmi/ipmifruinvprvt.H | 421 | ||||
-rw-r--r-- | src/usr/ipmi/makefile | 1 | ||||
-rwxr-xr-x | src/usr/targeting/common/genHwsvMrwXml.pl | 37 | ||||
-rw-r--r-- | src/usr/targeting/common/xmltohb/attribute_types.xml | 79 | ||||
-rw-r--r-- | src/usr/targeting/common/xmltohb/target_types.xml | 4 | ||||
-rw-r--r-- | src/usr/vpd/cvpd.H | 2 | ||||
-rw-r--r-- | src/usr/vpd/spd.C | 12 | ||||
-rwxr-xr-x | src/usr/vpd/test/spdtest.H | 10 |
13 files changed, 1476 insertions, 6 deletions
diff --git a/src/include/usr/ipmi/ipmifruinv.H b/src/include/usr/ipmi/ipmifruinv.H new file mode 100644 index 000000000..cc34b06e3 --- /dev/null +++ b/src/include/usr/ipmi/ipmifruinv.H @@ -0,0 +1,41 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/include/usr/ipmi/ipmifru.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#ifndef __IPMI_IPMIFRUINV_H +#define __IPMI_IMPIFRUINV_H + +namespace IPMIFRUINV +{ + /** + * @brief Base function to be called to set the IPMI Fru + * inventory data for all targets in system + * + * @param[out] errlHndl_t, Any errors encountered sending + * IPMI Fru Inventory Data + */ + errlHndl_t setData(void); +}; + +#endif diff --git a/src/include/usr/vpd/cvpdenums.H b/src/include/usr/vpd/cvpdenums.H index f3b534012..71da3f207 100644 --- a/src/include/usr/vpd/cvpdenums.H +++ b/src/include/usr/vpd/cvpdenums.H @@ -82,7 +82,7 @@ namespace CVPD VD = 0x17, VN = 0x18, VP = 0x19, - SV = 0x1a, + VS = 0x1a, M0 = 0x1b, M1 = 0x1c, M2 = 0x1d, diff --git a/src/usr/hwas/hostbootIstep.C b/src/usr/hwas/hostbootIstep.C index 77759c72a..1ea2d5b93 100644 --- a/src/usr/hwas/hostbootIstep.C +++ b/src/usr/hwas/hostbootIstep.C @@ -66,6 +66,7 @@ #include <ipmi/ipmisensor.H> +#include <ipmi/ipmifruinv.H> #include <config.h> namespace HWAS @@ -155,6 +156,12 @@ void* host_discover_targets( void *io_pArgs ) #ifdef CONFIG_BMC_IPMI // send DIMM/CORE/PROC sensor status to the BMC SENSOR::updateBMCSensorStatus(); + + if (errl == NULL) + { + // Gather + Send the IPMI Fru Inventory data to the BMC + errl = IPMIFRUINV::setData(); + } #endif TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace, diff --git a/src/usr/hwpf/plat/fapiPlatMBvpdAccess.C b/src/usr/hwpf/plat/fapiPlatMBvpdAccess.C index 73e9a4a19..d8f2922a4 100644 --- a/src/usr/hwpf/plat/fapiPlatMBvpdAccess.C +++ b/src/usr/hwpf/plat/fapiPlatMBvpdAccess.C @@ -141,7 +141,7 @@ fapi::ReturnCode MBvpdKeywordXlate(const fapi::MBvpdKeyword i_fapiKeyword, CVPD::VD, CVPD::VN, CVPD::VP, - CVPD::SV, + CVPD::VS, CVPD::M0, CVPD::M1, CVPD::M2, diff --git a/src/usr/ipmi/ipmifruinv.C b/src/usr/ipmi/ipmifruinv.C new file mode 100644 index 000000000..9ddb39c37 --- /dev/null +++ b/src/usr/ipmi/ipmifruinv.C @@ -0,0 +1,864 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/ipmi/ipmifru.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#include <vector> +#include <vpd/mvpdenums.H> +#include <devicefw/userif.H> +#include <vpd/spdenums.H> +#include <vpd/cvpdenums.H> +#include <ipmi/ipmifruinv.H> +#include "ipmifru.H" +#include "ipmifruinvprvt.H" +#include <targeting/common/commontargeting.H> +#include <targeting/common/utilFilter.H> + + +extern trace_desc_t * g_trac_ipmi; + +IpmiFruInv::IpmiFruInv(TARGETING::TargetHandle_t i_target) + :iv_target(i_target) +{ +}; + +IpmiFruInv::~IpmiFruInv() +{} + + +IpmiFruInv *IpmiFruInv::Factory(TARGETING::TargetHandle_t i_target) +{ + IpmiFruInv *l_fru = NULL; + + switch (i_target->getAttr<TARGETING::ATTR_TYPE>()) + { + case TARGETING::TYPE_DIMM: + l_fru = new isdimmIpmiFruInv(i_target); + break; + case TARGETING::TYPE_PROC: + l_fru = new procIpmiFruInv(i_target); + break; + case TARGETING::TYPE_MEMBUF: + // @todo-RTC:117702 + l_fru = new backplaneIpmiFruInv(i_target); + break; + default: + TRACFCOMP(g_trac_ipmi,"IpmiFruInv::Factory: No support for target type given: [%08x]", + i_target->getAttr<TARGETING::ATTR_TYPE>()); + assert(false); + break; + } + + return l_fru; +} + +void IpmiFruInv::sendFruData(uint8_t i_deviceId) +{ + if (iv_record_data.size() > 0) + { + //Use IMPIFRU::writeData to sand data to service processor + // it will do any error handling and memory management + IPMIFRU::writeData(i_deviceId, &iv_record_data[0], + iv_record_data.size(), IPMIFRUINV::DEFAULT_FRU_OFFSET); + } + else + { + TRACFCOMP(g_trac_ipmi,"IpmiFruInv::sendFruData: " + "Not sending data for deviceId[%08x], no data found for this record."); + } + + return; +} + + +void IpmiFruInv::printRecordDebugData(const std::vector<uint8_t> &i_data) +{ + if (i_data.size() > 0) + { + TRACFBIN(g_trac_ipmi, "IpmiRecordData", &i_data[0], i_data.size()); + } + else + { + TRACFCOMP(g_trac_ipmi,"IpmiRecordData empty"); + } +} + + +//This uses the template method design pattern +// Since all IPMI Fru Inventory records all contain the same 5 sections +// (whether they are populated or empty) this funciton will build all 5 +// sections, build the header for the entire record, and then combine all 5 +// records into one full record +errlHndl_t IpmiFruInv::buildFruInvRecord(void) +{ + errlHndl_t l_errl = NULL; + std::vector<uint8_t> l_iu_data; + std::vector<uint8_t> l_ci_data; + std::vector<uint8_t> l_bi_data; + std::vector<uint8_t> l_pi_data; + std::vector<uint8_t> l_mr_data; + + do { + //First build up all 5 records individually + l_errl = buildInternalUseArea(l_iu_data); + if (l_errl) { break; } + + l_errl = buildChassisInfoArea(l_ci_data); + if (l_errl) { break; } + + l_errl = buildBoardInfoArea(l_bi_data); + if (l_errl) { break; } + + l_errl = buildProductInfoArea(l_pi_data); + if (l_errl) { break; } + + l_errl = buildMultiRecordInfoArea(l_mr_data); + if (l_errl) { break; } + + //Now build common header with data for this FRU Inv Record + buildCommonHeader(l_iu_data, l_ci_data, l_bi_data, + l_pi_data, l_mr_data); + + //Combine everything into one full IPMI Fru Inventory Record + completeRecord(l_iu_data, l_ci_data, l_bi_data, + l_pi_data, l_mr_data); + + } while(0); + + if (l_errl) + { + TRACFCOMP(g_trac_ipmi,"IpmiFruInv::buildFruInvRecord Error encountered" + " building up Fru Inventory Record sections."); + } + + return l_errl; +} + + +void IpmiFruInv::buildCommonHeader( + const std::vector<uint8_t> &i_internal_use_data, + const std::vector<uint8_t> &i_chassis_data, + const std::vector<uint8_t> &i_board_data, + const std::vector<uint8_t> &i_product_data, + const std::vector<uint8_t> &i_multirecord_data) +{ + //Use this variable to increment size of header as we go along to determine + // offset for the subsequent area offsets + uint32_t l_cur_data_offset = 0; + + //First byte is id for version of FRU Info Storage Spec used + addHeaderFormat(iv_record_data); + + //2nd byte is offset to internal use data + buildCommonHeaderSection(iv_record_data, i_internal_use_data.size(), + l_cur_data_offset); + + //3rd byte is offset to chassis data + buildCommonHeaderSection(iv_record_data, i_chassis_data.size(), + l_cur_data_offset); + + //4th byte is offset to board data + buildCommonHeaderSection(iv_record_data, i_board_data.size(), + l_cur_data_offset); + + //5th byte is offset to product data + buildCommonHeaderSection(iv_record_data, i_product_data.size(), + l_cur_data_offset); + + //6th byte is offset to multirecord data + buildCommonHeaderSection(iv_record_data, i_multirecord_data.size(), + l_cur_data_offset); + + //7th byte is PAD + padData(iv_record_data); + + //8th (Final byte of Header Format) is the checksum + addDataChecksum(iv_record_data); +} + +void IpmiFruInv::completeRecord(const std::vector<uint8_t> &i_internal_use_data, + const std::vector<uint8_t> &i_chassis_data, + const std::vector<uint8_t> &i_board_data, + const std::vector<uint8_t> &i_product_data, + const std::vector<uint8_t> &i_multirecord_data) +{ + addDataToRecord(i_internal_use_data); + addDataToRecord(i_chassis_data); + addDataToRecord(i_board_data); + addDataToRecord(i_product_data); + addDataToRecord(i_multirecord_data); +} + +//Helper function to simply combine vectors together +void IpmiFruInv::addDataToRecord(const std::vector<uint8_t> &i_data) +{ + iv_record_data.insert(iv_record_data.end(), i_data.begin(), i_data.end()); +} + +//Helper function to create an 'empty' record +errlHndl_t IpmiFruInv::buildEmptyArea(std::vector<uint8_t> &i_data) +{ + return NULL; +} + +//Helper function to pad a data record. Most of the IPMI Fru Invenotry +// Record format works with each section being a multiple of 8 bytes +// so padding is needed to make records properly formatted +void IpmiFruInv::padData(std::vector<uint8_t> &io_data) +{ + + io_data.insert(io_data.end(), + ((io_data.size() + IPMIFRUINV::CHECKSUM_SIZE) % + IPMIFRUINV::RECORD_UNIT_OF_MEASUREMENT), + uint8_t(0)); + + return; +} + +//Creates a 2's complement checksum at the end of the given data vector +void IpmiFruInv::addDataChecksum(std::vector<uint8_t> &io_data) +{ + uint8_t l_checksum_val = 0; + std::vector<uint8_t>::iterator l_iter; + + for (l_iter = io_data.begin(); l_iter != io_data.end(); ++l_iter) + { + l_checksum_val += *l_iter; + } + + // Push the Zero checksum as the last byte of this data + // This appears to be a simple summation of all the bytes + io_data.push_back(-l_checksum_val); + + return; +} + +//The Common Header points to the offset for each of the 5 data record +// sections, this function is used in helping to build that up. +void IpmiFruInv::buildCommonHeaderSection(std::vector<uint8_t> &io_out_data, + uint32_t i_section_data_size, + uint32_t &io_cur_data_offset) +{ + //Check if data for internal use section populated + if (i_section_data_size == 0) + { + //Indicate record not prsent + io_out_data.push_back(IPMIFRUINV::RECORD_NOT_PRESENT); + } + else { + //Place data to define offset to internal_use_data section + io_out_data.push_back((io_cur_data_offset + + IPMIFRUINV::COMMON_HEADER_FORMAT_SIZE) + / IPMIFRUINV::RECORD_UNIT_OF_MEASUREMENT); + io_cur_data_offset += i_section_data_size; + } + + return; +} + +//Helper function to add the IPMI Fru Inventory Format to the +// beginning of the data vector passed in +void IpmiFruInv::addHeaderFormat(std::vector<uint8_t> &io_data) +{ + //Add id for version of FRU Info Storage Spec used + io_data.push_back(IPMIFRUINV::SPEC_VERSION); + return; +} + +//Helper function to complete the formatting for a given section +// that can be completed prior to adding section data +// It will add the spec version, create a placeholder for the data +// size and set the language code if desired +void IpmiFruInv::preFormatProcessing(std::vector<uint8_t> &io_data, + bool i_setLanguageCode) +{ + //Add id for version of FRU Info Storage Spec used + addHeaderFormat(io_data); + + //Add Data Size - 0 as a placeholder, can edit after the data is finalized + io_data.push_back(uint8_t(0)); + + if (i_setLanguageCode) + { + //Add Language Code + io_data.push_back(uint8_t(IPMIFRUINV::ENGLISH_LANGUAGE_CODE)); + } +} +//Helper function to complete the formatting for a given section +// It will calculate overall section size, +// pad the section if needed, and add the data checksum +void IpmiFruInv::postFormatProcessing(std::vector<uint8_t> &io_data) +{ + //This area needs to be padded to a multiple of 8 bytes (after checksum) + padData(io_data); + + //Set size of board info area + setAreaSize(io_data, 1); + + //Finally add board info checksum + addDataChecksum(io_data); + + return; +} + +//Helper function containing the logic to set the proper size of a data section +void IpmiFruInv::setAreaSize(std::vector<uint8_t> &io_data, uint8_t i_offset) +{ + io_data.at(i_offset) = (io_data.size() + IPMIFRUINV::CHECKSUM_SIZE) + / IPMIFRUINV::RECORD_UNIT_OF_MEASUREMENT; + + return; +} + +//############################################################################## +isdimmIpmiFruInv::isdimmIpmiFruInv( TARGETING::TargetHandle_t i_target ) + :IpmiFruInv(i_target) +{ + +}; + +errlHndl_t isdimmIpmiFruInv::buildInternalUseArea(std::vector<uint8_t> &io_data) +{ + //This section not needed for isdimm type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t isdimmIpmiFruInv::buildChassisInfoArea(std::vector<uint8_t> &io_data) +{ + //This section not needed for isdimm type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t isdimmIpmiFruInv::buildBoardInfoArea(std::vector<uint8_t> &io_data) +{ + //This section not needed for isdimm type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t isdimmIpmiFruInv::buildMultiRecordInfoArea( + std::vector<uint8_t> &io_data) +{ + //This section not needed for isdimm type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t isdimmIpmiFruInv::buildProductInfoArea(std::vector<uint8_t> &io_data) +{ + errlHndl_t l_errl = NULL; + + do { + //Set formatting data that goes at the beginning of the record + preFormatProcessing(io_data, true); + + //Set Manufacturer's Name - Use JEDEC standard MFG ID + l_errl = addVpdData(io_data, SPD::MODULE_MANUFACTURER_ID); + if (l_errl) { break; } + //Set Product Name - Use Basic SPD Memory Type + l_errl = addVpdData(io_data, SPD::BASIC_MEMORY_TYPE); + if (l_errl) { break; } + //Set Product Part/Model Number + l_errl = addVpdData(io_data, SPD::MODULE_PART_NUMBER); + if (l_errl) { break; } + //Set Product Version + l_errl = addVpdData(io_data, SPD::MODULE_REVISION_CODE); + if (l_errl) { break; } + //Set Product Serial Number + l_errl = addVpdData(io_data, SPD::MODULE_SERIAL_NUMBER); + if (l_errl) { break; } + + //Add Asset Tag + io_data.push_back(uint8_t(1)); //Asset Tag is One Byte for now + io_data.push_back(uint8_t(0)); + + //FRU File ID - Empty + io_data.push_back(IPMIFRUINV::TYPELENGTH_BYTE_NULL); + io_data.push_back(uint8_t(0)); // Empty FRU File ID bytes + io_data.push_back(IPMIFRUINV::END_OF_CUSTOM_FIELDS); + + //Finalize section formatting + postFormatProcessing(io_data); + + } while (0); + + if (l_errl) + { + TRACFCOMP(g_trac_ipmi,"isdimIpmiFruInv::buildProductInfoArea - Errors " + "collecting product info data from VPD"); + } + + return l_errl; +} + +errlHndl_t isdimmIpmiFruInv::addVpdData(std::vector<uint8_t> &io_data, + uint8_t i_keyword) +{ + size_t l_vpdSize = 0; + errlHndl_t l_errl = NULL; + + do { + //First get size with NULL call: + errlHndl_t l_errl = deviceRead(iv_target, + NULL, + l_vpdSize, + DEVICE_SPD_ADDRESS(i_keyword)); + + if (l_errl) + { + TRACFCOMP(g_trac_ipmi,"isdimmIpmiFruInv::addVpdData - " + "Error while reading SPD keyword size"); + break; + } + + //Assert if vpd field is too large to fit in IPMI fru inventory format + assert(l_vpdSize < IPMIFRUINV::TYPELENGTH_BYTE_ASCII); + + if (l_vpdSize > 0) + { + uint8_t l_vDataPtr[l_vpdSize]; + l_errl = deviceRead(iv_target, l_vDataPtr, l_vpdSize, + DEVICE_SPD_ADDRESS(i_keyword)); + + //First append data size to vector data + io_data.push_back(l_vpdSize); + + //Second append all data found onto vector data + io_data.insert(io_data.end(), + &l_vDataPtr[0], &l_vDataPtr[l_vpdSize]); + + } + else + { + TRACFCOMP(g_trac_ipmi,"isdimmIpmiFruInv::addVpdData - " + " No size returned for SPD keyword"); + } + + } while(0); + + if (l_errl) + { + TRACFCOMP(g_trac_ipmi, "addVpdData - Error acquiring data from Vpd."); + } + + return l_errl; +} + +//############################################################################## +procIpmiFruInv::procIpmiFruInv( TARGETING::TargetHandle_t i_target ) + :IpmiFruInv(i_target) +{ + +}; + +errlHndl_t procIpmiFruInv::buildInternalUseArea(std::vector<uint8_t> &io_data) +{ + //This section not needed for proc type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t procIpmiFruInv::buildChassisInfoArea(std::vector<uint8_t> &io_data) +{ + //This section not needed for proc type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t procIpmiFruInv::buildBoardInfoArea(std::vector<uint8_t> &io_data) +{ + errlHndl_t l_errl = NULL; + + do { + //Set formatting data that goes at the beginning of the record + preFormatProcessing(io_data, true); + + //MFG Date/Time - Blank + io_data.push_back(0); + io_data.push_back(0); + io_data.push_back(0); + + //Board Manufacturer - IBM + //Board MFG - Type/Length Byte + // - Indicate 8-bit Ascii + Latin 1 (0xC0) + // - and a size of 3 for "IBM" - 0x3 + // - add together and the value for this byte is 0xC3 + io_data.push_back(0xC3); + // - Now put in 'IBM' + io_data.push_back(0x49); //I + io_data.push_back(0x42); //B + io_data.push_back(0x4D); //M + + //Set Board Info description + l_errl = addVpdData(io_data, MVPD::VINI, MVPD::DR, true); + if (l_errl) { break; } + //Set Board Info serial number + l_errl = addVpdData(io_data, MVPD::VINI, MVPD::SN); + if (l_errl) { break; } + //Set Board part number + l_errl = addVpdData(io_data, MVPD::VINI, MVPD::FN); + if (l_errl) { break; } + //Set Board FRU File ID + l_errl = addVpdData(io_data, MVPD::VINI, MVPD::VZ); + if (l_errl) { break; } + io_data.push_back(IPMIFRUINV::END_OF_CUSTOM_FIELDS); + + //Complete formatting for this data record + postFormatProcessing(io_data); + + } while (0); + + if (l_errl) + { + TRACFCOMP(g_trac_ipmi,"buildBoardInfoArea - Errors Collecting ISDimm " + "FRU Inventory Board Info Data"); + } + + return l_errl; +} + +errlHndl_t procIpmiFruInv::buildProductInfoArea(std::vector<uint8_t> &io_data) +{ + //This section not needed for proc type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t procIpmiFruInv::buildMultiRecordInfoArea( + std::vector<uint8_t> &io_data) +{ + //This section not needed for proc type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t procIpmiFruInv::addVpdData(std::vector<uint8_t> &io_data, + uint8_t i_record, + uint8_t i_keyword, + bool i_ascii) +{ + size_t l_vpdSize = 0; + errlHndl_t l_errl = NULL; + + do { + + //First get size of data by passing NULL + errlHndl_t l_errl = deviceRead(iv_target, + NULL, + l_vpdSize, + DEVICE_MVPD_ADDRESS(i_record, i_keyword)); + + if (l_errl) + { + TRACFCOMP(g_trac_ipmi,"procIpmiFruInv::addVpdData - Error while " + "reading MVPD keyword size"); + break; + } + + //Assert if vpd field is too large to fit in IPMI fru inventory format + assert(l_vpdSize < IPMIFRUINV::TYPELENGTH_BYTE_ASCII); + + if (l_vpdSize > 0) + { + uint8_t l_vDataPtr[l_vpdSize]; + + l_errl = deviceRead(iv_target, l_vDataPtr, l_vpdSize, + DEVICE_MVPD_ADDRESS(i_record, i_keyword)); + + //Add on the data to the type/length byte indicating it is ascii + // otherwise leave it as binary + if (i_ascii) + { + io_data.push_back(l_vpdSize + + IPMIFRUINV::TYPELENGTH_BYTE_ASCII); + } + else + { + //First push back the size of this data + io_data.push_back(l_vpdSize); + } + + //Second append all data found onto vector data + io_data.insert(io_data.end(), + &l_vDataPtr[0], &l_vDataPtr[l_vpdSize]); + + } + else + { + TRACFCOMP(g_trac_ipmi,"procIpmiFruInv::addVpdData - " + " No size returned for MVPD keyword"); + } + } while(0); + + if (l_errl) + { + TRACFCOMP(g_trac_ipmi, "addVpdData - Error acquiring data from Vpd."); + } + + return l_errl; +} + + +//############################################################################## +backplaneIpmiFruInv::backplaneIpmiFruInv( TARGETING::TargetHandle_t i_target ) + :IpmiFruInv(i_target) +{ + +}; + +errlHndl_t backplaneIpmiFruInv::buildInternalUseArea( + std::vector<uint8_t> &io_data) +{ + //This section not needed for the backplane type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t backplaneIpmiFruInv::buildChassisInfoArea( + std::vector<uint8_t> &io_data) +{ + errlHndl_t l_errl = NULL; + + do { + //Set formatting data that goes at the beginning of the record + preFormatProcessing(io_data, true); + + //Set default chassis type + io_data.push_back(IPMIFRUINV::DEFAULT_CHASSIS_TYPE); + //Set chassis part number - ascii formatted field + //@fixme RTC Story 118373 + l_errl = addVpdData(io_data, CVPD::OPFR, CVPD::VP, true); + if (l_errl) { break; } + //Set chassis serial number - ascii formatted field + //@fixme RTC Story 118373 + l_errl = addVpdData(io_data, CVPD::OPFR, CVPD::VS, true); + if (l_errl) { break; } + + //Indicate no custom fields + io_data.push_back(IPMIFRUINV::TYPELENGTH_BYTE_NULL); + io_data.push_back(IPMIFRUINV::END_OF_CUSTOM_FIELDS); + + //Complete record data formatting + postFormatProcessing(io_data); + } while (0); + + if (l_errl) + { + TRACFCOMP(g_trac_ipmi,"backplaneIpmiFruInv::buildChassisInfoArea - " + "Errors collecting chassis info data"); + } + + return l_errl; +} + +errlHndl_t backplaneIpmiFruInv::buildBoardInfoArea( + std::vector<uint8_t> &io_data) +{ + errlHndl_t l_errl = NULL; + + do { + //Set formatting data that goes at the beginning of the record + preFormatProcessing(io_data, true); + + //Set MFG Date/Time - Blank + io_data.push_back(0); + io_data.push_back(0); + io_data.push_back(0); + + //Set Vendor Name - ascii formatted data + //@fixme RTC Story 118373 + l_errl = addVpdData(io_data, CVPD::OPFR, CVPD::VN, true); + if (l_errl) { break; } + //Set Product Name - ascii formatted data + //@fixme RTC Story 118373 + l_errl = addVpdData(io_data, CVPD::OPFR, CVPD::DR, true); + if (l_errl) { break; } + //Set Product Part number - ascii formatted data + //@fixme RTC Story 118373 + l_errl = addVpdData(io_data, CVPD::OPFR, CVPD::VS, true); + if (l_errl) { break; } + //Set Product Serial number - ascii formatted data + //@fixme RTC Story 118373 + l_errl = addVpdData(io_data, CVPD::OPFR, CVPD::VP, true); + + //Indicate No Custom Fields + io_data.push_back(IPMIFRUINV::TYPELENGTH_BYTE_NULL); + io_data.push_back(IPMIFRUINV::END_OF_CUSTOM_FIELDS); + + ////Complete record data formatting + postFormatProcessing(io_data); + + } while (0); + + if (l_errl) + { + TRACFCOMP(g_trac_ipmi,"backplaneIpmiFruInv::buildBoardInfoArea - " + "Errors collecting board info data"); + } + + return l_errl; +} + +errlHndl_t backplaneIpmiFruInv::buildProductInfoArea( + std::vector<uint8_t> &io_data) +{ + //This section not needed for the backplane type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t backplaneIpmiFruInv::buildMultiRecordInfoArea( + std::vector<uint8_t> &io_data) +{ + //This section not needed for the backplane type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t backplaneIpmiFruInv::addVpdData(std::vector<uint8_t> &io_data, + uint8_t i_record, + uint8_t i_keyword, + bool i_ascii) +{ + size_t l_vpdSize = 0; + errlHndl_t l_errl = NULL; + + do { + //First get size of data with NULL parameter + errlHndl_t l_errl = deviceRead(iv_target, + NULL, + l_vpdSize, + //@fixme RTC Story 118373 + DEVICE_CVPD_ADDRESS(i_record, i_keyword)); + + if (l_errl) + { + TRACFCOMP(g_trac_ipmi,"backplaneIpmiFruInv::addVpdData - Error " + "while reading CVPD keyword size"); + break; + } + + //Assert if vpd field is too large to fit in IPMI fru inventory format + assert(l_vpdSize < IPMIFRUINV::TYPELENGTH_BYTE_ASCII); + + if (l_vpdSize > 0) + { + uint8_t l_vDataPtr[l_vpdSize]; + l_errl = deviceRead(iv_target, l_vDataPtr, l_vpdSize, + DEVICE_CVPD_ADDRESS(i_record, i_keyword)); + + //Add on the data to the type/length byte indicating it is ascii + // otherwise leave it as binary + if (i_ascii) + { + io_data.push_back(l_vpdSize + + IPMIFRUINV::TYPELENGTH_BYTE_ASCII); + } + else + { + //First addon the size of this data + io_data.push_back(l_vpdSize); + } + + //Then add on the data returnd from the VPD read + io_data.insert(io_data.end(), + &l_vDataPtr[0], &l_vDataPtr[l_vpdSize]); + } + else + { + TRACFCOMP(g_trac_ipmi,"backplaneIpmiFruInv::addVpdData - " + " No size returned for CVPD keyword"); + } + } while(0); + + if (l_errl) + { + TRACFCOMP(g_trac_ipmi, "backplaneIpmiFruInv::addVpdData - Error " + "acquiring data from Vpd."); + } + + return l_errl; +} + +errlHndl_t IPMIFRUINV::setData() +{ + errlHndl_t l_errl = NULL; + + do + { + // find CLASS_SYS (the top level target) + TARGETING::Target* pSys; + TARGETING::targetService().getTopLevelTarget(pSys); + + if (!(pSys)) + { + TRACFCOMP(g_trac_ipmi,"IPMIFRUINV::setData - No CLASS_SYS TopLevelTarget found:" + " not setting IPMI Fru Inventory"); + break; + } + + // Find list of all target types that may need a fru inventory + // record created for them + TARGETING::PredicateCTM predChip(TARGETING::CLASS_CHIP); + TARGETING::PredicateCTM predDimm(TARGETING::CLASS_LOGICAL_CARD, + TARGETING::TYPE_DIMM); + TARGETING::PredicatePostfixExpr checkExpr; + TARGETING::PredicateHwas l_present; + l_present.present(true); + checkExpr.push(&predChip).push(&predDimm).Or().push(&l_present).And(); + + TARGETING::TargetHandleList pCheckPres; + TARGETING::targetService().getAssociated( pCheckPres, pSys, + TARGETING::TargetService::CHILD, TARGETING::TargetService::ALL, + &checkExpr ); + + for (TARGETING::TargetHandleList::const_iterator pTarget_it = + pCheckPres.begin(); + pTarget_it != pCheckPres.end(); + ++pTarget_it + ) + { + + TARGETING::TargetHandle_t pTarget = *pTarget_it; + + //Check if EEPROM_VPD_FRU_INFO attribute exists + TARGETING::EepromVpdFruInfo eepromVpdFruInfo; + bool getFruInfo = + pTarget->tryGetAttr<TARGETING::ATTR_EEPROM_VPD_FRU_INFO> + (eepromVpdFruInfo); + if (getFruInfo) + { + TRACFCOMP(g_trac_ipmi, "IPMIFRUINV::setData - Sending IPMI FRU Inventory Data for target with HUID: [%08x]", + pTarget->getAttr<TARGETING::ATTR_HUID>()); + + IpmiFruInv *l_fru = IpmiFruInv::Factory(pTarget); + + if (l_fru != NULL) + { + //Target recognized, build & send IPMI FRU Invenotry record + l_errl = l_fru->buildFruInvRecord(); + if (l_errl) + { + TRACFCOMP(g_trac_ipmi, "IPMIFRUINV::setData - Errors encountered, will skip setting the rest of the data"); + break; + } + l_fru->sendFruData(eepromVpdFruInfo.fruId); + delete l_fru; + } + } + } + } while(0); + + return l_errl; +} diff --git a/src/usr/ipmi/ipmifruinvprvt.H b/src/usr/ipmi/ipmifruinvprvt.H new file mode 100644 index 000000000..4f0ff4d46 --- /dev/null +++ b/src/usr/ipmi/ipmifruinvprvt.H @@ -0,0 +1,421 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/include/usr/ipmi/ipmifru.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#ifndef __IPMI_IPMIFRUINVPRVT_H +#define __IPMI_IMPIFRUINVPRVT_H + +namespace IPMIFRUINV +{ + enum recordFields + { + //Storage Definition Headers will use version 1.2 + SPEC_VERSION = 1, + RECORD_UNIT_OF_MEASUREMENT = 8, //size in bytes + CHECKSUM_SIZE = 1, //size in bytes + RECORD_NOT_PRESENT = 0, + ENGLISH_LANGUAGE_CODE = 0, + TYPELENGTH_BYTE_NULL = 0, + TYPELENGTH_BYTE_ASCII = 0xC0, + END_OF_CUSTOM_FIELDS = 0xC1, + COMMON_HEADER_FORMAT_SIZE = 8, //size in bytes + DEFAULT_CHASSIS_TYPE = 0x05, + DEFAULT_FRU_OFFSET = 0, + }; +}; + + +//Parent Class Contains all common functions to build up, format, +// and send IPMI Fru Inventory Record Data +//The parent Class also defines pure virtual functions so the child +// is responsible to build up the individual record sections +// as the data for those is specific to each child. +class IpmiFruInv +{ + public: + + + /** + * @brief Constructor + * + * @param[in] TargetHandle_t, Handle to target for which + * to get relevant IPMI FRU Data from + */ + IpmiFruInv(TARGETING::TargetHandle_t i_target); + + /** + * @brief Default Destructor + */ + virtual ~IpmiFruInv(); + + /** + * @brief Factory Pattern Creator function + * @param[in] TargetHandle_t, Handle to target for which + * to get relevant IPMI FRU Data from + */ + static IpmiFruInv *Factory(TARGETING::TargetHandle_t i_target); + + /** + * @brief Package and send the IPMI FRU Data + * + * @param[in] uint8_t, IPMI Fru Device ID + */ + void sendFruData(uint8_t i_deviceId); + + /** + * @brief Gather and Format relevant IPMI Fru Inventory Data + * + * @param[in] void + * @param[out] errlHndl_t, error encountered getting data + */ + errlHndl_t buildFruInvRecord(void); + + protected: + //The target to build an IPMI fru inventory record for + TARGETING::TargetHandle_t iv_target; + + //The overall IPMI Fru Inventory record to send + std::vector<uint8_t> iv_record_data; + + /** + * @brief Format Beginning of Individual IPMI Fru Data Section + * + * @param[in/out] data, Data to be updated with formatting + header + * @param[in] i_setLanguagCode, Indicator to set/not set Language Code + */ + void preFormatProcessing(std::vector<uint8_t>& io_data, + bool i_setLanguageCode); + + /** + * @brief Format End of Individual IPMI Fru Data Section + * + * @param[in/out] data, Data container to be updated with formatting + */ + void postFormatProcessing(std::vector<uint8_t>& io_data); + /** + * @brief Complete + Set size of Data Section + * + * @param[in/out] data, Data container with size to be updated + * @param[in] offset, Indicate where to update size of data section + */ + void setAreaSize(std::vector<uint8_t>& io_data, uint8_t i_offset); + + /** + * @brief Add inputted data to overall IPMI Fru Record + * + * @param[in] data, Data container to be added to overall record + */ + void addDataToRecord(const std::vector<uint8_t>& i_data); + + /** + * @brief Builds the Internal Use Area Data Section + * @param[in/out] data, The container to put intenral use area data in + */ + virtual errlHndl_t buildInternalUseArea(std::vector<uint8_t> &io_data)=0; + + /** + * @brief Builds the Chassis Info Area Data Section + * @param[in/out] data, The container to put chassis info area data in + */ + virtual errlHndl_t buildChassisInfoArea(std::vector<uint8_t> &io_data)=0; + + /** + * @brief Builds the Board Info Area Data Section + * @param[in/out] data, The container to put board info area data in + */ + virtual errlHndl_t buildBoardInfoArea(std::vector<uint8_t> &io_data)=0; + + /** + * @brief Builds the Product Info Area Data Section + * @param[in/out] data, The container to put product info area data in + */ + virtual errlHndl_t buildProductInfoArea(std::vector<uint8_t> &io_data)=0; + + /** + * @brief Builds the MultiRecord Info Area Data Section + * @param[in/out] data, The container to put multirecord info area data in + */ + virtual errlHndl_t buildMultiRecordInfoArea( + std::vector<uint8_t> &io_data)=0; + + /** + * @brief Builds a standard data section that is empty + * @param[in] data, The container to put the data in + */ + virtual errlHndl_t buildEmptyArea(std::vector<uint8_t> &i_data); + + /** + * @brief Debug function to print data to console + * @param[in] data, The data to be printed + */ + void printRecordDebugData(const std::vector<uint8_t> &i_data); + + private: + + /** + * @brief Compute and Add data checsum to data record + * + * @param[in/out] data, Data to be updated with checsum + */ + void addDataChecksum(std::vector<uint8_t>& io_data); + + /** + * @brief Pad data section to proper size + * + * @param[in/out] data, Data to be padded + */ + void padData(std::vector<uint8_t>& io_data); + + /** + * @brief Builds a section of the common header + * + * @param[in/out] data, Common Header section data container + * @param[in] section_data, Data from one particular record section + * @param[in/out] cur_offset, Current offset for data in overall record + */ + void buildCommonHeaderSection(std::vector<uint8_t>& io_out_data, + uint32_t i_section_data, + uint32_t &io_cur_offset); + + /** + * @brief Sets IPMI Fru Spec Revision Header Format Value + * + * @param[in/out] data, data to add format value to + */ + void addHeaderFormat(std::vector<uint8_t>& io_data); + + /** + * @brief Builds the common header data in iv_record + * + * @param[in] internal_use_data, IPMI internal use section data + * @param[in] chassis_data, IPMI chassis section data + * @param[in] board_data, IPMI board section data + * @param[in] product_data, IPMI product section data + * @param[in] multirecord_data, IPMI multirecord section data + * @param[out] void + */ + void buildCommonHeader( const std::vector<uint8_t> &i_internal_use_data, + const std::vector<uint8_t> &i_chassis_data, + const std::vector<uint8_t> &i_board_data, + const std::vector<uint8_t> &i_product_data, + const std::vector<uint8_t> &i_multirecord_data ); + + /** + * @brief Complete entire record by combining all data parts + * + * @param[in] internal_use_data, IPMI internal use section data + * @param[in] chassis_data, IPMI chassis section data + * @param[in] board_data, IPMI board section data + * @param[in] product_data, IPMI product section data + * @param[in] multirecord_data, IPMI multirecord section data + */ + void completeRecord(const std::vector<uint8_t> &i_internal_use_data, + const std::vector<uint8_t> &i_chassis_data, + const std::vector<uint8_t> &i_board_data, + const std::vector<uint8_t> &i_product_data, + const std::vector<uint8_t> &i_multirecord_data); + +}; + + +//Child class for building up ISDimm Fru Inventory Record Data +class isdimmIpmiFruInv : public IpmiFruInv +{ + + public: + + /** + * @brief Constructor + * + * @param[in] TargetHandle_t, Handle to target for which + * to get relevant IPMI FRU Data from + */ + isdimmIpmiFruInv( TARGETING::TargetHandle_t i_target ); + + /** + * @brief Builds the Internal Use Area Data Section + * @param[in/out] data, The container to put internal use area data in + */ + errlHndl_t buildInternalUseArea(std::vector<uint8_t> &io_data); + + /** + * @brief Builds the Chassis Info Area Data Section + * @param[in/out] data, The container to put chassis info area data in + */ + errlHndl_t buildChassisInfoArea(std::vector<uint8_t> &io_data); + + /** + * @brief Builds the Board Info Area Data Section + * @param[in/out] data, The container to put board info area data in + */ + errlHndl_t buildBoardInfoArea(std::vector<uint8_t> &io_data); + + /** + * @brief Builds the Product Info Area Data Section + * @param[in/out] data, The container to put product info area data in + */ + errlHndl_t buildProductInfoArea(std::vector<uint8_t> &io_data); + + /** + * @brief Builds the MultiRecord Info Area Data Section + * @param[in/out] data, The container to put multirecord info area data in + */ + errlHndl_t buildMultiRecordInfoArea(std::vector<uint8_t> &io_data); + + private: + + /** + * @brief Adds the specified VPD data to the data to build up a given + * record + * @param[in/out] data, The container with record data + * @param[in] keyword, Indicates where in the VPD to get more data + + */ + errlHndl_t addVpdData(std::vector<uint8_t> &io_data, uint8_t i_keyword); + +}; + +//Child class for building up Processor Fru Inventory Record Data +class procIpmiFruInv : public IpmiFruInv +{ + + public: + + /** + * @brief Constructor + * + * @param[in] TargetHandle_t, Handle to target for which + * to get relevant IPMI FRU Data from + */ + procIpmiFruInv( TARGETING::TargetHandle_t i_target ); + + /** + * @brief Builds the Internal Use Area Data Section + * @param[in/out] data, The container to put internal use area data in + */ + errlHndl_t buildInternalUseArea(std::vector<uint8_t> &io_data); + + /** + * @brief Builds the Chassis Info Area Data Section + * @param[in/out] data, The container to put chassis info area data in + */ + errlHndl_t buildChassisInfoArea(std::vector<uint8_t> &io_data); + + /** + * @brief Builds the Board Info Area Data Section + * @param[in/out] data, The container to put board info area data in + */ + errlHndl_t buildBoardInfoArea(std::vector<uint8_t> &io_data); + + /** + * @brief Builds the Product Info Area Data Section + * @param[in/out] data, The container to put product info area data in + */ + errlHndl_t buildProductInfoArea(std::vector<uint8_t> &io_data); + + /** + * @brief Builds the MultiRecord Info Area Data Section + * @param[in/out] data, The container to put multirecord info area data in + */ + errlHndl_t buildMultiRecordInfoArea(std::vector<uint8_t> &io_data); + + private: + + /** + * @brief Adds the specified VPD data to the data to build up a given + * IPMI Fru Inventory record + * @param[in/out] data, The container with record data + * @param[in] record, Indicates major offset in the VPD to get more data + * @param[in] keyword, Indicates minor offset in the VPD to get more data + * @param[in] ascii, Indicates if VPD field is in ascii format or not + */ + errlHndl_t addVpdData(std::vector<uint8_t> &io_data, + uint8_t i_record, + uint8_t i_keyword, + bool i_ascii=false); + +}; + +//Child class for building up backplane Fru Inventory Record Data +class backplaneIpmiFruInv : public IpmiFruInv +{ + + public: + + /** + * @brief Constructor + * + * @param[in] TargetHandle_t, Handle to target for which + * to get relevant IPMI FRU Data from + */ + backplaneIpmiFruInv( TARGETING::TargetHandle_t i_target ); + + /** + * @brief Builds the Internal Use Area Data Section + * @param[in/out] data, The container to put internal use area data in + */ + errlHndl_t buildInternalUseArea(std::vector<uint8_t> &io_data); + + /** + * @brief Builds the Chassis Info Area Data Section + * @param[in/out] data, The container to put chassis info area data in + */ + errlHndl_t buildChassisInfoArea(std::vector<uint8_t> &io_data); + + /** + * @brief Builds the Board Info Area Data Section + * @param[in/out] data, The container to put board info area data in + */ + errlHndl_t buildBoardInfoArea(std::vector<uint8_t> &io_data); + + /** + * @brief Builds the Product Info Area Data Section + * @param[in/out] data, The container to put product info area data in + */ + errlHndl_t buildProductInfoArea(std::vector<uint8_t>& io_data); + + /** + * @brief Builds the MultiRecord Info Area Data Section + * @param[in/out] data, The container to put multirecord info area data in + */ + errlHndl_t buildMultiRecordInfoArea(std::vector<uint8_t>& io_data); + + private: + + /** + * @brief Adds the specified VPD data to the data to build up a given + * IPMI Fru Inventory record + * @param[in/out] data, The container with record data + * @param[in] record, Indicates major offset in the VPD to get more data + * @param[in] keyword, Indicates minor offset in the VPD to get more data + * @param[in] ascii, Indicates if VPD field is in ascii format or not + */ + errlHndl_t addVpdData(std::vector<uint8_t> &io_data, + uint8_t i_record, + uint8_t i_keyword, + bool i_ascii=false); + +}; + +#endif diff --git a/src/usr/ipmi/makefile b/src/usr/ipmi/makefile index 52f3dadfd..00a60052e 100644 --- a/src/usr/ipmi/makefile +++ b/src/usr/ipmi/makefile @@ -33,6 +33,7 @@ OBJS += ipmifru.o OBJS += ipmiconfig.o OBJS += ipmisensor.o OBJS += ipmiwatchdog.o +OBJS += ipmifruinv.o #SUBDIRS += test.d diff --git a/src/usr/targeting/common/genHwsvMrwXml.pl b/src/usr/targeting/common/genHwsvMrwXml.pl index a6ebb2fd6..6861782d8 100755 --- a/src/usr/targeting/common/genHwsvMrwXml.pl +++ b/src/usr/targeting/common/genHwsvMrwXml.pl @@ -93,7 +93,7 @@ my $usage = 0; my $DEBUG = 0; my $outFile = ""; my $build = "fsp"; - +my $ipmiFruid = 0; use Getopt::Long; GetOptions( "mrwdir:s" => \$mrwdir, @@ -4254,6 +4254,23 @@ sub generate_is_dimm } print " + </attribute> + <attribute> + <id>EEPROM_VPD_FRU_INFO</id> + <default> + <field><id>i2cMasterPath</id><value>physical:sys-$sys/node-$node/membuf-$ctaur</value></field> + <field><id>port</id><value>$dimmI2C->{$i+1}->{'i2c-master'}->{'i2c-port'}</value></field> + <field><id>devAddr</id><value>0x$dimmI2C->{$i+1}->{'address'}</value></field> + <field><id>engine</id><value>0</value></field> + <field><id>byteAddrOffset</id><value>0x01</value></field> + <field><id>maxMemorySizeKB</id><value>0x01</value></field> + <field><id>writePageSize</id><value>0x00</value></field> + <field><id>writeCycleTime</id><value>0x05</value></field> + <field><id>fruId</id><value>$ipmiFruid++</value></field> + </default> + </attribute>"; + + print" <attribute> <id>VPD_REC_NUM</id> <default>$pos</default> @@ -4959,6 +4976,24 @@ sub addEepromsCentaur print " </default>\n"; print " </attribute>\n"; + if ($id_name eq "EEPROM_VPD_PRIMARY_INFO") + { + print " <attribute>\n"; + print " <id>EEPROM_VPD_FRU_INFO</id>\n"; + print " <default>\n"; + print " <field><id>i2cMasterPath</id><value>physical:sys-$sys/node-$node/proc-$proc</value></field>\n"; + print " <field><id>port</id><value>$port</value></field>\n"; + print " <field><id>devAddr</id><value>$devAddr_hex</value></field>\n"; + print " <field><id>engine</id><value>0</value></field>\n"; + print " <field><id>byteAddrOffset</id><value>0x02</value></field>\n"; + print " <field><id>maxMemorySizeKB</id><value>0x40</value></field>\n"; + print " <field><id>writePageSize</id><value>0x80</value></field>\n"; + print " <field><id>writeCycleTime</id><value>0x05</value></field>\n"; + print " <field><id>fruId</id><value>$ipmiFruid++</value></field>\n"; + print " </default>\n"; + print " </attribute>\n"; + } + } } diff --git a/src/usr/targeting/common/xmltohb/attribute_types.xml b/src/usr/targeting/common/xmltohb/attribute_types.xml index 4a0a1ffbb..b2c403141 100644 --- a/src/usr/targeting/common/xmltohb/attribute_types.xml +++ b/src/usr/targeting/common/xmltohb/attribute_types.xml @@ -1391,6 +1391,85 @@ ID for the sensor number returned with the elog. --> </attribute> <attribute> + <id>EEPROM_VPD_FRU_INFO</id> + <description>Information needed to address the EEPROM slaves for + IPMI Fru Inventory Purposes</description> + <complexType> + <description>Structure to define the addressing for an I2C + slave device.</description> + <field> + <name>i2cMasterPath</name> + <description>Entity path to the chip that contains the I2C + master</description> + <type>EntityPath</type> + <default>physical:sys-0</default> + </field> + <field> + <name>port</name> + <description>Port from the I2C Master device. This is a 6-bit + value.</description> + <type>uint8_t</type> + <default>0x80</default> + </field> + <field> + <name>devAddr</name> + <description>Device address on the I2C bus. This is a 7-bit value, + but then shifted 1 bit left.</description> + <type>uint8_t</type> + <default>0x80</default> + </field> + <field> + <name>engine</name> + <description>I2C master engine. This is a 2-bit + value.</description> + <type>uint8_t</type> + <default>0x80</default> + </field> + <field> + <name>byteAddrOffset</name> + <description>The number of bytes a device requires to set its + internal address/offset.</description> + <type>uint8_t</type> + <default>0x02</default> + </field> + <field> + <name>maxMemorySizeKB</name> + <description>The number of kilobytes a device can hold. 'Zero' + value possible for some devices.</description> + <type>uint64_t</type> + <default>0x0</default> + </field> + <field> + <name>writePageSize</name> + <description>The maximum number of bytes that can be written to + a device at one time. 'Zero' value means no maximum + value is expected or checked.</description> + <type>uint64_t</type> + <default>0x0</default> + </field> + <field> + <name>writeCycleTime</name> + <description>The amount of time in milliseconds a device requires + on the completion of a write command to update its + internal memory.</description> + <type>uint64_t</type> + <default>0x0</default> + </field> + <field> + <name>fruId</name> + <description>The IPMI Fru Inventory ID number. This must be a + unique number for every individual FRU within a + system.</description> + <type>uint8_t</type> + <default>0x0</default> + </field> + </complexType> + <persistency>non-volatile</persistency> + <readable/> +</attribute> + + +<attribute> <id>EEPROM_VPD_BACKUP_INFO</id> <description>Information needed to address the EERPROM slaves</description> <complexType> diff --git a/src/usr/targeting/common/xmltohb/target_types.xml b/src/usr/targeting/common/xmltohb/target_types.xml index 24269bbd3..6def4603f 100644 --- a/src/usr/targeting/common/xmltohb/target_types.xml +++ b/src/usr/targeting/common/xmltohb/target_types.xml @@ -516,6 +516,7 @@ <attribute><id>DUMMY_HEAP_ZERO_DEFAULT</id></attribute> <attribute><id>MSS_MEM_MC_IN_GROUP</id></attribute> <attribute><id>EEPROM_VPD_PRIMARY_INFO</id></attribute> + <attribute><id>EEPROM_VPD_FRU_INFO</id></attribute> <attribute><id>EEPROM_VPD_BACKUP_INFO</id></attribute> <attribute><id>EEPROM_SBE_PRIMARY_INFO</id></attribute> <attribute><id>EEPROM_SBE_BACKUP_INFO</id></attribute> @@ -852,6 +853,7 @@ </attribute> <attribute><id>CDM_DOMAIN</id><default>NODE</default></attribute> <attribute><id>IPMI_SENSORS</id></attribute> + <attribute><id>EEPROM_VPD_FRU_INFO</id></attribute> </targetType> <targetType> @@ -1357,6 +1359,7 @@ </default> </attribute> <attribute><id>EEPROM_VPD_PRIMARY_INFO</id></attribute> + <attribute><id>EEPROM_VPD_FRU_INFO</id></attribute> <attribute> <id>I2C_BUS_SPEED_ARRAY</id> <default>400,0,0,0,0,0</default> @@ -1491,6 +1494,7 @@ </attribute> <attribute><id>EEPROM_VPD_PRIMARY_INFO</id></attribute> + <attribute><id>EEPROM_VPD_FRU_INFO</id></attribute> <attribute><id>VPD_REC_NUM</id></attribute> <attribute><id>MSS_EFF_VPD_VERSION</id></attribute> diff --git a/src/usr/vpd/cvpd.H b/src/usr/vpd/cvpd.H index f7b2b120a..b71b98008 100644 --- a/src/usr/vpd/cvpd.H +++ b/src/usr/vpd/cvpd.H @@ -115,7 +115,7 @@ namespace CVPD { VD, "VD" }, { VN, "VN" }, { VP, "VP" }, - { SV, "SV" }, + { VS, "VS" }, { M0, "M0" }, { M1, "M1" }, { M2, "M2" }, diff --git a/src/usr/vpd/spd.C b/src/usr/vpd/spd.C index 0f5c9866b..27b34f643 100644 --- a/src/usr/vpd/spd.C +++ b/src/usr/vpd/spd.C @@ -213,7 +213,10 @@ errlHndl_t spdGetKeywordValue ( DeviceFW::OperationType i_opType, if( BASIC_MEMORY_TYPE == keyword ) { io_buflen = MEM_TYPE_SZ; - memcpy( io_buffer, &memType, io_buflen ); + if (io_buffer != NULL) + { + memcpy( io_buffer, &memType, io_buflen ); + } break; } @@ -658,6 +661,13 @@ errlHndl_t spdGetValue ( VPD::vpdKeyword i_keyword, break; } + // Support passing in NULL buffer to return VPD field size + if ( NULL == io_buffer ) + { + io_buflen = (*entry).length; + break; + } + // Check io_buflen versus size in table err = spdCheckSize( io_buflen, (*entry).length, diff --git a/src/usr/vpd/test/spdtest.H b/src/usr/vpd/test/spdtest.H index 83de74c7f..c94e8af98 100755 --- a/src/usr/vpd/test/spdtest.H +++ b/src/usr/vpd/test/spdtest.H @@ -736,7 +736,9 @@ class SPDTest: public CxxTest::TestSuite // Test on first DIMM only. theTarget = dimmList[0]; - uint8_t * theData = NULL; + //If theData is NULL, deviceRead will return the size + // need to give this an arbitrary size so test is still valid` + uint8_t * theData = static_cast<uint8_t*>(malloc( 0x1 )); size_t theSize = 0x0; // Invalid size of 0x0 cmds++; @@ -745,6 +747,12 @@ class SPDTest: public CxxTest::TestSuite theSize, DEVICE_SPD_ADDRESS( SPD::SPD_FIRST_NORM_KEYWORD ) ); + // clean up the data + if( NULL != theData ) + { + delete theData; + theData = NULL; + } if( NULL == err ) { fails++; |