1#!/usr/bin/env perl 2 3use strict; 4use warnings; 5use mrw::Targets; 6use mrw::Inventory; 7use mrw::Util; 8use Getopt::Long; # For parsing command line arguments 9use YAML::Tiny qw(LoadFile); 10 11# Globals 12my $serverwizFile = ""; 13my $debug = 0; 14my $outputFile = ""; 15my $metaDataFile = ""; 16my $skipBrokenMrw = 0; 17 18# Command line argument parsing 19GetOptions( 20"i=s" => \$serverwizFile, # string 21"m=s" => \$metaDataFile, # string 22"o=s" => \$outputFile, # string 23"skip-broken-mrw" => \$skipBrokenMrw, 24"d" => \$debug, 25) 26or printUsage(); 27 28if (($serverwizFile eq "") or ($outputFile eq "") or ($metaDataFile eq "")) 29{ 30 printUsage(); 31} 32 33my $targetObj = Targets->new; 34$targetObj->loadXML($serverwizFile); 35 36#open the mrw xml and the metaData file for the sensor. 37#Fetch the sensorid,sensortype,class,object path from the mrw. 38#Get the metadata for that sensor from the metadata file. 39#Merge the data into the outputfile 40 41open(my $fh, '>', $outputFile) or die "Could not open file '$outputFile' $!"; 42my $sensorTypeConfig = LoadFile($metaDataFile); 43 44my @interestedTypes = keys %{$sensorTypeConfig}; 45my %types; 46my %entityDict; 47 48@types{@interestedTypes} = (); 49 50my @inventory = Inventory::getInventory($targetObj); 51#Process all the targets in the XML 52foreach my $target (sort keys %{$targetObj->getAllTargets()}) 53{ 54 my $sensorID = ''; 55 my $sensorType = ''; 56 my $sensorReadingType = ''; 57 my $path = ''; 58 my $obmcPath = ''; 59 my $sensorName = ''; 60 my $entityID = ''; 61 my $entityInstance = ''; 62 63 if ($targetObj->getTargetType($target) eq "unit-ipmi-sensor") { 64 65 $sensorName = $targetObj->getInstanceName($target); 66 #not interested in this sensortype 67 next if (not exists $types{$sensorName}); 68 69 $entityID = $targetObj->getAttribute($target, "IPMI_ENTITY_ID"); 70 if (exists ($entityDict{$entityID})) 71 { 72 $entityDict{$entityID}++; 73 } 74 else 75 { 76 $entityDict{$entityID} = '1'; 77 } 78 $entityInstance = $entityDict{$entityID}; 79 80 $sensorID = $targetObj->getAttribute($target, "IPMI_SENSOR_ID"); 81 82 $sensorType = hex($targetObj->getAttribute($target, 83 "IPMI_SENSOR_TYPE")); 84 85 $sensorReadingType = $targetObj->getAttribute($target, 86 "IPMI_SENSOR_READING_TYPE"); 87 88 $path = $targetObj->getAttribute($target, "INSTANCE_PATH"); 89 90 #if there is ipmi sensor without sensorid or sensorReadingType or 91 #Instance path then die 92 93 if ($sensorID eq '' or $sensorReadingType eq '' or $path eq '') { 94 next if $skipBrokenMrw; 95 close $fh; 96 die("sensor without info for target=$target"); 97 } 98 99 if (exists $sensorTypeConfig->{$sensorName}{"path"}) { 100 $obmcPath = $sensorTypeConfig->{$sensorName}->{"path"}; 101 } 102 else { 103 #removing the string "instance:" from path 104 $path =~ s/^instance:/\//; 105 $obmcPath = Util::getObmcName(\@inventory,$path); 106 } 107 108 # TODO via openbmc/openbmc#2144 - this fixup shouldn't be needed. 109 $obmcPath = checkOccPathFixup($obmcPath); 110 111 if (not defined $obmcPath) { 112 close $fh; 113 die("Unable to get the obmc path for path=$path"); 114 } 115 116 print $fh $sensorID.":\n"; 117 118 my $serviceInterface = 119 $sensorTypeConfig->{$sensorName}->{"serviceInterface"}; 120 my $readingType = $sensorTypeConfig->{$sensorName}->{"readingType"}; 121 my $sensorNamePattern = 122 $sensorTypeConfig->{$sensorName}->{"sensorNamePattern"}; 123 my $mutability = 124 $sensorTypeConfig->{$sensorName}->{"mutability"}; 125 126 # store the values in hash 127 my %data; 128 $data{'SENSOR_NAME'} = $sensorName; 129 $data{'SENSOR_TYPE'} = $sensorType; 130 $data{'SERVICE_INTF'} = $serviceInterface; 131 $data{'READING_TYPE'} = $readingType; 132 $data{'SENSOR_NAME_PATTERN'} = $sensorNamePattern; 133 $data{'MUTABILITY'} = $mutability; 134 $data{'ENTITY_ID'} = $entityID; 135 $data{'ENTITY_INSTANCE'} = $entityInstance; 136 $data{'FH'} = $fh; 137 138 my $debug = "$sensorID : $sensorName : $sensorType : "; 139 $debug .= "$serviceInterface: $readingType : $sensorNamePattern : "; 140 $debug .= "$serviceInterface: $readingType : $mutability : "; 141 $debug .= "$entityID : $entityInstance : "; 142 # temperature sensor 143 if($sensorType == 0x01) { 144 my $dbusPath = 145 temperatureSensorPathFixup($sensorName, $target, $obmcPath); 146 if (not defined $dbusPath) { 147 warn("Unsupported sensor $sensorName, Ignoring\n"); 148 next; 149 } 150 my $multiplierM = $sensorTypeConfig->{$sensorName}->{"multiplierM"}; 151 my $offsetB = $sensorTypeConfig->{$sensorName}->{"offsetB"}; 152 my $bExp = $sensorTypeConfig->{$sensorName}->{"bExp"}; 153 my $rExp = $sensorTypeConfig->{$sensorName}->{"rExp"}; 154 my $unit = $sensorTypeConfig->{$sensorName}->{"unit"}; 155 my $scale = $sensorTypeConfig->{$sensorName}->{"scale"}; 156 # TODO: openbmc/openbmc#3026 157 # Fix IPMI_SENSOR_READING_TYPE for vrm_vdd_temp_sensor 158 if ($sensorName eq "vrm_vdd_temp_sensor") { 159 $sensorReadingType = 1; 160 } 161 $data{'MULTIPLIER_M'} = $multiplierM; 162 $data{'OFFSET_B'} = $offsetB; 163 $data{'B_EXP'} = $bExp; 164 $data{'R_EXP'} = $rExp; 165 $data{'UNIT'} = $unit; 166 $data{'SCALE'} = $scale; 167 $data{'PATH'} = $dbusPath; 168 $debug .= "$multiplierM : $offsetB : $bExp : $rExp : $unit : "; 169 $debug .= "$scale : $dbusPath : $obmcPath : "; 170 } 171 else { 172 $debug .= "$obmcPath : "; 173 $data{'PATH'} = $obmcPath; 174 } 175 $data{'SENSOR_READING_TYPE'} = $sensorReadingType; 176 writeToFile(%data); 177 $debug .= "$sensorReadingType\n"; 178 printDebug("$debug"); 179 180 } 181} 182close $fh; 183 184# Construct DBus object path for temperature sensors 185sub temperatureSensorPathFixup 186{ 187 my ($sensorName, $target, $path) = @_; 188 $path = "/xyz/openbmc_project/sensors/temperature/"; 189 if($sensorName eq "cpucore_temp_sensor") { 190 my $core = $targetObj->getTargetParent($target); 191 my $coreNo = $targetObj->getAttribute($core, "IPMI_INSTANCE"); 192 my $proc = Util::getEnclosingFru($targetObj, $core); 193 my $procNo = $targetObj->getAttribute($proc, "POSITION"); 194 my $size = Util::getSizeOfChildUnitsWithType($targetObj, "CORE", $proc); 195 $coreNo = $coreNo - ($procNo * $size); 196 $path .= "p" . $procNo . "_core" . $coreNo . "_temp"; 197 } 198 elsif ($sensorName eq "dimm_temp_sensor") { 199 my $dimm = $targetObj->getTargetParent($target); 200 my $dimmconn = $targetObj->getTargetParent($dimm); 201 my $pos = $targetObj->getAttribute($dimmconn, "POSITION"); 202 $path .= "dimm" . $pos . "_temp"; 203 } 204 elsif ($sensorName eq "vrm_vdd_temp_sensor") { 205 my $proc = Util::getEnclosingFru($targetObj, $target); 206 my $procNo = $targetObj->getAttribute($proc, "POSITION"); 207 $path .= "p" . $procNo . "_vdd_temp"; 208 } 209 elsif ($sensorName eq "memory_temp_sensor") { 210 my $gvcard = $targetObj->getTargetParent($target); 211 my $pos = $targetObj->getAttribute($gvcard, "IPMI_INSTANCE"); 212 $path .= "gpu" . $pos . "_mem_temp"; 213 } 214 elsif ($sensorName eq "gpu_temp_sensor") { 215 my $gvcard = $targetObj->getTargetParent($target); 216 my $pos = $targetObj->getAttribute($gvcard, "IPMI_INSTANCE"); 217 $path .= "gpu" . $pos . "_core_temp"; 218 } 219 else { 220 return undef; 221 } 222 return $path; 223} 224 225#Write the interfaces data into the output file 226sub writeInterfaces 227{ 228 my ($interfaces, $fh) = @_; 229 print $fh " interfaces:"."\n"; 230 #Walk over all the interfces as it needs to be written 231 while (my ($interface,$properties) = each %{$interfaces}) { 232 print $fh " ".$interface.":\n"; 233 #walk over all the properties as it needs to be written 234 while (my ($dbusProperty,$dbusPropertyValue) = each %{$properties}) { 235 #will write property named "Property" first then 236 #other properties. 237 print $fh " ".$dbusProperty.":\n"; 238 while (my ($condition,$offsets) = each %{$dbusPropertyValue}) { 239 print $fh " $condition:\n"; 240 while (my ($offset,$values) = each %{$offsets}) { 241 print $fh " $offset:\n"; 242 while (my ($key,$value) = each %{$values}) { 243 print $fh " $key: ". $value."\n"; 244 } 245 } 246 } 247 } 248 } 249} 250 251#Get the metadata for the incoming sensortype from the loaded config file. 252#Write the sensor data into the output file 253sub writeToFile 254{ 255 my (%data) = @_; 256 my $sensorType = $data{'SENSOR_TYPE'}; 257 my $fs = $data{'FH'}; 258 print $fh " entityID: ".$data{'ENTITY_ID'}."\n"; 259 print $fh " entityInstance: ".$data{'ENTITY_INSTANCE'}."\n"; 260 print $fh " sensorType: ".$data{'SENSOR_TYPE'}."\n"; 261 print $fh " path: ".$data{'PATH'}."\n"; 262 print $fh " sensorReadingType: ".$data{'SENSOR_READING_TYPE'}."\n"; 263 print $fh " serviceInterface: ".$data{'SERVICE_INTF'}."\n"; 264 print $fh " readingType: ".$data{'READING_TYPE'}."\n"; 265 print $fh " sensorNamePattern: ".$data{'SENSOR_NAME_PATTERN'}."\n"; 266 print $fh " mutability: ".$data{'MUTABILITY'}."\n"; 267 268 # temperature sensor 269 if ($sensorType == 0x01) { 270 print $fh " multiplierM: ".$data{'MULTIPLIER_M'}."\n"; 271 print $fh " offsetB: ".$data{'OFFSET_B'}."\n"; 272 print $fh " bExp: ".$data{'B_EXP'}."\n"; 273 print $fh " rExp: ".$data{'R_EXP'}."\n"; 274 print $fh " unit: ".$data{'UNIT'}."\n"; 275 print $fh " scale: ".$data{'SCALE'}."\n"; 276 } 277 278 my $sensorName = $data{'SENSOR_NAME'}; 279 my $interfaces = $sensorTypeConfig->{$sensorName}->{"interfaces"}; 280 writeInterfaces($interfaces, $fh); 281} 282 283# Convert MRW OCC inventory path to application d-bus path 284sub checkOccPathFixup 285{ 286 my ($path) = @_; 287 if ("/system/chassis/motherboard/cpu0/occ" eq $path) { 288 return "/org/open_power/control/occ0"; 289 } 290 if ("/system/chassis/motherboard/cpu/occ" eq $path) { 291 return "/org/open_power/control/occ0"; 292 } 293 if ("/system/chassis/motherboard/cpu1/occ" eq $path) { 294 return "/org/open_power/control/occ1"; 295 } 296 return $path; 297} 298 299# Usage 300sub printUsage 301{ 302 print " 303 $0 -i [MRW filename] -m [SensorMetaData filename] -o [Output filename] [OPTIONS] 304Options: 305 --skip-broken-mrw = Skip broken MRW targets 306 -d = debug mode 307 \n"; 308 exit(1); 309} 310 311# Helper function to put debug statements. 312sub printDebug 313{ 314 my $str = shift; 315 print "DEBUG: ", $str, "\n" if $debug; 316} 317