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 2009 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26
27#
28# The fan topologies can be quite complicated, but are ultimately regular.  This
29# perl file uses some simplified internal structures to generate an .xml file
30# without the maintenance overhead.
31#
32
33use Getopt::Std;
34use strict;
35
36#
37# Master table of platforms.
38#
39my @platforms = (
40    #
41    # Galaxy 1/2 platforms.
42    #
43    # These systems have 2 fan-connector boards.  Each fan-connector board has 3
44    # fan modules.  Each fan module is an individual FRU.  The fan-connector
45    # boards are also FRUs.
46    #
47    {
48	set => "Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|" .
49	    "Sun-Fire-X4100-M2|Sun-Fire-X4200-M2",
50	topology => [
51	    {
52		label => "FT %d",
53		count => 2,
54		fru => "self"
55	    }, {
56	        fac_enum => 1,
57		provider => "fac_prov_ipmi",
58		count => 3,
59		label => "FT %d FM %d",
60		entity_ref => "ft%d.fm%d.led",
61		entity_ref_nparams => 2,
62		fm_service_indctr => "ft%d.fm%d.led",
63		fru => "self"
64	    }
65	]
66    },
67
68    #
69    # Thumper platforms
70    #
71    # These systems have 5 fan modules, with each fan module containing 2 fans.
72    # The FRUs for the individual fans are the containing fan module.
73    #
74    {
75	set => "Sun-Fire-X4500|Sun-Fire-X4540",
76	topology => [
77	    {
78	        fac_enum => 0,
79		provider => "fac_prov_ipmi",
80		label => "FT %d",
81		count => 5,
82		fru => "self",
83		entity_ref => "ft%d.prsnt",
84		entity_ref_nparams => 1,
85		fm_service_indctr => "ft%d.service.led",
86		fm_ok2rm_indctr => "ft%d.ok2rm.led",
87	    }, {
88	        fac_enum => 1,
89		provider => "fac_prov_ipmi",
90		count => 2,
91		entity_ref => "ft%d.f%d.speed",
92		entity_ref_nparams => 2,
93		fru => "parent"
94	    }
95	]
96    },
97
98    #
99    # Fan Module/Fan topology for all G1N/G2N platforms.
100    #
101    # There are two fan boards, which are FRU's.  Each fan board has
102    # 3 fan modules for a total of 6 fan modules, with each fan module
103    # containing 2 fans.  The FRU's for the individual fans are the
104    # containing fan module.
105    #
106    # Unfortunately, the IPMI topology on these systems is rather broken, and
107    # all the SDRs that should be separate entities in fact refer to the same
108    # entity IDs.  So we have to use the alternative 'entity_present' option
109    # using a single SDR record.
110    #
111    {
112	set => "Sun-Fire-X4240|Sun-Fire-X4440",
113	topology => [
114	    {
115		count => 2,
116		label => "FANBD%d",
117		fru => "self"
118	    }, {
119		label => "FANBD%d FM%d",
120		count => 3,
121		fru => "self",
122		provider => "fac_prov_ipmi",
123		entity_present => "fb%d.fm%d.prsnt",
124		fm_service_indctr=> "fb%d.fm%d.led",
125		entity_ref_nparams => 2
126	    }, {
127		fac_enum => 1,
128		count => 2,
129		fru => "parent",
130		provider => "fac_prov_ipmi",
131		entity_ref => "fb%d.fm%d.f%d.speed",
132		entity_present => "fb%d.fm%d.prsnt",
133		entity_ref_nparams => 3
134	    }
135
136	]
137    },
138
139    #
140    # Fan Module/Fan topology for G4F platforms.
141    #
142    # These systems have 4 fan assemblies with a single fan per assembly.
143    # Each fan assembly is a FRU.  The fan assemblies have a service LED
144    # but no other indicators.
145    #
146    {
147	set => "Sun-Fire-X4600|Sun-Fire-X4600-M2",
148	topology => [
149	    {
150	        fac_enum => 1,
151		provider => "fac_prov_ipmi",
152		count => 4,
153		label => "FT %d",
154		fru => "self",
155		entity_ref => "ft%d.fm0.prsnt",
156		entity_ref_nparams => 1,
157		fm_service_indctr => "ft%d.fm0.led"
158	    }
159	]
160    }
161);
162
163#
164# Process an entry in the topology list.  We are passed the indentation level,
165# the current topology array, and any pushed indices.  This is called
166# recursively.
167#
168sub process_topology
169{
170	my ($indent, $toporef, @indices) = @_;
171	my @topo = @$toporef;
172	my $level = shift @topo;
173	my $type = $#topo == -1 ? "fan" : "fanmodule";
174
175	printf("%*s<range name='%s' min='%d' max='%d'>\n",
176	    $indent, "", $type, 0, $level->{count} - 1);
177	$indent += 2;
178
179	for (my $i = 0; $i < $level->{count}; $i++) {
180		push @indices, $i;
181
182		printf("%*s<node instance='%d'>\n", $indent, "", $i);
183
184		$indent += 2;
185
186		# Facility enumerator
187		if ($level->{fac_enum}) {
188			printf("%*s<fac-enum provider='",
189			    $indent, "");
190			printf($level->{provider}, @indices);
191			printf("' />\n");
192		}
193
194		# Facility nodes for service and ok2rm LED's
195		if ($level->{fm_service_indctr}) {
196			printf("%*s<facility name='service' type='indicator' ".
197			    "provider='fac_prov_ipmi' >\n", $indent+2, "");
198			printf("%*s<propgroup name='facility' version='1' ".
199			    "name-stability='Private' data-stability='Private' >\n",
200			    $indent+4, "");
201			printf("%*s<propval name='type' type='uint32' ".
202			    "value='1' />\n", $indent+6, "");
203			printf("%*s<propmethod name='ipmi_entity' version='0' ".
204			    "propname='entity_ref' proptype='string' >\n",
205			    $indent+6, "");
206			printf("%*s<argval name='format' type='string' ".
207			    "value='%s' />\n", $indent+8, "",
208			    $level->{fm_service_indctr});
209			printf("%*s<argval name='offset' type='uint32' ".
210			    "value='0' />\n", $indent+8, "");
211			printf("%*s<argval name='nparams' type='uint32' ".
212			    "value='%d' />\n", $indent+8, "",
213			    $level->{entity_ref_nparams});
214			printf("%*s</propmethod>\n", $indent+6, "");
215			printf("%*s<propmethod name='ipmi_indicator_mode' ".
216			    "version='0' propname='mode' proptype='uint32' ".
217			    "mutable='1' >\n", $indent+6, "");
218			printf("%*s</propmethod>\n", $indent+6, "");
219			printf("%*s</propgroup>\n", $indent+4, "");
220			printf("%*s</facility>\n", $indent+2, "");
221		}
222		if ($level->{fm_ok2rm_indctr}) {
223			printf("%*s<facility name='ok2rm' type='indicator' ".
224			    "provider='fac_prov_ipmi' >\n", $indent+2, "");
225			printf("%*s<propgroup name='facility' version='1' ".
226			    "name-stability='Private' data-stability='Private' >\n",
227			    $indent+4, "");
228			printf("%*s<propval name='type' type='uint32' ".
229			    "value='2' />\n", $indent+6, "");
230			printf("%*s<propmethod name='ipmi_entity' version='0' ".
231			    "propname='entity_ref' proptype='string' >\n",
232			    $indent+6, "");
233			printf("%*s<argval name='format' type='string' ".
234			    "value='%s' />\n", $indent+8, "",
235			    $level->{fm_ok2rm_indctr});
236			printf("%*s<argval name='offset' type='uint32' ".
237			    "value='0' />\n", $indent+8, "");
238			printf("%*s<argval name='nparams' type='uint32' ".
239			    "value='%d' />\n", $indent+8, "",
240			    $level->{entity_ref_nparams});
241			printf("%*s</propmethod>\n", $indent+6, "");
242			printf("%*s<propmethod name='ipmi_indicator_mode' ".
243			    "version='0' propname='mode' proptype='uint32' mutable='1' >\n",
244			    $indent+6, "");
245			printf("%*s</propmethod>\n", $indent+6, "");
246			printf("%*s</propgroup>\n", $indent+4, "");
247			printf("%*s</facility>\n", $indent+2, "");
248		}
249
250		# Protocol properties (label, fmri)
251		printf("%*s<propgroup name='protocol' version='1' " .
252		    "name-stability='Private' data-stability='Private'>\n",
253		    $indent, "");
254
255		$indent += 2;
256
257		if ($level->{label}) {
258			printf("%*s<propval name='label' type='string' " .
259			    "value='", $indent, "");
260			printf($level->{label}, @indices);
261			printf("' />\n");
262		}
263
264		printf("%*s<propmethod name='ipmi_fru_fmri' " .
265		    "version='0' propname='FRU' proptype='fmri'>\n",
266		    $indent, "");
267		printf("%*s<argval name='entity' type='string' " .
268		    "value='%s' />\n", $indent + 2, "", $level->{fru});
269		printf("%*s</propmethod>\n", $indent, "");
270
271		$indent -= 2;
272
273		printf("%*s</propgroup>\n", $indent, "");
274
275		#
276		# Entity references (if any)
277		#
278		if ($level->{entity_ref}) {
279			my $val = $level->{entity_ref};
280			printf("%*s<propgroup name='ipmi' version='1' " .
281			    "name-stability='Private' " .
282			    "data-stability='Private' >\n", $indent, "");
283			printf("%*s<propval name='entity_ref' " .
284			    "type='string' value='", $indent + 2, "");
285			printf($val, @indices);
286			printf("' />\n");
287			printf("%*s</propgroup>\n", $indent, "");
288		}
289		if ($level->{entity_present}) {
290			my $val = $level->{entity_present};
291			printf("%*s<propgroup name='ipmi' version='1' " .
292			    "name-stability='Private' " .
293			    "data-stability='Private' >\n", $indent, "");
294			printf("%*s<propval name='entity_present' " .
295			    "type='string' value='", $indent + 2, "");
296			printf($val, @indices);
297			printf("' />\n");
298			printf("%*s</propgroup>\n", $indent, "");
299		}
300
301		#
302		# Post-process IPMI enumerator method
303		#
304		printf("%*s<enum-method name='ipmi' version='1' ".
305		    "/>\n", $indent, "");
306
307		#
308		# Children (if any)
309		#
310		if ($#topo != -1) {
311			printf("%*s<dependents grouping='children'>\n",
312			    $indent, "");
313			process_topology($indent + 2, \@topo, @indices);
314			printf("%*s</dependents>\n", $indent, "");
315		}
316
317		$indent -= 2;
318
319		printf("%*s</node>\n", $indent, "");
320		pop @indices;
321	}
322
323	$indent -= 2;
324	printf("%*s</range>\n", $indent, "");
325}
326
327#
328# Process a single platform file.
329#
330sub process_platform
331{
332	my ($desc) = @_;
333	my $indent = 2;
334
335	printf("%*s<set type='product' setlist='%s'>\n", $indent, "",
336	    $desc->{set});
337
338	process_topology($indent + 2, $desc->{topology});
339
340	printf("%*s</set>\n", $indent, "");
341}
342
343print "<topology name='fan' scheme='hc'>\n";
344
345my $desc;
346foreach $desc (@platforms) {
347	process_platform($desc);
348}
349
350print "</topology>\n";
351