summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBill Hoffa <wghoffa@us.ibm.com>2014-12-01 11:48:01 -0600
committerA. Patrick Williams III <iawillia@us.ibm.com>2014-12-14 17:34:09 -0600
commit8f0edf314a9c9198d95b0c7598e269cf8b7f232a (patch)
treeb6e09d66845e500bbaf036a40874aea461691044
parent9b53fb2a9083e62380f7bf2fb041378ef4de96ee (diff)
downloadtalos-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>
-rw-r--r--src/include/usr/ipmi/ipmifruinv.H41
-rw-r--r--src/include/usr/vpd/cvpdenums.H2
-rw-r--r--src/usr/hwas/hostbootIstep.C7
-rw-r--r--src/usr/hwpf/plat/fapiPlatMBvpdAccess.C2
-rw-r--r--src/usr/ipmi/ipmifruinv.C864
-rw-r--r--src/usr/ipmi/ipmifruinvprvt.H421
-rw-r--r--src/usr/ipmi/makefile1
-rwxr-xr-xsrc/usr/targeting/common/genHwsvMrwXml.pl37
-rw-r--r--src/usr/targeting/common/xmltohb/attribute_types.xml79
-rw-r--r--src/usr/targeting/common/xmltohb/target_types.xml4
-rw-r--r--src/usr/vpd/cvpd.H2
-rw-r--r--src/usr/vpd/spd.C12
-rwxr-xr-xsrc/usr/vpd/test/spdtest.H10
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++;
OpenPOWER on IntegriCloud