1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * 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 2001-2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * PICL plug-in that creates the FRU Hierarchy for the 29 * SUNW,Sun-Fire-480R (Cherrystone) platform 30 */ 31 32 #include <stdio.h> 33 #include <string.h> 34 #include <libintl.h> 35 #include <libnvpair.h> 36 #include <syslog.h> 37 #include <picl.h> 38 #include <picltree.h> 39 #include <picldefs.h> 40 41 /* 42 * Plugin registration entry points 43 */ 44 static void picl_frutree_register(void); 45 static void picl_frutree_init(void); 46 static void picl_frutree_fini(void); 47 static void picl_frutree_evhandler(const char *ename, const void *earg, 48 size_t size, void *cookie); 49 50 #pragma init(picl_frutree_register) 51 52 /* 53 * Log message texts 54 */ 55 #define CREATE_FRUTREE_FAIL gettext("Failed to create frutree node\n") 56 #define CREATE_CHASSIS_FAIL gettext("Failed to create chassis node\n") 57 #define IOBRD_INIT_FAIL gettext("do_ioboard_init() failed\n") 58 #define RSCBRD_INIT_FAIL gettext("do_rscboard_init() failed\n") 59 #define FCAL_INIT_FAIL gettext("do_fcal_init() failed\n") 60 #define PS_INIT_FAIL gettext("do_power_supplies_init() failed\n") 61 #define SYSBOARD_INIT_FAIL gettext("do_centerplane_init() failed\n") 62 63 /* 64 * Viewpoints property field used by SunMC 65 */ 66 #define CHASSIS_VIEWPOINTS gettext("front top rear") 67 68 /* 69 * Ref prop values 70 */ 71 #define SEEPROM_SOURCE "_seeprom_source" 72 #define FRU_PARENT "_fru_parent" 73 74 /* 75 * List of all the FRU locations in the platform_frupath[] array, and 76 * location_label[] array 77 */ 78 #define PS0 0 79 #define PS1 1 80 #define RSC 2 81 #define DISKBACKPLANE 3 82 #define PDB 4 83 #define CENTERPLANE 5 84 #define IOBRD 6 85 #define CPUMOD0 7 86 #define CPUMOD1 8 87 #define CPU0_DIMM0 9 88 #define DIMMS_PER_MOD 8 89 #define DIMMS_PER_SLOT 16 90 91 /* 92 * Local variables 93 */ 94 static picld_plugin_reg_t my_reg_info = { 95 PICLD_PLUGIN_VERSION_1, 96 PICLD_PLUGIN_NON_CRITICAL, 97 "SUNW_Cherrystone_frutree", 98 picl_frutree_init, 99 picl_frutree_fini 100 }; 101 102 /* 103 * List of all the FRUs in the /platform tree with SEEPROMs 104 */ 105 static char *platform_frupath[] = { 106 "/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a2", /* PS 0 */ 107 "/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a0", /* PS 1 */ 108 "/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a6", /* RSC */ 109 "/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a8", /* Disk Backplane */ 110 "/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,ae", /* PDB */ 111 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@4,a8", /* Centerplane */ 112 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@4,aa", /* IO */ 113 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@4,a0", /* CPU MOD 0 */ 114 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@4,a2", /* CPU MOD 1 */ 115 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a0", /* CPU0 DIMM0 */ 116 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a2", /* CPU0 DIMM1 */ 117 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a4", /* CPU0 DIMM2 */ 118 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a6", /* CPU0 DIMM3 */ 119 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a8", /* CPU0 DIMM4 */ 120 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,aa", /* CPU0 DIMM5 */ 121 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,ac", /* CPU0 DIMM6 */ 122 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,ae", /* CPU0 DIMM7 */ 123 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a0", /* CPU2 DIMM0 */ 124 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a2", /* CPU2 DIMM1 */ 125 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a4", /* CPU2 DIMM2 */ 126 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a6", /* CPU2 DIMM3 */ 127 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a8", /* CPU2 DIMM4 */ 128 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,aa", /* CPU2 DIMM5 */ 129 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,ac", /* CPU2 DIMM6 */ 130 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,ae", /* CPU2 DIMM7 */ 131 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a0", /* CPU1 DIMM0 */ 132 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a2", /* CPU1 DIMM1 */ 133 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a4", /* CPU1 DIMM2 */ 134 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a6", /* CPU1 DIMM3 */ 135 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a8", /* CPU1 DIMM4 */ 136 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,aa", /* CPU1 DIMM5 */ 137 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,ac", /* CPU1 DIMM6 */ 138 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,ae", /* CPU1 DIMM7 */ 139 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a0", /* CPU3 DIMM0 */ 140 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a2", /* CPU3 DIMM1 */ 141 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a4", /* CPU3 DIMM2 */ 142 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a6", /* CPU3 DIMM3 */ 143 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a8", /* CPU3 DIMM4 */ 144 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,aa", /* CPU3 DIMM5 */ 145 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,ac", /* CPU3 DIMM6 */ 146 "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,ae", /* CPU3 DIMM7 */ 147 NULL}; 148 149 /* 150 * List of Labels for FRU locations (uses the #define's from above) 151 */ 152 static char *location_label[] = { 153 "0", /* PS0 */ 154 "1", /* PS1 */ 155 NULL, /* RSC */ 156 NULL, /* DISKBACKPLANE */ 157 NULL, /* PDB */ 158 NULL, /* CENTERPLANE */ 159 NULL, /* IOBRD */ 160 "A", /* CPUMOD0 */ 161 "B", /* CPUMOD1 */ 162 "J2900", /* CPU0 DIMM0 */ 163 "J3100", /* CPU0 DIMM1 */ 164 "J2901", /* CPU0 DIMM2 */ 165 "J3101", /* CPU0 DIMM3 */ 166 "J3000", /* CPU0 DIMM4 */ 167 "J3200", /* CPU0 DIMM5 */ 168 "J3001", /* CPU0 DIMM6 */ 169 "J3201", /* CPU0 DIMM7 */ 170 "J7900", /* CPU1 DIMM0 */ 171 "J8100", /* CPU1 DIMM1 */ 172 "J7901", /* CPU1 DIMM2 */ 173 "J8101", /* CPU1 DIMM3 */ 174 "J8000", /* CPU1 DIMM4 */ 175 "J8200", /* CPU1 DIMM5 */ 176 "J8001", /* CPU1 DIMM6 */ 177 "J8201", /* CPU1 DIMM7 */ 178 "0", /* CPU0 label */ 179 "1", /* CPU1 label */ 180 NULL}; 181 182 /* 183 * List of all the FRU slots for power supplies (hotpluggable) 184 */ 185 static char *frutree_power_supply[] = { 186 "/frutree/chassis/power-dist-board/power-supply-slot?Slot=0", 187 "/frutree/chassis/power-dist-board/power-supply-slot?Slot=1", 188 NULL}; 189 190 /* PICL handle for the root node of the "frutree" */ 191 static picl_nodehdl_t frutreeh; 192 193 static int do_ioboard_init(picl_nodehdl_t); 194 static int do_rscboard_init(picl_nodehdl_t); 195 static int do_fcal_init(picl_nodehdl_t); 196 static int do_power_supplies_init(picl_nodehdl_t); 197 static int do_centerplane_init(picl_nodehdl_t); 198 static int do_cpu_module_init(picl_nodehdl_t, int); 199 static int do_dimms_init(picl_nodehdl_t, int, int); 200 201 static int add_ref_prop(picl_nodehdl_t, picl_nodehdl_t, char *); 202 static int add_slot_prop(picl_nodehdl_t, int); 203 static int add_label_prop(picl_nodehdl_t, char *); 204 static int add_void_fda_prop(picl_nodehdl_t); 205 static int add_viewpoints_prop(picl_nodehdl_t, char *); 206 static int add_all_nodes(); 207 static int remove_all_nodes(picl_nodehdl_t); 208 209 static int add_hotplug_fru_device(void); 210 static int rem_hotplug_fru_device(void); 211 static int is_added_device(char *, char *); 212 static int is_removed_device(char *, char *); 213 static int add_power_supply(int); 214 static int remove_power_supply(int); 215 216 /* 217 * This function is executed as part of .init when the plugin is 218 * dlopen()ed 219 */ 220 static void 221 picl_frutree_register() 222 { 223 (void) picld_plugin_register(&my_reg_info); 224 } 225 226 /* 227 * This function is the init entry point of the plugin. 228 * It initializes the /frutree tree 229 */ 230 static void 231 picl_frutree_init() 232 { 233 int err; 234 235 err = add_all_nodes(); 236 if (err != PICL_SUCCESS) { 237 (void) remove_all_nodes(frutreeh); 238 return; 239 } 240 241 /* Register the event handler routine */ 242 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, 243 picl_frutree_evhandler, NULL); 244 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED, 245 picl_frutree_evhandler, NULL); 246 } 247 248 /* 249 * This function is the fini entry point of the plugin 250 */ 251 static void 252 picl_frutree_fini(void) 253 { 254 /* Unregister the event handler routine */ 255 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, 256 picl_frutree_evhandler, NULL); 257 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED, 258 picl_frutree_evhandler, NULL); 259 260 (void) remove_all_nodes(frutreeh); 261 } 262 263 /* 264 * This function is the event handler of this plug-in. 265 * 266 * It processes the following events: 267 * 268 * PICLEVENT_SYSEVENT_DEVICE_ADDED 269 * PICLEVENT_SYSEVENT_DEVICE_REMOVED 270 */ 271 /* ARGSUSED */ 272 static void 273 picl_frutree_evhandler(const char *ename, const void *earg, size_t size, 274 void *cookie) 275 { 276 if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) { 277 /* Check for and add any hotplugged device(s) */ 278 (void) add_hotplug_fru_device(); 279 280 } else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) { 281 /* Check for and remove any hotplugged device(s) */ 282 (void) rem_hotplug_fru_device(); 283 } 284 } 285 286 /* Initializes the FRU nodes for the IO board */ 287 static int 288 do_ioboard_init(picl_nodehdl_t rooth) 289 { 290 picl_nodehdl_t iobrdh; 291 picl_nodehdl_t tmph; 292 int err; 293 294 /* Create the node for the IO board (if it exists) */ 295 if (ptree_get_node_by_path(platform_frupath[IOBRD], &tmph) == 296 PICL_SUCCESS) { 297 err = ptree_create_node("io-board", "fru", &iobrdh); 298 if (err != PICL_SUCCESS) 299 return (err); 300 301 err = add_ref_prop(iobrdh, tmph, SEEPROM_SOURCE); 302 if (err != PICL_SUCCESS) 303 return (err); 304 305 err = add_void_fda_prop(iobrdh); 306 if (err != PICL_SUCCESS) 307 return (err); 308 309 err = ptree_add_node(rooth, iobrdh); 310 if (err != PICL_SUCCESS) 311 return (err); 312 313 err = add_ref_prop(tmph, iobrdh, FRU_PARENT); 314 if (err != PICL_SUCCESS) 315 return (err); 316 } 317 return (PICL_SUCCESS); 318 } 319 320 /* Initializes the FRU node for the RSC card */ 321 static int 322 do_rscboard_init(picl_nodehdl_t rooth) 323 { 324 picl_nodehdl_t rscbrdh; 325 picl_nodehdl_t tmph; 326 int err; 327 328 /* Create the node for the RSC board (if it exists) */ 329 if (ptree_get_node_by_path(platform_frupath[RSC], &tmph) == 330 PICL_SUCCESS) { 331 err = ptree_create_node("rsc-board", "fru", &rscbrdh); 332 if (err != PICL_SUCCESS) 333 return (err); 334 335 err = add_ref_prop(rscbrdh, tmph, SEEPROM_SOURCE); 336 if (err != PICL_SUCCESS) 337 return (err); 338 339 err = add_void_fda_prop(rscbrdh); 340 if (err != PICL_SUCCESS) 341 return (err); 342 343 err = ptree_add_node(rooth, rscbrdh); 344 if (err != PICL_SUCCESS) 345 return (err); 346 347 err = add_ref_prop(tmph, rscbrdh, FRU_PARENT); 348 if (err != PICL_SUCCESS) 349 return (err); 350 } 351 return (PICL_SUCCESS); 352 } 353 354 /* Initializes the FRU nodes for the FCAL backplaned */ 355 static int 356 do_fcal_init(picl_nodehdl_t rooth) 357 { 358 picl_nodehdl_t fcalsloth; 359 picl_nodehdl_t fcalmodh; 360 picl_nodehdl_t tmph; 361 int err; 362 363 /* Create the node for the FCAL backplane slot */ 364 err = ptree_create_node("fcal-backplane-slot", 365 "location", &fcalsloth); 366 if (err != PICL_SUCCESS) 367 return (err); 368 369 err = add_slot_prop(fcalsloth, 0); 370 if (err != PICL_SUCCESS) 371 return (err); 372 373 err = ptree_add_node(rooth, fcalsloth); 374 if (err != PICL_SUCCESS) 375 return (err); 376 377 /* If the FCAL backplane exists, create a node for it */ 378 if (ptree_get_node_by_path(platform_frupath[DISKBACKPLANE], &tmph) == 379 PICL_SUCCESS) { 380 err = ptree_create_node("fcal-backplane", "fru", 381 &fcalmodh); 382 if (err != PICL_SUCCESS) 383 return (err); 384 385 err = add_ref_prop(fcalmodh, tmph, SEEPROM_SOURCE); 386 if (err != PICL_SUCCESS) 387 return (err); 388 389 err = add_void_fda_prop(fcalmodh); 390 if (err != PICL_SUCCESS) 391 return (err); 392 393 err = ptree_add_node(fcalsloth, fcalmodh); 394 if (err != PICL_SUCCESS) 395 return (err); 396 397 err = add_ref_prop(tmph, fcalmodh, FRU_PARENT); 398 if (err != PICL_SUCCESS) 399 return (err); 400 } 401 return (PICL_SUCCESS); 402 } 403 404 /* Initializes the FRU nodes for the PDB and the power supplies */ 405 static int 406 do_power_supplies_init(picl_nodehdl_t rooth) 407 { 408 picl_nodehdl_t powerbrdh; 409 picl_nodehdl_t powersloth; 410 picl_nodehdl_t powermodh; 411 picl_nodehdl_t tmph; 412 int i, err, slotnum; 413 414 /* Create the node for the PDB (if it exists) */ 415 if (ptree_get_node_by_path(platform_frupath[PDB], &tmph) == 416 PICL_SUCCESS) { 417 err = ptree_create_node("power-dist-board", "fru", &powerbrdh); 418 if (err != PICL_SUCCESS) 419 return (err); 420 421 err = add_ref_prop(powerbrdh, tmph, SEEPROM_SOURCE); 422 if (err != PICL_SUCCESS) 423 return (err); 424 425 err = add_void_fda_prop(powerbrdh); 426 if (err != PICL_SUCCESS) 427 return (err); 428 429 err = ptree_add_node(rooth, powerbrdh); 430 if (err != PICL_SUCCESS) 431 return (err); 432 433 err = add_ref_prop(tmph, powerbrdh, FRU_PARENT); 434 if (err != PICL_SUCCESS) 435 return (err); 436 437 for (i = PS0; i <= PS1; i++) { 438 /* Create the node for the power supply slot */ 439 err = ptree_create_node("power-supply-slot", 440 "location", &powersloth); 441 if (err != PICL_SUCCESS) 442 return (err); 443 444 slotnum = i - PS0; 445 err = add_slot_prop(powersloth, slotnum); 446 if (err != PICL_SUCCESS) 447 return (err); 448 449 err = add_label_prop(powersloth, location_label[i]); 450 if (err != PICL_SUCCESS) 451 return (err); 452 453 err = ptree_add_node(powerbrdh, powersloth); 454 if (err != PICL_SUCCESS) 455 return (err); 456 457 /* If the PS exists, create a node for it */ 458 if (ptree_get_node_by_path(platform_frupath[i], 459 &tmph) == PICL_SUCCESS) { 460 err = ptree_create_node("power-supply", 461 "fru", &powermodh); 462 if (err != PICL_SUCCESS) 463 return (err); 464 465 err = add_ref_prop(powermodh, tmph, 466 SEEPROM_SOURCE); 467 if (err != PICL_SUCCESS) 468 return (err); 469 470 err = add_void_fda_prop(powermodh); 471 if (err != PICL_SUCCESS) 472 return (err); 473 474 err = ptree_add_node(powersloth, powermodh); 475 if (err != PICL_SUCCESS) 476 return (err); 477 478 err = add_ref_prop(tmph, powermodh, FRU_PARENT); 479 if (err != PICL_SUCCESS) 480 return (err); 481 } 482 } 483 } 484 return (PICL_SUCCESS); 485 } 486 487 /* Initializes the FRU nodes for the centerplane and CPU Memory modules */ 488 static int 489 do_centerplane_init(picl_nodehdl_t rooth) 490 { 491 picl_nodehdl_t sysboardh; 492 picl_nodehdl_t cpumemsloth; 493 picl_nodehdl_t cpumemmodh; 494 picl_nodehdl_t tmph; 495 int i, err, slotnum; 496 497 /* Create the node for the system board (if it exists) */ 498 if (ptree_get_node_by_path(platform_frupath[CENTERPLANE], &tmph) == 499 PICL_SUCCESS) { 500 err = ptree_create_node("centerplane", "fru", 501 &sysboardh); 502 if (err != PICL_SUCCESS) 503 return (err); 504 505 err = add_ref_prop(sysboardh, tmph, SEEPROM_SOURCE); 506 if (err != PICL_SUCCESS) 507 return (err); 508 509 err = add_void_fda_prop(sysboardh); 510 if (err != PICL_SUCCESS) 511 return (err); 512 513 err = ptree_add_node(rooth, sysboardh); 514 if (err != PICL_SUCCESS) 515 return (err); 516 517 err = add_ref_prop(tmph, sysboardh, FRU_PARENT); 518 if (err != PICL_SUCCESS) 519 return (err); 520 521 for (i = CPUMOD0; i <= CPUMOD1; i++) { 522 /* Create the node for the CPU Memory slot */ 523 err = ptree_create_node("cpu-mem-slot", "location", 524 &cpumemsloth); 525 if (err != PICL_SUCCESS) 526 return (err); 527 528 slotnum = i - CPUMOD0; 529 err = add_slot_prop(cpumemsloth, slotnum); 530 if (err != PICL_SUCCESS) 531 return (err); 532 533 err = add_label_prop(cpumemsloth, location_label[i]); 534 if (err != PICL_SUCCESS) 535 return (err); 536 537 err = ptree_add_node(sysboardh, cpumemsloth); 538 if (err != PICL_SUCCESS) 539 return (err); 540 541 /* If CPU Mem module exists, create a node for it */ 542 if (ptree_get_node_by_path(platform_frupath[i], 543 &tmph) == PICL_SUCCESS) { 544 err = ptree_create_node("cpu-mem-module", 545 "fru", &cpumemmodh); 546 if (err != PICL_SUCCESS) 547 return (err); 548 549 err = add_ref_prop(cpumemmodh, tmph, 550 SEEPROM_SOURCE); 551 if (err != PICL_SUCCESS) 552 return (err); 553 554 err = add_void_fda_prop(cpumemmodh); 555 if (err != PICL_SUCCESS) 556 return (err); 557 558 err = ptree_add_node(cpumemsloth, cpumemmodh); 559 if (err != PICL_SUCCESS) 560 return (err); 561 562 err = add_ref_prop(tmph, cpumemmodh, 563 FRU_PARENT); 564 if (err != PICL_SUCCESS) 565 return (err); 566 567 err = do_cpu_module_init(cpumemmodh, slotnum); 568 if (err != PICL_SUCCESS) 569 return (err); 570 } 571 } 572 } 573 return (PICL_SUCCESS); 574 } 575 576 /* Creates the FRU nodes for the CPU Module and associated DIMMs */ 577 static int 578 do_cpu_module_init(picl_nodehdl_t rooth, int slot) 579 { 580 picl_nodehdl_t cpumodh; 581 int i, c, err; 582 583 for (i = 0; i <= 1; i++) { 584 err = ptree_create_node("cpu-module", "location", 585 &cpumodh); 586 if (err != PICL_SUCCESS) 587 return (err); 588 589 err = add_slot_prop(cpumodh, i); 590 if (err != PICL_SUCCESS) 591 return (err); 592 593 c = CPU0_DIMM0 + DIMMS_PER_SLOT + i; 594 595 err = add_label_prop(cpumodh, location_label[c]); 596 if (err != PICL_SUCCESS) 597 return (err); 598 599 err = ptree_add_node(rooth, cpumodh); 600 if (err != PICL_SUCCESS) 601 return (err); 602 603 /* Create the nodes for the memory (if they exist) */ 604 err = do_dimms_init(cpumodh, slot, i); 605 if (err != PICL_SUCCESS) 606 return (err); 607 } 608 return (PICL_SUCCESS); 609 } 610 611 /* Creates the FRU nodes for the DIMMs on a particular CPU Module */ 612 static int 613 do_dimms_init(picl_nodehdl_t rooth, int slot, int module) 614 { 615 picl_nodehdl_t dimmsloth; 616 picl_nodehdl_t dimmmodh; 617 picl_nodehdl_t tmph; 618 int i, c, l, err; 619 620 for (i = 0; i < DIMMS_PER_MOD; i++) { 621 /* Create the node for the memory slot */ 622 err = ptree_create_node("dimm-slot", "location", 623 &dimmsloth); 624 if (err != PICL_SUCCESS) 625 return (err); 626 627 err = add_slot_prop(dimmsloth, i); 628 if (err != PICL_SUCCESS) 629 return (err); 630 631 c = ((slot * DIMMS_PER_SLOT) + 632 (module * DIMMS_PER_MOD) + i) + CPU0_DIMM0; 633 634 l = c - (DIMMS_PER_SLOT * slot); 635 636 err = add_label_prop(dimmsloth, location_label[l]); 637 if (err != PICL_SUCCESS) 638 return (err); 639 640 err = ptree_add_node(rooth, dimmsloth); 641 if (err != PICL_SUCCESS) 642 return (err); 643 644 /* If the memory module exists, create a node for it */ 645 if (ptree_get_node_by_path(platform_frupath[c], &tmph) == 646 PICL_SUCCESS) { 647 err = ptree_create_node("dimm-module", "fru", 648 &dimmmodh); 649 if (err != PICL_SUCCESS) 650 return (err); 651 652 err = add_ref_prop(dimmmodh, tmph, SEEPROM_SOURCE); 653 if (err != PICL_SUCCESS) 654 return (err); 655 656 err = add_void_fda_prop(dimmmodh); 657 if (err != PICL_SUCCESS) 658 return (err); 659 660 err = ptree_add_node(dimmsloth, dimmmodh); 661 if (err != PICL_SUCCESS) 662 return (err); 663 664 err = add_ref_prop(tmph, dimmmodh, FRU_PARENT); 665 if (err != PICL_SUCCESS) 666 return (err); 667 } 668 } 669 return (PICL_SUCCESS); 670 } 671 672 /* Creates a "reference" property between two PICL nodes */ 673 static int 674 add_ref_prop(picl_nodehdl_t nodeh, picl_nodehdl_t tmph, char *str) 675 { 676 picl_prophdl_t proph; 677 ptree_propinfo_t propinfo; 678 int err; 679 680 if (str == NULL) 681 return (PICL_FAILURE); 682 683 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 684 PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t), 685 str, NULL, NULL); 686 if (err != PICL_SUCCESS) 687 return (err); 688 689 err = ptree_create_and_add_prop(nodeh, &propinfo, &tmph, &proph); 690 if (err != PICL_SUCCESS) 691 return (err); 692 693 return (PICL_SUCCESS); 694 } 695 696 /* Creates a "slot" property for a given PICL node */ 697 static int 698 add_slot_prop(picl_nodehdl_t nodeh, int slotnum) 699 { 700 picl_prophdl_t proph; 701 ptree_propinfo_t propinfo; 702 int err; 703 704 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 705 PICL_PTYPE_INT, PICL_READ, 4, "Slot", NULL, NULL); 706 if (err != PICL_SUCCESS) 707 return (err); 708 709 err = ptree_create_and_add_prop(nodeh, &propinfo, &slotnum, &proph); 710 if (err != PICL_SUCCESS) 711 return (err); 712 713 return (PICL_SUCCESS); 714 } 715 716 /* Creates a "Label" property for a given PICL node */ 717 static int 718 add_label_prop(picl_nodehdl_t nodeh, char *label) 719 { 720 picl_prophdl_t proph; 721 ptree_propinfo_t propinfo; 722 int err; 723 724 if (label == NULL) 725 return (PICL_FAILURE); 726 727 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 728 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(label)+1, "Label", 729 NULL, NULL); 730 if (err != PICL_SUCCESS) 731 return (err); 732 733 err = ptree_create_and_add_prop(nodeh, &propinfo, label, &proph); 734 if (err != PICL_SUCCESS) 735 return (err); 736 737 return (PICL_SUCCESS); 738 } 739 740 /* Creates a "FRUDataAvailable" void property for the given PICL node */ 741 static int 742 add_void_fda_prop(picl_nodehdl_t nodeh) 743 { 744 picl_prophdl_t proph; 745 ptree_propinfo_t propinfo; 746 int err; 747 748 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 749 PICL_PTYPE_VOID, PICL_READ, 0, "FRUDataAvailable", NULL, NULL); 750 if (err != PICL_SUCCESS) 751 return (err); 752 753 err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph); 754 if (err != PICL_SUCCESS) 755 return (err); 756 757 return (PICL_SUCCESS); 758 } 759 760 /* Creates a "ViewPoints" property -- used for chassis */ 761 static int 762 add_viewpoints_prop(picl_nodehdl_t nodeh, char *string) 763 { 764 picl_prophdl_t proph; 765 ptree_propinfo_t propinfo; 766 int err; 767 768 if (string == NULL) 769 return (PICL_FAILURE); 770 771 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 772 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(string)+1, "ViewPoints", 773 NULL, NULL); 774 if (err != PICL_SUCCESS) 775 return (err); 776 777 err = ptree_create_and_add_prop(nodeh, &propinfo, string, &proph); 778 if (err != PICL_SUCCESS) 779 return (err); 780 781 return (PICL_SUCCESS); 782 } 783 784 /* Creates and adds all of the frutree nodes */ 785 static int 786 add_all_nodes() 787 { 788 picl_nodehdl_t rooth; 789 picl_nodehdl_t chassish; 790 int err; 791 792 /* Get the root node of the PICL tree */ 793 err = ptree_get_root(&rooth); 794 if (err != PICL_SUCCESS) { 795 return (err); 796 } 797 798 /* Create and add the root node of the FRU subtree */ 799 err = ptree_create_and_add_node(rooth, "frutree", "picl", &frutreeh); 800 if (err != PICL_SUCCESS) { 801 syslog(LOG_ERR, CREATE_FRUTREE_FAIL); 802 return (err); 803 } 804 805 /* Create and add the chassis node */ 806 err = ptree_create_and_add_node(frutreeh, "chassis", "fru", &chassish); 807 if (err != PICL_SUCCESS) { 808 syslog(LOG_ERR, CREATE_CHASSIS_FAIL); 809 return (err); 810 } 811 812 /* Add ViewPoints prop to chassis node */ 813 err = add_viewpoints_prop(chassish, CHASSIS_VIEWPOINTS); 814 if (err != PICL_SUCCESS) 815 return (err); 816 817 /* Initialize the FRU nodes for the IO board */ 818 err = do_ioboard_init(chassish); 819 if (err != PICL_SUCCESS) { 820 syslog(LOG_ERR, IOBRD_INIT_FAIL); 821 return (err); 822 } 823 824 /* Initialize the FRU node for the RSC card */ 825 err = do_rscboard_init(chassish); 826 if (err != PICL_SUCCESS) { 827 syslog(LOG_ERR, RSCBRD_INIT_FAIL); 828 return (err); 829 } 830 831 /* Initialize the FRU nodes for the DISK backplane */ 832 err = do_fcal_init(chassish); 833 if (err != PICL_SUCCESS) { 834 syslog(LOG_ERR, FCAL_INIT_FAIL); 835 return (err); 836 } 837 838 /* Initialize the FRU nodes for the PDB and the power supplies */ 839 err = do_power_supplies_init(chassish); 840 if (err != PICL_SUCCESS) { 841 syslog(LOG_ERR, PS_INIT_FAIL); 842 return (err); 843 } 844 845 /* Initialize the FRU nodes for the CPU Memory modules */ 846 err = do_centerplane_init(chassish); 847 if (err != PICL_SUCCESS) { 848 syslog(LOG_ERR, SYSBOARD_INIT_FAIL); 849 return (err); 850 } 851 852 return (PICL_SUCCESS); 853 } 854 855 /* Deletes and destroys all PICL nodes for which rooth is a ancestor */ 856 static int 857 remove_all_nodes(picl_nodehdl_t rooth) 858 { 859 picl_nodehdl_t chdh; 860 int err, done = 0; 861 862 while (!done) { 863 err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh, 864 sizeof (picl_nodehdl_t)); 865 if (err != PICL_PROPNOTFOUND) { 866 (void) remove_all_nodes(chdh); 867 } else { 868 err = ptree_delete_node(rooth); 869 if (err != PICL_SUCCESS) { 870 return (err); 871 } else { 872 (void) ptree_destroy_node(rooth); 873 } 874 done = 1; 875 } 876 } 877 return (PICL_SUCCESS); 878 } 879 880 /* Searches the list of hotpluggable FRUs, adds the appropriate node(s) */ 881 static int 882 add_hotplug_fru_device() 883 { 884 int i, err, slotnum; 885 886 /* Check for hotplugged power supplies */ 887 for (i = PS0; i <= PS1; i++) { 888 /* Compare the /platform tree to the frutree */ 889 slotnum = i - PS0; 890 err = is_added_device(platform_frupath[i], 891 frutree_power_supply[slotnum]); 892 if (err != PICL_SUCCESS) 893 continue; 894 895 /* If they are different, then add a power supply */ 896 err = add_power_supply(slotnum); 897 if (err != PICL_SUCCESS) 898 continue; 899 } 900 return (PICL_SUCCESS); 901 } 902 903 /* Searches the list of hotpluggable FRUs, removes the appropriate node(s) */ 904 static int 905 rem_hotplug_fru_device() 906 { 907 int i, err, slotnum; 908 909 /* Check for hotplugged power supplies */ 910 for (i = PS0; i <= PS1; i++) { 911 /* Compare the /platform tree to the frutree */ 912 slotnum = i - PS0; 913 err = is_removed_device(platform_frupath[i], 914 frutree_power_supply[slotnum]); 915 if (err != PICL_SUCCESS) 916 continue; 917 918 /* If they are different, then remove a power supply */ 919 err = remove_power_supply(slotnum); 920 if (err != PICL_SUCCESS) 921 continue; 922 } 923 return (PICL_SUCCESS); 924 } 925 926 /* 927 * Compare the /platform tree to the /frutree to determine if a 928 * new device has been added 929 */ 930 static int 931 is_added_device(char *plat, char *fru) 932 { 933 int err; 934 picl_nodehdl_t plath, frusloth, frumodh; 935 936 /* Check for node in the /platform tree */ 937 err = ptree_get_node_by_path(plat, &plath); 938 if (err != PICL_SUCCESS) 939 return (err); 940 941 /* 942 * The node is in /platform, so find the corresponding slot in 943 * the frutree 944 */ 945 err = ptree_get_node_by_path(fru, &frusloth); 946 if (err != PICL_SUCCESS) 947 return (err); 948 949 /* 950 * If the slot in the frutree has a child, then return 951 * PICL_FAILURE. This means that the /platform tree and 952 * the frutree are consistent and no action is necessary. 953 * Otherwise return PICL_SUCCESS to indicate that a node needs 954 * to be added to the frutree 955 */ 956 err = ptree_get_propval_by_name(frusloth, PICL_PROP_CHILD, 957 &frumodh, sizeof (picl_nodehdl_t)); 958 if (err == PICL_SUCCESS) 959 return (PICL_FAILURE); 960 961 return (PICL_SUCCESS); 962 } 963 964 /* 965 * Compare the /platform tree to the /frutree to determine if a 966 * device has been removed 967 */ 968 static int 969 is_removed_device(char *plat, char *fru) 970 { 971 int err; 972 picl_nodehdl_t plath, frusloth, frumodh; 973 974 975 /* Check for node in /platform tree */ 976 err = ptree_get_node_by_path(plat, &plath); 977 if (err == PICL_SUCCESS) 978 return (PICL_FAILURE); 979 980 /* 981 * The node is not in /platform, so find the corresponding slot in 982 * the frutree 983 */ 984 err = ptree_get_node_by_path(fru, &frusloth); 985 if (err != PICL_SUCCESS) 986 return (err); 987 988 /* 989 * If the slot in the frutree does not have a child, then return 990 * PICL_FAILURE. This means that the /platform tree and 991 * the frutree are consistent and no action is necessary. 992 * Otherwise return PICL_SUCCESS to indicate that the needs 993 * to be removed from the frutree 994 */ 995 err = ptree_get_propval_by_name(frusloth, PICL_PROP_CHILD, 996 &frumodh, sizeof (picl_nodehdl_t)); 997 if (err != PICL_SUCCESS) 998 return (err); 999 1000 return (PICL_SUCCESS); 1001 } 1002 1003 static int 1004 remove_picl_node(picl_nodehdl_t nodeh) 1005 { 1006 int err; 1007 err = ptree_delete_node(nodeh); 1008 if (err != PICL_SUCCESS) 1009 return (err); 1010 (void) ptree_destroy_node(nodeh); 1011 return (PICL_SUCCESS); 1012 } 1013 1014 /* event completion handler for PICL_FRU_ADDED/PICL_FRU_REMOVED events */ 1015 static void 1016 frudr_completion_handler(char *ename, void *earg, size_t size) 1017 { 1018 picl_nodehdl_t fruh; 1019 1020 if (strcmp(ename, PICL_FRU_REMOVED) == 0) { 1021 /* 1022 * now frudata has been notified that the node is to be 1023 * removed, we can actually remove it 1024 */ 1025 fruh = 0; 1026 (void) nvlist_lookup_uint64(earg, 1027 PICLEVENTARG_FRUHANDLE, &fruh); 1028 if (fruh != 0) { 1029 (void) remove_picl_node(fruh); 1030 } 1031 } 1032 nvlist_free(earg); 1033 free(earg); 1034 free(ename); 1035 } 1036 1037 /* 1038 * Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event 1039 */ 1040 static void 1041 post_frudr_event(char *ename, picl_nodehdl_t parenth, picl_nodehdl_t fruh) 1042 { 1043 nvlist_t *nvl; 1044 char *ev_name; 1045 1046 ev_name = strdup(ename); 1047 if (ev_name == NULL) 1048 return; 1049 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) { 1050 free(ev_name); 1051 return; 1052 } 1053 if (parenth != 0L && 1054 nvlist_add_uint64(nvl, PICLEVENTARG_PARENTHANDLE, parenth)) { 1055 free(ev_name); 1056 nvlist_free(nvl); 1057 return; 1058 } 1059 if (fruh != 0L && 1060 nvlist_add_uint64(nvl, PICLEVENTARG_FRUHANDLE, fruh)) { 1061 free(ev_name); 1062 nvlist_free(nvl); 1063 return; 1064 } 1065 if (ptree_post_event(ev_name, nvl, sizeof (nvl), 1066 frudr_completion_handler) != 0) { 1067 free(ev_name); 1068 nvlist_free(nvl); 1069 } 1070 } 1071 1072 /* Hotplug routine used to add a new power supply */ 1073 static int 1074 add_power_supply(int slotnum) 1075 { 1076 picl_nodehdl_t powersloth; 1077 picl_nodehdl_t powermodh; 1078 picl_nodehdl_t tmph; 1079 int i, err; 1080 1081 /* Find the node for the given power supply slot */ 1082 if (ptree_get_node_by_path(frutree_power_supply[slotnum], 1083 &powersloth) == PICL_SUCCESS) { 1084 1085 i = slotnum + PS0; 1086 1087 /* Make sure it's in /platform and create the frutree node */ 1088 if (ptree_get_node_by_path(platform_frupath[i], &tmph) == 1089 PICL_SUCCESS) { 1090 err = ptree_create_node("power-supply", "fru", 1091 &powermodh); 1092 if (err != PICL_SUCCESS) 1093 return (err); 1094 1095 err = add_ref_prop(powermodh, tmph, SEEPROM_SOURCE); 1096 if (err != PICL_SUCCESS) 1097 return (err); 1098 1099 err = add_void_fda_prop(powermodh); 1100 if (err != PICL_SUCCESS) 1101 return (err); 1102 1103 err = ptree_add_node(powersloth, powermodh); 1104 if (err != PICL_SUCCESS) 1105 return (err); 1106 1107 err = add_ref_prop(tmph, powermodh, FRU_PARENT); 1108 if (err != PICL_SUCCESS) 1109 return (err); 1110 1111 /* Post picl-fru-added event */ 1112 post_frudr_event(PICL_FRU_ADDED, 0, powermodh); 1113 } 1114 } 1115 return (PICL_SUCCESS); 1116 } 1117 1118 /* Hotplug routine used to remove an existing power supply */ 1119 static int 1120 remove_power_supply(int slotnum) 1121 { 1122 picl_nodehdl_t powersloth; 1123 picl_nodehdl_t powermodh; 1124 int err; 1125 1126 /* Find the node for the given power supply slot */ 1127 if (ptree_get_node_by_path(frutree_power_supply[slotnum], 1128 &powersloth) == PICL_SUCCESS) { 1129 /* Make sure it's got a child, then delete it */ 1130 err = ptree_get_propval_by_name(powersloth, PICL_PROP_CHILD, 1131 &powermodh, sizeof (picl_nodehdl_t)); 1132 if (err != PICL_SUCCESS) { 1133 return (err); 1134 } 1135 1136 err = ptree_delete_node(powermodh); 1137 if (err != PICL_SUCCESS) { 1138 return (err); 1139 } 1140 (void) ptree_destroy_node(powermodh); 1141 /* Post picl-fru-removed event */ 1142 post_frudr_event(PICL_FRU_REMOVED, 0, powermodh); 1143 } 1144 return (PICL_SUCCESS); 1145 } 1146