From 8f0edf314a9c9198d95b0c7598e269cf8b7f232a Mon Sep 17 00:00:00 2001 From: Bill Hoffa Date: Mon, 1 Dec 2014 11:48:01 -0600 Subject: 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 --- src/include/usr/ipmi/ipmifruinv.H | 41 + src/include/usr/vpd/cvpdenums.H | 2 +- src/usr/hwas/hostbootIstep.C | 7 + src/usr/hwpf/plat/fapiPlatMBvpdAccess.C | 2 +- src/usr/ipmi/ipmifruinv.C | 864 +++++++++++++++++++++ src/usr/ipmi/ipmifruinvprvt.H | 421 ++++++++++ src/usr/ipmi/makefile | 1 + src/usr/targeting/common/genHwsvMrwXml.pl | 37 +- .../targeting/common/xmltohb/attribute_types.xml | 79 ++ src/usr/targeting/common/xmltohb/target_types.xml | 4 + src/usr/vpd/cvpd.H | 2 +- src/usr/vpd/spd.C | 12 +- src/usr/vpd/test/spdtest.H | 10 +- 13 files changed, 1476 insertions(+), 6 deletions(-) create mode 100644 src/include/usr/ipmi/ipmifruinv.H create mode 100644 src/usr/ipmi/ipmifruinv.C create mode 100644 src/usr/ipmi/ipmifruinvprvt.H 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 +#include #include 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 +#include +#include +#include +#include +#include +#include "ipmifru.H" +#include "ipmifruinvprvt.H" +#include +#include + + +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()) + { + 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()); + 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 &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 l_iu_data; + std::vector l_ci_data; + std::vector l_bi_data; + std::vector l_pi_data; + std::vector 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 &i_internal_use_data, + const std::vector &i_chassis_data, + const std::vector &i_board_data, + const std::vector &i_product_data, + const std::vector &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 &i_internal_use_data, + const std::vector &i_chassis_data, + const std::vector &i_board_data, + const std::vector &i_product_data, + const std::vector &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 &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 &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 &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 &io_data) +{ + uint8_t l_checksum_val = 0; + std::vector::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 &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 &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 &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 &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 &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 &io_data) +{ + //This section not needed for isdimm type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t isdimmIpmiFruInv::buildChassisInfoArea(std::vector &io_data) +{ + //This section not needed for isdimm type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t isdimmIpmiFruInv::buildBoardInfoArea(std::vector &io_data) +{ + //This section not needed for isdimm type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t isdimmIpmiFruInv::buildMultiRecordInfoArea( + std::vector &io_data) +{ + //This section not needed for isdimm type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t isdimmIpmiFruInv::buildProductInfoArea(std::vector &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 &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 &io_data) +{ + //This section not needed for proc type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t procIpmiFruInv::buildChassisInfoArea(std::vector &io_data) +{ + //This section not needed for proc type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t procIpmiFruInv::buildBoardInfoArea(std::vector &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 &io_data) +{ + //This section not needed for proc type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t procIpmiFruInv::buildMultiRecordInfoArea( + std::vector &io_data) +{ + //This section not needed for proc type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t procIpmiFruInv::addVpdData(std::vector &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 &io_data) +{ + //This section not needed for the backplane type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t backplaneIpmiFruInv::buildChassisInfoArea( + std::vector &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 &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 &io_data) +{ + //This section not needed for the backplane type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t backplaneIpmiFruInv::buildMultiRecordInfoArea( + std::vector &io_data) +{ + //This section not needed for the backplane type + return IpmiFruInv::buildEmptyArea(io_data); +} + +errlHndl_t backplaneIpmiFruInv::addVpdData(std::vector &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 + (eepromVpdFruInfo); + if (getFruInfo) + { + TRACFCOMP(g_trac_ipmi, "IPMIFRUINV::setData - Sending IPMI FRU Inventory Data for target with HUID: [%08x]", + pTarget->getAttr()); + + 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 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& 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& 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& 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& 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 &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 &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 &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 &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 &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 &i_data); + + /** + * @brief Debug function to print data to console + * @param[in] data, The data to be printed + */ + void printRecordDebugData(const std::vector &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& io_data); + + /** + * @brief Pad data section to proper size + * + * @param[in/out] data, Data to be padded + */ + void padData(std::vector& 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& 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& 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 &i_internal_use_data, + const std::vector &i_chassis_data, + const std::vector &i_board_data, + const std::vector &i_product_data, + const std::vector &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 &i_internal_use_data, + const std::vector &i_chassis_data, + const std::vector &i_board_data, + const std::vector &i_product_data, + const std::vector &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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& 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& 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 &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 " + + + EEPROM_VPD_FRU_INFO + + i2cMasterPathphysical:sys-$sys/node-$node/membuf-$ctaur + port$dimmI2C->{$i+1}->{'i2c-master'}->{'i2c-port'} + devAddr0x$dimmI2C->{$i+1}->{'address'} + engine0 + byteAddrOffset0x01 + maxMemorySizeKB0x01 + writePageSize0x00 + writeCycleTime0x05 + fruId$ipmiFruid++ + + "; + + print" VPD_REC_NUM $pos @@ -4959,6 +4976,24 @@ sub addEepromsCentaur print " \n"; print " \n"; + if ($id_name eq "EEPROM_VPD_PRIMARY_INFO") + { + print " \n"; + print " EEPROM_VPD_FRU_INFO\n"; + print " \n"; + print " i2cMasterPathphysical:sys-$sys/node-$node/proc-$proc\n"; + print " port$port\n"; + print " devAddr$devAddr_hex\n"; + print " engine0\n"; + print " byteAddrOffset0x02\n"; + print " maxMemorySizeKB0x40\n"; + print " writePageSize0x80\n"; + print " writeCycleTime0x05\n"; + print " fruId$ipmiFruid++\n"; + print " \n"; + print " \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 @@ -1390,6 +1390,85 @@ ID for the sensor number returned with the elog. --> + + EEPROM_VPD_FRU_INFO + Information needed to address the EEPROM slaves for + IPMI Fru Inventory Purposes + + Structure to define the addressing for an I2C + slave device. + + i2cMasterPath + Entity path to the chip that contains the I2C + master + EntityPath + physical:sys-0 + + + port + Port from the I2C Master device. This is a 6-bit + value. + uint8_t + 0x80 + + + devAddr + Device address on the I2C bus. This is a 7-bit value, + but then shifted 1 bit left. + uint8_t + 0x80 + + + engine + I2C master engine. This is a 2-bit + value. + uint8_t + 0x80 + + + byteAddrOffset + The number of bytes a device requires to set its + internal address/offset. + uint8_t + 0x02 + + + maxMemorySizeKB + The number of kilobytes a device can hold. 'Zero' + value possible for some devices. + uint64_t + 0x0 + + + writePageSize + 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. + uint64_t + 0x0 + + + writeCycleTime + The amount of time in milliseconds a device requires + on the completion of a write command to update its + internal memory. + uint64_t + 0x0 + + + fruId + The IPMI Fru Inventory ID number. This must be a + unique number for every individual FRU within a + system. + uint8_t + 0x0 + + + non-volatile + + + + EEPROM_VPD_BACKUP_INFO Information needed to address the EERPROM slaves 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 @@ DUMMY_HEAP_ZERO_DEFAULT MSS_MEM_MC_IN_GROUP EEPROM_VPD_PRIMARY_INFO + EEPROM_VPD_FRU_INFO EEPROM_VPD_BACKUP_INFO EEPROM_SBE_PRIMARY_INFO EEPROM_SBE_BACKUP_INFO @@ -852,6 +853,7 @@ CDM_DOMAINNODE IPMI_SENSORS + EEPROM_VPD_FRU_INFO @@ -1357,6 +1359,7 @@ EEPROM_VPD_PRIMARY_INFO + EEPROM_VPD_FRU_INFO I2C_BUS_SPEED_ARRAY 400,0,0,0,0,0 @@ -1491,6 +1494,7 @@ EEPROM_VPD_PRIMARY_INFO + EEPROM_VPD_FRU_INFO VPD_REC_NUM MSS_EFF_VPD_VERSION 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(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++; -- cgit v1.2.1