Support building p10 PNOR images

Implements initial experimental support for building P10 PNOR images using
GCC8 (host and cross compiler) as the toolchain

- Introduced rainier configuration files
- Added p10 specific packages for sbe, hcode, hostboot, occ
- Pointed at starting commits for various pacakges to build op-build for p10
- Created various patches to fully compile all packages, to be removed
  when package owners have time to address them
- Generally updated package configurations to support p10 and p10 package
  variants

Signed-off-by: Nick Bofferding <bofferdn@us.ibm.com>
diff --git a/openpower/package/hostboot-p10/0001-mrw-parser-initial-fixes.patch b/openpower/package/hostboot-p10/0001-mrw-parser-initial-fixes.patch
new file mode 100644
index 0000000..e014d7d
--- /dev/null
+++ b/openpower/package/hostboot-p10/0001-mrw-parser-initial-fixes.patch
@@ -0,0 +1,2216 @@
+From c69095d5359b800068c258819014f0bb684046f6 Mon Sep 17 00:00:00 2001
+From: Roland Veloz <rveloz@us.ibm.com>
+Date: Fri, 6 Sep 2019 13:52:32 -0500
+Subject: [PATCH] P10 MRW parsing: Changes to the parser scripts
+
+This commit deals with refactoring and modularizing the processMrw.pl
+and Targets.pm scripts.  This commit is not about the artifact that
+gets produced by these files but the act of parsing an MRW file.
+
+Change-Id: I359afeebd9aa00ec6db2857a03ba0d9684c0858e
+RTC: 215164
+---
+ src/usr/targeting/common/Targets.pm    |  637 +++++++++++------
+ src/usr/targeting/common/processMrw.pl | 1183 +++++++++++++++++++++-----------
+ 2 files changed, 1218 insertions(+), 602 deletions(-)
+
+diff --git a/src/usr/targeting/common/Targets.pm b/src/usr/targeting/common/Targets.pm
+index dfd65d6..fb0bcbb 100644
+--- a/src/usr/targeting/common/Targets.pm
++++ b/src/usr/targeting/common/Targets.pm
+@@ -91,10 +91,29 @@ my %maxInstance = (
+     "SMPGROUP"      => 8,
+     "OMIC"          => 6,
+ );
++
++#--------------------------------------------------
++# @brief The constructor for the object Target
++#--------------------------------------------------
+ sub new
+ {
+     my $class = shift;
+     my $self  = {
++        # The following data are associated with the
++        # user command line options
++        build           => "hb",  # default to HB
++        force           => 0,
++        serverwiz_file  => "",    # input xml file
++        serverwiz_dir   => "",    # directory of input xml file
++        debug           => 0,
++        system_config   => "",
++        output_file     => "",
++        version         => 0,
++        report          => 0,
++        run_self_test   => 0,     # run internal test
++
++        # The following data are associated with the
++        # xml itself
+         xml          => undef,
+         data         => undef,
+         targeting    => undef,
+@@ -103,13 +122,11 @@ sub new
+         UNIT_COUNTS  => undef,
+         huid_idx     => undef,
+         mru_idx      => undef,
+-        force        => 0,
+-        debug        => 0,
+-        version      => "",
+         xml_version  => 0,
+         errorsExist  => 0,
+         NUM_PROCS    => 0,
+         TOP_LEVEL    => "",
++        TOP_LEVEL_HANDLE    => undef,
+         TOPOLOGY     => undef,
+         report_log   => "",
+         vpd_num      => 0,
+@@ -388,6 +405,162 @@ sub storeGroups
+     }
+ }
+ 
++#--------------------------------------------------
++# @brief Initialize a handle to the target instance.
++#
++# @details This method locates where the target instance
++#          resides and caches it for fast retrieval.
++#
++# @post A handle to the target instance is cached or exit
++#       stating that the target instance cannot be found.
++#
++# @param [in] $self - The global target object.
++#--------------------------------------------------
++sub initializeTargetInstanceHandle
++{
++    my $self = shift;
++
++    if ( (!defined $self->{TARGET_INST_HANDLE}) ||
++         ($self->{TARGET_INST_HANDLE} eq "") )
++    {
++        # Find the location of where target instances reside
++        my $targetInstances = $self->{xml}->{'targetInstance'};
++        if (!defined $targetInstances)
++        {
++            # Check one more level for the target instances
++            $targetInstances = $self->{xml}->{'targetInstances'}
++                                           ->{'targetInstance'};
++        }
++
++        # If can't find the target instances, then state so and exit
++        if (!defined $targetInstances)
++        {
++            die "No target instances defined\n";
++        }
++
++        $self->setTargetInstanceHandle($targetInstances);
++    } # end if ( (!defined $self->{TARGET_INST_HANDLE}) ||  ...
++}
++
++#--------------------------------------------------
++# @brief Return a handle to the target instances.
++#
++# @details This method will initialize the target instances
++#          if has not been already initialized.
++#
++# @param [in] $self - The global target object.
++#
++# @return - A handle to the target instance.
++#--------------------------------------------------
++sub getTargetInstanceHandle
++{
++    my $self = shift;
++
++    # If handle to target instances is not already cached, then initialize it
++    if ( (!defined $self->{TARGET_INST_HANDLE}) ||
++         ($self->{TARGET_INST_HANDLE} eq "") )
++    {
++        $self->initializeTargetInstanceHandle();
++    }
++
++    return ($self->{TARGET_INST_HANDLE});
++}
++
++#--------------------------------------------------
++# @brief Set the target instance handle to the given target handle
++#
++# @param [in] $self - The global target object.
++# @param [in] $targetHndl - The value the target instance handle is set to.
++#--------------------------------------------------
++sub setTargetInstanceHandle
++{
++    my $self = shift;
++    my $targetHndl = shift;
++
++    # Dynamically create and cache a handle to the target instance
++    $self->{TARGET_INST_HANDLE} = $targetHndl;
++}
++
++#--------------------------------------------------
++# @brief Initialize the top level target.
++#
++# @details This method locate the top level target
++#          and cache it for fast retrieval.
++#
++# @post The top level target is cached or exit stating that
++#       top level target not found.
++#
++# @param [in] $self - The global target object.
++#--------------------------------------------------
++sub initalizeTopLevel
++{
++    my $self = shift;
++
++    # If the top level target instance has not been found and set,
++    # then find that target and set top level to it
++    if ((!defined $self->{TOP_LEVEL}) || ($self->{TOP_LEVEL} eq ""))
++    {
++        # Get a handle to the target instances
++        my $targetInstancesHandle = $self->getTargetInstanceHandle();
++
++        # Find the system target which is the top level target
++        foreach my $target (keys(%{$targetInstancesHandle}))
++        {
++            # If target is of type 'SYS' then we found the top level target
++            if ($targetInstancesHandle->{$target}->{attribute}
++                                      ->{TYPE}->{default} eq "SYS")
++            {
++                # Set the top level target and search no more
++                $self->setTopLevel($target);
++                # YOU SHALL NOT PASS!!!
++                last;
++            }
++        }
++
++        # If unable to find top level target, then state so and exit
++        if ((!defined $self->{TOP_LEVEL}) || ($self->{TOP_LEVEL} eq ""))
++        {
++            die "Unable to find system top level target\n";
++        }
++    } # end if ((!defined $self->{TOP_LEVEL}) || ($self->{TOP_LEVEL} eq ""))
++}
++
++#--------------------------------------------------
++# @brief Return the top level target.
++#
++# @details This method will initialize the top level
++#          target if has not been already initialized.
++#
++# @param [in] $self - The global target object.
++#
++# @return - The top level target.
++#--------------------------------------------------
++sub getTopLevel
++{
++    my $self = shift;
++
++    # If the top level target is not already cached, then initialize it
++    if ((!defined $self->{TOP_LEVEL}) || ($self->{TOP_LEVEL} eq ""))
++    {
++        $self->initalizeTopLevel();
++    }
++    return ($self->{TOP_LEVEL});
++}
++
++#--------------------------------------------------
++# @brief Set the top level target to the given target.
++#
++# @param [in] $self - The global target object.
++# @param [in] $target - The value the top level target is set to.
++#--------------------------------------------------
++sub setTopLevel
++{
++    my $self = shift;
++    my $target = shift;
++
++    $self->{TOP_LEVEL} = $target;
++}
++
+ ####################################################
+ ## build target hierarchy recursively
+ ##
+@@ -422,34 +595,23 @@ sub buildHierarchy
+     my $self   = shift;
+     my $target = shift;
+ 
+-    my $instance_path = $self->{data}->{INSTANCE_PATH};
+-    if (!defined $instance_path)
+-    {
+-        $instance_path = "";
+-    }
+-    my $baseptr = $self->{xml}->{'targetInstance'};
+-    if ($self->{xml_version} == 1)
+-    {
+-        $baseptr = $self->{xml}->{'targetInstances'}->{'targetInstance'};
+-    }
++    # Get a handle to the target instances
++    my $targetInstanceRef = $self->getTargetInstanceHandle();
++
++    # If caller did not provide a target, then use the top level target
+     if ($target eq "")
+     {
+-        ## find system target
+-        foreach my $t (keys(%{$baseptr}))
+-        {
+-            if ($baseptr->{$t}->{attribute}->{TYPE}->{default} eq "SYS")
+-            {
+-                $self->{TOP_LEVEL} = $t;
+-                $target = $t;
+-            }
+-        }
++        $target = $self->getTopLevel();
+     }
+-    if ($target eq "")
++
++    my $instance_path = $self->{data}->{INSTANCE_PATH};
++    if (!defined $instance_path)
+     {
+-        die "Unable to find system top level target\n";
++        $instance_path = "";
+     }
++
+     my $old_path        = $instance_path;
+-    my $target_xml      = $baseptr->{$target};
++    my $target_xml      = $targetInstanceRef->{$target};
+     my $affinity_target = $target;
+     my $key             = $instance_path . "/" . $target;
+ 
+@@ -466,7 +628,6 @@ sub buildHierarchy
+     $self->{data}->{INSTANCE_PATH} = $old_path . "/" . $target;
+ 
+     ## copy attributes
+-
+     foreach my $attribute (keys %{ $target_xml->{attribute} })
+     {
+         my $value = $target_xml->{attribute}->{$attribute}->{default};
+@@ -2448,192 +2609,6 @@ sub findDestConnections
+ 
+ }
+ 
+-sub setEepromAttributesForAxone
+-{
+-    my $self      = shift;
+-    my $targetObj = shift;
+-    # Expects ocmb target
+-    my $target    = shift;
+-
+-    my %connections;
+-    my $num=0;
+-
+-    my $eeprom_name = "EEPROM_VPD_PRIMARY_INFO";
+-    my $fapi_name = "FAPI_I2C_CONTROL_INFO";
+-    # SPD contains data for EEPROM_VPD_PRIMARY_INFO and FAPI_I2C_CONTROL_INFO
+-    # SPD is the child of ocmb's parent, so get ocmb's parent
+-    # then look for the SPD child
+-    # With the resulting info, we populate pmic0, pmic1, ocmb, and dimm
+-    my $target_parent = $self->getTargetParent($target);
+-
+-    # Need to store pmic targets because they get parsed before we
+-    # do calculations for engine, port, and muxBusSelector
+-    # pmics need these values, so we store them until we need them later
+-    my $address = 0;
+-    my @pmic_array;
+-    foreach my $child (@{ $self->getTargetChildren($target_parent) })
+-    {
+-        my $type = $self->getTargetType($child);
+-        if ($type eq "chip-spd-device")
+-        {
+-            my $offset = $self->getAttribute($child, "BYTE_ADDRESS_OFFSET");
+-            my $memory_size = $self->getAttribute($child, "MEMORY_SIZE_IN_KB");
+-            my $cycle_time = $self->getAttribute($child, "WRITE_CYCLE_TIME");
+-            my $page_size = $self->getAttribute($child, "WRITE_PAGE_SIZE");
+-
+-            # Populate EEPROM for ocmb
+-            $targetObj->setAttributeField($target, $eeprom_name, "byteAddrOffset",
+-                $offset);
+-            $targetObj->setAttributeField($target, $eeprom_name, "maxMemorySizeKB",
+-                $memory_size);
+-            $targetObj->setAttributeField($target, $eeprom_name, "writeCycleTime",
+-                $cycle_time);
+-            $targetObj->setAttributeField($target, $eeprom_name, "writePageSize",
+-                $page_size);
+-
+-            # Populate EEPROM for dimm
+-            $targetObj->setAttributeField($target_parent, $eeprom_name, "byteAddrOffset",
+-                $offset);
+-            $targetObj->setAttributeField($target_parent, $eeprom_name, "maxMemorySizeKB",
+-                $memory_size);
+-            $targetObj->setAttributeField($target_parent, $eeprom_name, "writeCycleTime",
+-                $cycle_time);
+-            $targetObj->setAttributeField($target_parent, $eeprom_name, "writePageSize",
+-                $page_size);
+-
+-            # spd only child is i2c-slave, which contains devAddr info
+-            foreach my $i2c_slave (@{ $self->getTargetChildren($child) })
+-            {
+-                $address = $self->getAttribute($i2c_slave, "I2C_ADDRESS");
+-                # Populate EEPROM for dimm
+-                $targetObj->setAttributeField($target_parent, $eeprom_name, "devAddr",
+-                    $address);
+-
+-                # Populate EEPROM for ocmb
+-                $targetObj->setAttributeField($target, $eeprom_name, "devAddr",
+-                    $address);
+-            }
+-        }
+-        elsif ($type eq "chip-vreg-generic")
+-        {
+-            push(@pmic_array, $child);
+-            foreach my $i2c_slave (@{ $self->getTargetChildren($child) })
+-            {
+-                $type = $self->getTargetType($i2c_slave);
+-                # pmic has child i2c_slave which contains the device address
+-                if ($type eq "unit-i2c-slave")
+-                {
+-                    $address = $self->getAttribute($i2c_slave, "I2C_ADDRESS");
+-
+-                    # Populate FAPI for pmic
+-                    $targetObj->setAttributeField($child, $fapi_name, "devAddr",
+-                        $address);
+-                    last;
+-                }
+-            }
+-        }
+-        elsif ($type eq "chip-ocmb")
+-        {
+-            foreach my $i2c_slave (@{ $self->getTargetChildren($child) })
+-            {
+-                # ocmb has multiple i2c-slaves, so we query with instance_name
+-                my $instance_name = $self->getInstanceName($i2c_slave);
+-                if ($instance_name eq "i2c-ocmb")
+-                {
+-                    $address = $self->getAttribute($i2c_slave, "I2C_ADDRESS");
+-
+-                    # Populate FAPI for ocmb
+-                    $targetObj->setAttributeField($target, $fapi_name, "devAddr",
+-                        $address);
+-                    last;
+-                }
+-            }
+-        }
+-    }
+-
+-    # Get data from i2c-master-omi, which connects to the i2c_mux PCA9847
+-    my $conn = $self->findConnectionsByDirection($target, "I2C", "", 1);
+-    if ($conn ne "")
+-    {
+-        # There exists multiple i2c bus connections with chip-ocmb
+-        # They are all the same connections so we just take the first one
+-        # The mux channel has the i2cMuxBusSelector
+-        my $conn_source = @{$conn->{CONN}}[0]->{SOURCE};
+-        my $mux = $self->getAttribute($conn_source, "MUX_CHANNEL");
+-
+-        # Parent PCA9848 determines the mux path
+-        my $parent = $self->getTargetParent($conn_source);
+-        my $parent_pos = $self->getAttribute($parent, "POSITION");
+-        my $i2c_mux_path = "physical:sys-0/node-0/i2c_mux-$parent_pos";
+-
+-        # pmics and ocmb all grab FRU_ID from parent dimm
+-        my $fru = $self->getAttribute($target_parent, "FRU_ID");
+-
+-        my $master_i2c = $self->findConnectionsByDirection($self->getTargetParent($conn_source), "I2C", "", 1);
+-        if ($master_i2c ne "")
+-        {
+-            # There exists multiple i2c bus connections with the PCA9847 i2c_mux
+-            # They are all the same connections so we just take the first one
+-            $master_i2c = @{$master_i2c->{CONN}}[0];
+-            # i2c-master-omi source which has data we need
+-            my $source = $master_i2c->{SOURCE};
+-            my $dest = $master_i2c->{DEST};
+-            my $engine = $self->getAttribute($source, "I2C_ENGINE");
+-            my $port = $self->getAttribute($source, "I2C_PORT");
+-
+-            # Populate FAPI for ocmb
+-            $self->setAttributeField($target, $fapi_name, "engine",
+-                $engine);
+-            $self->setAttributeField($target, $fapi_name, "port",
+-                $port);
+-            $self->setAttributeField($target, $fapi_name, "i2cMuxBusSelector",
+-                $mux);
+-            $self->setAttributeField($target, $fapi_name, "i2cMuxPath",
+-                $i2c_mux_path);
+-            $self->setAttribute($target, "FRU_ID",
+-                $fru);
+-
+-            # Populate EEPROM for ocmb
+-            $self->setAttributeField($target, $eeprom_name, "i2cMuxPath",
+-                $i2c_mux_path);
+-            $self->setAttributeField($target, $eeprom_name, "engine",
+-                $engine);
+-            $self->setAttributeField($target, $eeprom_name, "port",
+-                $port);
+-            $self->setAttributeField($target, $eeprom_name, "i2cMuxBusSelector",
+-                $mux);
+-
+-
+-            # Populate FAPI for pmics
+-            foreach my $pmic (@pmic_array)
+-            {
+-                $self->setAttributeField($pmic, $fapi_name, "engine",
+-                    $engine);
+-                $self->setAttributeField($pmic, $fapi_name, "port",
+-                    $port);
+-                $self->setAttributeField($pmic, $fapi_name, "i2cMuxBusSelector",
+-                    $mux);
+-                $self->setAttributeField($pmic, $fapi_name, "i2cMuxPath",
+-                    $i2c_mux_path);
+-                $self->setAttribute($pmic, "FRU_ID",
+-                    $fru);
+-            }
+-
+-            # Populate EEPROM for dimm
+-            $self->setAttributeField($target_parent, $eeprom_name, "engine",
+-                $engine);
+-            $self->setAttributeField($target_parent, $eeprom_name, "port",
+-                $port);
+-            $self->setAttributeField($target_parent, $eeprom_name, "i2cMuxBusSelector",
+-                $mux);
+-            $self->setAttributeField($target_parent, $eeprom_name, "i2cMuxPath",
+-                $i2c_mux_path);
+-            $self->setAttribute($target_parent, "FRU_ID",
+-                $fru);
+-        }
+-    }
+-}
+-
+ # Find connections from/to $target (and it's children)
+ # $to_this_target indicates the direction to find.
+ sub findConnectionsByDirection
+@@ -2792,6 +2767,41 @@ sub getTargetType
+     return $target_ptr->{TARGET}->{type};
+ }
+ 
++
++#--------------------------------------------------
++# @brief Checks the given target for given attribute
++#
++# @details Will check the target for the given attribute.
++#          If attribute does not exist for target then
++#          return 0 (false), else if attribute does exist
++#          for target then return 1 (true).  This methods
++#          does not check the validity of the attribute
++#          or it's value.
++#
++# @param [in] $self - The global target object.
++# @param [in] $target - target to locate attribute on
++# @param [in] $attribut - attribute to locate
++#
++# @return true if attribute found, else false
++#--------------------------------------------------
++sub doesAttributeExistForTarget
++{
++    my $self       = shift;
++    my $target     = shift;
++    my $attribute  = shift;
++
++    my $target_ptr = $self->getTarget($target);
++
++    # If can't locate attribute for target then return back 0 (false)
++    if (!defined($target_ptr->{ATTRIBUTES}->{$attribute}))
++    {
++        return 0;
++    }
++
++    # Attribute for target was found, return back 1 (true)
++    return 1;
++}
++
+ ## checks if attribute is value
+ ## must be defined and have a non-empty value
+ sub isBadAttribute
+@@ -2818,6 +2828,7 @@ sub isBadAttribute
+     {
+         return 1;
+     }
++
+     return 0;
+ }
+ 
+@@ -2864,6 +2875,7 @@ sub getAttribute
+     my $target     = shift;
+     my $attribute  = shift;
+     my $target_ptr = $self->getTarget($target);
++
+     if (!defined($target_ptr->{ATTRIBUTES}->{$attribute}->{default}))
+     {
+         printf("ERROR: getAttribute(%s,%s) | Attribute not defined\n",
+@@ -3296,6 +3308,207 @@ sub writeReportFile
+     close R;
+ }
+ 
++#--------------------------------------------------
++# @brief Populates the EEPROM attributes for DDIMS
++#
++# @param [in] $self - The global target object.
++# @param [in] $target - An OCMB target
++#--------------------------------------------------
++sub setEepromAttributesForDDIMs
++{
++    my $self      = shift;
++    my $target    = shift;  # Expects ocmb target
++
++    my %connections;
++    my $num=0;
++
++    my $eeprom_name = "EEPROM_VPD_PRIMARY_INFO";
++    my $fapi_name = "FAPI_I2C_CONTROL_INFO";
++    # SPD contains data for EEPROM_VPD_PRIMARY_INFO and FAPI_I2C_CONTROL_INFO
++    # SPD is the child of ocmb's parent, so get ocmb's parent
++    # then look for the SPD child
++    # With the resulting info, we populate pmic0, pmic1, ocmb, and dimm
++    my $target_parent = $self->getTargetParent($target);
++
++    # Need to store pmic targets because they get parsed before we
++    # do calculations for engine, port, etc
++    # pmics need these values, so we store them until we need them later
++    my $address = 0;
++    my @pmic_array;
++    foreach my $child (@{ $self->getTargetChildren($target_parent) })
++    {
++        my $type = $self->getTargetType($child);
++        if ($type eq "chip-spd-device")
++        {
++            my $offset = $self->getAttribute($child, "BYTE_ADDRESS_OFFSET");
++            my $memory_size = $self->getAttribute($child, "MEMORY_SIZE_IN_KB");
++            my $cycle_time = $self->getAttribute($child, "WRITE_CYCLE_TIME");
++            my $page_size = $self->getAttribute($child, "WRITE_PAGE_SIZE");
++
++            # Populate EEPROM for ocmb
++            $self->setAttributeField($target, $eeprom_name, "byteAddrOffset",
++                $offset);
++            $self->setAttributeField($target, $eeprom_name, "maxMemorySizeKB",
++                $memory_size);
++            $self->setAttributeField($target, $eeprom_name, "writeCycleTime",
++                $cycle_time);
++            $self->setAttributeField($target, $eeprom_name, "writePageSize",
++                $page_size);
++
++            # Populate EEPROM for dimm
++            $self->setAttributeField($target_parent, $eeprom_name, "byteAddrOffset",
++                $offset);
++            $self->setAttributeField($target_parent, $eeprom_name, "maxMemorySizeKB",
++                $memory_size);
++            $self->setAttributeField($target_parent, $eeprom_name, "writeCycleTime",
++                $cycle_time);
++            $self->setAttributeField($target_parent, $eeprom_name, "writePageSize",
++                $page_size);
++
++            # spd only child is i2c-slave, which contains devAddr info
++            foreach my $i2c_slave (@{ $self->getTargetChildren($child) })
++            {
++                $address = $self->getAttribute($i2c_slave, "I2C_ADDRESS");
++                # Populate EEPROM for dimm
++                $self->setAttributeField($target_parent, $eeprom_name, "devAddr",
++                    $address);
++
++                # Populate EEPROM for ocmb
++                $self->setAttributeField($target, $eeprom_name, "devAddr",
++                    $address);
++            }
++        } # end if ($type eq "chip-spd-device") ...
++        elsif ($type eq "chip-vreg-generic")
++        {
++            push(@pmic_array, $child);
++            foreach my $i2c_slave (@{ $self->getTargetChildren($child) })
++            {
++                $type = $self->getTargetType($i2c_slave);
++                # pmic has child i2c_slave which contains the device address
++                if ($type eq "unit-i2c-slave")
++                {
++                    $address = $self->getAttribute($i2c_slave, "I2C_ADDRESS");
++
++                    # Populate FAPI for pmic
++                    $self->setAttributeField($child, $fapi_name, "devAddr",
++                        $address);
++                    last;
++                }
++            }
++        } # end elsif ($type eq "chip-vreg-generic")
++        elsif ($type eq "chip-ocmb")
++        {
++            foreach my $i2c_slave (@{ $self->getTargetChildren($child) })
++            {
++                # ocmb has multiple i2c-slaves, so we query with instance_name
++                my $instance_name = $self->getInstanceName($i2c_slave);
++                if ($instance_name eq "i2c-ocmb")
++                {
++                    $address = $self->getAttribute($i2c_slave, "I2C_ADDRESS");
++
++                    # Populate FAPI for ocmb
++                    $self->setAttributeField($target, $fapi_name, "devAddr",
++                        $address);
++                    last;
++                }
++            }
++        } # end elsif ($type eq "chip-ocmb")
++    } # end foreach my $child ...
++
++        # Get data from i2c-master-omi, which connects to the i2c_mux PCA9847
++    my $conn = $self->findConnectionsByDirection($target, "I2C", "", 1);
++    if ($conn ne "")
++    {
++        # There exists multiple i2c bus connections with chip-ocmb
++        # They are all the same connections so we just take the first one
++        # The mux channel has the i2cMuxBusSelector
++        my $conn_source = @{$conn->{CONN}}[0]->{SOURCE};
++# TODO FIX ROLAND
++# Will fix later in the process
++# ROLAND causing errors:
++# ERROR: getAttribute(/sys-0/node-0/nisqually-0/proc_socket-0/godel-0/power10-0/i2c-master-op3b,MUX_CHANNEL) | Attribute not defined
++# I only found MUX_CHANNEL on attributes /sys-0/node-0/nisqually-0/PCA9849-[0-7]/PCA9849.i2cm-[0..3]
++#
++#        my $mux = $self->getAttribute($conn_source, "MUX_CHANNEL");
++        my $mux = 0;
++
++        # Parent PCA9848 determines the mux path
++        my $parent = $self->getTargetParent($conn_source);
++        my $parent_pos = $self->getAttribute($parent, "POSITION");
++        my $i2c_mux_path = "physical:sys-0/node-0/i2c_mux-$parent_pos";
++
++        # pmics and ocmb all grab FRU_ID from parent dimm
++        my $fru = $self->getAttribute($target_parent, "FRU_ID");
++
++        my $master_i2c = $self->findConnectionsByDirection($self->getTargetParent($conn_source), "I2C", "", 1);
++        if ($master_i2c ne "")
++        {
++            # There exists multiple i2c bus connections with the PCA9847 i2c_mux
++            # They are all the same connections so we just take the first one
++            $master_i2c = @{$master_i2c->{CONN}}[0];
++            # i2c-master-omi source which has data we need
++            my $source = $master_i2c->{SOURCE};
++            my $dest = $master_i2c->{DEST};
++            my $engine = $self->getAttribute($source, "I2C_ENGINE");
++            my $port = $self->getAttribute($source, "I2C_PORT");
++
++            # Populate FAPI for ocmb
++            $self->setAttributeField($target, $fapi_name, "engine",
++                $engine);
++            $self->setAttributeField($target, $fapi_name, "port",
++                $port);
++            $self->setAttributeField($target, $fapi_name, "i2cMuxBusSelector",
++                $mux);
++            $self->setAttributeField($target, $fapi_name, "i2cMuxPath",
++                $i2c_mux_path);
++            $self->setAttribute($target, "FRU_ID",
++                $fru);
++
++            # Populate EEPROM for ocmb
++            $self->setAttributeField($target, $eeprom_name, "i2cMuxPath",
++                $i2c_mux_path);
++            $self->setAttributeField($target, $eeprom_name, "engine",
++                $engine);
++            $self->setAttributeField($target, $eeprom_name, "port",
++                $port);
++            $self->setAttributeField($target, $eeprom_name, "i2cMuxBusSelector",
++                $mux);
++
++            # Populate FAPI for pmics
++            foreach my $pmic (@pmic_array)
++            {
++                $self->setAttributeField($pmic, $fapi_name, "engine",
++                    $engine);
++                $self->setAttributeField($pmic, $fapi_name, "port",
++                    $port);
++                $self->setAttributeField($pmic, $fapi_name, "i2cMuxBusSelector",
++                    $mux);
++                $self->setAttributeField($pmic, $fapi_name, "i2cMuxPath",
++                    $i2c_mux_path);
++                $self->setAttribute($pmic, "FRU_ID",
++                    $fru);
++            }
++
++            # Populate EEPROM for dimm
++            $self->setAttributeField($target_parent, $eeprom_name, "engine",
++                $engine);
++            $self->setAttributeField($target_parent, $eeprom_name, "port",
++                $port);
++            $self->setAttributeField($target_parent, $eeprom_name, "i2cMuxBusSelector",
++                $mux);
++            $self->setAttributeField($target_parent, $eeprom_name, "i2cMuxPath",
++                $i2c_mux_path);
++            $self->setAttribute($target_parent, "FRU_ID",
++                $fru);
++        } # end if ($master_i2c  ne "")
++    } # end if ($conn ne "")
++}
++
++#--------------------------------------------------
++# @brief The end of the executable elements of this PERL module
++#
++# @details Don't forget to return the true value from this file
++#--------------------------------------------------
+ 1;
+ 
+ =head1 NAME
+diff --git a/src/usr/targeting/common/processMrw.pl b/src/usr/targeting/common/processMrw.pl
+index 7a63791..cd84b14 100755
+--- a/src/usr/targeting/common/processMrw.pl
++++ b/src/usr/targeting/common/processMrw.pl
+@@ -24,6 +24,9 @@
+ #
+ # IBM_PROLOG_END_TAG
+ 
++###############################################################################
++# Include these libraries
++###############################################################################
+ use strict;
+ use XML::Simple;
+ use Data::Dumper;
+@@ -32,112 +35,168 @@ use Math::BigInt;
+ use Getopt::Long;
+ use File::Basename;
+ 
+-use constant HZ_PER_KHZ=>1000;
+-use constant MAX_MCS_PER_PROC => 4; # 4 MCS per Nimbus
+ 
++###############################################################################
++# Define some global constants
++###############################################################################
+ my $VERSION = "1.0.0";
++my $targetObj = Targets->new;
+ 
+-my $force           = 0;
+-my $serverwiz_file  = "";
+-my $version         = 0;
+-my $debug           = 0;
+-my $report          = 0;
+-my $sdr_file        = "";
+-my $build           = "hb";
+-my $system_config   = "";
+-my $output_filename = "";
+-
+-# Map the OMI instance to its corresponding OMIC parent
+-my %omi_map         = (4  => "omic-0",
+-                       5  => "omic-0",
+-                       6  => "omic-0",
+-                       7  => "omic-1",
+-                       2  => "omic-1",
+-                       3  => "omic-1",
+-                       0  => "omic-2",
+-                       1  => "omic-2",
+-                       12 => "omic-0",
+-                       13 => "omic-0",
+-                       14 => "omic-0",
+-                       15 => "omic-1",
+-                       10 => "omic-1",
+-                       11 => "omic-1",
+-                       8  => "omic-2",
+-                       9  => "omic-2");
++# Define a true an false keyword
++use constant { true => 1, false => 0 };
++
++use constant HZ_PER_KHZ=>1000;
++use constant MAX_MCS_PER_PROC => 4; # 4 MCS per Nimbus
+ 
+ # TODO RTC:170860 - Remove this after dimm connector defines VDDR_ID
+-my $num_voltage_rails_per_proc = 1;
+-
+-GetOptions(
+-    "build=s" => \$build,
+-    "f"   => \$force,             # numeric
+-    "x=s" => \$serverwiz_file,    # string
+-    "d"   => \$debug,
+-    "c=s" => \$system_config,      #string
+-    "o=s" => \$output_filename,   #string
+-    "v"   => \$version,
+-    "r"   => \$report,
+-  )                               # flag
+-  or printUsage();
+-
+-if ($version == 1)
+-{
+-    die "\nprocessMrw.pl\tversion $VERSION\n";
+-}
++my $NUM_VOLTAGE_RAILS_PER_PROC = 1;
+ 
+-if ($serverwiz_file eq "")
+-{
+-    printUsage();
+-}
++## Used to setup GPU sensors on processors
++# key: OBUS slot target,
++# value: (GPU#, Function, Temp, MemTemp IPMI name/ids,
++my %GPU_SENSORS;
+ 
+-$XML::Simple::PREFERRED_PARSER = 'XML::Parser';
++# key: OBUS slot string
++# value: processor target string
++my %SLOT_TO_PROC;
+ 
+-my $targetObj = Targets->new;
+-if ($force == 1)
++our %hwsvmrw_plugins;
++
++###############################################################################
++# The starting point for this script
++###############################################################################
++main($targetObj);
++
++sub main
+ {
+-    $targetObj->{force} = 1;
++    my $targetObj = shift;
++
++    # Extract the caller's options off the command and validate.
++    # Will exit if options are not valid.
++    getAndValidateCallerInputOptions();
++
++
++    # Run tests if asked to do so
++    if ($targetObj->{run_self_test} == 1)
++    {
++        runTests($targetObj);
++        return 0;
++    }
++
++    # Load the XML and process the file, extracting targets and associating
++    # attributes, with their data, to the targets
++    loadXmlFile();
++
++    if ($targetObj->{build} eq "fsp")
++    {
++        doFspBuild();
++    }
++
++    # Process the targets - set some needed attribute values
++    processTargets();
++
++    # Check for errors in the targets
++    errorCheckTheTargets($targetObj);
++
++    # Write the results of processing the targets to an XML file
++    writeResultsToXml($targetObj);
+ }
+-if ($debug == 1)
++
++###############################################################################
++# Supporting subroutines
++###############################################################################
++#--------------------------------------------------
++# @brief Extract caller's command line options
++#
++# @details Extract caller's command line options and
++#          validate them.  If valid then store in the
++#          global Target object for easy retrieval.
++#          If options are not valid, then print
++#          usage statement and exit script.
++#--------------------------------------------------
++sub getAndValidateCallerInputOptions
+ {
+-    $targetObj->{debug} = 1;
+-}
++    # Local variables, and their defaults, to cache the command line options to
++    my $build           = "hb";
++    my $force           = 0;
++    my $serverwiz_file  = "";
++    my $debug           = 0;
++    my $system_config   = "";
++    my $output_file     = "";
++    my $version         = 0;
++    my $report          = 0;
++    my $run_self_test   = 0;
++
++    # Grab the user's command line options.  If options not recognized
++    # print usage statement and exit script.
++    GetOptions(
++        "build=s" => \$build,      # string
++        "f"   => \$force,          # numeric
++        "x=s" => \$serverwiz_file, # string
++        "d"   => \$debug,          # flag
++        "c=s" => \$system_config,  # string
++        "o=s" => \$output_file,    # string
++        "v"   => \$version,        # flag
++        "r"   => \$report,         # flag
++        "t"   => \$run_self_test,  # flag
++      )
++      or printUsage();
++
++    # Display current version of file
++    if ($version == 1)
++    {
++        die "\nprocessMrw.pl\tversion $VERSION\n";
++    }
++
++    # If caller did not specify an input file, then print usage and die
++    if ($serverwiz_file eq "")
++    {
++        printUsage();
++    }
++
++    # Save the caller's input options to global storage for easy retrieval
++    $targetObj->{build} = $build;
++    $targetObj->{force} = $force;
++    $targetObj->{serverwiz_file} = $serverwiz_file;
++    $targetObj->{serverwiz_dir} = dirname($serverwiz_file);
++    $targetObj->{debug} = $debug;
++    $targetObj->{system_config} = $system_config;
++    $targetObj->{output_file} = $output_file;
++    $targetObj->setVersion($VERSION);
++    $targetObj->{report} = $report;
++    $targetObj->{run_self_test} = $run_self_test;
++
++} # end getAndValidateCallerInputOptions
++
++# loadXmlFile
++sub loadXmlFile
++{
++    $XML::Simple::PREFERRED_PARSER = 'XML::Parser';
++    $targetObj->loadXML($targetObj->{serverwiz_file});
+ 
+-$targetObj->setVersion($VERSION);
+-my $xmldir = dirname($serverwiz_file);
+-$targetObj->loadXML($serverwiz_file);
++    my $str=sprintf(
++        " %30s | %10s | %6s | %4s | %9s | %4s | %4s | %4s | %10s | %s\n",
++        "Sensor Name","FRU Name","Ent ID","Type","Evt Type","ID","Inst","FRU",
++        "HUID","Target");
++
++    $targetObj->writeReport($str);
++    my $str=sprintf(
++        " %30s | %10s | %6s | %4s | %9s | %4s | %4s | %4s | %10s | %s\n",
++        "------------------------------","----------",
++        "------","----","---------","----","----","----","----------",
++        "----------");
++
++    $targetObj->writeReport($str);
++} # end loadXmlFile
+ 
+-our %hwsvmrw_plugins;
+ # FSP-specific functions
+-if ($build eq "fsp")
++sub doFspBuild
+ {
+     eval ("use processMrw_fsp; return 1;");
+     processMrw_fsp::return_plugins();
+-}
+-
+-my $str=sprintf(
+-    " %30s | %10s | %6s | %4s | %9s | %4s | %4s | %4s | %10s | %s\n",
+-    "Sensor Name","FRU Name","Ent ID","Type","Evt Type","ID","Inst","FRU",
+-    "HUID","Target");
++} # end doFspBuild
+ 
+-$targetObj->writeReport($str);
+-my $str=sprintf(
+-    " %30s | %10s | %6s | %4s | %9s | %4s | %4s | %4s | %10s | %s\n",
+-    "------------------------------","----------",
+-    "------","----","---------","----","----","----","----------",
+-    "----------");
+-
+-$targetObj->writeReport($str);
+-
+-########################
+-## Used to setup GPU sensors on processors
+-my %G_gpu_sensors;
+-# key: obusslot target,
+-# value: (GPU#, Function, Temp, MemTemp IPMI name/ids,
+ 
+-my %G_slot_to_proc;
+-# key: obusslot string
+-# value: processor target string
+-#########################
+ 
+ # convert a number string into a bit-position number
+ # example:  "0x02" -->  0b0100 = 4
+@@ -151,7 +210,7 @@ sub numToBitPositionNum
+     return $newNum;
+ }
+ 
+-# Used to populate G_gpu_sensors hash of array references
++# Used to populate GPU_SENSORS hash of array references
+ #
+ # Each array reference will be composed of 3 sensors +
+ # board cfg ID which together makes up a GPU.
+@@ -167,7 +226,7 @@ sub addSensorToGpuSensors
+     my $GPU_SENSORS_TEMP_OFFSET = 2;
+     my $GPU_SENSORS_MEM_TEMP_OFFSET = 4;
+ 
+-    my $rSensorArray = $G_gpu_sensors{$obusslot_str};
++    my $rSensorArray = $GPU_SENSORS{$obusslot_str};
+     unless ($rSensorArray) {
+         $rSensorArray = [ "0xFFFF","0xFF","0xFFFF","0xFF",
+                           "0xFFFF","0xFF","0x00" ];
+@@ -192,11 +251,11 @@ sub addSensorToGpuSensors
+         $rSensorArray->[$GPU_SENSORS_TEMP_OFFSET+1] = $sensorID;
+     }
+ 
+-    $G_gpu_sensors{$obusslot_str} = $rSensorArray;
++    $GPU_SENSORS{$obusslot_str} = $rSensorArray;
+ }
+ 
+ 
+-# Populates the G_slot_to_proc hash and updates the cfgID in G_gpu_sensors
++# Populates the SLOT_TO_PROC hash and updates the cfgID in GPU_SENSORS
+ # This is how we map the obusslot to the GPU sensors
+ sub addObusCfgToGpuSensors
+ {
+@@ -205,14 +264,14 @@ sub addObusCfgToGpuSensors
+ 
+     my $foundSlot = 0;
+ 
+-    $G_slot_to_proc{$obusslot_str} = $proc_target;
++    $SLOT_TO_PROC{$obusslot_str} = $proc_target;
+ 
+-    foreach my $obusslot (keys %G_gpu_sensors)
++    foreach my $obusslot (keys %GPU_SENSORS)
+     {
+         if ($obusslot =~ m/$obusslot_str/)
+         {
+             # Add in the cfg number
+-            my $rSensorArray = $G_gpu_sensors{$obusslot_str};
++            my $rSensorArray = $GPU_SENSORS{$obusslot_str};
+             $rSensorArray->[$GPU_SENSORS_OBUS_CFG_OFFSET] =
+                  sprintf("0x%02X",
+                         (oct($rSensorArray->[$GPU_SENSORS_OBUS_CFG_OFFSET]) |
+@@ -225,10 +284,10 @@ sub addObusCfgToGpuSensors
+     {
+         print STDOUT sprintf("%s:%d ", __FILE__,__LINE__);
+         print STDOUT "Found obus slot ($obusslot_str - processor $proc_target)".
+-                     " not in G_gpu_sensors hash\n";
++                     " not in GPU_SENSORS hash\n";
+ 
+         my $cfg_bit_num = numToBitPositionNum($cfg);
+-        $G_gpu_sensors{$obusslot_str} =
++        $GPU_SENSORS{$obusslot_str} =
+             ["0xFFFF","0xFF","0xFFFF","0xFF","0xFFFF",
+              "0xFF", sprintf("0x02X",oct($cfg_bit_num))];
+     }
+@@ -273,17 +332,207 @@ sub isMultiTpmSystem
+ }
+ 
+ #--------------------------------------------------
+-## loop through all targets and do stuff
+-my @targets = sort keys %{ $targetObj->getAllTargets() };
+-my $isMultiTpmSys = isMultiTpmSystem(\@targets);
+-foreach my $target (@targets)
++# @brief Loop through all targets and set attributes as needed
++#
++# @param [in] $targetObj - The global target object.
++#--------------------------------------------------
++sub processTargets
++{
++    my @targets = sort keys %{ $targetObj->getAllTargets() };
++    my $isMultiTpmSys = isMultiTpmSystem(\@targets);
++    foreach my $target (@targets)
++{
++        my $type = $targetObj->getType($target);
++        if ($type eq "SYS")
++        {
++            processSystem($targetObj, $target);
++
++            my $maxComputeNodes  = get_max_compute_nodes($targetObj , $target);
++            $targetObj->setAttribute($target, "MAX_COMPUTE_NODES_PER_SYSTEM", $maxComputeNodes);
++
++            #handle enumeration changes
++            my $enum_val = $targetObj->getAttribute($target,"PROC_FABRIC_PUMP_MODE");
++            if ( $enum_val =~ /MODE1/i)
++            {
++                $targetObj->setAttribute($target,"PROC_FABRIC_PUMP_MODE","CHIP_IS_NODE");
++            }
++            elsif ( $enum_val =~ /MODE2/i)
++            {
++                $targetObj->setAttribute($target,"PROC_FABRIC_PUMP_MODE","CHIP_IS_GROUP");
++            }
++        }
++        elsif ($type eq "PROC")
++        {
++            processProcessor($targetObj, $target);
++            if ($targetObj->{build} eq "fsp")
++            {
++                do_plugin("fsp_proc", $targetObj, $target);
++            }
++        }
++        elsif ($type eq "APSS")
++        {
++            processApss($targetObj, $target);
++        }
++
++        # @TODO RTC: 189374 Remove multiple TPMs filter when all platforms' MRW
++        # supports dynamically determining the processor driving it.
++        elsif (($type eq "TPM") && $isMultiTpmSys)
++        {
++            processTpm($targetObj, $target);
++        }
++        elsif ($type eq "POWER_SEQUENCER")
++        {
++            my $target_type = $targetObj->getTargetType($target);
++
++            # Strip off the chip- part of the target type name
++            $target_type =~ s/chip\-//g;
++
++            # Currently only UCD9090 and UCD90120A on FSP systems are supported.
++            # All other UCD types are skipped.
++            if (($target_type eq "UCD9090")
++                || ($target_type eq "UCD90120A"))
++            {
++                processUcd($targetObj, $target);
++            }
++        }
++        elsif ($type eq "OCMB_CHIP")
++        {
++            processOcmbChip($targetObj, $target);
++        }
++
++        # Once processing of the target type is complete, remove
++        # deprecated and un-needed attributes for this type
++        pruneTargetAttributes($targetObj, $target, $type);
++
++        processIpmiSensors($targetObj,$target);
++    }  # end foreach my $target (@targets)
++
++
++    if ($targetObj->{build} eq "fsp")
++    {
++        processMrw_fsp::loadFSP($targetObj);
++    }
++} # end processTargets
++
++#--------------------------------------------------
++# @brief Check the processed targets for errors
++#
++# @param [in] $targetObj - The global target object.
++#--------------------------------------------------
++sub errorCheckTheTargets
+ {
+-    my $type = $targetObj->getType($target);
++    my $targetObj = shift;
++
++# TODO FIX ROLAND
++# Will fix later in the process
++# check topology
++# ROLAND Having issues with the topology:
++# ERROR: Fabric topology invalid.  2 targets have same FABRIC_TOPOLOGY_ID (0x0)
++# Once resolved, add this check back in
++# The MRW XML has 2 procs: power10-0 of type chip-processor-power10 and
++#                          power10-1 of type chip-processor-power10 and
++# In the loadXmlFile method, it produces 4 procs, 2 on a socket:
++#  '/sys-0/node-0/nisqually-0/proc_socket-0/godel-0/power10-0';
++#  '/sys-0/node-0/nisqually-0/proc_socket-1/godel-0/power10-0';
++#  '/sys-0/node-0/nisqually-0/proc_socket-0/godel-0/power10-1';
++#  '/sys-0/node-0/nisqually-0/proc_socket-1/godel-0/power10-1';
++#     For both power10-0 procs it uses topologoy ID 0
++#     For both power10-1 procs it uses topologoy ID 1
++#       So this end up in duplicates being used
++
++#    foreach my $n (keys %{$targetObj->{TOPOLOGY}})
++#    {
++#        if ($targetObj->{TOPOLOGY}->{$n} > 1)
++#        {
++#            print "ERROR: Fabric topology invalid.  2 targets have same ".
++#                  "FABRIC_TOPOLOGY_ID ($n)\n";
++#            $targetObj->myExit(3);
++#        }
++#    }
++
++    foreach my $target (keys %{ $targetObj->getAllTargets() })
++    {
++    # TODO FIX ROLAND
++    # Will fix later in the process
++    # ROLAND Having issues with power10-0 so wrapped errorCheck with if statement:
++    # ERROR: EEPROM_VPD_PRIMARY_INFO/devAddr attribute is invalid (Target=/sys-0/node-0/nisqually-0/proc_socket-0/godel-0/power10-0)
++    #	I2C connection to target is not defined
++    ## Once resolved, will remove if statement
++        if ($target != "/sys-0/node-0/nisqually-0/proc_socket-0/godel-0/power10-0")
++        {
++            errorCheck($targetObj, $target);
++        }
++    }
++} # end sub errorCheckTheTargets
++
++#--------------------------------------------------
++# @brief Write out the results to an XML file
++#
++# @param [in] $targetObj - The global target object.
++#--------------------------------------------------
++sub writeResultsToXml
++{
++    my $targetObj = shift;
++
++    my $xml_fh;
++    my $filename;
++    my $config_str = $targetObj->{system_config};
++
++    #If user did not specify the output filename, then build one up by using
++    #config and build parameters
++    if ($targetObj->{output_file} eq "")
++    {
++        if ($config_str ne "")
++        {
++            $config_str = "_" . $config_str;
++        }
++
++        $filename = $targetObj->{serverwiz_dir} . "/" . $targetObj->getSystemName() . $config_str . "_" . $targetObj->{build} . ".mrw.xml";
++    }
++    else
++    {
++        $filename = $targetObj->{output_file};
++    }
++
++    print "Creating XML: $filename\n";
++    open($xml_fh, ">$filename") || die "Unable to create: $filename";
++
++    $targetObj->printXML($xml_fh, "top", $targetObj->{build});
++    close $xml_fh;
++    if (!$targetObj->{errorsExist})
++    {
++        ## optionally print out report
++        if ($targetObj->{report})
++        {
++            print "Writing report to: ".$targetObj->{report_filename}."\n";
++            $targetObj->writeReportFile();
++        }
++        print "MRW created successfully!\n";
++    }
++} # end sub writeResultsToXml
++
++#--------------------------------------------------
++# @brief Remove attributes associated with target.
++#        Either because they have been deprecated
++#        or simply not used/needed.
++# @param[in] $targetObj - The global target object
++#                         blob
++# @param[in] $target - The target to remove attributes
++#                      from
++# @param[in] $type -   The type of the target
++#
++# TODO RTC: 178351 Remove depricated Attribute from HB XML
++# these are obsolete
++#
++#--------------------------------------------------
++sub pruneTargetAttributes
++{
++    my $targetObj = shift;
++    my $target    = shift;
++    my $type      = shift;
++
+     if ($type eq "SYS")
+     {
+-        processSystem($targetObj, $target);
+-        #TODO RTC: 178351 Remove depricated Attribute from HB XML
+-        #these are obsolete
+         $targetObj->deleteAttribute($target,"FUSED_CORE_MODE");
+         $targetObj->deleteAttribute($target,"MRW_CDIMM_MASTER_I2C_TEMP_SENSOR_ENABLE");
+         $targetObj->deleteAttribute($target,"MRW_CDIMM_SPARE_I2C_TEMP_SENSOR_ENABLE");
+@@ -302,31 +551,9 @@ foreach my $target (@targets)
+         $targetObj->deleteAttribute($target,"SYSTEM_WOF_ENABLED");
+         $targetObj->deleteAttribute($target,"VDM_ENABLE");
+         $targetObj->deleteAttribute($target,"CHIP_HAS_SBE");
+-
+-        my $maxComputeNodes  = get_max_compute_nodes($targetObj , $target);
+-        $targetObj->setAttribute($target, "MAX_COMPUTE_NODES_PER_SYSTEM", $maxComputeNodes);
+-
+-        #handle enumeration changes
+-        my $enum_val = $targetObj->getAttribute($target,"PROC_FABRIC_PUMP_MODE");
+-        if ( $enum_val =~ /MODE1/i)
+-        {
+-            $targetObj->setAttribute($target,"PROC_FABRIC_PUMP_MODE","CHIP_IS_NODE");
+-        }
+-        elsif ( $enum_val =~ /MODE2/i)
+-        {
+-            $targetObj->setAttribute($target,"PROC_FABRIC_PUMP_MODE","CHIP_IS_GROUP");
+-        }
+-
+     }
+     elsif ($type eq "PROC")
+     {
+-        processProcessor($targetObj, $target);
+-        if ($build eq "fsp")
+-        {
+-            do_plugin("fsp_proc", $targetObj, $target);
+-        }
+-        #TODO RTC: 178351 Remove depricated Attribute from HB XML
+-        #these are obsolete
+         $targetObj->deleteAttribute($target,"CHIP_HAS_SBE");
+         $targetObj->deleteAttribute($target,"FSI_GP_REG_SCOM_ACCESS");
+         $targetObj->deleteAttribute($target,"I2C_SLAVE_ADDRESS");
+@@ -349,18 +576,8 @@ foreach my $target (@targets)
+         $targetObj->deleteAttribute($target,"PROC_SECURITY_SETUP_VECTOR");
+         $targetObj->deleteAttribute($target,"SBE_SEEPROM_I2C_ADDRESS_BYTES");
+     }
+-    elsif ($type eq "APSS")
+-    {
+-        processApss($targetObj, $target);
+-    }
+-    elsif ($type eq "MEMBUF")
+-    {
+-        processMembuf($targetObj, $target);
+-        $targetObj->deleteAttribute($target,"CEN_MSS_VREF_CAL_CNTL");
+-    }
+     elsif ($type eq "PHB")
+     {
+-        #TODO RTC: 178351 Remove depricated Attribute from HB XML
+         $targetObj->deleteAttribute($target,"DEVICE_ID");
+         $targetObj->deleteAttribute($target,"HDDW_ORDER");
+         $targetObj->deleteAttribute($target,"MAX_POWER");
+@@ -376,91 +593,7 @@ foreach my $target (@targets)
+         $targetObj->deleteAttribute($target,"SLOT_NAME");
+         $targetObj->deleteAttribute($target,"VENDOR_ID");
+     }
+-    # @TODO RTC: 189374 Remove multiple TPMs filter when all platforms' MRW
+-    # supports dynamically determining the processor driving it.
+-    elsif (($type eq "TPM") && $isMultiTpmSys)
+-    {
+-        processTpm($targetObj, $target);
+-    }
+-    elsif ($type eq "POWER_SEQUENCER")
+-    {
+-        my $target_type = $targetObj->getTargetType($target);
+-
+-        # Strip off the chip- part of the target type name
+-        $target_type =~ s/chip\-//g;
+-
+-        # Currently only UCD9090 and UCD90120A on FSP systems are supported.
+-        # All other UCD types are skipped.
+-        if (($target_type eq "UCD9090")
+-            || ($target_type eq "UCD90120A"))
+-        {
+-            processUcd($targetObj, $target);
+-        }
+-    }
+-    elsif ($type eq "OCMB_CHIP")
+-    {
+-        processOcmbChip($targetObj, $target);
+-    }
+-
+-    processIpmiSensors($targetObj,$target);
+-}
+-
+-if ($build eq "fsp")
+-{
+-    processMrw_fsp::loadFSP($targetObj);
+-}
+-## check topology
+-foreach my $n (keys %{$targetObj->{TOPOLOGY}}) {
+-    if ($targetObj->{TOPOLOGY}->{$n} > 1) {
+-        print "ERROR: Fabric topology invalid.  2 targets have same ".
+-              "FABRIC_TOPOLOGY_ID ($n)\n";
+-        $targetObj->myExit(3);
+-    }
+-}
+-## check for errors
+-foreach my $target (keys %{ $targetObj->getAllTargets() })
+-{
+-    errorCheck($targetObj, $target);
+-}
+-
+-#--------------------------------------------------
+-## write out final XML
+-my $xml_fh;
+-my $filename;
+-my $config_str = $system_config;
+-
+-#If user did not specify the output filename, then build one up by using
+-#config and build parameters
+-if ($output_filename eq "")
+-{
+-    if ($config_str ne "")
+-    {
+-        $config_str = "_" . $config_str;
+-    }
+-
+-    $filename = $xmldir . "/" . $targetObj->getSystemName() . $config_str . "_" . $build . ".mrw.xml";
+-}
+-else
+-{
+-    $filename = $output_filename;
+-}
+-
+-print "Creating XML: $filename\n";
+-open($xml_fh, ">$filename") || die "Unable to create: $filename";
+-
+-$targetObj->printXML($xml_fh, "top", $build);
+-close $xml_fh;
+-if (!$targetObj->{errorsExist})
+-{
+-    ## optionally print out report
+-    if ($report)
+-    {
+-        print "Writing report to: ".$targetObj->{report_filename}."\n";
+-        $targetObj->writeReportFile();
+-    }
+-    print "MRW created successfully!\n";
+-}
+-
++}  # end pruneTargetAttributes
+ 
+ #--------------------------------------------------
+ #--------------------------------------------------
+@@ -493,7 +626,7 @@ sub processSystem
+     my $system_name = $targetObj->getAttribute($target,"SYSTEM_NAME");
+     if ($system_name =~ /ZAIUS/i)
+     {
+-        $num_voltage_rails_per_proc = 2;
++        $NUM_VOLTAGE_RAILS_PER_PROC = 2;
+     }
+ 
+     # TODO RTC:182764 -- right now there is no support for CDIMMs. So,
+@@ -940,9 +1073,9 @@ sub processUcd
+ }
+ 
+ #--------------------------------------------------
+-## Processor
+-##
+-
++# @brief Process processors
++#
++#--------------------------------------------------
+ sub processProcessor
+ {
+     my $targetObj = shift;
+@@ -998,7 +1131,6 @@ sub processProcessor
+         }
+     }
+ 
+-
+     # I2C arrays
+     my @engine = ();
+     my @port = ();
+@@ -1051,11 +1183,11 @@ sub processProcessor
+             #   contain this information and this can be removed
+             my $socket_pos =  $targetObj->getAttribute($socket_target,
+                                   "POSITION");
+-            if ($num_voltage_rails_per_proc > 1)
++            if ($NUM_VOLTAGE_RAILS_PER_PROC > 1)
+             {
+                 my $mcbist_pos = $targetObj->getAttribute($child, "CHIP_UNIT");
+                 $targetObj->setAttribute($child, "VDDR_ID",
+-                         $socket_pos*$num_voltage_rails_per_proc + $mcbist_pos);
++                         $socket_pos*$NUM_VOLTAGE_RAILS_PER_PROC + $mcbist_pos);
+             }
+             else
+             {
+@@ -1097,16 +1229,16 @@ sub processProcessor
+ 
+     # Add GPU sensors to processor
+     my @aGpuSensors = ();
+-    foreach my $obusslot (sort keys %G_gpu_sensors)
++    foreach my $obusslot (sort keys %GPU_SENSORS)
+     {
+         # find matching obusslot to processor
+-        my $proc_target = $G_slot_to_proc{$obusslot};
++        my $proc_target = $SLOT_TO_PROC{$obusslot};
+ 
+         # if a processor target is found and it is the same as this target
+         if ($proc_target && ($target =~ m/$proc_target/))
+         {
+             # Add this GPU's sensors to the processor's array of GPU sensors
+-            push (@aGpuSensors, @{ $G_gpu_sensors{$obusslot} });
++            push (@aGpuSensors, @{ $GPU_SENSORS{$obusslot} });
+         }
+     }
+     if (@aGpuSensors)
+@@ -1216,10 +1348,11 @@ sub processProcessor
+                              $targetObj->getAttribute($target,
+                                                       "FABRIC_CHIP_ID"));
+ 
+-    processMembufVpdAssociation($targetObj,$target);
++
+     #TODO RTC: 191762 -- Need a generic way to source FABRIC_GROUP_ID and
+     #FABRIC_CHIP_ID from the MRW and select the right value in processMRW
+     #based on the system configuration we are compiling for.
++    my $system_config = $targetObj->{system_config};
+     if ($system_config eq "w")
+     {
+         my $huid_str = $targetObj->getAttribute($target, "HUID");
+@@ -1412,36 +1545,21 @@ sub processI2cSpeeds
+     $targetObj->setAttribute($target,"I2C_BUS_SPEED_ARRAY",$bus_speed_attr);
+ }
+ 
+-################################
+-## Setup address map
+-
++#--------------------------------------------------
++# @brief Setup address map
++#--------------------------------------------------
+ sub setupBars
+ {
+     my $targetObj = shift;
+     my $target = shift;
+-    #--------------------------------------------------
+-    ## Setup BARs
+-
+-    #The topology ID is a 4 bit value that must be converted to
+-    #a 5-bit topology index before we can use it to calculate the
+-    #address offset.
+-    #The conversion method depends on the topology mode.
+-    my $topoId = $targetObj->getAttribute($target, "PROC_FABRIC_TOPOLOGY_ID");
+-    my $topoMode = $targetObj->getAttribute($target, "PROC_FABRIC_TOPOLOGY_MODE");
+-
+-    #Assume topo mode 1 (GGCC -> 0GGCC)
+-    my $topoIndex = $topoId;
+-
+-    #Check for topo mode 0
+-    if ($topoMode == 0)
+-    {
+-        # GGGC -> GGG0C
+-        $topoIndex = (($topoIndex & 0xE) << 1) | ($topoIndex & 0x1);
+-    }
+ 
+-    #keep track of which topology ID's have been used
++    # Keep track of which topology ID's have been used
++    my $topoId = getTopologyId($targetObj, $target);
+     $targetObj->{TOPOLOGY}->{$topoId}++;
+ 
++    # Get the topology index
++    my $topologyIndex = getTopologyIndex($targetObj, $target);
++
+     #P10 has a defined memory map for all configurations,
+     #these are the base addresses for topology ID 0 (group0-chip0).
+     my %bars=(  "FSP_BASE_ADDR"             => 0x0006030100000000,
+@@ -1466,9 +1584,147 @@ sub setupBars
+     {
+         my $i_base = Math::BigInt->new($bars{$bar});
+         my $value=sprintf("0x%016s",substr((
+-                        $i_base+$topoIndexOffset*$topoIndex)->as_hex(),2));
++                        $i_base+$topoIndexOffset*$topologyIndex)->as_hex(),2));
+         $targetObj->setAttribute($target,$bar,$value);
+     }
++}  # end setupBars
++
++#--------------------------------------------------
++# @brief Retrieve the fabric topolgy mode
++#
++# @details The fabric topology mode, attribute PROC_FABRIC_TOPOLOGY_MODE,
++#          is an attribute of the top level target (sys-0), but retrieving
++#          the value from the attribute returns a string (MODE0 or MODE1).
++#          This string is used to get the actual value, tied that mode,
++#          within the enumeration types.
++#
++# @param[in] $targetObj - The global target object, needed to get topology mode
++#
++# @return the numerical value of the topology mode in base 10
++#--------------------------------------------------
++sub getTopologyMode
++{
++    my $targetObj = shift;
++
++    use constant TOPOLOGY_MODE_ATTRIBUTE => "PROC_FABRIC_TOPOLOGY_MODE";
++
++    # Get topology mode from top level target
++    # Need to prepend "/" to the returned top level target because targets
++    # are mapped slightly different in the TARGETS hash vs the xml hash.
++    my $topologoyMode = $targetObj->getAttribute("/".$targetObj->{TOP_LEVEL},
++                                                 TOPOLOGY_MODE_ATTRIBUTE);
++
++    # Return the value of the mode as defined in
++    # enumeration type PROC_FABRIC_TOPOLOGY_MODE
++    # Convert the value from hex to base 10
++    return hex($targetObj->{xml}->{enumerationTypes}->{enumerationType}
++                      ->{PROC_FABRIC_TOPOLOGY_MODE}
++                      ->{enumerator}->{$topologoyMode}->{value});
++}
++
++#--------------------------------------------------
++# @brief Convert the topology ID to a topology index.
++#
++# @details  The topology ID is a 4 bit value that will be converted to a 5 bit
++#           topology index. The topology index is an index into the topology
++#           table.
++#           The conversion method depends on the topology mode.
++#                Mode      ID      index
++#               MODE 0 => GGGC --> GGG0C
++#               MODE 1 => GGCC --> GG0CC
++#
++# @param[in] $topologyId - The topology ID to convert to an index
++# @param[in] $topologyMode - The topology mode that determines the conversion
++#                            method. Needs to be a base 10 numeral value.
++#
++# @return a toplogy index, that is a base 10 numeral value.
++#--------------------------------------------------
++sub convertTopologyIdToIndex
++{
++    my $topologyId = shift;
++    my $topologyMode = shift;
++
++    use constant TOPOLOGY_MODE_1 => 1;
++
++    # Assume topology mode 0 (GGGC -> GGG0C)
++    my $groupMask = 0xE; # Use 0xE, 1110b, to extract 'GGG' from 'GGGC'
++    my $chipMask = 0x1;  # Use 0x1, 0001b, to extract 'C' from 'GGGC'
++
++    # If topology mode 1 (GGCC -> GG0CC)
++    if (TOPOLOGY_MODE_1 == $topologyMode)
++    {
++        $groupMask = 0xC; # Use 0xC, 1100b, to extract 'GG' from 'GGCC'
++        $chipMask = 0x3;  # Use 0x3, 0011b, to extract 'CC' from 'GGCC'
++    }
++
++    # Set topology index to topology ID before doing conversion
++    my $topologyIndex = $topologyId;
++
++    ## Turn the 4 bit topology ID into a 5 bit index
++    ## convert GGGC to GGG0C
++    ##      OR GGCC to GG0CC
++    # If group mask equal to 0xE (mode 0) then extract 'GGG' from 'GGGC':
++    #  1) GGGC & 0xE (1110b) returns GGG0 then shift to left (<< 1) to get GGG00
++    #  2) extract C from GGGC: GGGC & 0x1 (0001b) returns C
++    # If group mask equal to 0xC (mode 1) then extract 'GG' from 'GGCC':
++    #  1) GGCC & 0xC (1100b) returns GG00 then shift to left (<< 1) to get GG000
++    #  2) extract CC from GGCC: GGCC & 0x3 (0011b) returns CC
++    # Bitwise 'OR' 1 and 2 together to produce a 5 bit index value: GGG0C OR GG0CC
++    #    Index     =                  1                  'OR'               2
++    $topologyIndex = (($topologyIndex & $groupMask) << 1) | ($topologyIndex & $chipMask);
++
++    return ($topologyIndex);
++}
++
++#--------------------------------------------------
++# @brief Get the topology ID from processor
++#
++#
++# @param[in] $targetObj - The global target object, needed to get topology mode
++# @param[in] $processorTarget - The processor target, has the attribute topology ID
++#
++# @return topology ID, that is a base 10 numeral value.
++#--------------------------------------------------
++sub getTopologyId
++{
++    my $targetObj = shift;
++    my $processorTarget = shift;
++
++    use constant TOPOLOGY_ID_ATTRIBUTE => "PROC_FABRIC_TOPOLOGY_ID";
++
++    # Get the topology ID from the processor.
++    # Convert hex value to base 10 numerical value
++    return hex($targetObj->getAttribute($processorTarget,
++                                        TOPOLOGY_ID_ATTRIBUTE));
++
++}
++
++#--------------------------------------------------
++# @brief Get the topology index, an index into the topology table.
++#
++# @details The topology index needs to be calculated using the topology mode
++#          and the topology ID.  @see convertTopologyIdToIndex for
++#          more details
++#
++# @param[in] $targetObj - The global target object, needed to get topology mode
++# @param[in] $processorTarget - The processor target has the attribute topology ID
++#
++# @return a topology index, that is base 10 numeral value.
++#--------------------------------------------------
++sub getTopologyIndex
++{
++    my $targetObj = shift;
++    my $processorTarget = shift;
++
++    # Get the topology mode: MODE 0 (0) or MODE 1 (1)
++    my $topologyMode = getTopologyMode($targetObj);
++
++    # Get the topology ID from the processor.
++    my $topologyId = getTopologyId($targetObj, $processorTarget);
++
++    # Convert the topology ID to a topology index. The conversion method is
++    # based on the topology mode.
++    return (convertTopologyIdToIndex($topologyId, $topologyMode));
+ }
+ 
+ #--------------------------------------------------
+@@ -1572,10 +1828,14 @@ sub processEq
+         $targetObj->log($target,
+             "Processing EQ child: $child Type: $child_type");
+ 
+-        if ($child_type eq "EX")
++        if ($child_type eq "EQ")
+         {
+             processEx($targetObj, $child, $chip_unit);
+         }
++        elsif ($child_type eq "FC")
++        {
++            processFc($targetObj, $child, $chip_unit);
++        }
+     }
+ 
+     my $value = sprintf("0x%x",
+@@ -1584,6 +1844,35 @@ sub processEq
+     $targetObj->setAttribute( $target, "CHIPLET_ID", $value);
+ }
+ 
++## FC
++sub processFc
++{
++    my $targetObj        = shift;
++    my $target           = shift;
++    my $parent_chip_unit = shift;
++
++    foreach my $child (@{ $targetObj->getTargetChildren($target) })
++    {
++        my $child_type = $targetObj->getType($child);
++
++        $targetObj->log($target,
++            "Processing EX child: $child Type: $child_type");
++
++        if ($child_type eq "CORE")
++        {
++            processCore($targetObj, $child);
++        }
++    }
++
++    my $value = sprintf("0x%x",
++                        Targets::PERVASIVE_PARENT_EQ_OFFSET
++                        + $parent_chip_unit);
++
++    $targetObj->setAttribute( $target, "CHIPLET_ID", $value);
++}
++
++
++
+ ## EX
+ sub processEx
+ {
+@@ -1672,9 +1961,9 @@ sub processMcbist
+ ##
+ sub processMc
+ {
+-    # NOTE: OMI_INBAND_BAR_BASE_ADDR_OFFSET will be set for the MC                         
+-    # targets via a specific child OMI Target. View the                                    
+-    # processOmi function for further details.                                             
++    # NOTE: OMI_INBAND_BAR_BASE_ADDR_OFFSET will be set for the MC
++    # targets via a specific child OMI Target. View the
++    # processOmi function for further details.
+     my $targetObj    = shift;
+     my $target       = shift;
+ 
+@@ -1751,8 +2040,28 @@ sub processMcc
+ ##
+ sub processOmi
+ {
+-    my $mrwObj   = shift;
+-    my $omitarg      = shift;
++    my $mrwObj  = shift;
++    my $omitarg = shift;
++
++# TODO This may need to be updated if layout is different
++# ROLAND investigate this
++    # Map the OMI instance to its corresponding OMIC parent
++    my %omi_map = (4  => "omic-0",
++                   5  => "omic-0",
++                   6  => "omic-0",
++                   7  => "omic-1",
++                   2  => "omic-1",
++                   3  => "omic-1",
++                   0  => "omic-2",
++                   1  => "omic-2",
++                   12 => "omic-0",
++                   13 => "omic-0",
++                   14 => "omic-0",
++                   15 => "omic-1",
++                   10 => "omic-1",
++                   11 => "omic-1",
++                   8  => "omic-2",
++                   9  => "omic-2");
+ 
+     use integer;
+     # There are a total of eight OMI units on an MC unit. So, to
+@@ -1834,15 +2143,15 @@ sub processOmic
+ }
+ 
+ #--------------------------------------------------
+-## OCMB_CHIP
+-##
+-##
++# @brief OCMB_CHIP
++#
++#--------------------------------------------------
+ sub processOcmbChip
+ {
+     my $targetObj    = shift;
+     my $target       = shift;
+ 
+-    $targetObj->setEepromAttributesForAxone($targetObj, $target);
++    $targetObj->setEepromAttributesForDDIMs($target);
+ }
+ 
+ #-------------------------------------------------g
+@@ -2032,6 +2341,7 @@ sub processXbus
+         #For example, in wrap config, CONFIG_APPLY is expected to have "w"
+         #If "w" is not there, then we skip the connection and mark peers
+         #as NULL
++        my $system_config = $targetObj->{system_config};
+         if (($system_config eq $wrap_config && $config =~ /$wrap_config/) ||
+            ($system_config ne $wrap_config && $config =~ /$default_config/))
+         {
+@@ -2098,7 +2408,7 @@ sub processAbus
+     # A-bus connection has to be conisdered or not
+     # If user has passed 2N as argument, then we consider only those
+     # A-bus connections where token "2" is present
+-
++    my $system_config = $targetObj->{system_config};
+     if($system_config eq "2N" && $config =~ /$twonode/)
+     {
+         #Looking for Abus connections pertaining to 2 node system only
+@@ -2634,123 +2944,6 @@ sub processOcc
+     $targetObj->setAttribute($target,"OCC_MASTER_CAPABLE",$master_capable);
+ }
+ 
+-sub processMembufVpdAssociation
+-{
+-    my $targetObj = shift;
+-    my $target    = shift;
+-
+-    my $vpds=$targetObj->findConnections($target,"I2C","VPD");
+-    if ($vpds ne "" ) {
+-        my $vpd = $vpds->{CONN}->[0];
+-        my $membuf_assocs=$targetObj->findConnections($vpd->{DEST_PARENT},
+-                          "LOGICAL_ASSOCIATION","MEMBUF");
+-
+-        if ($membuf_assocs ne "") {
+-            foreach my $membuf_assoc (@{$membuf_assocs->{CONN}}) {
+-                my $membuf_target = $membuf_assoc->{DEST_PARENT};
+-                setEepromAttributes($targetObj,
+-                       "EEPROM_VPD_PRIMARY_INFO",$membuf_target,$vpd);
+-                my $index = $targetObj->getBusAttribute($membuf_assoc->{SOURCE},
+-                                $membuf_assoc->{BUS_NUM}, "ISDIMM_MBVPD_INDEX");
+-                $targetObj->setAttribute(
+-                            $membuf_target,"ISDIMM_MBVPD_INDEX",$index);
+-                $targetObj->setAttribute($membuf_target,
+-                            "VPD_REC_NUM",$targetObj->{vpd_num});
+-            }
+-        }
+-        my $group_assocs=$targetObj->findConnections($vpd->{DEST_PARENT},
+-                          "LOGICAL_ASSOCIATION","CARD");
+-
+-        if ($group_assocs ne "") {
+-            foreach my $group_assoc (@{$group_assocs->{CONN}}) {
+-                my $mb_target = $group_assoc->{DEST_PARENT};
+-                my $group_target = $targetObj->getTargetParent($mb_target);
+-                $targetObj->setAttribute($group_target,
+-                            "VPD_REC_NUM",$targetObj->{vpd_num});
+-            }
+-        }
+-        $targetObj->{vpd_num}++;
+-    }
+-}
+-
+-#--------------------------------------------------
+-## MEMBUF
+-##
+-## Finds I2C connections to DIMM and creates EEPROM attributes
+-## FYI:  I had to handle DMI busses in framework because they
+-## define affinity path
+-sub processMembuf
+-{
+-    my $targetObj = shift;
+-    my $membufTarg    = shift;
+-    if ($targetObj->isBadAttribute($membufTarg, "PHYS_PATH", ""))
+-    {
+-        ##dmi is probably not connected.  will get caught in error checking
+-        return;
+-    }
+-
+-    processMembufVpdAssociation($targetObj,$membufTarg);
+-
+-    ## find port mapping
+-    my %dimm_portmap;
+-    foreach my $child (@{$targetObj->getTargetChildren($membufTarg)})
+-    {
+-         if ($targetObj->getType($child) eq "MBA")
+-         {
+-             # find this MBA's position relative to the membuf
+-             my $mba_num = $targetObj->getAttribute($child,"MBA_NUM");
+-             # follow the DDR4 bus connection to find the 'ddr' targets
+-             my $ddrs = $targetObj->findConnections($child,"DDR4","");
+-
+-             if($ddrs eq "")
+-             {
+-                # on multi node system there is a possibility that either
+-                # DDR4 or DDR3 dimms are connected under a node
+-                my $ddrs = $targetObj->findConnections($child,"DDR3","");
+-             }
+-
+-             if ($ddrs ne "")
+-             {
+-                 foreach my $ddr (@{$ddrs->{CONN}})
+-                 {
+-                       my $port_num = $targetObj->getDimmPort($ddr->{SOURCE});
+-                       my $dimm_num = $targetObj->getDimmPos($ddr->{SOURCE});
+-                       my $map = oct("0b".$mba_num.$port_num.$dimm_num);
+-                       $dimm_portmap{$ddr->{DEST_PARENT}} = $map;
+-                 }
+-             }
+-         }
+-    }
+-
+-
+-    ## Process MEMBUF to DIMM I2C connections
+-    my @addr_map=('0','0','0','0','0','0','0','0');
+-    my $dimms=$targetObj->findConnections($membufTarg,"I2C","SPD");
+-    if ($dimms ne "") {
+-        foreach my $dimm (@{$dimms->{CONN}}) {
+-            my $dimm_target = $targetObj->getTargetParent($dimm->{DEST_PARENT});
+-            setEepromAttributes($targetObj,
+-                       "EEPROM_VPD_PRIMARY_INFO",$dimm_target,
+-                       $dimm);
+-
+-            my $field=getI2cMapField($targetObj,$dimm_target,$dimm);
+-            my $map = $dimm_portmap{$dimm_target};
+-
+-            if ($map eq "") {
+-                print "ERROR: $dimm_target doesn't map to a dimm/port\n";
+-                $targetObj->myExit(3);
+-            }
+-            $addr_map[$map] = $field;
+-        }
+-    }
+-    $targetObj->setAttribute($membufTarg,
+-            "MRW_MEM_SENSOR_CACHE_ADDR_MAP","0x".join("",@addr_map));
+-
+-    ## Update bus speeds
+-    processI2cSpeeds($targetObj,$membufTarg);
+-
+-    processPowerRails($targetObj, $membufTarg);
+-}
+ 
+ sub getI2cMapField
+ {
+@@ -2794,7 +2987,7 @@ sub getI2cMapField
+     return $hexfield;
+ }
+ 
+-#------------------------------------------------------------------------------
++#--------------------------------------------------
+ # I2C
+ #
+ sub processI2C
+@@ -3253,7 +3446,9 @@ sub get_max_compute_nodes
+ }
+ 
+ #--------------------------------------------------
+-## ERROR checking
++# @brief Error checking
++#
++#--------------------------------------------------
+ sub errorCheck
+ {
+     my $targetObj = shift;
+@@ -3363,9 +3558,9 @@ Options:
+              2N = special 2 node config with extra ABUS links
+              w = Special MST wrap config
+         -o = output filename
+-        -s [SDR XML file] = import SDRs
+         -r = create report and save to [system_name].rpt
+-        -v = version
++        -v = display current version
++        -t = run self test
+ ";
+     exit(1);
+ }
+@@ -3380,8 +3575,216 @@ sub do_plugin
+     {
+         $hwsvmrw_plugins{$step}(@_);
+     }
+-    elsif ($debug && ($build eq "fsp"))
++    elsif ($targetObj->{debug} && ($targetObj->{build} eq "fsp"))
++    {
++        print STDERR "build is $targetObj->{build} but no plugin for $step\n";
++    }
++}
++
++###############################################################################
++# Self tests
++###############################################################################
++#--------------------------------------------------
++# @brief The main procedure to run the tests
++#
++# @param[in] $targetObj - The global target object
++#--------------------------------------------------
++sub runTests
++{
++    print "\nRunning tests: \n\n";
++    my $targetObj = shift;
++
++    # Load the XML and process the file, extracting targets and associating
++    # attributes, with their data, to the targets
++    loadXmlFile();
++
++    # Process the targets, setting the targets attributes.
++    processTargets();
++
++    # Each one of the test build on each other, if one fails then no point in
++    # running the other
++    testGetTopologyMode($targetObj)   &&
++    testTopologyIdToTopologyIndex()   &&
++    testGetTopologyIndex($targetObj);
++}
++
++#--------------------------------------------------
++# @brief Test the method that gets the topology mode.
++#
++# @param[in] $targetObj - The global target object
++#
++# @return true if test passed, false other wise
++#--------------------------------------------------
++sub testGetTopologyMode
++{
++    print ">> Running testgetTopologyMode \n";
++    my $targetObj = shift;
++
++    my $testPassed = true;
++
++    use constant TOPOLOGY_MODE_ATTRIBUTE => "PROC_FABRIC_TOPOLOGY_MODE";
++    use constant TOPOLOGY_MODES => qw/ MODE0 MODE1 /;
++    my @topologyModes = (TOPOLOGY_MODES);
++
++    # Cache the current mode to restore later
++    my $persistMode = $targetObj->getAttribute("/".$targetObj->{TOP_LEVEL},
++                                               TOPOLOGY_MODE_ATTRIBUTE);
++
++    # Test getting the topology mode
++    foreach my $topologyMode (@topologyModes)
+     {
+-        print STDERR "build is $build but no plugin for $step\n";
++        $targetObj->setAttribute("/".$targetObj->{TOP_LEVEL},
++                                 TOPOLOGY_MODE_ATTRIBUTE,
++                                 $topologyMode);
++        my $topologyModeNumber = chop($topologyMode);
++        if (getTopologyMode($targetObj) != $topologyModeNumber)
++        {
++
++            $testPassed = false;
++            print "ERROR: Expected topology mode '$topologyModeNumber' but got " .
++                   getTopologyMode($targetObj) . "\n";
++        }
+     }
++
++    # Restore mode
++    $targetObj->setAttribute("/".$targetObj->{TOP_LEVEL},
++                             TOPOLOGY_MODE_ATTRIBUTE,
++                             $persistMode);
++
++    print "<< Running testgetTopologyMode: test " .
++          getPassFailString($testPassed) . "\n";
++
++    return $testPassed;
+ }
++
++#--------------------------------------------------
++# @brief Tests the conversion method that converts the topology ID,
++#        with given topology mode, to the topology index.
++#
++# @return true if test passed, false other wise
++#--------------------------------------------------
++sub testTopologyIdToTopologyIndex
++{
++    print ">> Running testTopologyIdToTopologyIndex \n";
++
++    my $testPassed = true;
++
++    # The different values expected when mode is 0 or 1
++    use constant TOPOLOGY_MODE_0_ARRAY => qw/ 0 1 4 5 8 9 12 13 16 17 20 21 24 25 28 29 /;
++    use constant TOPOLOGY_MODE_1_ARRAY => qw/ 0 1 2 3 8 9 10 11 16 17 18 19 24 25 26 27 /;
++
++    # The different topology modes
++    use constant TOPOLOGY_MODES => qw/ MODE0 MODE1 /;
++    my @topologyModes = (TOPOLOGY_MODES);
++
++    # Default with mode 0
++    my @toplogyModeArray = (TOPOLOGY_MODE_0_ARRAY);
++
++    # Test the conversion on the different IDs and modes
++    for my $topologyMode (@topologyModes)
++    {
++        my $topologyModeNumber = chop($topologyMode);
++        if (1 == $topologyModeNumber)
++        {
++            @toplogyModeArray = (TOPOLOGY_MODE_1_ARRAY);
++        }
++
++        # Needed variable
++        my $topologyIndex = 0;
++
++        # Iterate thru each permutation of the topology ID and
++        # test conversion to index
++        for (my $topologyId = 0; $topologyId < 16; ++$topologyId)
++        {
++            $topologyIndex = convertTopologyIdToIndex($topologyId,
++                                                      $topologyModeNumber);
++            if ($topologyIndex != $toplogyModeArray[$topologyId])
++            {
++                $testPassed = false;
++                print "ERROR: conversion on topology Id($topologyId) with ";
++                print "topology mode($topologyMode) returned ";
++                print "topology index($topologyIndex), but expected ";
++                print "topology index($toplogyModeArray[$topologyId]) \n";
++            }
++        }  # end for (my $topologyId = 0 ...
++    } # end foreach my $topologyMode (@topologyModes)
++
++    print "<< Running testTopologyIdToTopologyIndex: test " .
++          getPassFailString($testPassed) . "\n";
++
++    return $testPassed;
++}
++
++#--------------------------------------------------
++# @brief Test the method that gets the topology index based
++#        based on the current processors within the MRW XML
++#
++# @param[in] $targetObj - The global target object
++#
++# @return true if test passed, false other wise
++#--------------------------------------------------
++sub testGetTopologyIndex
++{
++    my $targetObj = shift;
++
++    my $testPassed = true;
++
++    my $system_name = $targetObj->getAttribute('/sys-0',"SYSTEM_NAME");
++    if ($system_name =~ /RAINIER/i)
++    {
++        print ">> Running testGetTopologyIndex \n";
++
++        # The different procs available
++        use constant PROC_0 => "/sys-0/node-0/nisqually-0/proc_socket-0/godel-0/power10-0";
++        use constant PROC_1 => "/sys-0/node-0/nisqually-0/proc_socket-0/godel-0/power10-1";
++
++        # Get processor 1's index
++        my $processorTarget = PROC_0;
++        my $topologyIndex = getTopologyIndex($targetObj, $processorTarget);
++
++        # For the current MRW, proc 0 has index 0 with mode 0
++        my $expectedTopologyIndex = 0;
++        if ($topologyIndex != $expectedTopologyIndex)
++        {
++            $testPassed = false;
++            my @fullProc = split(/\//, $processorTarget);
++            print "ERROR: retrieved topology index $topologyIndex for processor " .
++                   "@fullProc[-1] but expected $expectedTopologyIndex \n";
++        }
++
++        # Get processor 2's index
++        $processorTarget = PROC_1;
++        $topologyIndex = getTopologyIndex($targetObj, $processorTarget);
++
++        # For the current MRW, proc 1 has index 4 with mode 0
++        $expectedTopologyIndex = 4;
++        if ($topologyIndex != $expectedTopologyIndex)
++        {
++            $testPassed = false;
++            my @fullProc = split(/\//, $processorTarget);
++            print "ERROR: retrieved topology index $topologyIndex for processor " .
++                   "@fullProc[-1] but expected $expectedTopologyIndex \n";
++        }
++
++        print "<< Running testGetTopologyIndex: test " .
++              getPassFailString($testPassed) . "\n";
++
++    } # end if ($system_name =~ /RAINIER/i)
++
++    return $testPassed;
++}
++
++sub getPassFailString
++{
++    my $passFailBoolean = shift;
++    my $failPassString = "passed";
++
++    if ($passFailBoolean == false)
++    {
++        $failPassString = "failed";
++    }
++
++    return $failPassString;
++}
++
++
+-- 
+1.8.2.2
+