Add additional Redfish Processor properties

This commit adds the following inventory properties for the
Processor resource in bmcweb:

a) LocationCode, a free form, implementation-defined string
to provide the location of the processor. This is needed so an
implementation can identify the processor via system diagrams.

b) SparePartNumber, also field-replaceable unit (FRU) Part
Number, is a part number that identifies the FRU for replacement
specifically ordering of a new part.

c) PartNumber, also called a Marketing Number, describes a
specific part within a specific system among a manufactures various
product lines. These numbers tell IT infrastructure technicians
exactly which parts are included in their servers, storage and
networking equipment.

These properties are essential to locate and replace the FRU.

Validator has been executed and no new error has been found.

Sample Output:
{
  "@odata.id": "/redfish/v1/Systems/system/Processors/cpu0",
  "@odata.type": "#Processor.v1_11_0.Processor",
  "Id": "cpu0",
  "Location": {
    "PartLocation": {
      "ServiceLabel": "Ufcs-P0-C15"
    }
  },
  "Manufacturer": "",
  "Model": "AB41",
  "Name": "Processor",
  "PartNumber": "2345678",
  "ProcessorType": "CPU",
  "SerialNumber": "YLAB41010000",
  "Status": {
    "Health": "OK",
    "HealthRollup": "OK",
    "State": "Absent"
  }
}

Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
Change-Id: Ifc0e13fd7eb94e86eade223608a1ecad2487ed37
diff --git a/redfish-core/lib/processor.hpp b/redfish-core/lib/processor.hpp
index e85b616..ddb88c6 100644
--- a/redfish-core/lib/processor.hpp
+++ b/redfish-core/lib/processor.hpp
@@ -281,6 +281,30 @@
                         }
                     }
                 }
+                else if (property.first == "PartNumber")
+                {
+                    const std::string* partNumber =
+                        std::get_if<std::string>(&property.second);
+
+                    if (partNumber == nullptr)
+                    {
+                        messages::internalError(aResp->res);
+                        return;
+                    }
+                    aResp->res.jsonValue["PartNumber"] = *partNumber;
+                }
+                else if (property.first == "SparePartNumber")
+                {
+                    const std::string* sparePartNumber =
+                        std::get_if<std::string>(&property.second);
+
+                    if (sparePartNumber == nullptr)
+                    {
+                        messages::internalError(aResp->res);
+                        return;
+                    }
+                    aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
+                }
             }
         },
         service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
@@ -544,6 +568,47 @@
         "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig");
 }
 
+/**
+ * @brief Fill out location info of a processor by
+ * requesting data from the given D-Bus object.
+ *
+ * @param[in,out]   aResp       Async HTTP response.
+ * @param[in]       service     D-Bus service to query.
+ * @param[in]       objPath     D-Bus object to query.
+ */
+inline void getCpuLocationCode(std::shared_ptr<AsyncResp> aResp,
+                               const std::string& service,
+                               const std::string& objPath)
+{
+    BMCWEB_LOG_DEBUG << "Get Cpu Location Data";
+    crow::connections::systemBus->async_method_call(
+        [objPath,
+         aResp{std::move(aResp)}](const boost::system::error_code ec,
+                                  const std::variant<std::string>& property) {
+            if (ec)
+            {
+                BMCWEB_LOG_DEBUG << "DBUS response error";
+                messages::internalError(aResp->res);
+                return;
+            }
+
+            const std::string* value = std::get_if<std::string>(&property);
+
+            if (value == nullptr)
+            {
+                // illegal value
+                BMCWEB_LOG_DEBUG << "Location code value error";
+                messages::internalError(aResp->res);
+                return;
+            }
+
+            aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
+                *value;
+        },
+        service, objPath, "org.freedesktop.DBus.Properties", "Get",
+        "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode");
+}
+
 inline void getProcessorData(std::shared_ptr<AsyncResp> aResp,
                              const std::string& processorId)
 {
@@ -605,6 +670,11 @@
                             getCpuConfigData(aResp, processorId, serviceName,
                                              objectPath);
                         }
+                        else if (interface == "xyz.openbmc_project.Inventory."
+                                              "Decorator.LocationCode")
+                        {
+                            getCpuLocationCode(aResp, serviceName, objectPath);
+                        }
                     }
                 }
                 return;
@@ -617,10 +687,11 @@
         "/xyz/openbmc_project/object_mapper",
         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
         "/xyz/openbmc_project/inventory", 0,
-        std::array<const char*, 5>{
+        std::array<const char*, 6>{
             "xyz.openbmc_project.Inventory.Decorator.Asset",
             "xyz.openbmc_project.Inventory.Decorator.Revision",
             "xyz.openbmc_project.Inventory.Item.Cpu",
+            "xyz.openbmc_project.Inventory.Decorator.LocationCode",
             "xyz.openbmc_project.Inventory.Item.Accelerator",
             "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"});
 }
@@ -973,7 +1044,7 @@
             return;
         }
         const std::string& processorId = params[0];
-        res.jsonValue["@odata.type"] = "#Processor.v1_9_0.Processor";
+        res.jsonValue["@odata.type"] = "#Processor.v1_11_0.Processor";
         res.jsonValue["@odata.id"] =
             "/redfish/v1/Systems/system/Processors/" + processorId;