Add a helper function findFruAreaLocationAndField to
updateFRUProperty
Refactoring updateFRUProperty function and created a new helper
function findFruAreaLocationAndField. Moved this function to
fru_utils.cpp as it is common for all fru-device deamons and
avoid code duplication.
This patch is created based on suggestion on the below patch.
https://gerrit.openbmc.org/c/openbmc/entity-manager/+/51555
TESTED : Built Facebook YosemiteV2 images and loaded
on the target hardware. Verified all the fru's read and write.
Signed-off-by: Kumar Thangavel <thangavel.k@hcl.com>
Change-Id: I82265e66ea5db10003e96978979250ea45c2052d
diff --git a/include/fru_utils.hpp b/include/fru_utils.hpp
index e50b580..f1d8e94 100644
--- a/include/fru_utils.hpp
+++ b/include/fru_utils.hpp
@@ -62,6 +62,14 @@
fruAreaMultirecord
};
+struct FruArea
+{
+ size_t start; // Fru Area Start offset
+ size_t size; // Fru Area Size
+ size_t end; // Fru Area end offset
+ size_t updateFieldLoc; // Fru Area update Field Location
+};
+
const std::vector<std::string> fruAreaNames = {"INTERNAL", "CHASSIS", "BOARD",
"PRODUCT", "MULTIRECORD"};
const std::regex nonAsciiRegex("[^\x01-\x7f]");
@@ -157,3 +165,15 @@
/// \param area - the area
/// \return the field offset
unsigned int getHeaderAreaFieldOffset(fruAreas area);
+
+/// \brief Iterate fruArea Names and find offset/location and fields and size of
+/// properties
+/// \param fruData - vector to store fru data
+/// \param propertyName - fru property Name
+/// \param fruAreaParams - struct to have fru Area paramteters like length,
+/// size. \return true if fru field is found, fruAreaParams are updated with
+/// fruArea and field info.
+bool findFruAreaLocationAndField(std::vector<uint8_t>& fruData,
+ const std::string& propertyName,
+ struct FruArea& fruAreaParams,
+ size_t& fruDataIter);
diff --git a/src/fru_device.cpp b/src/fru_device.cpp
index ed55e4a..50f1e4b 100644
--- a/src/fru_device.cpp
+++ b/src/fru_device.cpp
@@ -1108,100 +1108,20 @@
return false;
}
- const std::vector<std::string>* fruAreaFieldNames = nullptr;
+ struct FruArea fruAreaParams{};
+ size_t fruDataIter = 0;
- uint8_t fruAreaOffsetFieldValue = 0;
- size_t offset = 0;
- std::string areaName = propertyName.substr(0, propertyName.find('_'));
- std::string propertyNamePrefix = areaName + "_";
- auto it = std::find(fruAreaNames.begin(), fruAreaNames.end(), areaName);
- if (it == fruAreaNames.end())
+ if (!findFruAreaLocationAndField(fruData, propertyName, fruAreaParams,
+ fruDataIter))
{
- std::cerr << "Can't parse area name for property " << propertyName
- << " \n";
- return false;
- }
- fruAreas fruAreaToUpdate = static_cast<fruAreas>(it - fruAreaNames.begin());
- fruAreaOffsetFieldValue =
- fruData[getHeaderAreaFieldOffset(fruAreaToUpdate)];
- switch (fruAreaToUpdate)
- {
- case fruAreas::fruAreaChassis:
- offset = 3; // chassis part number offset. Skip fixed first 3 bytes
- fruAreaFieldNames = &chassisFruAreas;
- break;
- case fruAreas::fruAreaBoard:
- offset = 6; // board manufacturer offset. Skip fixed first 6 bytes
- fruAreaFieldNames = &boardFruAreas;
- break;
- case fruAreas::fruAreaProduct:
- // Manufacturer name offset. Skip fixed first 3 product fru bytes
- // i.e. version, area length and language code
- offset = 3;
- fruAreaFieldNames = &productFruAreas;
- break;
- default:
- std::cerr << "Don't know how to handle property " << propertyName
- << " \n";
- return false;
- }
- if (fruAreaOffsetFieldValue == 0)
- {
- std::cerr << "FRU Area for " << propertyName << " not present \n";
+ std::cerr << "findFruAreaLocationAndField failed \n";
return false;
}
- size_t fruAreaStart = fruAreaOffsetFieldValue * fruBlockSize;
- size_t fruAreaSize = fruData[fruAreaStart + 1] * fruBlockSize;
- size_t fruAreaEnd = fruAreaStart + fruAreaSize;
- size_t fruDataIter = fruAreaStart + offset;
- size_t skipToFRUUpdateField = 0;
ssize_t fieldLength = 0;
- bool found = false;
- for (const auto& field : *fruAreaFieldNames)
- {
- skipToFRUUpdateField++;
- if (propertyName == propertyNamePrefix + field)
- {
- found = true;
- break;
- }
- }
- if (!found)
- {
- std::size_t pos = propertyName.find(fruCustomFieldName);
- if (pos == std::string::npos)
- {
- std::cerr << "PropertyName doesn't exist in FRU Area Vectors: "
- << propertyName << "\n";
- return false;
- }
- std::string fieldNumStr =
- propertyName.substr(pos + fruCustomFieldName.length());
- size_t fieldNum = std::stoi(fieldNumStr);
- if (fieldNum == 0)
- {
- std::cerr << "PropertyName not recognized: " << propertyName
- << "\n";
- return false;
- }
- skipToFRUUpdateField += fieldNum;
- }
-
- for (size_t i = 1; i < skipToFRUUpdateField; i++)
- {
- fieldLength = getFieldLength(fruData[fruDataIter]);
- if (fieldLength < 0)
- {
- break;
- }
- fruDataIter += 1 + fieldLength;
- }
- size_t fruUpdateFieldLoc = fruDataIter;
-
// Push post update fru field bytes to a vector
- fieldLength = getFieldLength(fruData[fruUpdateFieldLoc]);
+ fieldLength = getFieldLength(fruData[fruAreaParams.updateFieldLoc]);
if (fieldLength < 0)
{
std::cerr << "Property " << propertyName << " not present \n";
@@ -1212,9 +1132,9 @@
size_t endOfFieldsLoc = 0;
while ((fieldLength = getFieldLength(fruData[fruDataIter])) >= 0)
{
- if (fruDataIter >= (fruAreaStart + fruAreaSize))
+ if (fruDataIter >= (fruAreaParams.start + fruAreaParams.size))
{
- fruDataIter = fruAreaStart + fruAreaSize;
+ fruDataIter = fruAreaParams.start + fruAreaParams.size;
break;
}
fruDataIter += 1 + fieldLength;
@@ -1249,8 +1169,9 @@
// check FRU area size
size_t fruAreaDataSize =
- ((fruUpdateFieldLoc - fruAreaStart + 1) + restFRUAreaFieldsData.size());
- size_t fruAreaAvailableSize = fruAreaSize - fruAreaDataSize;
+ ((fruAreaParams.updateFieldLoc - fruAreaParams.start + 1) +
+ restFRUAreaFieldsData.size());
+ size_t fruAreaAvailableSize = fruAreaParams.size - fruAreaDataSize;
if ((updatePropertyReqLen + 1) > fruAreaAvailableSize)
{
@@ -1259,10 +1180,11 @@
// round size to 8-byte blocks
newFRUAreaSize =
((newFRUAreaSize - 1) / fruBlockSize + 1) * fruBlockSize;
- size_t newFRUDataSize = fruData.size() + newFRUAreaSize - fruAreaSize;
+ size_t newFRUDataSize =
+ fruData.size() + newFRUAreaSize - fruAreaParams.size;
fruData.resize(newFRUDataSize);
- fruAreaSize = newFRUAreaSize;
- fruAreaEnd = fruAreaStart + fruAreaSize;
+ fruAreaParams.size = newFRUAreaSize;
+ fruAreaParams.end = fruAreaParams.start + fruAreaParams.size;
#else
std::cerr << "FRU field length: " << updatePropertyReqLen + 1
<< " should not be greater than available FRU area size: "
@@ -1273,21 +1195,21 @@
// write new requested property field length and data
constexpr uint8_t newTypeLenMask = 0xC0;
- fruData[fruUpdateFieldLoc] =
+ fruData[fruAreaParams.updateFieldLoc] =
static_cast<uint8_t>(updatePropertyReqLen | newTypeLenMask);
- fruUpdateFieldLoc++;
+ fruAreaParams.updateFieldLoc++;
std::copy(updatePropertyReq.begin(), updatePropertyReq.end(),
- fruData.begin() + fruUpdateFieldLoc);
+ fruData.begin() + fruAreaParams.updateFieldLoc);
// Copy remaining data to main fru area - post updated fru field vector
- restFRUFieldsLoc = fruUpdateFieldLoc + updatePropertyReqLen;
+ restFRUFieldsLoc = fruAreaParams.updateFieldLoc + updatePropertyReqLen;
size_t fruAreaDataEnd = restFRUFieldsLoc + restFRUAreaFieldsData.size();
std::copy(restFRUAreaFieldsData.begin(), restFRUAreaFieldsData.end(),
fruData.begin() + restFRUFieldsLoc);
// Update final fru with new fru area length and checksum
unsigned int nextFRUAreaNewLoc = updateFRUAreaLenAndChecksum(
- fruData, fruAreaStart, fruAreaDataEnd, fruAreaEnd);
+ fruData, fruAreaParams.start, fruAreaDataEnd, fruAreaParams.end);
#ifdef ENABLE_FRU_AREA_RESIZE
++nextFRUAreaNewLoc;
diff --git a/src/fru_utils.cpp b/src/fru_utils.cpp
index bc59af8..e030ac8 100644
--- a/src/fru_utils.cpp
+++ b/src/fru_utils.cpp
@@ -784,3 +784,111 @@
return ret;
}
+
+// Iterate FruArea Names and find start and size of the fru area that contains
+// the propertyName and the field start location for the property. fruAreaParams
+// struct values fruAreaStart, fruAreaSize, fruAreaEnd, fieldLoc values gets
+// updated/returned if successful.
+
+bool findFruAreaLocationAndField(std::vector<uint8_t>& fruData,
+ const std::string& propertyName,
+ struct FruArea& fruAreaParams,
+ size_t& fruDataIter)
+{
+ const std::vector<std::string>* fruAreaFieldNames = nullptr;
+
+ uint8_t fruAreaOffsetFieldValue = 0;
+ size_t offset = 0;
+ std::string areaName = propertyName.substr(0, propertyName.find('_'));
+ std::string propertyNamePrefix = areaName + "_";
+ auto it = std::find(fruAreaNames.begin(), fruAreaNames.end(), areaName);
+ if (it == fruAreaNames.end())
+ {
+ std::cerr << "Can't parse area name for property " << propertyName
+ << " \n";
+ return false;
+ }
+ fruAreas fruAreaToUpdate = static_cast<fruAreas>(it - fruAreaNames.begin());
+ fruAreaOffsetFieldValue =
+ fruData[getHeaderAreaFieldOffset(fruAreaToUpdate)];
+ switch (fruAreaToUpdate)
+ {
+ case fruAreas::fruAreaChassis:
+ offset = 3; // chassis part number offset. Skip fixed first 3 bytes
+ fruAreaFieldNames = &chassisFruAreas;
+ break;
+ case fruAreas::fruAreaBoard:
+ offset = 6; // board manufacturer offset. Skip fixed first 6 bytes
+ fruAreaFieldNames = &boardFruAreas;
+ break;
+ case fruAreas::fruAreaProduct:
+ // Manufacturer name offset. Skip fixed first 3 product fru bytes
+ // i.e. version, area length and language code
+ offset = 3;
+ fruAreaFieldNames = &productFruAreas;
+ break;
+ default:
+ std::cerr << "Invalid PropertyName " << propertyName << " \n";
+ return false;
+ }
+ if (fruAreaOffsetFieldValue == 0)
+ {
+ std::cerr << "FRU Area for " << propertyName << " not present \n";
+ return false;
+ }
+
+ fruAreaParams.start = fruAreaOffsetFieldValue * fruBlockSize;
+ fruAreaParams.size = fruData[fruAreaParams.start + 1] * fruBlockSize;
+ fruAreaParams.end = fruAreaParams.start + fruAreaParams.size;
+ fruDataIter = fruAreaParams.start + offset;
+ size_t skipToFRUUpdateField = 0;
+ ssize_t fieldLength = 0;
+
+ bool found = false;
+ for (const auto& field : *fruAreaFieldNames)
+ {
+ skipToFRUUpdateField++;
+ if (propertyName == propertyNamePrefix + field)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ std::size_t pos = propertyName.find(fruCustomFieldName);
+ if (pos == std::string::npos)
+ {
+ std::cerr << "PropertyName doesn't exist in FRU Area Vectors: "
+ << propertyName << "\n";
+ return false;
+ }
+ std::string fieldNumStr =
+ propertyName.substr(pos + fruCustomFieldName.length());
+ size_t fieldNum = std::stoi(fieldNumStr);
+ if (fieldNum == 0)
+ {
+ std::cerr << "PropertyName not recognized: " << propertyName
+ << "\n";
+ return false;
+ }
+ skipToFRUUpdateField += fieldNum;
+ }
+
+ for (size_t i = 1; i < skipToFRUUpdateField; i++)
+ {
+ if (fruDataIter < fruData.size())
+ {
+ fieldLength = getFieldLength(fruData[fruDataIter]);
+
+ if (fieldLength < 0)
+ {
+ break;
+ }
+ fruDataIter += 1 + fieldLength;
+ }
+ }
+ fruAreaParams.updateFieldLoc = fruDataIter;
+
+ return true;
+}