Blob Blame History Raw
From 68a4d47bdfbe4ebcc048e9f08862e2639bbec2e7 Mon Sep 17 00:00:00 2001
From: Ankit Kumar <ankit@linux.vnet.ibm.com>
Date: Thu, 21 Sep 2017 18:34:20 +0530
Subject: [PATCH 3/3] lsmcode: Support firmware info on BMC based Power9 system

P9 system supports various service processor stack like FSP based system,
SMC system, AMI with OpenBMC stack etc. Some of these systems supports full
ipmi stack and few other systems doesn't (at least for now).

lsmcode uses ipmi interface (ipmitool fru) to get firmware information. It
fails on some of the P9 system where we donot have full ipmi support.

Recently we added support in OPAL to export firmware information via device
tree for P9 BMC systems (/ibm,firmware-versions node). Even recent hostboot
firmware on P8 BMC system exports these information via mini device tree.

This patch enables lsmcode to collect firmware information via device tree.

Sample output on Power9 system after applying this patch:
./lsmcode
Version of System Firmware :
 Product Name          : OpenPOWER Firmware
 Product Version       : open-power-firestone-v1.17-101-g1c57f18-dirty
 Product Extra         : 	occ-site_local-akshay-28f2cec-dirty
 Product Extra         : 	skiboot-5.6.0-158-ga1e0a047b2a0
 Product Extra         : 	buildroot-2017.02.2-7-g23118ce
 Product Extra         : 	capp-ucode-9c73e9f
 Product Extra         : 	petitboot-v1.4.3-pa6836f6
 Product Extra         : 	hostboot-binaries-711147e
 Product Extra         : 	machine-xml-2494a43
 Product Extra         : 	hostboot-695bd89
 Product Extra         : 	linux-4.11.6-openpower1-p1e59f24

root@fir02:/home/ankit/lsvpd# ./lsmcode --All
sys0!system: open-power-firestone-v1.17-101-g1c57f18-dirty
sg0 0:0:0:0 sda !ST1000NX0313.BE33

Sample output on Power8 system after applying this patch:
./lsmcode
Version of System Firmware :
 Product Name          : OpenPOWER Firmware
 Product Version       : open-power-firestone-v1.17-101-g1c57f18-dirty
 Product Extra         : 	buildroot-2017.02.2-7-g23118ce
 Product Extra         : 	skiboot-5.6.0-158-ga1e0a047b2a0
 Product Extra         : 	hostboot-695bd89
 Product Extra         : 	linux-4.11.6-openpower1-p1e59f24
 Product Extra         : 	petitboot-v1.4.3-pa6836f6
 Product Extra         : 	machine-xml-2494a43
 Product Extra         : 	occ-site_local-28f2cec-dirty

root@fir:lsvpd# ./lsmcode --All
sys0!system: open-power-firestone-v1.17-101-g1c57f18-dirty
sg0 0:0:0:0 sda !ST1000NX0313.BE33

Signed-off-by: Ankit Kumar <ankit@linux.vnet.ibm.com>
[Updated description, Changed "product version" property name - Vasant]
Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
---
 src/output/lsmcode.cpp | 135 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 129 insertions(+), 6 deletions(-)

diff --git a/src/output/lsmcode.cpp b/src/output/lsmcode.cpp
index a8d9f11..c96a176 100644
--- a/src/output/lsmcode.cpp
+++ b/src/output/lsmcode.cpp
@@ -23,6 +23,7 @@
 
 #include <rtascollector.hpp>
 #include <platformcollector.hpp>
+#include <devicetreecollector.hpp>
 #include <libvpd-2/vpdretriever.hpp>
 #include <libvpd-2/component.hpp>
 #include <libvpd-2/dataitem.hpp>
@@ -39,6 +40,7 @@
 #define _GNU_SOURCE // for getopt_long
 #endif
 
+#include <dirent.h>
 #include <unistd.h>
 #include <getopt.h>
 #include <zlib.h>
@@ -50,6 +52,9 @@
 #include <iomanip>
 #include <limits.h>
 
+/* Firmware information device tree node on PowerNV system */
+#define FW_VERSION_DT_NODE DEVTREEPATH"/ibm,firmware-versions/"
+
 /* IPMI tool */
 #define CMD_IPMITOOL	"ipmitool"
 
@@ -152,6 +157,117 @@ parse_err:
 	return string();
 }
 
