1#!/usr/bin/perl -w
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22#
23# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26#ident	"%Z%%M%	%I%	%E% SMI"
27
28#
29# The fan topologies can be quite complicated, but are ultimately regular.  This
30# perl file uses some simplified internal structures to generate an .xml file
31# without the maintenance overhead.
32#
33
34use Getopt::Std;
35use strict;
36
37#
38# Master table of platforms.
39#
40my @platforms = (
41    #
42    # Galaxy 1/2 platforms.
43    #
44    # These systems have 2 fan-connector boards.  Each fan-connector board has 3
45    # fan modules.  Each fan module is an individual FRU.  The fan-connector
46    # boards are also FRUs.
47    #
48    {
49	set => "Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|" .
50	    "Sun-Fire-X4100-M2|Sun-Fire-X4200-M2",
51	topology => [
52	    {
53		label => "FT %d",
54		count => 2,
55		fru => "self"
56	    }, {
57		count => 3,
58		label => "FT %d FM %d",
59		entity_ref => "ft%d.fm%d.led",
60		fru => "self"
61	    }
62	]
63    },
64
65    #
66    # Thumper platforms
67    #
68    # These systems have 5 fan modules, with each fan module containing 2 fans.
69    # The FRUs for the individual fans are the containing fan module.
70    #
71    {
72	set => "Sun-Fire-X4500|Sun-Fire-X4540",
73	topology => [
74	    {
75		label => "FT %d",
76		count => 5,
77		fru => "self",
78		entity_ref => "ft%d.prsnt",
79	    }, {
80		count => 2,
81		fru => "parent"
82	    }
83	]
84    },
85
86    #
87    # Fan Module/Fan topology for all G1N/G2N platforms.
88    #
89    # These systems have 6 fan modules, with each fan module containing 2 fans.
90    # The FRU's for the individual fans are the containing fan module.
91    #
92    # Unfortunately, the IPMI topology on these systems is rather broken, and
93    # all the SDRs that should be separate entities in fact refer to the same
94    # entity IDs.  So we have to use the alternative 'entity_present' option
95    # using a single SDR record.
96    #
97    {
98	set => "Sun-Fire-X4240|Sun-Fire-X4440",
99	topology => [
100	    {
101		count => 2,
102		label => "FT %d",
103		fru => "self"
104	    }, {
105		label => "FT %d FM %d",
106		count => 3,
107		fru => "self",
108		entity_present => "fb%d.fm%d.prsnt",
109	    }, {
110		count => 2,
111		fru => "parent"
112	    }
113
114	]
115    }
116);
117
118sub usage
119{
120	print STDERR "Usage: xml-gen -p <platform> -i <input_xml_file> -o <output_xml_file>\n";
121}
122
123#
124# Process an entry in the topology list.  We are passed the indentation level,
125# the current topology array, and any pushed indices.  This is called
126# recursively.
127#
128sub process_topology
129{
130	my ($indent, $toporef, @indices) = @_;
131	my @topo = @$toporef;
132	my $level = shift @topo;
133	my $type = $#topo == -1 ? "fan" : "fanmodule";
134
135	printf(OFILE "%*s<range name='%s' min='%d' max='%d'>\n",
136	    $indent, "", $type, 0, $level->{count} - 1);
137	$indent += 2;
138
139	for (my $i = 0; $i < $level->{count}; $i++) {
140		push @indices, $i;
141
142		printf(OFILE "%*s<node instance='%d'>\n", $indent, "", $i);
143
144		$indent += 2;
145
146		# Protocol properties (label, fmri)
147		printf(OFILE "%*s<propgroup name='protocol' version='1' " .
148		    "name-stability='Private' data-stability='Private'>\n",
149		    $indent, "");
150
151		$indent += 2;
152
153		if ($level->{label}) {
154			printf(OFILE "%*s<propval name='label' type='string' " .
155			    "value='", $indent, "");
156			printf(OFILE $level->{label}, @indices);
157			printf(OFILE "' />\n");
158		}
159
160		printf(OFILE "%*s<propmethod name='ipmi_fru_fmri' " .
161		    "version='0' propname='FRU' proptype='fmri'>\n",
162		    $indent, "");
163		printf(OFILE "%*s<argval name='entity' type='string' " .
164		    "value='%s' />\n", $indent + 2, "", $level->{fru});
165		printf(OFILE "%*s</propmethod>\n", $indent, "");
166
167		$indent -= 2;
168
169		printf(OFILE "%*s</propgroup>\n", $indent, "");
170
171		#
172		# Entity reference (if any)
173		#
174		if ($level->{entity_ref} || $level->{entity_present}) {
175			my $name = $level->{entity_ref} ? "entity_ref" :
176			    "entity_present";
177			my $val = $level->{$name};
178			printf(OFILE "%*s<propgroup name='ipmi' version='1' " .
179			    "name-stability='Private' " .
180			    "data-stability='Private' >\n", $indent, "");
181			printf(OFILE "%*s<propval name='%s' " .
182			    "type='string' value='", $indent + 2, "", $name);
183			printf(OFILE $val, @indices);
184			printf(OFILE "' />\n");
185			printf(OFILE "%*s</propgroup>\n", $indent, "");
186		}
187
188
189		#
190		# Children (if any)
191		#
192		if ($#topo != -1) {
193			printf(OFILE "%*s<dependents grouping='children'>\n",
194			    $indent, "");
195			process_topology($indent + 2, \@topo, @indices);
196			printf(OFILE "%*s</dependents>\n", $indent, "");
197		}
198
199		#
200		# Post-process IPMI enumerator method
201		#
202		printf(OFILE "%*s<enum-method name='ipmi' version='1' />\n",
203		   $indent, "");
204
205		$indent -= 2;
206
207		printf(OFILE "%*s</node>\n", $indent, "");
208		pop @indices;
209	}
210
211	$indent -= 2;
212	printf(OFILE "%*s</range>\n", $indent, "");
213}
214
215#
216# Process a single platform file.
217#
218sub process_platform
219{
220	my ($desc) = @_;
221	my $indent = 2;
222
223	printf(OFILE "%*s<set type='product' setlist='%s'>\n", $indent, "",
224	    $desc->{set});
225
226	process_topology($indent + 2, $desc->{topology});
227
228	printf(OFILE "%*s</set>\n", $indent, "");
229}
230
231my %options;
232getopts("p:i:o:h", \%options);
233if ($options{'h'}) {
234	usage();
235	exit (1);
236}
237
238my $platform = $options{'p'};
239my $input_file = $options{'i'};
240my $output_file = $options{'o'};
241
242if (!$platform || !$input_file || !$output_file) {
243	usage();
244	exit (1);
245}
246
247open(IFILE, "< $input_file") || die("$input_file cannot be opened.");
248open(OFILE, "> $output_file") || die("$output_file cannot be opened.");
249
250#
251# Open the file and read in the header until we reach the <topology> node.
252#
253while (<IFILE>) {
254	last if /<topology/;
255	print OFILE;
256}
257
258#
259# Construct the framework.
260#
261print OFILE "<topology name='fan' scheme='hc'>\n";
262
263my $desc;
264foreach $desc (@platforms) {
265	my $set = $desc->{set};
266	process_platform($desc);
267}
268
269print OFILE "</topology>\n";
270