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