#!/usr/bin/perl -w # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # The fan topologies can be quite complicated, but are ultimately regular. This # perl file uses some simplified internal structures to generate an .xml file # without the maintenance overhead. # use Getopt::Std; use strict; # # Master table of platforms. # my @platforms = ( # # Galaxy 1/2 platforms. # # These systems have 2 fan-connector boards. Each fan-connector board has 3 # fan modules. Each fan module is an individual FRU. The fan-connector # boards are also FRUs. # { set => "Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|" . "Sun-Fire-X4100-M2|Sun-Fire-X4200-M2", topology => [ { label => "FT %d", count => 2, fru => "self" }, { fac_enum => 1, provider => "fac_prov_ipmi", count => 3, label => "FT %d FM %d", entity_ref => "ft%d.fm%d.led", entity_ref_nparams => 2, fm_service_indctr => "ft%d.fm%d.led", fru => "self" } ] }, # # Thumper platforms # # These systems have 5 fan modules, with each fan module containing 2 fans. # The FRUs for the individual fans are the containing fan module. # { set => "Sun-Fire-X4500|Sun-Fire-X4540", topology => [ { fac_enum => 0, provider => "fac_prov_ipmi", label => "FT %d", count => 5, fru => "self", entity_ref => "FT%d/PRSNT,ft%d.prsnt", entity_ref_nparams => 1, fm_service_indctr => "FT%d/SVC,ft%d.service.led", fm_ok2rm_indctr => "FT%d/OK,ft%d.ok2rm.led", }, { fac_enum => 1, provider => "fac_prov_ipmi", count => 2, entity_ref => "FT%d/FAN%d/TACH,ft%d.f%d.speed", entity_ref_nparams => 2, fru => "parent" } ] }, # # Fan Module/Fan topology for all G1N/G2N platforms. # # There are two fan boards, which are FRU's. Each fan board has # 3 fan modules for a total of 6 fan modules, with each fan module # containing 2 fans. The FRU's for the individual fans are the # containing fan module. # # Unfortunately, the IPMI topology on these systems is rather broken, and # all the SDRs that should be separate entities in fact refer to the same # entity IDs. So we have to use the alternative 'entity_present' option # using a single SDR record. # { set => "Sun-Fire-X4240|Sun-Fire-X4440", topology => [ { count => 2, label => "FANBD%d", fru => "self" }, { label => "FANBD%d FM%d", count => 3, fru => "self", provider => "fac_prov_ipmi", entity_present => "FB%d/FM%d/PRSNT,fb%d.fm%d.prsnt", fm_service_indctr=> "FB%d/FM%d/SERVICE,fb%d.fm%d.led", entity_ref_nparams => 2 }, { fac_enum => 1, count => 2, fru => "parent", provider => "fac_prov_ipmi", entity_ref => "FB%d/FM%d/F%d/TACH,fb%d.fm%d.f%d.speed", entity_present => "FB%d/FM%d/PRSNT,fb%d.fm%d.prsnt", entity_ref_nparams => 3 } ] }, # # Fan Module/Fan topology for the Sun Fire X4600/X4600 M2 platforms. # # These systems have 4 fan assemblies with a single fan per assembly. # Each fan assembly is a FRU. The fan assemblies have a service LED # but no other indicators. # { set => "Sun-Fire-X4600|Sun-Fire-X4600-M2", topology => [ { fac_enum => 1, provider => "fac_prov_ipmi", count => 4, label => "FT %d", fru => "self", entity_ref => "ft%d.fm0.prsnt", entity_ref_nparams => 1, fm_service_indctr => "ft%d.fm0.led" } ] }, # # Fan Module/Fan topology for Sun Fire X4140. # # There are two fan boards, which are FRU's. The first fanboard has 4 # fanmodules (which are also FRU's). The second fan board has 3 fan # modules. Each fanmodule contains two fans. # { set => "Sun-Fire-X4140", topology => [ { count => 2, label => "FANBD%d", fru => "self", }, { fac_enum => 1, provider => "fac_prov_ipmi", label => "FANBD%d FM%d", count => 4, fru => "self", fm_service_indctr=> "FB%d/FM%d/SERVICE,fb%d.fm%d.led", entity_ref_nparams => 2 }, { fac_enum => 1, provider => "fac_prov_ipmi", count => 2, fru => "parent", entity_ref => "FB%d/FM%d/F%d/TACH,fb%d.fm%d.f%d.speed", entity_ref_nparams => 3 } ] }, # # Fan Module/Fan topology for the Sun Fire X4150. # # There are two fan boards, which are FRU's. The first fanboard has 4 # fanmodules (which are also FRU's). The second fan board has 3 fan # modules. Each fanmodule contains two fans. # { set => "SUN-FIRE-X4150", topology => [ { count => 2, label => "FANBD%d", fru => "self", entity_present => "FB%d/PRSRNT" }, { label => "FANBD%d FM%d", count => 4, fru => "self", provider => "fac_prov_ipmi", entity_ref => "FB%d/FM%d/PRSNT", fm_service_indctr=> "", entity_ref_nparams => 2 }, { fac_enum => 1, count => 2, fru => "parent", provider => "fac_prov_ipmi", entity_ref => "FB%d/FM%d/F%d/TACH", entity_ref_nparams => 3 } ] }, # # Fan Module/Fan topology for Duradi 2U. # # There are two fan boards, which are FRU's. Both fanboards have 3 # fanmodules (which are also FRU's). Each fanmodule contains two fans. # { set => "SUN-FIRE-X4250|SUN-FIRE-X4450", topology => [ { count => 2, label => "FANBD%d", fru => "self", entity_present => "FB%d/PRSRNT" }, { label => "FANBD%d FM%d", count => 3, fru => "self", provider => "fac_prov_ipmi", entity_ref => "FB%d/FM%d/PRSNT", fm_service_indctr=> "", entity_ref_nparams => 2 }, { fac_enum => 1, count => 2, fru => "parent", provider => "fac_prov_ipmi", entity_ref => "FB%d/FM%d/F%d/TACH", entity_ref_nparams => 3 } ] } ); # # Process an entry in the topology list. We are passed the indentation level, # the current topology array, the set list, and any pushed indices. This is # called recursively. # sub process_topology { my ($indent, $toporef, $set, @indices) = @_; my @topo = @$toporef; my $level = shift @topo; my $type = $#topo == -1 ? "fan" : "fanmodule"; printf("%*s<range name='%s' min='%d' max='%d'>\n", $indent, "", $type, 0, $level->{count} - 1); $indent += 2; for (my $i = 0; $i < $level->{count}; $i++) { # # Special case code for the 1U version of Durado and Duradi, # both of which have an assymetric fan topology # last if ((($set eq "SUN-FIRE-X4150") || ($set eq "Sun-Fire-X4140")) && ($type eq "fanmodule") && ($#indices == 0) && ($indices[0] == 1) && ($i == 3)); push @indices, $i; printf("%*s<node instance='%d'>\n", $indent, "", $i); $indent += 2; # Facility enumerator if ($level->{fac_enum}) { printf("%*s<fac-enum provider='", $indent, ""); printf($level->{provider}); printf("' />\n"); } # Facility nodes for service and ok2rm LED's if ($level->{fm_service_indctr}) { printf("%*s<facility name='service' type='indicator' ". "provider='fac_prov_ipmi' >\n", $indent+2, ""); printf("%*s<propgroup name='facility' version='1' ". "name-stability='Private' data-stability='Private' >\n", $indent+4, ""); printf("%*s<propval name='type' type='uint32' ". "value='0' />\n", $indent+6, ""); printf("%*s<propmethod name='ipmi_entity' version='0' ". "propname='entity_ref' proptype='string_array' >\n", $indent+6, ""); printf("%*s<argval name='format' type='string_array'>\n", $indent+8, ""); my @refs = split(/\,/, $level->{fm_service_indctr}); foreach my $ref (@refs) { printf("%*s<argitem value='", $indent+10, ""); printf($ref, @indices); printf("' />\n"); } printf("%*s</argval>\n", $indent+8, ""); printf("%*s<argval name='offset' type='uint32' ". "value='0' />\n", $indent+8, ""); printf("%*s<argval name='nparams' type='uint32' ". "value='%d' />\n", $indent+8, "", $level->{entity_ref_nparams}); printf("%*s</propmethod>\n", $indent+6, ""); printf("%*s<propmethod name='ipmi_indicator_mode' ". "version='0' propname='mode' proptype='uint32' ". "mutable='1' >\n", $indent+6, ""); printf("%*s</propmethod>\n", $indent+6, ""); printf("%*s</propgroup>\n", $indent+4, ""); printf("%*s</facility>\n", $indent+2, ""); } if ($level->{fm_ok2rm_indctr}) { printf("%*s<facility name='ok2rm' type='indicator' ". "provider='fac_prov_ipmi' >\n", $indent+2, ""); printf("%*s<propgroup name='facility' version='1' ". "name-stability='Private' data-stability='Private' >\n", $indent+4, ""); printf("%*s<propval name='type' type='uint32' ". "value='2' />\n", $indent+6, ""); printf("%*s<propmethod name='ipmi_entity' version='0' ". "propname='entity_ref' proptype='string_array' >\n", $indent+6, ""); printf("%*s<argval name='format' type='string_array'>\n", $indent+8, ""); my @refs = split(/\,/, $level->{fm_ok2rm_indctr}); foreach my $ref (@refs) { printf("%*s<argitem value='", $indent+10, ""); printf($ref, @indices); printf("' />\n"); } printf("%*s</argval>\n", $indent+8, ""); printf("%*s<argval name='offset' type='uint32' ". "value='0' />\n", $indent+8, ""); printf("%*s<argval name='nparams' type='uint32' ". "value='%d' />\n", $indent+8, "", $level->{entity_ref_nparams}); printf("%*s</propmethod>\n", $indent+6, ""); printf("%*s<propmethod name='ipmi_indicator_mode' ". "version='0' propname='mode' proptype='uint32' mutable='1' >\n", $indent+6, ""); printf("%*s</propmethod>\n", $indent+6, ""); printf("%*s</propgroup>\n", $indent+4, ""); printf("%*s</facility>\n", $indent+2, ""); } # Protocol properties (label, fmri) printf("%*s<propgroup name='protocol' version='1' " . "name-stability='Private' data-stability='Private'>\n", $indent, ""); $indent += 2; if ($level->{label}) { printf("%*s<propval name='label' type='string' " . "value='", $indent, ""); printf($level->{label}, @indices); printf("' />\n"); } printf("%*s<propmethod name='ipmi_fru_fmri' " . "version='0' propname='FRU' proptype='fmri'>\n", $indent, ""); printf("%*s<argval name='entity' type='string' " . "value='%s' />\n", $indent + 2, "", $level->{fru}); printf("%*s</propmethod>\n", $indent, ""); $indent -= 2; printf("%*s</propgroup>\n", $indent, ""); # # Entity references (if any) # if ($level->{entity_ref}) { my $val = $level->{entity_ref}; printf("%*s<propgroup name='ipmi' version='1' " . "name-stability='Private' " . "data-stability='Private' >\n", $indent, ""); printf("%*s<propval name='entity_ref' ". "type='string_array'>\n", $indent + 2, ""); my @refs = split(/\,/, $val); foreach my $ref (@refs) { printf("%*s<propitem value='", $indent+4, ""); printf($ref, @indices); printf("' />\n"); } printf("%*s</propval>\n", $indent+2, ""); printf("%*s</propgroup>\n", $indent, ""); } if ($level->{entity_present}) { my $val = $level->{entity_present}; printf("%*s<propgroup name='ipmi' version='1' " . "name-stability='Private' " . "data-stability='Private' >\n", $indent, ""); printf("%*s<propval name='entity_present' " . "type='string_array'>\n", $indent + 2, ""); my @refs = split(/\,/, $val); foreach my $ref (@refs) { printf("%*s<propitem value='", $indent+4, ""); printf($ref, @indices); printf("' />\n"); } printf("%*s</propval>\n", $indent+4, ""); printf("%*s</propgroup>\n", $indent, ""); } # # Post-process IPMI enumerator method # printf("%*s<enum-method name='ipmi' version='1' ". "/>\n", $indent, ""); # # Children (if any) # if ($#topo != -1) { printf("%*s<dependents grouping='children'>\n", $indent, ""); process_topology($indent + 2, \@topo, $set, @indices); printf("%*s</dependents>\n", $indent, ""); } $indent -= 2; printf("%*s</node>\n", $indent, ""); pop @indices; } $indent -= 2; printf("%*s</range>\n", $indent, ""); } # # Process a single platform file. # sub process_platform { my ($desc) = @_; my $indent = 2; printf("%*s<set type='product' setlist='%s'>\n", $indent, "", $desc->{set}); process_topology($indent + 2, $desc->{topology}, $desc->{set}); printf("%*s</set>\n", $indent, ""); } print "<topology name='fan' scheme='hc'>\n"; my $desc; foreach $desc (@platforms) { process_platform($desc); } print "</topology>\n";