+static string read_dt_property(const string& path, const string& attrName)
+{
+	struct stat info;
+	string fullPath;
+	string ret = "";
+
+	ostringstream os;
+	os << path << "/" << attrName;
+	fullPath = os.str( );
+
+	if (stat(fullPath.c_str( ), &info) != 0) {
+		ostringstream os;
+		if (errno != ENOENT) {
+			os << "Error statting " << fullPath << ", errno: " << errno;
+			Logger().log( os.str( ), LOG_ERR );
+		}
+		return ret;
+	}
+
+	ifstream attrIn;
+	attrIn.exceptions ( std::ifstream::failbit | std::ifstream::badbit );
+	try {
+		attrIn.open( fullPath.c_str( ) );
+	}
+	catch (std::ifstream::failure e) {
+		ostringstream os;
+		os << "Error opening " << fullPath;
+		Logger().log(os.str( ), LOG_WARNING);
+		return ret;
+	}
+
+	if (attrIn) {
+		char * strBuf;
+		try
+		{
+			strBuf = new char [ info.st_size + 1 ];
+		}
+		catch (exception& e)
+		{
+			return ret;
+		}
+		memset( strBuf, '\0', info.st_size + 1 );
+		attrIn.read( strBuf, info.st_size );
+		ret = strBuf;
+		attrIn.close( );
+		delete [] strBuf;
+	}
+	return ret;
+}
+
+/* Get system firmware information on BMC based system via device tree */
+static string bmc_get_fw_dt_info(void)
+{
+	string fwdata, tag, val, prod_ver = "", prod_extra = "";
+	struct dirent *ent;
+	DIR * pDBdir = NULL;
+	/* Properties to ignore from DT/ibm,firmware-versions node */
+	const char *ignore_dt[] = {"phandle", "name"};
+	int i;
+	bool ignore_dt_flag = false;
+
+	pDBdir = opendir(FW_VERSION_DT_NODE);
+	if (pDBdir == NULL) {
+		stringstream os;
+		os << "Error opening directory " << FW_VERSION_DT_NODE << endl;
+		Logger().log(os.str( ), LOG_ERR);
+		return string("");
+	}
+
+	fwdata = string("\n Product Name          : OpenPOWER Firmware\n");
+	while ((ent = readdir( pDBdir )) != NULL) {
+		string fname = ent->d_name;
+		for (i = 0; i < (int)(sizeof(ignore_dt)/sizeof(char *)); i++) {
+			if (fname.compare(string(ignore_dt[i])) == 0) {
+				ignore_dt_flag = true;
+				break;
+			}
+		}
+
+		if (ignore_dt_flag == true) {
+			ignore_dt_flag = false;
+			continue;
+		}
+
+		/*
+		 * Looks like some system has open-power property and some
+		 * other has "IBM" property. Lets use one of these property
+		 * for Product Version.
+		 */
+		if (fname.compare("IBM") == 0 || fname.compare("open-power") == 0) {
+			if (prod_ver == string("")) {
+				tag = string(" Product Version       : ");
+				prod_ver = read_dt_property(string(FW_VERSION_DT_NODE), fname);
+				if (prod_ver == string(""))
+					continue;
+				prod_ver = tag + fname + string("-") + prod_ver + string("\n");
+				continue;
+			}
+		}
+
+		tag = string(" Product Extra         : \t");
+		val = read_dt_property(string(FW_VERSION_DT_NODE), fname);
+		if (val == string(""))
+			continue;
+		prod_extra = prod_extra + tag + fname + string("-") +  val + string("\n");
+	}
+
+	fwdata = fwdata + prod_ver + prod_extra;
+	return fwdata;
+}
+
 /* Get production version */
 static string bmc_get_product_version(string fwData)
 {
@@ -181,13 +297,20 @@ bool printSystem( const vector<Component*>& leaves )
 	 * based system. Hence we don't store this information in VPD db.
 	 */
 	if (PlatformCollector::isBMCBasedSystem()) {
-		string ipmitool = get_ipmitool_path();
-		if (ipmitool.empty())
-			return false;
+		string fwData;
+		if (!access(FW_VERSION_DT_NODE, F_OK | R_OK)) {
+			fwData = bmc_get_fw_dt_info();
+			if (fwData.empty())
+				return false;
+		} else {
+			string ipmitool = get_ipmitool_path();
+			if (ipmitool.empty())
+				return false;
 
-		string fwData = bmc_get_fw_fru_info(ipmitool);
-		if (fwData.empty())
-			return false;
+			fwData = bmc_get_fw_fru_info(ipmitool);
+			if (fwData.empty())
+				return false;
+		}
 
 		if ( all ) {
 			string pVersion = bmc_get_product_version(fwData);
-- 
2.14.3