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,ft%d.prsnt",
84		entity_ref_nparams => 1,
85		fm_service_indctr => "FT%d/SVC,ft%d.service.led",
86		fm_ok2rm_indctr => "FT%d/OK,ft%d.ok2rm.led",
87	    }, {
88	        fac_enum => 1,
89		provider => "fac_prov_ipmi",
90		count => 2,
91		entity_ref => "FT%d/FAN%d/TACH,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,fb%d.fm%d.prsnt",
124		fm_service_indctr=> "FB%d/FM%d/SERVICE,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/TACH,fb%d.fm%d.f%d.speed",
132		entity_present => "FB%d/FM%d/PRSNT,fb%d.fm%d.prsnt",
133		entity_ref_nparams => 3
134	    }
135
136	]
137    },
138
139    #
140    # Fan Module/Fan topology for the Sun Fire X4600/X4600 M2 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    # Fan Module/Fan topology for Sun Fire X4140.
164    #
165    # There are two fan boards, which are FRU's.  The first fanboard has 4
166    # fanmodules (which are also FRU's).  The second fan board has 3 fan
167    # modules.  Each fanmodule contains two fans.
168    #
169    {
170	set => "Sun-Fire-X4140",
171	topology => [
172	    {
173		count => 2,
174		label => "FANBD%d",
175		fru => "self",
176	    }, {
177		fac_enum => 1,
178		provider => "fac_prov_ipmi",
179		label => "FANBD%d FM%d",
180		count => 4,
181		fru => "self",
182		fm_service_indctr=> "FB%d/FM%d/SERVICE,fb%d.fm%d.led",
183		entity_ref_nparams => 2
184	    }, {
185		fac_enum => 1,
186		provider => "fac_prov_ipmi",
187		count => 2,
188		fru => "parent",
189		entity_ref => "FB%d/FM%d/F%d/TACH,fb%d.fm%d.f%d.speed",
190		entity_ref_nparams => 3
191	    }
192
193	]
194    },
195    #
196    # Fan Module/Fan topology for the Sun Fire X4150.
197    #
198    # There are two fan boards, which are FRU's.  The first fanboard has 4
199    # fanmodules (which are also FRU's).  The second fan board has 3 fan
200    # modules.  Each fanmodule contains two fans.
201    #
202    {
203	set => "SUN-FIRE-X4150",
204	topology => [
205	    {
206		count => 2,
207		label => "FANBD%d",
208		fru => "self",
209		entity_present => "FB%d/PRSRNT"
210	    }, {
211		label => "FANBD%d FM%d",
212		count => 4,
213		fru => "self",
214		provider => "fac_prov_ipmi",
215		entity_ref => "FB%d/FM%d/PRSNT",
216		fm_service_indctr=> "",
217		entity_ref_nparams => 2
218	    }, {
219		fac_enum => 1,
220		count => 2,
221		fru => "parent",
222		provider => "fac_prov_ipmi",
223		entity_ref => "FB%d/FM%d/F%d/TACH",
224		entity_ref_nparams => 3
225	    }
226
227	]
228    },
229    #
230    # Fan Module/Fan topology for Duradi 2U.
231    #
232    # There are two fan boards, which are FRU's.  Both fanboards have 3
233    # fanmodules (which are also FRU's). Each fanmodule contains two fans.
234    #
235    {
236	set => "SUN-FIRE-X4250|SUN-FIRE-X4450",
237	topology => [
238	    {
239		count => 2,
240		label => "FANBD%d",
241		fru => "self",
242		entity_present => "FB%d/PRSRNT"
243	    }, {
244		label => "FANBD%d FM%d",
245		count => 3,
246		fru => "self",
247		provider => "fac_prov_ipmi",
248		entity_ref => "FB%d/FM%d/PRSNT",
249		fm_service_indctr=> "",
250		entity_ref_nparams => 2
251	    }, {
252		fac_enum => 1,
253		count => 2,
254		fru => "parent",
255		provider => "fac_prov_ipmi",
256		entity_ref => "FB%d/FM%d/F%d/TACH",
257		entity_ref_nparams => 3
258	    }
259
260	]
261    }
262);
263
264#
265# Process an entry in the topology list.  We are passed the indentation level,
266# the current topology array, the set list, and any pushed indices.  This is
267# called recursively.
268#
269sub process_topology
270{
271	my ($indent, $toporef, $set, @indices) = @_;
272	my @topo = @$toporef;
273	my $level = shift @topo;
274	my $type = $#topo == -1 ? "fan" : "fanmodule";
275
276	printf("%*s<range name='%s' min='%d' max='%d'>\n",
277	    $indent, "", $type, 0, $level->{count} - 1);
278	$indent += 2;
279
280	for (my $i = 0; $i < $level->{count}; $i++) {
281		#
282		# Special case code for the 1U version of Durado and Duradi,
283		# both of which have an assymetric fan topology
284		#
285		last if ((($set eq "SUN-FIRE-X4150") || ($set eq "Sun-Fire-X4140"))
286		    && ($type eq "fanmodule") && ($#indices == 0)
287		    && ($indices[0] == 1) && ($i == 3));
288
289		push @indices, $i;
290
291		printf("%*s<node instance='%d'>\n", $indent, "", $i);
292
293		$indent += 2;
294
295		# Facility enumerator
296		if ($level->{fac_enum}) {
297			printf("%*s<fac-enum provider='",
298			    $indent, "");
299			printf($level->{provider});
300			printf("' />\n");
301		}
302
303		# Facility nodes for service and ok2rm LED's
304		if ($level->{fm_service_indctr}) {
305			printf("%*s<facility name='service' type='indicator' ".
306			    "provider='fac_prov_ipmi' >\n", $indent+2, "");
307			printf("%*s<propgroup name='facility' version='1' ".
308			    "name-stability='Private' data-stability='Private' >\n",
309			    $indent+4, "");
310			printf("%*s<propval name='type' type='uint32' ".
311			    "value='0' />\n", $indent+6, "");
312			printf("%*s<propmethod name='ipmi_entity' version='0' ".
313			    "propname='entity_ref' proptype='string_array' >\n",
314			    $indent+6, "");
315
316			printf("%*s<argval name='format' type='string_array'>\n",
317			    $indent+8, "");
318			my @refs = split(/\,/, $level->{fm_service_indctr});
319			foreach my $ref (@refs) {
320				printf("%*s<argitem value='", $indent+10, "");
321				printf($ref, @indices);
322				printf("' />\n");
323			}
324
325			printf("%*s</argval>\n", $indent+8, "");
326			printf("%*s<argval name='offset' type='uint32' ".
327			    "value='0' />\n", $indent+8, "");
328			printf("%*s<argval name='nparams' type='uint32' ".
329			    "value='%d' />\n", $indent+8, "",
330			    $level->{entity_ref_nparams});
331			printf("%*s</propmethod>\n", $indent+6, "");
332			printf("%*s<propmethod name='ipmi_indicator_mode' ".
333			    "version='0' propname='mode' proptype='uint32' ".
334			    "mutable='1' >\n", $indent+6, "");
335			printf("%*s</propmethod>\n", $indent+6, "");
336			printf("%*s</propgroup>\n", $indent+4, "");
337			printf("%*s</facility>\n", $indent+2, "");
338		}
339		if ($level->{fm_ok2rm_indctr}) {
340			printf("%*s<facility name='ok2rm' type='indicator' ".
341			    "provider='fac_prov_ipmi' >\n", $indent+2, "");
342			printf("%*s<propgroup name='facility' version='1' ".
343			    "name-stability='Private' data-stability='Private' >\n",
344			    $indent+4, "");
345			printf("%*s<propval name='type' type='uint32' ".
346			    "value='2' />\n", $indent+6, "");
347			printf("%*s<propmethod name='ipmi_entity' version='0' ".
348			    "propname='entity_ref' proptype='string_array' >\n",
349			    $indent+6, "");
350
351			printf("%*s<argval name='format' type='string_array'>\n",
352			    $indent+8, "");
353			my @refs = split(/\,/, $level->{fm_ok2rm_indctr});
354			foreach my $ref (@refs) {
355				printf("%*s<argitem value='", $indent+10, "");
356				printf($ref, @indices);
357				printf("' />\n");
358			}
359			printf("%*s</argval>\n", $indent+8, "");
360			printf("%*s<argval name='offset' type='uint32' ".
361			    "value='0' />\n", $indent+8, "");
362			printf("%*s<argval name='nparams' type='uint32' ".
363			    "value='%d' />\n", $indent+8, "",
364			    $level->{entity_ref_nparams});
365			printf("%*s</propmethod>\n", $indent+6, "");
366			printf("%*s<propmethod name='ipmi_indicator_mode' ".
367			    "version='0' propname='mode' proptype='uint32' mutable='1' >\n",
368			    $indent+6, "");
369			printf("%*s</propmethod>\n", $indent+6, "");
370			printf("%*s</propgroup>\n", $indent+4, "");
371			printf("%*s</facility>\n", $indent+2, "");
372		}
373
374		# Protocol properties (label, fmri)
375		printf("%*s<propgroup name='protocol' version='1' " .
376		    "name-stability='Private' data-stability='Private'>\n",
377		    $indent, "");
378
379		$indent += 2;
380
381		if ($level->{label}) {
382			printf("%*s<propval name='label' type='string' " .
383			    "value='", $indent, "");
384			printf($level->{label}, @indices);
385			printf("' />\n");
386		}
387
388		printf("%*s<propmethod name='ipmi_fru_fmri' " .
389		    "version='0' propname='FRU' proptype='fmri'>\n",
390		    $indent, "");
391		printf("%*s<argval name='entity' type='string' " .
392		    "value='%s' />\n", $indent + 2, "", $level->{fru});
393		printf("%*s</propmethod>\n", $indent, "");
394
395		$indent -= 2;
396
397		printf("%*s</propgroup>\n", $indent, "");
398
399		#
400		# Entity references (if any)
401		#
402		if ($level->{entity_ref}) {
403			my $val = $level->{entity_ref};
404			printf("%*s<propgroup name='ipmi' version='1' " .
405			    "name-stability='Private' " .
406			    "data-stability='Private' >\n", $indent, "");
407
408			printf("%*s<propval name='entity_ref' ".
409			    "type='string_array'>\n", $indent + 2, "");
410			my @refs = split(/\,/, $val);
411			foreach my $ref (@refs) {
412				printf("%*s<propitem value='", $indent+4, "");
413				printf($ref, @indices);
414				printf("' />\n");
415			}
416			printf("%*s</propval>\n", $indent+2, "");
417			printf("%*s</propgroup>\n", $indent, "");
418		}
419		if ($level->{entity_present}) {
420			my $val = $level->{entity_present};
421			printf("%*s<propgroup name='ipmi' version='1' " .
422			    "name-stability='Private' " .
423			    "data-stability='Private' >\n", $indent, "");
424
425			printf("%*s<propval name='entity_present' " .
426			    "type='string_array'>\n", $indent + 2, "");
427			my @refs = split(/\,/, $val);
428			foreach my $ref (@refs) {
429				printf("%*s<propitem value='", $indent+4, "");
430				printf($ref, @indices);
431				printf("' />\n");
432			}
433			printf("%*s</propval>\n", $indent+4, "");
434			printf("%*s</propgroup>\n", $indent, "");
435		}
436
437		#
438		# Post-process IPMI enumerator method
439		#
440		printf("%*s<enum-method name='ipmi' version='1' ".
441		    "/>\n", $indent, "");
442
443		#
444		# Children (if any)
445		#
446		if ($#topo != -1) {
447			printf("%*s<dependents grouping='children'>\n",
448			    $indent, "");
449			process_topology($indent + 2, \@topo, $set, @indices);
450			printf("%*s</dependents>\n", $indent, "");
451		}
452
453		$indent -= 2;
454
455		printf("%*s</node>\n", $indent, "");
456		pop @indices;
457	}
458
459	$indent -= 2;
460	printf("%*s</range>\n", $indent, "");
461}
462
463#
464# Process a single platform file.
465#
466sub process_platform
467{
468	my ($desc) = @_;
469	my $indent = 2;
470
471	printf("%*s<set type='product' setlist='%s'>\n", $indent, "",
472	    $desc->{set});
473
474	process_topology($indent + 2, $desc->{topology}, $desc->{set});
475
476	printf("%*s</set>\n", $indent, "");
477}
478
479print "<topology name='fan' scheme='hc'>\n";
480
481my $desc;
482foreach $desc (@platforms) {
483	process_platform($desc);
484}
485
486print "</topology>\n";
487