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
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		fac_enum => 1,
120		provider => "fac_prov_ipmi",
121		label => "FANBD%d FM%d",
122		count => 3,
123		fru => "self",
124		entity_present => "fb%d.fm%d.prsnt",
125		entity_ref => "fb%d.fm%d.prsnt",
126		entity_ref_nparams => 2,
127		fm_service_indctr=> "fb%d.fm%d.led",
128	    }, {
129		count => 2,
130		fru => "parent"
131	    }
132
133	]
134    },
135
136    #
137    # Fan Module/Fan topology for G4F platforms.
138    #
139    # These systems have 4 fan assemblies with a single fan per assembly.
140    # Each fan assembly is a FRU.  The fan assemblies have a service LED
141    # but no other indicators.
142    #
143    {
144	set => "Sun-Fire-X4600-M2",
145	topology => [
146	    {
147	        fac_enum => 1,
148		provider => "fac_prov_ipmi",
149		count => 4,
150		label => "FT %d",
151		fru => "self",
152		entity_ref => "ft%d.fm0.prsnt",
153		entity_ref_nparams => 1,
154		fm_service_indctr => "ft%d.fm0.led"
155	    }
156	]
157    }
158);
159
160#
161# Process an entry in the topology list.  We are passed the indentation level,
162# the current topology array, and any pushed indices.  This is called
163# recursively.
164#
165sub process_topology
166{
167	my ($indent, $toporef, @indices) = @_;
168	my @topo = @$toporef;
169	my $level = shift @topo;
170	my $type = $#topo == -1 ? "fan" : "fanmodule";
171
172	printf("%*s<range name='%s' min='%d' max='%d'>\n",
173	    $indent, "", $type, 0, $level->{count} - 1);
174	$indent += 2;
175
176	for (my $i = 0; $i < $level->{count}; $i++) {
177		push @indices, $i;
178
179		printf("%*s<node instance='%d'>\n", $indent, "", $i);
180
181		$indent += 2;
182
183		# Facility enumerator
184		if ($level->{fac_enum}) {
185			printf("%*s<fac-enum provider='",
186			    $indent, "");
187			printf($level->{provider}, @indices);
188			printf("' />\n");
189		}
190
191		# Facility nodes for service and ok2rm LED's
192		if ($level->{fm_service_indctr}) {
193			printf("%*s<facility name='service' type='indicator' ".
194			    "provider='fac_prov_ipmi' >\n", $indent+2, "");
195			printf("%*s<propgroup name='facility' version='1' ".
196			    "name-stability='Private' data-stability='Private' >\n",
197			    $indent+4, "");
198			printf("%*s<propval name='type' type='uint32' ".
199			    "value='1' />\n", $indent+6, "");
200			printf("%*s<propmethod name='ipmi_entity' version='0' ".
201			    "propname='entity_ref' proptype='string' >\n",
202			    $indent+6, "");
203			printf("%*s<argval name='format' type='string' ".
204			    "value='%s' />\n", $indent+8, "",
205			    $level->{fm_service_indctr});
206			printf("%*s<argval name='offset' type='uint32' ".
207			    "value='0' />\n", $indent+8, "");
208			printf("%*s<argval name='nparams' type='uint32' ".
209			    "value='%d' />\n", $indent+8, "",
210			    $level->{entity_ref_nparams});
211			printf("%*s</propmethod>\n", $indent+6, "");
212			printf("%*s<propmethod name='ipmi_indicator_mode' ".
213			    "version='0' propname='mode' proptype='uint32' ".
214			    "mutable='1' >\n", $indent+6, "");
215			printf("%*s</propmethod>\n", $indent+6, "");
216			printf("%*s</propgroup>\n", $indent+4, "");
217			printf("%*s</facility>\n", $indent+2, "");
218		}
219		if ($level->{fm_ok2rm_indctr}) {
220			printf("%*s<facility name='ok2rm' type='indicator' ".
221			    "provider='fac_prov_ipmi' >\n", $indent+2, "");
222			printf("%*s<propgroup name='facility' version='1' ".
223			    "name-stability='Private' data-stability='Private' >\n",
224			    $indent+4, "");
225			printf("%*s<propval name='type' type='uint32' ".
226			    "value='2' />\n", $indent+6, "");
227			printf("%*s<propmethod name='ipmi_entity' version='0' ".
228			    "propname='entity_ref' proptype='string' >\n",
229			    $indent+6, "");
230			printf("%*s<argval name='format' type='string' ".
231			    "value='%s' />\n", $indent+8, "",
232			    $level->{fm_ok2rm_indctr});
233			printf("%*s<argval name='offset' type='uint32' ".
234			    "value='0' />\n", $indent+8, "");
235			printf("%*s<argval name='nparams' type='uint32' ".
236			    "value='%d' />\n", $indent+8, "",
237			    $level->{entity_ref_nparams});
238			printf("%*s</propmethod>\n", $indent+6, "");
239			printf("%*s<propmethod name='ipmi_indicator_mode' ".
240			    "version='0' propname='mode' proptype='uint32' mutable='1' >\n",
241			    $indent+6, "");
242			printf("%*s</propmethod>\n", $indent+6, "");
243			printf("%*s</propgroup>\n", $indent+4, "");
244			printf("%*s</facility>\n", $indent+2, "");
245		}
246
247		# Protocol properties (label, fmri)
248		printf("%*s<propgroup name='protocol' version='1' " .
249		    "name-stability='Private' data-stability='Private'>\n",
250		    $indent, "");
251
252		$indent += 2;
253
254		if ($level->{label}) {
255			printf("%*s<propval name='label' type='string' " .
256			    "value='", $indent, "");
257			printf($level->{label}, @indices);
258			printf("' />\n");
259		}
260
261		printf("%*s<propmethod name='ipmi_fru_fmri' " .
262		    "version='0' propname='FRU' proptype='fmri'>\n",
263		    $indent, "");
264		printf("%*s<argval name='entity' type='string' " .
265		    "value='%s' />\n", $indent + 2, "", $level->{fru});
266		printf("%*s</propmethod>\n", $indent, "");
267
268		$indent -= 2;
269
270		printf("%*s</propgroup>\n", $indent, "");
271
272		#
273		# Entity references (if any)
274		#
275		if ($level->{entity_ref} || $level->{entity_present}) {
276			my $name = $level->{entity_ref} ? "entity_ref" :
277			    "entity_present";
278			my $val = $level->{$name};
279			printf("%*s<propgroup name='ipmi' version='1' " .
280			    "name-stability='Private' " .
281			    "data-stability='Private' >\n", $indent, "");
282			printf("%*s<propval name='%s' " .
283			    "type='string' value='", $indent + 2, "", $name);
284			printf($val, @indices);
285			printf("' />\n");
286			printf("%*s</propgroup>\n", $indent, "");
287		}
288
289		#
290		# Post-process IPMI enumerator method
291		#
292		printf("%*s<enum-method name='ipmi' version='1' ".
293		    "/>\n", $indent, "");
294
295		#
296		# Children (if any)
297		#
298		if ($#topo != -1) {
299			printf("%*s<dependents grouping='children'>\n",
300			    $indent, "");
301			process_topology($indent + 2, \@topo, @indices);
302			printf("%*s</dependents>\n", $indent, "");
303		}
304
305		$indent -= 2;
306
307		printf("%*s</node>\n", $indent, "");
308		pop @indices;
309	}
310
311	$indent -= 2;
312	printf("%*s</range>\n", $indent, "");
313}
314
315#
316# Process a single platform file.
317#
318sub process_platform
319{
320	my ($desc) = @_;
321	my $indent = 2;
322
323	printf("%*s<set type='product' setlist='%s'>\n", $indent, "",
324	    $desc->{set});
325
326	process_topology($indent + 2, $desc->{topology});
327
328	printf("%*s</set>\n", $indent, "");
329}
330
331print "<topology name='fan' scheme='hc'>\n";
332
333my $desc;
334foreach $desc (@platforms) {
335	process_platform($desc);
336}
337
338print "</topology>\n";
339