1#!/usr/bin/env perl
2
3#This script generates fan definitions from the MRW
4#and outputs them in a YAML file.
5
6use strict;
7use warnings;
8
9use Getopt::Long;
10use mrw::Inventory;
11use mrw::Targets;
12use mrw::Util;
13use Scalar::Util qw(looks_like_number);
14
15my $serverwizFile;
16my $outputFile;
17GetOptions("i=s" => \$serverwizFile,
18           "o=s" => \$outputFile) or printUsage();
19
20if ((not defined $serverwizFile) ||
21    (not defined $outputFile))
22{
23    printUsage();
24}
25
26my $targets = Targets->new;
27$targets->loadXML($serverwizFile);
28
29my @inventory = Inventory::getInventory($targets);
30
31my %fans = findFans();
32
33printFanYAML(\%fans, $outputFile);
34
35
36#This function returns a hash representing the fans in the system.
37#The hash looks like:
38#  $fans{<name>}{<zone>}
39#  $fans{<name>}{<profile>}
40#  @fans{<name>}{sensors}
41#
42#  Where:
43#    <name> = inventory name
44#    <zone> = cooling zone number
45#    <profile> = cooling zone profile, such as air, water, or all
46#    <sensors> = an array of the hwmon sensors for the fan's tachs
47sub findFans
48{
49    my %tachs;
50    my %fans;
51
52    #Find fans by looking at the TACH connections.  We could also find
53    #parts of type FAN, but we need the tach connection anyway to
54    #lookup the sensors on the other end...
55    for my $target (keys %{$targets->getAllTargets()})
56    {
57        my $connections = $targets->findConnections($target, "TACH");
58        next if ($connections eq "");
59
60        for my $tach (sort @{$connections->{CONN}})
61        {
62            #Because findConnections is recursive, we can hit this same
63            #connection multiple times, so only use it once.
64            next if (exists $tachs{$tach->{SOURCE}}{$tach->{DEST}});
65            $tachs{$tach->{SOURCE}}{$tach->{DEST}} = 1;
66
67            #Note: SOURCE = tach unit on fan, DEST = tach unit on fan ctlr
68
69            my $fru = Util::getEnclosingFru($targets, $tach->{SOURCE});
70            my $name = Util::getObmcName(\@inventory, $fru);
71
72            my $sensor = getSensor($tach->{DEST});
73            push @{$fans{$name}{sensors}}, $sensor;
74
75            #Get the cooling zone and profile from the fan controller part
76            my $part = $targets->getTargetParent($tach->{SOURCE});
77            my $zone = $targets->getAttribute($part, "COOLING_ZONE");
78            if (!looks_like_number($zone))
79            {
80                die "Cooling zone '$zone' on $part is not a number\n";
81            }
82
83            #If the profile isn't set, just set it to be 'all'.
84            my $profile = "";
85            if (!$targets->isBadAttribute($part, "COOLING_ZONE_PROFILE"))
86            {
87                $profile = $targets->getAttribute($part,
88                                                  "COOLING_ZONE_PROFILE");
89            }
90
91            if ($profile eq "")
92            {
93                $profile = "all";
94            }
95
96            $fans{$name}{profile} = lc $profile;
97            $fans{$name}{zone} = $zone;
98        }
99    }
100
101    return %fans;
102}
103
104
105#Find what hwmon will call this unit's reading by looking in
106#the child unit-hwmon-feature unit.
107sub getSensor
108{
109    my ($unit) = @_;
110
111    my @hwmons = Util::getChildUnitsWithTargetType($targets,
112                                                   "unit-hwmon-feature",
113                                                   $unit);
114    die "No HWMON children found for $unit\n" unless (scalar @hwmons != 0);
115
116    my $name = $targets->getAttributeField($hwmons[0],
117                                           "HWMON_FEATURE",
118                                           "DESCRIPTIVE_NAME");
119    die "No HWMON name for hwmon unit $hwmons[0]\n" if ($name eq "");
120
121    return $name;
122}
123
124
125#Creates the YAML representation of the data
126sub printFanYAML
127{
128    my ($fans, $file) = @_;
129
130    open (F, ">$file") or die "Could not open $file\n";
131
132    print F "fans:\n";
133
134    while (my ($fan, $data) = each(%{$fans}))
135    {
136        print F "  - inventory: $fan\n";
137        print F "    cooling_zone: $data->{zone}\n";
138        print F "    cooling_profile: $data->{profile}\n";
139        print F "    sensors:\n";
140        for my $s (@{$data->{sensors}})
141        {
142            print F "      - $s\n";
143        }
144    }
145
146    close F;
147}
148
149
150sub printUsage
151{
152    print "$0 -i [XML filename] -o [output YAML filename]\n";
153    exit(1);
154}
155