summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMeng Li <shlimeng@cn.ibm.com>2018-04-24 21:21:07 +0800
committerDaniel M. Crowell <dcrowell@us.ibm.com>2018-05-19 17:09:16 -0400
commitfd23ae8d50f307a1aca530d5a204d67261b58fea (patch)
tree61f2c614ef320538de97d46ead72cab829d56a90
parent42327316097c17cb3a0ef2ba212c2722121af861 (diff)
downloadtalos-hostboot-fd23ae8d50f307a1aca530d5a204d67261b58fea.tar.gz
talos-hostboot-fd23ae8d50f307a1aca530d5a204d67261b58fea.zip
Get SN from BMC and update into PVPD EEPROM
Resolves #135 Change-Id: I46b5c2208ed28822c6001a955f4056d976e79339 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/58010 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
-rw-r--r--src/include/usr/ipmi/ipmifruinv.H17
-rw-r--r--src/include/usr/ipmi/ipmiif.H5
-rw-r--r--src/usr/ipmi/ipmifru.C123
-rw-r--r--src/usr/ipmi/ipmifru.H26
-rw-r--r--src/usr/ipmi/ipmifruinv.C76
-rw-r--r--src/usr/ipmi/ipmifruinvprvt.H10
-rw-r--r--src/usr/vpd/HBconfig7
-rw-r--r--src/usr/vpd/pvpd.C3
-rwxr-xr-xsrc/usr/vpd/vpd.C62
-rw-r--r--src/usr/vpd/vpd.H3
10 files changed, 322 insertions, 10 deletions
diff --git a/src/include/usr/ipmi/ipmifruinv.H b/src/include/usr/ipmi/ipmifruinv.H
index 0df72462b..140395acb 100644
--- a/src/include/usr/ipmi/ipmifruinv.H
+++ b/src/include/usr/ipmi/ipmifruinv.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2014,2015 */
+/* Contributors Listed Below - COPYRIGHT 2014,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -40,6 +40,13 @@ namespace IPMIFRUINV
void setData(bool i_updateData=false);
/**
+ * @brief Reads the entire FRU inventory record
+ * @param[in] deviceId, The Record number to be read
+ * @param[o_data] The resultant pointer to the record data read
+ */
+ void readFruData(uint8_t i_deviceId, uint8_t *o_data);
+
+ /**
* @brief Clears fru data from BMC
* @param[in] fruId, The fruId to be cleared
*/
@@ -70,6 +77,14 @@ namespace IPMIFRUINV
io_potentialFrus,
bool i_updateData);
+ /**
+ * @brief Reads the Serial Number of the Product Info Area and returns it
+ * @param[in] fruId, The Record number to be read
+ * @return the pointer with the serial number - The caller is required
+ * to clear up this memory
+ */
+ char* getProductSN(uint8_t i_fruId);
+
};
#endif
diff --git a/src/include/usr/ipmi/ipmiif.H b/src/include/usr/ipmi/ipmiif.H
index 55546d13e..ee83a5923 100644
--- a/src/include/usr/ipmi/ipmiif.H
+++ b/src/include/usr/ipmi/ipmiif.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2012,2017 */
+/* Contributors Listed Below - COPYRIGHT 2012,2018 */
/* [+] Google Inc. */
/* [+] International Business Machines Corp. */
/* */
@@ -252,6 +252,9 @@ namespace IPMI
inline const command_t set_sel_time(void)
{ return std::make_pair(NETFUN_STORAGE, 0x49); }
+ inline const command_t read_fru_data(void)
+ { return std::make_pair(NETFUN_STORAGE, 0x11); }
+
inline const command_t write_fru_data(void)
{ return std::make_pair(NETFUN_STORAGE, 0x12); }
diff --git a/src/usr/ipmi/ipmifru.C b/src/usr/ipmi/ipmifru.C
index 4082f5bed..9f62e9a7f 100644
--- a/src/usr/ipmi/ipmifru.C
+++ b/src/usr/ipmi/ipmifru.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2014,2015 */
+/* Contributors Listed Below - COPYRIGHT 2014,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -48,6 +48,7 @@ extern trace_desc_t * g_trac_ipmi;
#ifdef CONFIG_BMC_IPMI
const uint8_t writeDataHeader = 3;
+const uint8_t readDataCmd = 4;
/**
* setup _start and handle barrier
@@ -107,6 +108,11 @@ void IpmiFRU::execute(void)
// done with the msg
msg_free(msg);
break;
+
+ case IPMIFRU::MSG_READ_FRU_DATA:
+ sendReadFruData(msg);
+ msg_respond(iv_msgQ, msg);
+ break;
};
} // while
} while (false);
@@ -191,6 +197,78 @@ void IpmiFRU::sendWriteFruData(msg_t *i_msg)
return;
} // sendWriteFruData
+void IpmiFRU::sendReadFruData(msg_t *i_msg)
+{
+ errlHndl_t err = NULL;
+
+ const uint8_t &l_deviceId = (i_msg->data[0] >> 32);
+ uint16_t l_offset = (i_msg->data[0] & 0xFFFFFFFF);
+ size_t l_dataSize = i_msg->data[1]; // FRU data size
+ uint8_t *l_data = static_cast<uint8_t*>(i_msg->extra_data);
+
+ uint16_t l_dataOffset = 0; // start at the l_data[0]
+ size_t l_fruSize = 0;
+
+ //TODO RTC 167956
+ const size_t l_maxBuffer = 16;
+
+ IPMI_TRAC(ENTER_MRK "sendReadFruData for dev 0x%x, size %d",
+ l_deviceId, l_dataSize);
+
+ while ((l_dataSize > 0) && (err == NULL))
+ {
+ size_t this_size = readDataCmd;
+ uint8_t *this_data = new uint8_t[this_size];
+
+ l_fruSize = std::min(l_dataSize, l_maxBuffer); // read data size
+
+ // copy device ID, offset, fru data to new buffer
+ this_data[0] = l_deviceId;
+ this_data[1] = l_offset & 0xFF;
+ this_data[2] = l_offset >> 8;
+ this_data[3] = l_fruSize;
+
+ IPMI_TRAC(INFO_MRK "sending read_fru_data fru size %d offset %d, "
+ "data offset %d",
+ l_fruSize, l_offset, l_dataOffset);
+
+ IPMI::completion_code cc = IPMI::CC_UNKBAD;
+ err = IPMI::sendrecv(IPMI::read_fru_data(), cc, this_size, this_data);
+ if (err)
+ {
+ IPMI_TRAC(ERR_MRK "Failed to send read_fru_data dev 0x%x",
+ l_deviceId);
+ // err is set, so we'll break out of the while loop
+ }
+ else if (cc != IPMI::CC_OK)
+ {
+ IPMI_TRAC(ERR_MRK "Failed to send read_fru_data dev 0x%x CC 0x%x",
+ l_deviceId, cc);
+ // stop sending; breaks out of the while loop
+ l_dataSize = 0;
+ } else {
+ this_size = this_data[0];
+ this_size = std::min(this_size, l_dataSize);
+ memcpy(l_data + l_dataOffset, &this_data[1], this_size);
+ // update the offsets for the next time around
+ l_offset += l_fruSize;
+ l_dataOffset += l_fruSize;
+ l_dataSize -= l_fruSize;
+ }
+
+ // delete the buffer returned from sendrecv
+ delete [] this_data;
+ }
+
+ if (err)
+ {
+ err->collectTrace(IPMI_COMP_NAME);
+ errlCommit(err, IPMI_COMP_ID);
+ }
+
+ return;
+} // sendReadFruData
+
namespace IPMIFRU
{
///
@@ -232,5 +310,48 @@ namespace IPMIFRU
return;
} // writeData
+ void readData(uint8_t i_deviceId, uint8_t *io_data)
+ {
+ IPMI_TRAC(ENTER_MRK "readData(deviceId 0x%x", i_deviceId);
+
+ // one message queue to the FRU thread
+ static msg_q_t mq = Singleton<IpmiFRU>::instance().msgQueue();
+ uint32_t i_offset = 0;
+ size_t i_dataSize = IPMIFRU::MAX_RECORD_SIZE;
+
+ // send data in msg to fru thread
+ msg_t *msg = msg_allocate();
+
+ msg->type = MSG_READ_FRU_DATA;
+ msg->data[0] = (static_cast<uint64_t>(i_deviceId) << 32) | i_offset;
+ msg->data[1] = i_dataSize;
+
+ //Setup data structure to pass in message to read FRU record
+ uint8_t *l_data = new uint8_t[i_dataSize];
+ memset(l_data, 0, i_dataSize);
+ memset(io_data, 0, i_dataSize);
+ msg->extra_data = l_data;
+
+ //Send the msg (sync) to the fru thread
+ int rc = msg_sendrecv(mq, msg);
+
+ //Return code is non-zero when the message queue is invalid
+ //or the message type is invalid.
+ if ( rc )
+ {
+ IPMI_TRAC(ERR_MRK "Failed (rc=%d) to send message to read"
+ "FRU Inventory Record: %d",
+ rc, i_deviceId);
+ delete [] l_data; // delete, since msg wasn't sent
+ return;
+ }
+
+ //Copy data from local data structure to output data structure
+ memcpy(&io_data[0], l_data, i_dataSize);
+ msg_free(msg);
+
+ return;
+ }
+
}; // IPMIFRU namespace
#endif // CONFIG_BMC_IPMI
diff --git a/src/usr/ipmi/ipmifru.H b/src/usr/ipmi/ipmifru.H
index 47e0459da..fe950a1bb 100644
--- a/src/usr/ipmi/ipmifru.H
+++ b/src/usr/ipmi/ipmifru.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2014 */
+/* Contributors Listed Below - COPYRIGHT 2014,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -34,6 +34,8 @@
#include <stdint.h>
#include <ipmi/ipmiif.H>
#include "ipmibt.H"
+#include <console/consoleif.H>
+
/**
*
@@ -44,12 +46,23 @@ namespace IPMIFRU
void writeData(uint8_t i_deviceId, uint8_t *i_data,
uint32_t i_dataSize, uint32_t i_offset = 0);
+ /*
+ * @brief Read the IPMI FRU Record
+ * @param[in] deviceId - The device ID to be read
+ * @param[in/out] data - The buffer pointing to the data read
+ */
+ void readData(uint8_t i_deviceId, uint8_t *io_data);
+
enum msg_type
{
MSG_WRITE_FRU_DATA, // async message - no reply
-
+ MSG_READ_FRU_DATA, // sync message - has reply
// Used to check range. Leave as last.
- MSG_LAST_TYPE = MSG_WRITE_FRU_DATA,
+ MSG_LAST_TYPE = MSG_READ_FRU_DATA,
+ };
+ enum record_info
+ {
+ MAX_RECORD_SIZE = 256,
};
}
@@ -96,6 +109,13 @@ class IpmiFRU
void sendWriteFruData(msg_t *i_msg);
/**
+ * @brief Handle a message with fru inventory data; msg is sync
+ * #param[in] i_msg
+ */
+ void sendReadFruData(msg_t *i_msg);
+
+
+ /**
* ipmi fru msg queue
*/
msg_q_t iv_msgQ;
diff --git a/src/usr/ipmi/ipmifruinv.C b/src/usr/ipmi/ipmifruinv.C
index b8f012709..267782e27 100644
--- a/src/usr/ipmi/ipmifruinv.C
+++ b/src/usr/ipmi/ipmifruinv.C
@@ -42,6 +42,7 @@
#include <assert.h>
#include <pnor/pnorif.H>
#include <ipmi/ipmi_reasoncodes.H>
+#include <console/consoleif.H>
extern trace_desc_t * g_trac_ipmi;
/**
@@ -1764,6 +1765,81 @@ void IPMIFRUINV::setData(bool i_updateData)
return;
}
+void IPMIFRUINV::readFruData(uint8_t i_deviceId, uint8_t *o_data)
+{
+ //Use IMPIFRU::readData to send data to service processor
+ // it will do any error handling and memory management
+ IPMIFRU::readData(i_deviceId, o_data);
+}
+
+char * IPMIFRUINV::getProductSN(uint8_t i_deviceId)
+{
+ //If we cannot read the product serial number, default is 0's (set below)
+ char * l_prodSN = NULL;
+
+ //First read the entire record that contains the SN
+ uint8_t *l_record = new uint8_t[IPMIFRU::MAX_RECORD_SIZE];
+ memset(l_record, 0, IPMIFRU::MAX_RECORD_SIZE);
+ readFruData(i_deviceId, l_record);
+
+ do {
+
+ //Code only supports version 1 of the FRU spec if for whatever reason
+ // we didn't get data, this would be 0
+ if (l_record[IPMIFRUINV::HEADER_FORMART_VERSION]
+ != IPMIFRUINV::SPEC_VERSION)
+ {
+ TRACFCOMP(g_trac_ipmi, "FW does not support IPMI FRU Version: %d",
+ l_record[1]);
+ break;
+ }
+
+ //Get the offset in the record pointed to the product info area
+ // (where the SN is located)
+ uint8_t l_prodInfoOffset = l_record[IPMIFRUINV::PRODUCT_INFO_AREA];
+
+ if (l_prodInfoOffset == IPMIFRUINV::RECORD_NOT_PRESENT)
+ {
+ TRACFCOMP(g_trac_ipmi, "Product Info Area Not present "
+ "- returning empty SN");
+ break;
+ }
+
+ //Start at the beginning of the Product Info Record and traverse to the
+ // serial number entry
+ uint8_t l_prodIndex = l_prodInfoOffset * RECORD_UNIT_OF_MEASUREMENT;
+ l_prodIndex += 3; //Version, Length Byte, Language Code
+
+ //MFG NAME Length + TYPELENGTH Byte
+ l_prodIndex += ((TYPELENGTH_SIZE_MASK&l_record[l_prodIndex]) + 1);
+
+ //Prod NAME Length + TYPELENGTH Byte
+ l_prodIndex += ((TYPELENGTH_SIZE_MASK&l_record[l_prodIndex]) + 1);
+
+ //Prod Part/Model Number Length + TYPELENGTH Byte
+ l_prodIndex += ((TYPELENGTH_SIZE_MASK&l_record[l_prodIndex]) + 1);
+
+ //Prod Version Length + TYPELEGNTH Byte
+ l_prodIndex += ((TYPELENGTH_SIZE_MASK&l_record[l_prodIndex]) + 1);
+
+ //Serial number located after Prod Version
+ uint8_t l_prodSNOffset = l_prodIndex;
+ uint8_t l_prodSNsize = TYPELENGTH_SIZE_MASK&l_record[l_prodSNOffset];
+
+ //Grab Serial Number as char array
+ l_prodSN = new char[l_prodSNsize+1];
+ memcpy(l_prodSN, &l_record[l_prodSNOffset+1], l_prodSNsize);
+ l_prodSN[l_prodSNsize] = '\0';
+
+ //Can skip the rest.
+
+ } while (0);
+
+
+ delete[] l_record;
+
+ return l_prodSN;
+}
void IPMIFRUINV::gatherClearData(const TARGETING::Target* i_pSys,
std::map<uint8_t,bool>& io_frusToClear)
diff --git a/src/usr/ipmi/ipmifruinvprvt.H b/src/usr/ipmi/ipmifruinvprvt.H
index 61c1ab7e7..488e49289 100644
--- a/src/usr/ipmi/ipmifruinvprvt.H
+++ b/src/usr/ipmi/ipmifruinvprvt.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2014,2017 */
+/* Contributors Listed Below - COPYRIGHT 2014,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -42,9 +42,17 @@ namespace IPMIFRUINV
COMMON_HEADER_FORMAT_SIZE = 8, //size in bytes
DEFAULT_CHASSIS_TYPE = 0x05,
DEFAULT_FRU_OFFSET = 0,
+ TYPELENGTH_SIZE_MASK = 0x3F, //bits 5:0 define num data bytes
MAX_ASCII_FIELD_SIZE = 0x3F, //size in bytes
MAX_RECORD_SIZE = 0xFF, //size in bytes
};
+
+ enum commonHeaderEntryOffsets
+ {
+ HEADER_FORMART_VERSION = 0,
+ PRODUCT_INFO_AREA = 4,
+ };
+
};
diff --git a/src/usr/vpd/HBconfig b/src/usr/vpd/HBconfig
index 70c533dd2..0d321192c 100644
--- a/src/usr/vpd/HBconfig
+++ b/src/usr/vpd/HBconfig
@@ -136,3 +136,10 @@ config PALMETTO_PASS1
default n
help
Palmetto pass1 specific changes
+
+config UPDATE_SN_FROM_BMC
+ default n
+ depends on BMC_IPMI
+ help
+ Read Planar serial number from BMC
+ via IPMI FRU Record 0
diff --git a/src/usr/vpd/pvpd.C b/src/usr/vpd/pvpd.C
index f58e795cd..371a87deb 100644
--- a/src/usr/vpd/pvpd.C
+++ b/src/usr/vpd/pvpd.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2013,2017 */
+/* Contributors Listed Below - COPYRIGHT 2013,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -274,6 +274,7 @@ errlHndl_t nodePresenceDetect(DeviceFW::OperationType i_opType,
pvpd_present = true; //node PVDP always returns present
}
#endif
+ VPD::updateSerialNumberFromBMC( i_target );
//Fsp sets PN/SN so if there is none, do it here
if(!INITSERVICE::spBaseServicesEnabled())
diff --git a/src/usr/vpd/vpd.C b/src/usr/vpd/vpd.C
index e50b673f5..585c168fa 100755
--- a/src/usr/vpd/vpd.C
+++ b/src/usr/vpd/vpd.C
@@ -40,6 +40,10 @@
#include "ipvpd.H"
#include "dvpd.H"
#include <map>
+#include <console/consoleif.H>
+#include <initservice/istepdispatcherif.H>
+#include <ipmi/ipmifruinv.H>
+
// ----------------------------------------------
// Trace - defined in vpd_common
@@ -465,7 +469,63 @@ void setPartAndSerialNumberAttributes( TARGETING::Target * i_target )
}
-
+// ------------------------------------------------------------------
+// setPartAndSerialNumberAttributes
+// ------------------------------------------------------------------
+void updateSerialNumberFromBMC( TARGETING::Target * i_nodetarget )
+{
+#ifdef CONFIG_UPDATE_SN_FROM_BMC
+ errlHndl_t l_errl = NULL;
+ size_t l_vpdSize = 0;
+
+ //Get Product Serial Number from Backplane
+ char* l_sn_prod = NULL;
+ l_sn_prod = IPMIFRUINV::getProductSN(0);
+ if (l_sn_prod != NULL)
+ {
+ TRACFCOMP(g_trac_vpd, "Got system serial number from BMC.");
+ TRACFCOMP(g_trac_vpd, "SN from BMC is: %s", l_sn_prod);
+
+ l_errl = deviceRead(i_nodetarget, NULL, l_vpdSize,
+ DEVICE_PVPD_ADDRESS( PVPD::OSYS, PVPD::SS ));
+
+ if(l_errl == NULL)
+ {
+ uint8_t l_vpddata[l_vpdSize];
+
+ l_errl = deviceRead(i_nodetarget, l_vpddata, l_vpdSize,
+ DEVICE_PVPD_ADDRESS( PVPD::OSYS, PVPD::SS ));
+
+ if(l_errl == NULL)
+ {
+ TRACFCOMP(g_trac_vpd, "SN in PVPD::OSYS:SS: %s, size: %d", l_vpddata, l_vpdSize);
+
+ if (strncmp(l_sn_prod, l_vpddata, l_vpdSize) != 0)
+ {
+ l_errl = deviceWrite(i_nodetarget, l_sn_prod, l_vpdSize,
+ DEVICE_PVPD_ADDRESS( PVPD::OSYS, PVPD::SS ));
+ CONSOLE::displayf(NULL, "updated SN from BMC into PVPD.");
+ CONSOLE::flush();
+ CONSOLE::displayf(NULL, "Need a reboot.");
+ CONSOLE::flush();
+ INITSERVICE::requestReboot();
+ }
+ }
+ }
+
+ if(l_errl)
+ {
+ ERRORLOG::errlCommit(l_errl,VPD_COMP_ID);
+ }
+
+ //getProductSN requires the caller to delete the char array
+ delete[] l_sn_prod;
+ l_sn_prod = NULL;
+
+ TRACFCOMP(g_trac_vpd, "End updateSerialNumberFromBMC.");
+ }
+#endif
+}
// ------------------------------------------------------------------
// getPnAndSnRecordAndKeywords
diff --git a/src/usr/vpd/vpd.H b/src/usr/vpd/vpd.H
index 22dd062fc..2753a476d 100644
--- a/src/usr/vpd/vpd.H
+++ b/src/usr/vpd/vpd.H
@@ -258,6 +258,7 @@ errlHndl_t getPnAndSnRecordAndKeywords( TARGETING::Target * i_target,
vpdKeyword & io_partKeyword,
vpdKeyword & io_serialKeyword);
-}; //end VPD namespace
+void updateSerialNumberFromBMC( TARGETING::Target * i_nodetarget );
+}; //end VPD namespace
#endif
OpenPOWER on IntegriCloud