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