# IBM_PROLOG_BEGIN_TAG
# This is an automatically generated prolog.
#
# $Source: src/usr/targeting/common/Targets.pm $
#
# OpenPOWER HostBoot Project
#
# Contributors Listed Below - COPYRIGHT 2015,2016
# [+] International Business Machines Corp.
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License.
#
# IBM_PROLOG_END_TAG
package Targets;
use strict;
use XML::Simple;
use XML::Parser;
use Data::Dumper;
sub new
{
my $class = shift;
my $self = {
xml => undef,
data => undef,
targeting => undef,
enumerations => undef,
MAX_MCS => 0,
master_proc => undef,
huid_idx => undef,
mru_idx => undef,
force => 0,
debug => 0,
version => "",
xml_version => 0,
errorsExist => 0,
NUM_PROCS => 0,
TOP_LEVEL => "",
TOPOLOGY => undef,
report_log => "",
vpd_num => 0,
DMI_FSI_MAP => {
'0' => '3',
'1' => '2',
'4' => '7',
'5' => '6'
}
# TODO RTC:132549
# DMI_FSI_MAP is a lookup table for DMI channel to FSI and ref clock.
# It is processor specific and needs to be pulled from a
# processor attribute instead of being hardcoded
};
return bless $self, $class;
}
sub setVersion
{
my $self = shift;
my $version = shift;
$self->{version} = $version;
}
sub getData
{
my $self = shift;
return $self->{data};
}
## loads ServerWiz XML format
sub loadXML
{
my $self = shift;
my $filename = shift;
$XML::Simple::PREFERRED_PARSER = 'XML::Parser';
print "Loading MRW XML: $filename\n";
$self->{xml} =
XMLin($filename,forcearray => [ 'child_id', 'hidden_child_id', 'bus',
'property', 'field', 'attribute' ]);
if (defined($self->{xml}->{'enumerationTypes'}))
{
$self->{xml_version} = 1;
}
$self->storeEnumerations();
$self->storeGroups();
$self->buildHierarchy();
$self->buildAffinity();
$self->{report_filename}=$filename.".rpt";
$self->{report_filename}=~s/\.xml//g;
}
################################################
## prints out final XML for HOSTBOOT consumption
sub printXML
{
my $self = shift;
my $fh = shift;
my $t = shift;
my $atTop = 0;
if ($t eq "top")
{
$atTop = 1;
$t = $self->{targeting}->{SYS};
print $fh "\n";
print $fh "" . $self->{version} . "\n";
}
if (ref($t) ne "ARRAY")
{
return;
}
for (my $p = 0; $p < scalar(@{$t}); $p++)
{
if (ref($t->[$p]) ne "HASH") { next; }
my $target = $t->[$p]->{KEY};
$self->printTarget($fh, $target);
my $children = $t->[$p];
foreach my $u (sort(keys %{$children}))
{
if ($u ne "KEY")
{
$self->printXML($fh, $t->[$p]->{$u});
}
}
}
if ($atTop)
{
print $fh "\n";
}
}
sub printTarget
{
my $self = shift;
my $fh = shift;
my $target = shift;
my $target_ptr = $self->getTarget($target);
print $fh "\n";
my $target_id = $self->getAttribute($target, "PHYS_PATH");
$target_id = substr($target_id, 9);
$target_id =~ s/\///g;
$target_id =~ s/\-//g;
print $fh "\t" . $target_id . "\n";
print $fh "\t" . $self->getTargetType($target) . "\n";
## get attributes
foreach my $attr (sort (keys %{ $target_ptr->{ATTRIBUTES} }))
{
$self->printAttribute($fh, $target_ptr->{ATTRIBUTES}, $attr);
}
print $fh "\n";
}
sub printAttribute
{
my $self = shift;
my $fh = shift;
my $target_ptr = shift;
my $attribute = shift;
my $r = "";
# TODO RTC: TBD
# temporary until we converge attribute types
my %filter;
$filter{MRW_TYPE} = 1;
$filter{INSTANCE_PATH} = 1;
$filter{SYSTEM_NAME} = 1;
$filter{BUS_TYPE} = 1;
$filter{DIRECTION} = 1;
$filter{ENABLE_CAPI} = 1;
$filter{PCIE_CONFIG_NUM} = 1;
$filter{PCIE_LANE_MASK} = 1;
$filter{PCIE_LANE_SET} = 1;
$filter{PCIE_NUM_LANES} = 1;
$filter{PHB_NUM} = 1;
$filter{IOP_NUM} = 1;
$filter{LOCATION_CODE} = 1;
$filter{MCS_NUM} = 1;
$filter{SCHEMATIC_INTERFACE} = 1;
$filter{ENTITY_ID} = 1;
$filter{CLASS} = 1;
$filter{MODEL} = 1;
$filter{TYPE} = 1;
$filter{CDM_POLICIES} = 1;
$filter{CDM_POLICIES_BITMASK} = 1;
$filter{ENTITY_ID_LOOKUP} = 1;
$filter{ENTITY_INSTANCE} = 1;
$filter{MBA_NUM} = 1;
$filter{IPMI_NAME} = 1;
$filter{INSTANCE_ID} = 1;
$filter{IO_CONFIG_SELECT} = 1;
$filter{FRU_NAME} = 1;
if ($filter{$attribute} == 1)
{
return;
}
print $fh "\t\n";
print $fh "\t\t$attribute\n";
my $value = $target_ptr->{$attribute}->{default};
if (ref($value) eq "HASH")
{
if (defined($value->{field}))
{
print $fh "\t\t\n";
foreach my $f (sort keys %{ $value->{field} })
{
my $v = $value->{field}->{$f}->{value};
print $fh "\t\t\t$f$v\n";
}
print $fh "\t\t\n";
}
}
else
{
print $fh "\t\t$value\n";
}
print $fh "\t\n";
}
## stores TYPE enumeration values which is used to generate HUIDs
sub storeEnumerations
{
my $self = shift;
my $baseptr = $self->{xml}->{enumerationType};
if ($self->{xml_version} == 1)
{
$baseptr = $self->{xml}->{enumerationTypes}->{enumerationType};
}
foreach my $enumType (keys(%{ $baseptr }))
{
foreach my $enum (
keys(%{$baseptr->{$enumType}->{enumerator}}))
{
$self->{enumeration}->{$enumType}->{$enum} =
$baseptr->{$enumType}->{enumerator}->{$enum}->{value};
}
}
}
sub storeGroups
{
my $self = shift;
foreach my $grp (keys(%{ $self->{xml}->{attributeGroups}
->{attributeGroup} }))
{
foreach my $attr (@{$self->{xml}->{attributeGroups}
->{attributeGroup}->{$grp}->{'attribute'}})
{
$self->{groups}->{$grp}->{$attr} = 1;
}
}
}
####################################################
## build target hierarchy recursively
##
## creates convenient data structure
## for accessing targets and busses
## Structure:
##
##{TARGETS} # location of all targets
##{NSTANCE_PATH} # keeps track of hierarchy
## path while iterating
##{TARGETS} -> target_name # specific target
##{TARGETS} -> target_name -> {TARGET} # pointer to target data
## from XML data struture
##{TARGETS} -> target_name -> {TYPE}# special attribute
##{TARGETS} -> target_name -> {PARENT} # parent target name
##{TARGETS} -> target_name -> {CHILDREN} # array of children targets
##{TARGETS} -> target_name -> {CONNECTION} -> {DEST} # array of connection
## destination targets
##{TARGETS} -> target_name -> {CONNECTION} -> {BUS} # array of busses
##{TARGETS} -> target_name -> {CHILDREN} # array of children targets
##{TARGETS} -> target_name -> {ATTRIBUTES} # attributes
## {ENUMERATION} -> enumeration_type -> enum # value of enumeration
## {BUSSES} -> bus_type[] # array of busses by
## bus_type (I2C, FSI, etc)
## {BUSSES} -> bus_type[] -> {BUS} # pointer to bus target
## from xml structure
## {BUSSES} -> bus_type[] -> {SOURCE_TARGET} # source target name
## {BUSSES} -> bus_type[] -> {DEST_TARGET} # dest target name
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'};
}
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;
}
}
}
if ($target eq "")
{
die "Unable to find system top level target\n";
}
my $old_path = $instance_path;
my $target_xml = $baseptr->{$target};
my $affinity_target = $target;
my $key = $instance_path . "/" . $target;
if ($instance_path ne "")
{
$instance_path = "instance:" . substr($instance_path, 1);
}
else
{
$instance_path = "instance:";
}
$self->setAttribute($key, "INSTANCE_PATH", $instance_path);
$self->{data}->{TARGETS}->{$key}->{TARGET} = $target_xml;
$self->{data}->{INSTANCE_PATH} = $old_path . "/" . $target;
## copy attributes
foreach my $attribute (keys %{ $target_xml->{attribute} })
{
my $value = $target_xml->{attribute}->{$attribute}->{default};
if (ref($value) eq "HASH")
{
if (defined($value->{field}))
{
foreach my $f (keys %{ $value->{field} })
{
my $field_val=$value->{field}{$f}{value};
if (ref($field_val)) {
$self->setAttributeField($key, $attribute, $f,"");
}
else
{
$self->setAttributeField($key, $attribute, $f,
$value->{field}{$f}{value});
}
}
}
else
{
$self->setAttribute($key, $attribute, "");
}
}
else
{
$self->setAttribute($key, $attribute, $value);
}
}
## global attributes overwrite local
my $settingptr = $self->{xml}->{globalSetting};
if ($self->{xml_version} == 1)
{
$settingptr = $self->{xml}->{globalSettings}->{globalSetting};
}
foreach my $prop (keys %{$settingptr->{$key}->{property}})
{
my $val=$settingptr->{$key}->{property}->
{$prop}->{value};
$self->setAttribute($key, $prop, $val);
}
## Save busses
if (defined($target_xml->{bus}))
{
foreach my $b (@{ $target_xml->{bus} })
{
if (ref($b->{dest_path}) eq "HASH") {
$b->{dest_path}="";
}
if (ref($b->{source_path}) eq "HASH") {
$b->{source_path}="";
}
my $source_target =
$key . "/" . $b->{source_path} . $b->{source_target};
my $dest_target = $key . "/" . $b->{dest_path} . $b->{dest_target};
my $bus_type = $b->{bus_type};
push(
@{
$self->{data}->{TARGETS}->{$source_target}->{CONNECTION}
->{DEST}
},
$dest_target
);
push(
@{
$self->{data}->{TARGETS}->{$source_target}->{CONNECTION}
->{BUS}
},
$b
);
my %bus_entry;
$bus_entry{SOURCE_TARGET} = $source_target;
$bus_entry{DEST_TARGET} = $dest_target;
$bus_entry{BUS_TARGET} = $b;
push(@{ $self->{data}->{BUSSES}->{$bus_type} }, \%bus_entry);
}
}
foreach my $child (@{ $target_xml->{child_id} })
{
my $child_key = $self->{data}->{INSTANCE_PATH} . "/" . $child;
$self->{data}->{TARGETS}->{$child_key}->{PARENT} = $key;
push(@{ $self->{data}->{TARGETS}->{$key}->{CHILDREN} }, $child_key);
$self->buildHierarchy($child);
}
foreach my $child (@{ $target_xml->{hidden_child_id} })
{
my $child_key = $self->{data}->{INSTANCE_PATH} . "/" . $child;
$self->{data}->{TARGETS}->{$child_key}->{PARENT} = $key;
push(@{ $self->{data}->{TARGETS}->{$key}->{CHILDREN} }, $child_key);
$self->buildHierarchy($child);
}
$self->{data}->{INSTANCE_PATH} = $old_path;
}
##########################################################
## traces busses and builds affinity hierarchy
## HOSTBOOT expected hierarchy: sys/node/proc/
## sys/node/proc/mcs/membuf/
## sys/node/proc/mcs/membuf/mba/dimm
sub buildAffinity
{
my $self = shift;
my $node = -1;
my $tpm = -1;
my $proc = -1;
my $node_phys = "";
my $node_aff = "";
my $core_num = 0;
$self->{membuf_inst_num}=0;
foreach my $target (sort keys %{ $self->{data}->{TARGETS} })
{
my $target_ptr = $self->{data}->{TARGETS}{$target};
my $type = $self->getType($target);
my $type_id = $self->getEnumValue("TYPE", $type);
if ($type_id eq "") { $type_id = 0; }
if ($type eq "SYS")
{
$proc = -1;
$node = -1;
$self->{targeting}{SYS}[0]{KEY} = $target;
$self->setAttribute($target, "AFFINITY_PATH",
"affinity:".$self->{TOP_LEVEL});
$self->setAttribute($target, "PHYS_PATH",
"physical:".$self->{TOP_LEVEL});
$self->setAttribute($target, "ENTITY_INSTANCE","0");
}
elsif ($type eq "NODE")
{
$core_num = 0;
$proc = -1;
$self->{dimm_tpos} = 0;
$self->{membuf_inst_num}=0;
$node++;
$node_phys = "physical:".$self->{TOP_LEVEL}."/node-$node";
$node_aff = "affinity:".$self->{TOP_LEVEL}."/node-$node";
$self->{targeting}{SYS}[0]{NODES}[$node]{KEY} = $target;
$self->setAttribute($target, "AFFINITY_PATH",
"affinity:".$self->{TOP_LEVEL}."/node-$node");
$self->setAttribute($target, "PHYS_PATH",
"physical:".$self->{TOP_LEVEL}."/node-$node");
$self->setHuid($target, 0, $node);
$self->setAttribute($target, "ENTITY_INSTANCE",$node);
}
elsif ($type eq "TPM")
{
$tpm++;
$self->{targeting}{SYS}[0]{NODES}[$node]{TPMS}[$tpm]{KEY} = $target;
$self->setAttribute($target, "AFFINITY_PATH",
"affinity:".$self->{TOP_LEVEL}.
"/node-$node/tpm-$tpm");
$self->setAttribute($target, "PHYS_PATH",
"physical:".$self->{TOP_LEVEL}.
"/node-$node/tpm-$tpm");
$self->setHuid($target, 0, $tpm);
$self->setAttribute($target, "ENTITY_INSTANCE",$tpm);
}
elsif ($type eq "PROC")
{
$proc++;
my $num_mcs = 0;
### count number of MCSs
foreach my $unit (@{ $self->{data}->{TARGETS}{$target}{CHILDREN} })
{
my $unit_type = $self->getType($unit);
if ($unit_type eq "MCS")
{
$num_mcs++;
}
}
if ($num_mcs > $self->{MAX_MCS})
{
$self->{MAX_MCS} = $num_mcs;
}
$self->{NUM_PROCS_PER_NODE} = $proc + 1;
$self->{targeting}->{SYS}[0]{NODES}[$node]{PROCS}[$proc]{KEY} =
$target;
$self->setHuid($target, 0, $node);
my $socket = $self->getTargetParent(
$self->getTargetParent($target));
my $parent_affinity = "affinity:".$self->{TOP_LEVEL}
."/node-$node/proc-$proc";
my $parent_physical = "physical:".$self->{TOP_LEVEL}
."/node-$node/proc-$proc";
$self->setAttribute($target, "AFFINITY_PATH", $parent_affinity);
$self->setAttribute($target, "PHYS_PATH", $parent_physical);
$self->setAttribute($target, "POSITION", $proc);
$self->setAttribute($target, "ENTITY_INSTANCE",$proc);
$self->setAttribute($target, "FABRIC_GROUP_ID",
$self->getAttribute($socket,"FABRIC_GROUP_ID"));
$self->setAttribute($target, "FABRIC_CHIP_ID",
$self->getAttribute($socket,"FABRIC_CHIP_ID"));
$self->setAttribute($target, "VPD_REC_NUM", $proc);
foreach my $unit (@{ $self->{data}->{TARGETS}{$target}{CHILDREN} })
{
my $unit_ptr = $self->getTarget($unit);
my $unit_type = $self->getType($unit);
my $unit_type_id = $self->getEnumValue("TYPE", $unit_type);
if ( $unit_type_id eq "" || $unit_type eq "FSI"
|| $unit_type eq "MCS")
{
$unit_type_id = 0;
}
## don't want non-hostboot targets
if ($unit_type_id > 0)
{
push(@{$self->{targeting}
->{SYS}[0]{NODES}[$node]{PROCS}[$proc]{$unit_type}},
{ 'KEY' => $unit });
my $affinity_path =
$parent_affinity . "/"
. $self->getTarget($unit)->{TARGET}->{instance_name};
my $physical_path =
$parent_physical . "/"
. $self->getTarget($unit)->{TARGET}->{instance_name};
$self->setAttribute($unit, "AFFINITY_PATH",$affinity_path);
$self->setAttribute($unit, "PHYS_PATH", $physical_path);
$self->setHuid($unit, 0, $node);
if ($unit_type eq "OCC")
{
$self->setAttribute($unit, "ENTITY_INSTANCE",$proc);
}
## export core
if ($unit_type eq "EX")
{
my $core_unit_num = $self->getAttribute($unit,
"CHIP_UNIT");
my $core_unit =
$self->{data}->{TARGETS}{$unit}{CHILDREN}[0];
push(
@{
$self->{targeting}
->{SYS}[0]{NODES}[$node]{PROCS}[$proc]{CORE}
},
{ 'KEY' => $core_unit }
);
my $core_affinity_path =
$affinity_path . "/"
. $self->getTarget($core_unit)->{TARGET}
->{instance_name};
my $core_physical_path =
$physical_path . "/"
. $self->getTarget($core_unit)->{TARGET}
->{instance_name};
$self->setAttribute($core_unit, "AFFINITY_PATH",
$core_affinity_path);
$self->setAttribute($core_unit, "PHYS_PATH",
$core_physical_path);
$self->setAttribute($core_unit, "CHIP_UNIT",
$core_unit_num);
$self->setHuid($core_unit, 0, $node);
$self->setAttribute($core_unit, "ENTITY_INSTANCE",
$core_num);
$core_num++;
}
}
elsif ($unit_type eq "MCS")
{
$self->processMcs($unit, $node, $proc, $parent_affinity,
$parent_physical, $node_phys);
}
}
}
}
}
sub processMcs
{
my $self = shift;
my $unit = shift;
my $node = shift;
my $proc = shift;
my $parent_affinity = shift;
my $parent_physical = shift;
my $node_phys = shift;
my $mcs = $self->getAttribute($unit, "CHIP_UNIT");
my $membufnum = $proc * $self->{MAX_MCS} + $mcs;
$self->setAttribute($unit, "AFFINITY_PATH",$parent_affinity . "/mcs-$mcs");
$self->setAttribute($unit, "PHYS_PATH", $parent_physical . "/mcs-$mcs");
$self->setAttribute($unit, "MCS_NUM", $mcs);
$self->setHuid($unit, 0, $node);
$self->{targeting}->{SYS}[0]{NODES}[$node]{PROCS}[$proc]{MCSS}[$mcs]{KEY} =
$unit;
$self->setAttribute($unit, "EI_BUS_TX_LANE_INVERT","0");
$self->setAttribute($unit, "EI_BUS_TX_MSBSWAP","0");
$self->setAttribute($unit, "DMI_REFCLOCK_SWIZZLE","0");
## Find connected membufs
my $membuf_dmi = $self->{data}->{TARGETS}{$unit}{CONNECTION}{DEST}[0];
if (defined($membuf_dmi))
{
## found membuf connected
my $membuf =
$self->{data}->{TARGETS}{$membuf_dmi}
{PARENT}; ## get parent of dmi unit which is membuf
my $dmi_bus = $self->{data}->{TARGETS}{$unit}{CONNECTION}{BUS}[0];
$self->setAttribute($membuf, "POSITION",$membufnum);
$self->setAttribute($membuf, "AFFINITY_PATH",
$parent_affinity . "/mcs-$mcs/membuf-$membufnum");
$self->setAttribute($membuf, "PHYS_PATH",
$node_phys . "/membuf-$membufnum");
## copy DMI bus attributes to membuf
$self->setAttribute($unit, "EI_BUS_TX_LANE_INVERT",
$dmi_bus->{bus_attribute}->{PROC_TX_LANE_INVERT}->{default});
$self->setAttribute($unit, "EI_BUS_TX_MSBSWAP",
$dmi_bus->{bus_attribute}->{PROC_TX_MSBSWAP}->{default});
$self->setAttribute($membuf, "EI_BUS_TX_LANE_INVERT",
$dmi_bus->{bus_attribute}->{MEMBUF_TX_LANE_INVERT}->{default});
$self->setAttribute($membuf, "EI_BUS_TX_MSBSWAP",
$dmi_bus->{bus_attribute}->{MEMBUF_TX_MSBSWAP}->{default});
## auto setup FSI assuming schematic symbol. If FSI busses are
## defined in serverwiz2, this will be overridden
## in the schematic symbol, the fsi port num matches dmi ref clk num
my $fsi_port = $self->{DMI_FSI_MAP}->{$mcs};
my $proc_key =
$self->{targeting}->{SYS}[0]{NODES}[$node]{PROCS}[$proc]{KEY};
my $proc_path = $self->getAttribute($proc_key,"PHYS_PATH");
$self->setFsiAttributes($membuf,"FSICM",0,$proc_path,$fsi_port,0);
$self->setAttribute($unit, "DMI_REFCLOCK_SWIZZLE",$fsi_port);
my $dmi_swizzle =
$self->getBusAttribute($unit,0,"DMI_REFCLOCK_SWIZZLE");
if ($dmi_swizzle ne "")
{
$self->setAttribute($unit, "DMI_REFCLOCK_SWIZZLE",$dmi_swizzle);
}
$self->setHuid($membuf, 0, $node);
$self->{targeting}
->{SYS}[0]{NODES}[$node]{PROCS}[$proc]{MCSS}[$mcs] {MEMBUFS}[0]{KEY} =
$membuf;
$self->setAttribute($membuf, "ENTITY_INSTANCE",
$self->{membuf_inst_num});
$self->{membuf_inst_num}++;
## get the mbas
foreach my $child (@{ $self->{data}->{TARGETS}{$membuf}{CHILDREN} })
{
## need to not hardcard the subunits
if ($self->getType($child) eq "L4")
{
$self->{targeting}
->{SYS}[0]{NODES}[$node]{PROCS}[$proc]{MCSS}[$mcs]{MEMBUFS}[0]
{L4S}[0] {KEY} = $child;
$self->setAttribute($child, "AFFINITY_PATH",
$parent_affinity . "/mcs-$mcs/membuf-$membufnum/l4-0");
$self->setAttribute($child, "PHYS_PATH",
$node_phys . "/membuf-$membufnum/l4-0");
$self->setHuid($child, 0, $node);
}
if ($self->getType($child) eq "MBA")
{
my $mba = $self->getAttribute($child,"MBA_NUM");
$self->setAttribute($child, "AFFINITY_PATH",
$parent_affinity . "/mcs-$mcs/membuf-$membufnum/mba-$mba");
$self->setAttribute($child, "PHYS_PATH",
$node_phys . "/membuf-$membufnum/mba-$mba");
$self->setHuid($child, 0, $node);
$self->{targeting}
->{SYS}[0]{NODES}[$node]{PROCS}[$proc]{MCSS}[$mcs]{MEMBUFS}[0]
{MBAS}[$mba]{KEY} = $child;
## Trace the DDR busses to find connected DIMM
my $ddrs = $self->findConnections($child,"DDR3","");
if ($ddrs ne "")
{
my $affinitypos=0;
foreach my $dimms (@{$ddrs->{CONN}})
{
my $ddr = $dimms->{SOURCE};
my $port_num = $self->getAttribute($ddr,"MBA_PORT");
my $dimm_num = $self->getAttribute($ddr,"MBA_DIMM");
my $dimm=$dimms->{DEST_PARENT};
$self->setAttribute($dimm,"MBA_PORT",$port_num);
$self->setAttribute($dimm,"MBA_DIMM",$dimm_num);
my $aff_pos=16*$proc+$mcs*$self->{MAX_MCS}+4*$mba+
2*$port_num+$dimm_num;
$self->setAttribute($dimm, "AFFINITY_PATH",
$parent_affinity
. "/mcs-$mcs/membuf-$membufnum/mba-$mba/dimm-$affinitypos"
);
$self->setAttribute($dimm, "PHYS_PATH",
$node_phys . "/dimm-" . $self->{dimm_tpos});
$self->setAttribute($dimm, "POSITION",
$aff_pos);
$self->setAttribute($dimm, "VPD_REC_NUM",
$aff_pos);
$self->setHuid($dimm, 0, $node);
$self->{targeting}
->{SYS}[0]{NODES}[$node]{PROCS}[$proc] {MCSS}[$mcs]
{MEMBUFS}[0]{MBAS}[$mba] {DIMMS}[$affinitypos]{KEY} =
$dimm;
$self->setAttribute($dimm, "ENTITY_INSTANCE",
$self->{dimm_tpos});
$self->{dimm_tpos}++;
$affinitypos++;
}
}
}
}
}
}
sub setFsiAttributes
{
my $self = shift;
my $target = shift;
my $type = shift;
my $cmfsi = shift;
my $phys_path = shift;
my $fsi_port = shift;
my $flip_port = shift;
$self->setAttribute($target, "FSI_MASTER_TYPE","NO_MASTER");
if ($type eq "FSIM")
{
$self->setAttribute($target, "FSI_MASTER_TYPE","MFSI");
}
if ($type eq "FSICM")
{
$self->setAttribute($target, "FSI_MASTER_TYPE","CMFSI");
}
$self->setAttribute($target, "FSI_MASTER_CHIP","physical:sys");
$self->setAttribute($target, "FSI_MASTER_PORT","0xFF");
$self->setAttribute($target, "ALTFSI_MASTER_CHIP","physical:sys");
$self->setAttribute($target, "ALTFSI_MASTER_PORT","0xFF");
$self->setAttribute($target, "FSI_SLAVE_CASCADE", "0");
if ($cmfsi == 0)
{
$self->setAttribute($target, "FSI_MASTER_CHIP",$phys_path);
$self->setAttribute($target, "FSI_MASTER_PORT", $fsi_port);
}
else
{
$self->setAttribute($target, "ALTFSI_MASTER_CHIP",$phys_path);
$self->setAttribute($target, "ALTFSI_MASTER_PORT", $fsi_port);
}
#my $phys_path = $targetObj->getAttribute($parentTarget, "PHYS_PATH");
$self->setAttributeField($target, "FSI_OPTION_FLAGS","flipPort",
$flip_port);
$self->setAttributeField($target, "FSI_OPTION_FLAGS","reserved", "0");
}
## returns pointer to target from target name
sub getTarget
{
my $self = shift;
my $target = shift;
return $self->{data}->{TARGETS}->{$target};
}
## returns pointer to array of all targets
sub getAllTargets
{
my $self = shift;
my $target = shift;
return $self->{data}->{TARGETS};
}
## returns the target name of the parent of passed in target
sub getTargetParent
{
my $self = shift;
my $target = shift;
my $target_ptr = $self->getTarget($target);
return $target_ptr->{PARENT};
}
## returns the number of connections associated with target
sub getNumConnections
{
my $self = shift;
my $target = shift;
my $target_ptr = $self->getTarget($target);
if (!defined($target_ptr->{CONNECTION}->{DEST}))
{
return 0;
}
return scalar(@{ $target_ptr->{CONNECTION}->{DEST} });
}
## returns destination target name of first connection
## useful for point to point busses with only 1 endpoint
sub getFirstConnectionDestination
{
my $self = shift;
my $target = shift;
my $target_ptr = $self->getTarget($target);
return $target_ptr->{CONNECTION}->{DEST}->[0];
}
## returns pointer to bus of first connection
sub getFirstConnectionBus
{
my $self = shift;
my $target = shift;
my $target_ptr = $self->getTarget($target);
return $target_ptr->{CONNECTION}->{BUS}->[0];
}
## returns target name of $i connection
sub getConnectionDestination
{
my $self = shift;
my $target = shift;
my $i = shift;
my $target_ptr = $self->getTarget($target);
return $target_ptr->{CONNECTION}->{DEST}->[$i];
}
sub getConnectionBus
{
my $self = shift;
my $target = shift;
my $i = shift;
my $target_ptr = $self->getTarget($target);
return $target_ptr->{CONNECTION}->{BUS}->[$i];
}
sub findFirstEndpoint
{
my $self = shift;
my $target = shift;
my $bus_type = shift;
my $end_type = shift;
my $target_children = $self->getTargetChildren($target);
if ($target_children eq "") { return ""; }
foreach my $child (@{ $self->getTargetChildren($target) })
{
my $child_bus_type = $self->getBusType($child);
if ($child_bus_type eq $bus_type)
{
for (my $i = 0; $i < $self->getNumConnections($child); $i++)
{
my $dest_target = $self->getConnectionDestination($child, $i);
my $dest_parent = $self->getTargetParent($dest_target);
my $type = $self->getMrwType($dest_parent);
my $dest_type = $self->getType($dest_parent);
if ($type eq "NA") { $type = $dest_type; }
if ($type eq $end_type)
{
return $dest_parent;
}
}
}
}
return "";
}
sub findConnections
{
my $self = shift;
my $target = shift;
my $bus_type = shift;
my $end_type = shift;
my %connections;
my $num=0;
my $target_children = $self->getTargetChildren($target);
if ($target_children eq "")
{
return "";
}
foreach my $child (@{ $self->getTargetChildren($target) })
{
my $child_bus_type = $self->getBusType($child);
if ($child_bus_type eq $bus_type)
{
for (my $i = 0; $i < $self->getNumConnections($child); $i++)
{
my $dest_target = $self->getConnectionDestination($child, $i);
my $dest_parent = $self->getTargetParent($dest_target);
my $type = $self->getMrwType($dest_parent);
my $dest_type = $self->getType($dest_parent);
my $dest_class = $self->getAttribute($dest_parent,"CLASS");
if ($type eq "NA")
{
$type = $dest_type;
}
if ($type eq "NA") {
$type = $dest_class;
}
if ($type eq $end_type || $end_type eq "")
{
$connections{CONN}[$num]{SOURCE}=$child;
$connections{CONN}[$num]{SOURCE_PARENT}=$target;
$connections{CONN}[$num]{DEST}=$dest_target;
$connections{CONN}[$num]{DEST_PARENT}=$dest_parent;
$connections{CONN}[$num]{BUS_NUM}=$i;
$num++;
}
}
}
}
if ($num==0) { return ""; }
return \%connections;
}
## returns BUS_TYPE attribute of target
sub getBusType
{
my $self = shift;
my $target = shift;
my $type = $self->getAttribute($target, "BUS_TYPE");
if ($type eq "") { $type = "NA"; }
return $type;
}
## return target type
sub getType
{
my $self = shift;
my $target = shift;
my $type = $self->getAttribute($target, "TYPE");
if ($type eq "") { $type = "NA"; }
return $type;
}
## return target type
sub getMrwType
{
my $self = shift;
my $target = shift;
my $type = $self->getAttribute($target, "MRW_TYPE");
if ($type eq "") { $type = "NA"; }
return $type;
}
## returns target instance name
sub getInstanceName
{
my $self = shift;
my $target = shift;
my $target_ptr = $self->getTarget($target);
return $target_ptr->{TARGET}->{instance_name};
}
## returns the parent target type
sub getTargetType
{
my $self = shift;
my $target = shift;
my $target_ptr = $self->getTarget($target);
return $target_ptr->{TARGET}->{type};
}
## checks if attribute is value
## must be defined and have a non-empty value
sub isBadAttribute
{
my $self = shift;
my $target = shift;
my $attribute = shift;
my $badvalue = shift;
my $target_ptr = $self->getTarget($target);
if (!defined($target_ptr->{ATTRIBUTES}->{$attribute}))
{
return 1;
}
if (!defined($target_ptr->{ATTRIBUTES}->{$attribute}->{default}))
{
return 1;
}
if ($target_ptr->{ATTRIBUTES}->{$attribute}->{default} eq "")
{
return 1;
}
if (defined $badvalue &&
$target_ptr->{ATTRIBUTES}->{$attribute}->{default} eq $badvalue)
{
return 1;
}
return 0;
}
## checks if complex attribute field is
## defined and non-empty
sub isBadComplexAttribute
{
my $self = shift;
my $target = shift;
my $attribute = shift;
my $field = shift;
my $badvalue = shift;
my $target_ptr = $self->getTarget($target);
if (!defined($target_ptr->{ATTRIBUTES}->{$attribute}))
{
return 1;
}
if (!defined($target_ptr->{ATTRIBUTES}->{$attribute}->{default}))
{
return 1;
}
if (!defined($target_ptr->{ATTRIBUTES}->{$attribute}->{default}->{field}))
{
return 1;
}
if ($target_ptr->{ATTRIBUTES}->{$attribute}->{default}->{field}->{$field}
->{value} eq "")
{
return 1;
}
if ($target_ptr->{ATTRIBUTES}->{$attribute}->{default}->{field}->{$field}
->{value} eq $badvalue)
{
return 1;
}
return 0;
}
## returns attribute value
sub getAttribute
{
my $self = shift;
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",
$target, $attribute);
$self->myExit(4);
}
if (ref($target_ptr->{ATTRIBUTES}->{$attribute}->{default}) eq "HASH")
{
return "";
}
return $target_ptr->{ATTRIBUTES}->{$attribute}->{default};
}
sub getAttributeGroup
{
my $self = shift;
my $target = shift;
my $group = shift;
my $target_ptr = $self->getTarget($target);
if (!defined($self->{groups}->{$group})) {
printf("ERROR: getAttributeGroup(%s,%s) | Group not defined\n",
$target, $group);
$self->myExit(4);
}
my %attr;
foreach my $attribute (keys(%{$self->{groups}->{$group}}))
{
if (defined($target_ptr->{ATTRIBUTES}->{$attribute}->{default}))
{
$attr{$attribute} = $target_ptr->{ATTRIBUTES}->{$attribute};
}
}
return \%attr;
}
## renames a target attribute
sub renameAttribute
{
my $self = shift;
my $target = shift;
my $oldName = shift;
my $newName = shift;
my $target_ptr = $self->{data}->{TARGETS}->{$target};
if (!defined($target_ptr->{ATTRIBUTES}->{$oldName}))
{
return 1;
}
$target_ptr->{ATTRIBUTES}->{$newName}->{default} =
$target_ptr->{ATTRIBUTES}->{$oldName}->{default};
delete($target_ptr->{ATTRIBUTES}->{$oldName});
$self->log($target, "Renaming attribute: $oldName => $newName");
return 0;
}
## copy an attribute between targets
sub copyAttribute
{
my $self = shift;
my $source_target = shift;
my $dest_target = shift;
my $attribute = shift;
my $value=$self->getAttribute($source_target,$attribute);
$self->setAttribute($dest_target,$attribute,$value);
$self->log($dest_target, "Copy Attribute: $attribute=$value");
}
## sets an attribute
sub setAttribute
{
my $self = shift;
my $target = shift;
my $attribute = shift;
my $value = shift;
my $target_ptr = $self->getTarget($target);
$target_ptr->{ATTRIBUTES}->{$attribute}->{default} = $value;
$self->log($target, "Setting Attribute: $attribute=$value");
}
## sets the field of a complex attribute
sub setAttributeField
{
my $self = shift;
my $target = shift;
my $attribute = shift;
my $field = shift;
my $value = shift;
$self->{data}->{TARGETS}->{$target}->{ATTRIBUTES}->{$attribute}->{default}
->{field}->{$field}->{value} = $value;
}
## returns complex attribute value
sub getAttributeField
{
my $self = shift;
my $target = shift;
my $attribute = shift;
my $field = shift;
my $target_ptr = $self->getTarget($target);
if (!defined($target_ptr->{ATTRIBUTES}->{$attribute}->
{default}->{field}->{$field}->{value}))
{
printf("ERROR: getAttributeField(%s,%s,%s) | Attribute not defined\n",
$target, $attribute,$field);
$self->myExit(4);
}
return $target_ptr->{ATTRIBUTES}->{$attribute}->
{default}->{field}->{$field}->{value};
}
## returns an attribute from a bus
sub getBusAttribute
{
my $self = shift;
my $target = shift;
my $busnum = shift;
my $attr = shift;
my $target_ptr = $self->getTarget($target);
if (
!defined(
$target_ptr->{CONNECTION}->{BUS}->[$busnum]->{bus_attribute}
->{$attr}->{default}
)
)
{
printf("ERROR: getBusAttribute(%s,%d,%s) | Attribute not defined\n",
$target, $busnum, $attr);
$self->myExit(4);
}
if (ref($target_ptr->{CONNECTION}->{BUS}->[$busnum]->{bus_attribute}->{$attr}
->{default}) eq "HASH") {
return "";
}
return $target_ptr->{CONNECTION}->{BUS}->[$busnum]->{bus_attribute}->{$attr}
->{default};
}
## returns a pointer to an array of children target names
sub getTargetChildren
{
my $self = shift;
my $target = shift;
my $target_ptr = $self->getTarget($target);
## this is an array
return $target_ptr->{CHILDREN};
}
sub getEnumValue
{
my $self = shift;
my $enumType = shift;
my $enumName = shift;
if (!defined($self->{enumeration}->{$enumType}->{$enumName}))
{
printf("ERROR: getEnumValue(%s,%s) | enumType not defined\n",
$enumType, $enumName);
$self->myExit(4);
}
return $self->{enumeration}->{$enumType}->{$enumName};
}
sub getEnumHash
{
my $self = shift;
my $enumType = shift;
my $enumName = shift;
if (!defined($self->{enumeration}->{$enumType}))
{
printf("ERROR: getEnumValue(%s) | enumType not defined\n",
$enumType);
print Dumper($self->{enumeration});
$self->myExit(4);
}
return $self->{enumeration}->{$enumType};
}
sub setHuid
{
my $self = shift;
my $target = shift;
my $sys = shift;
my $node = shift;
my $type = $self->getType($target);
my $type_id = $self->{enumeration}->{TYPE}->{$type};
if ($type_id eq "") { $type_id = 0; }
if ($type_id == 0) { return; }
my $index = 0;
if (defined($self->{huid_idx}->{$type}))
{
$index = $self->{huid_idx}->{$type};
}
else { $self->{huid_idx}->{$type} = 0; }
# Format: SSSS NNNN TTTTTTTT iiiiiiiiiiiiiiii
my $huid = sprintf("%01x%01x%02x%04x", $sys, $node, $type_id, $index);
$huid = "0x" . uc($huid);
$self->setAttribute($target, "HUID", $huid);
$self->{huid_idx}->{$type}++;
$self->log($target, "Setting HUID: $huid");
$self->setMruid($target, $node);
}
sub setMruid
{
my $self = shift;
my $target = shift;
my $node = shift;
my $type = $self->getType($target);
my $mru_prefix_id = $self->{enumeration}->{MRU_PREFIX}->{$type};
if (!defined $mru_prefix_id || $mru_prefix_id eq "")
{
$mru_prefix_id = "0xFFFF";
}
if ($mru_prefix_id eq "0xFFFF") { return; }
my $index = 0;
if (defined($self->{mru_idx}->{$node}->{$type}))
{
$index = $self->{mru_idx}->{$node}->{$type};
}
else { $self->{mru_idx}->{$node}->{$type} = 0; }
my $mruid = sprintf("%s%04x", $mru_prefix_id, $index);
$self->setAttribute($target, "MRU_ID", $mruid);
$self->{mru_idx}->{$node}->{$type}++;
}
sub getMasterProc
{
my $self = shift;
return $self->{master_proc};
}
sub setMasterProc
{
my $self = shift;
my $target = shift;
$self->{master_proc}=$target;
}
sub getSystemName
{
my $self = shift;
return $self->getAttribute("/".$self->{TOP_LEVEL}, "SYSTEM_NAME");
}
sub myExit
{
my $self = shift;
my $exit_code = shift;
if ($exit_code eq "") { $exit_code = 0; }
$self->{errorsExist} = 1;
if ($self->{force} == 0)
{
exit($exit_code);
}
}
sub log
{
my $self = shift;
my $target = shift;
my $msg = shift;
if ($self->{debug})
{
print "DEBUG: ($target) $msg\n";
}
}
sub writeReport
{
my $self = shift;
my $msg = shift;
$self->{report_log}=$self->{report_log}.$msg;
}
sub writeReportFile
{
my $self = shift;
open(R,">$self->{report_filename}") ||
die "Unable to create file: ".$self->{report_filename};
print R $self->{report_log};
close R;
}
1;
=head1 NAME
Targets
=head1 SYNOPSIS
use Targets;
my $targets = Targets->new;
$targets->loadXML("myfile.xml");
foreach my $target ( sort keys %{ $targets->getAllTargets() } ) {
## do stuff with targets
}
$targets->printXML( $file_handle, "top" );
=head1 DESCRIPTION
C is a class that consumes XML generated by ServerWiz2. The XML
describes a POWER system topology including nodes, cards, chips, and busses.
=head1 OVERVIEW
A simple example of a ServerWiz2 topology would be:
=over 4
=item Topology Example:
-system
-node
-motherboard
-processor
-pcie card
- daughtercard
- memory buffer
- dimms
=back
Targets->loadXML("myfile.xml") reads this topology and creates 2 data
structures. One data structure simply represents the hierarchical system
topology. The other data structure represents the hierarchical structure
that hostboot expects (affinity path).
Unlike hostboot, everything in ServerWiz2 is represented as a target.
For example, FSI and I2C units are targets under the processor that have a
bus type and therefore allow connections to be made.
=head1 CONSTRUCTOR
=over 4
=item new ()
There are no arguments for the constructor.
=back
=head1 METHODS
C is a pointer to data structure containing all target information.
C is the hierarchical target string used as key for data
structure. An example for C would be:
C
=over 4
=item loadXml (C)
Reads ServerWiz2 XML C and stores into a data structure for
manipulation and printing.
=item getTarget(C)
Returns pointer to data structure (C)
=item getAllTargets(C)
Returns array with all existing target data structures
=item getTargetParent(C)
Returns C of parent target
=item getNumConnections(C)
Returns the number of bus connections to this target
=item getFirstConnectionDestination(C)
Returns the target string of the first target found connected to
C. This is useful because many busses are guaranteed
to only have one connection because they are point to point.
=item getFirstConnectionBus(C)
Returns the data structure of the bus of the first target found connected to
C. The bus data structure is also a target with attributes.
=item getConnectionDestination(C,C)
Returns the target string of the C target found connected to
C.
=item getConnectionBus(C)
Returns the data structure of the C bus target found connected to
C.
=item findEndpoint(C,C,C)
Searches through all connections to C
for a endpoint C and C
=item getBusType(C)
Returns the BUS_TYPE attribute of (C). Examples are I2C and DMI.
=item getType(C)
Returns the TYPE attribute of (C).
Examples are PROC and MEMBUF.
=item getMrwType(C)
Returns the MRW_TYPE attribute of (C).
Examples are CARD and PCI_CONFIG. This
is an extension to the TYPE attribute and are types that hostboot does
not care about.
=item getTargetType(C)
Returns the target type id of (C).
This is not the TYPE attribute. This is the
from target_types.xml. Examples are unit-pci-power8 and enc-node-power8.
=item isBadAttribute(C,C)
Tests where attribute (C) has been set in
target (C). Returns true if attribute is undefined or empty
and false if attribute is defined and not empty.
=item getAttribute(C,C)
Returns the value of attribute C in target C.
=item renameAttribute(C,C,
C)
Renames attribute C to C in target
C.
=item setAttribute(C,C,C)
Sets attribute C of target C to value C.
=item setAttributeField(C,C,C,C)
Sets attribute C and field C of target C
to value C. This is for complex attributes.
=item getBusAttribute(C,C,C)
Gets the attribute C from bus C bus number
C.
=item getTargetChildren(C)
Returns an array of target strings representing all the children of target
C.
=item getEnumValue(C,C)
Returns the enum value of type C and name C. The
enumerations are also defined in ServerWiz2 XML output and are directly
copied from attribute_types.xml.
=item getMasterProc()
Returns the target string of the master processor.
=item myExit(C)
Calls exit(C) when force flag is not set.
=item log(C,C)
Prints to stdout log message is debug mode is turned on.
=back
=head1 CREDITS
Norman James
=cut