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