/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * PICL plug-in that creates the FRU Hierarchy for the * SUNW,Sun-Fire-880 (Daktari) platform */ #include #include #include #include #include #include #include #include /* * Plugin registration entry points */ static void picl_frutree_register(void); static void picl_frutree_init(void); static void picl_frutree_fini(void); static void picl_frutree_evhandler(const char *ename, const void *earg, size_t size, void *cookie); #pragma init(picl_frutree_register) /* * Log message texts */ #define CREATE_FRUTREE_FAIL gettext("Failed to create frutree node\n") #define CREATE_CHASSIS_FAIL gettext("Failed to create chassis node\n") #define IOBRD_INIT_FAIL gettext("do_ioboard_init() failed\n") #define RSCBRD_INIT_FAIL gettext("do_rscboard_init() failed\n") #define FCAL_INIT_FAIL gettext("do_fcal_init() failed\n") #define PS_INIT_FAIL gettext("do_power_supplies_init() failed\n") #define SYSBOARD_INIT_FAIL gettext("do_motherboard_init() failed\n") /* * Viewpoints property field used by SunMC */ #define CHASSIS_VIEWPOINTS gettext("front left right rear") /* * Ref prop values */ #define SEEPROM_SOURCE "_seeprom_source" #define FRU_PARENT "_fru_parent" /* * List of all the FRU locations in the platform_frupath[] array, and * location_label[] array */ #define IOBRD 0 #define RSC 1 #define FCAL0 2 #define FCAL1 3 #define FCALGBIC 4 #define PDB 5 #define PS0 6 #define PS1 7 #define PS2 8 #define SYSBRD 9 #define CPUMOD0 10 #define CPUMOD1 11 #define CPUMOD2 12 #define CPUMOD3 13 #define CPU0_DIMM0 14 #define DIMMS_PER_MOD 8 #define DIMMS_PER_SLOT 16 /* * Local variables */ static picld_plugin_reg_t my_reg_info = { PICLD_PLUGIN_VERSION_1, PICLD_PLUGIN_NON_CRITICAL, "SUNW_Sun-Fire-880_frutree", picl_frutree_init, picl_frutree_fini }; /* * List of all the FRUs in the /platform tree with SEEPROMs */ static char *platform_frupath[] = { "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@4,aa", /* IO */ "/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a6", /* RSC */ "/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a8", /* FCAL 0 */ "/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,ac", /* FCAL 1 */ "/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,aa", /* FCAL-GBIC */ "/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,ae", /* PDB */ "/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a0", /* PS 0 */ "/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a2", /* PS 1 */ "/platform/pci@9,700000/ebus@1/i2c@1,30/fru@0,a4", /* PS 2 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@4,a8", /* SYS BRD */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@4,a0", /* CPU MOD 0 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@4,a2", /* CPU MOD 1 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@4,a4", /* CPU MOD 2 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@4,a6", /* CPU MOD 3 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a0", /* CPU0 DIMM0 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a2", /* CPU0 DIMM1 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a4", /* CPU0 DIMM2 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a6", /* CPU0 DIMM3 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a8", /* CPU0 DIMM4 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,aa", /* CPU0 DIMM5 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,ac", /* CPU0 DIMM6 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@0,ae", /* CPU0 DIMM7 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a0", /* CPU2 DIMM0 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a2", /* CPU2 DIMM1 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a4", /* CPU2 DIMM2 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a6", /* CPU2 DIMM3 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a8", /* CPU2 DIMM4 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,aa", /* CPU2 DIMM5 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,ac", /* CPU2 DIMM6 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@2,ae", /* CPU2 DIMM7 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a0", /* CPU1 DIMM0 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a2", /* CPU1 DIMM1 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a4", /* CPU1 DIMM2 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a6", /* CPU1 DIMM3 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a8", /* CPU1 DIMM4 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,aa", /* CPU1 DIMM5 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,ac", /* CPU1 DIMM6 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@1,ae", /* CPU1 DIMM7 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a0", /* CPU3 DIMM0 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a2", /* CPU3 DIMM1 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a4", /* CPU3 DIMM2 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a6", /* CPU3 DIMM3 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a8", /* CPU3 DIMM4 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,aa", /* CPU3 DIMM5 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,ac", /* CPU3 DIMM6 */ "/platform/pci@9,700000/ebus@1/i2c@1,2e/fru@3,ae", /* CPU3 DIMM7 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,a0", /* CPU4 DIMM0 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,a2", /* CPU4 DIMM1 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,a4", /* CPU4 DIMM2 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,a6", /* CPU4 DIMM3 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,a8", /* CPU4 DIMM4 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,aa", /* CPU4 DIMM5 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,ac", /* CPU4 DIMM6 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@0,ae", /* CPU4 DIMM7 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,a0", /* CPU6 DIMM0 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,a2", /* CPU6 DIMM1 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,a4", /* CPU6 DIMM2 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,a6", /* CPU6 DIMM3 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,a8", /* CPU6 DIMM4 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,aa", /* CPU6 DIMM5 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,ac", /* CPU6 DIMM6 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@2,ae", /* CPU6 DIMM7 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,a0", /* CPU5 DIMM0 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,a2", /* CPU5 DIMM1 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,a4", /* CPU5 DIMM2 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,a6", /* CPU5 DIMM3 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,a8", /* CPU5 DIMM4 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,aa", /* CPU5 DIMM5 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,ac", /* CPU5 DIMM6 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@1,ae", /* CPU5 DIMM7 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,a0", /* CPU7 DIMM0 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,a2", /* CPU7 DIMM1 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,a4", /* CPU7 DIMM2 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,a6", /* CPU7 DIMM3 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,a8", /* CPU7 DIMM4 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,aa", /* CPU7 DIMM5 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,ac", /* CPU7 DIMM6 */ "/platform/pci@9,700000/ebus@1/i2c@1,50002e/fru@3,ae", /* CPU7 DIMM7 */ NULL}; /* * List of Labels for FRU locations (uses the #define's from above) */ static char *location_label[] = { NULL, /* IOBRD */ NULL, /* RSC */ "0", /* FCAL0 */ "1", /* FCAL1 */ NULL, /* FCALGBIC */ NULL, /* PDB */ "0", /* PS0 */ "1", /* PS1 */ "2", /* PS2 */ NULL, /* SYSBRD */ "A", /* CPUMOD0 */ "B", /* CPUMOD1 */ "C", /* CPUMOD2 */ "D", /* CPUMOD3 */ "J2900", /* CPU0 DIMM0 */ "J3100", /* CPU0 DIMM1 */ "J2901", /* CPU0 DIMM2 */ "J3101", /* CPU0 DIMM3 */ "J3000", /* CPU0 DIMM4 */ "J3200", /* CPU0 DIMM5 */ "J3001", /* CPU0 DIMM6 */ "J3201", /* CPU0 DIMM7 */ "J7900", /* CPU1 DIMM0 */ "J8100", /* CPU1 DIMM1 */ "J7901", /* CPU1 DIMM2 */ "J8101", /* CPU1 DIMM3 */ "J8000", /* CPU1 DIMM4 */ "J8200", /* CPU1 DIMM5 */ "J8001", /* CPU1 DIMM6 */ "J8201", /* CPU1 DIMM7 */ "0", /* CPU0 label */ "1", /* CPU1 label */ NULL}; /* * List of all the FRU slots for power supplies (hotpluggable) */ static char *frutree_power_supply[] = { "/frutree/chassis/power-dist-board/power-supply-slot?Slot=0", "/frutree/chassis/power-dist-board/power-supply-slot?Slot=1", "/frutree/chassis/power-dist-board/power-supply-slot?Slot=2", NULL}; /* * List of all the FRU slots for CPU Memory modules (hotpluggable) */ static char *frutree_cpu_module[] = { "/frutree/chassis/system-board/cpu-mem-slot?Slot=0", "/frutree/chassis/system-board/cpu-mem-slot?Slot=1", "/frutree/chassis/system-board/cpu-mem-slot?Slot=2", "/frutree/chassis/system-board/cpu-mem-slot?Slot=3", NULL}; /* PICL handle for the root node of the "frutree" */ static picl_nodehdl_t frutreeh; static int do_ioboard_init(picl_nodehdl_t); static int do_rscboard_init(picl_nodehdl_t); static int do_fcal_init(picl_nodehdl_t); static int do_power_supplies_init(picl_nodehdl_t); static int do_motherboard_init(picl_nodehdl_t); static int do_cpu_module_init(picl_nodehdl_t, int); static int do_dimms_init(picl_nodehdl_t, int, int); static int add_ref_prop(picl_nodehdl_t, picl_nodehdl_t, char *); static int add_slot_prop(picl_nodehdl_t, int); static int add_label_prop(picl_nodehdl_t, char *); static int add_void_fda_prop(picl_nodehdl_t); static int add_viewpoints_prop(picl_nodehdl_t, char *); static int add_all_nodes(); static int remove_all_nodes(picl_nodehdl_t); static int add_hotplug_fru_device(void); static int rem_hotplug_fru_device(void); static int is_added_device(char *, char *); static int is_removed_device(char *, char *); static int add_power_supply(int); static int remove_power_supply(int); static int add_cpu_module(int); static int remove_cpu_module(int); /* * This function is executed as part of .init when the plugin is * dlopen()ed */ static void picl_frutree_register() { (void) picld_plugin_register(&my_reg_info); } /* * This function is the init entry point of the plugin. * It initializes the /frutree tree */ static void picl_frutree_init() { int err; err = add_all_nodes(); if (err != PICL_SUCCESS) { (void) remove_all_nodes(frutreeh); return; } /* Register the event handler routine */ (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, picl_frutree_evhandler, NULL); (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED, picl_frutree_evhandler, NULL); } /* * This function is the fini entry point of the plugin */ static void picl_frutree_fini(void) { /* Unregister the event handler routine */ (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, picl_frutree_evhandler, NULL); (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED, picl_frutree_evhandler, NULL); (void) remove_all_nodes(frutreeh); } /* * This function is the event handler of this plug-in. * * It processes the following events: * * PICLEVENT_SYSEVENT_DEVICE_ADDED * PICLEVENT_SYSEVENT_DEVICE_REMOVED */ /* ARGSUSED */ static void picl_frutree_evhandler(const char *ename, const void *earg, size_t size, void *cookie) { if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) { /* Check for and add any hotplugged device(s) */ (void) add_hotplug_fru_device(); } else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) { /* Check for and remove any hotplugged device(s) */ (void) rem_hotplug_fru_device(); } } /* Initializes the FRU nodes for the IO board */ static int do_ioboard_init(picl_nodehdl_t rooth) { picl_nodehdl_t iobrdh; picl_nodehdl_t tmph; int err; /* Create the node for the IO board (if it exists) */ if (ptree_get_node_by_path(platform_frupath[IOBRD], &tmph) == PICL_SUCCESS) { err = ptree_create_node("io-board", "fru", &iobrdh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(iobrdh, tmph, SEEPROM_SOURCE); if (err != PICL_SUCCESS) return (err); err = add_void_fda_prop(iobrdh); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(rooth, iobrdh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(tmph, iobrdh, FRU_PARENT); if (err != PICL_SUCCESS) return (err); } return (PICL_SUCCESS); } /* Initializes the FRU node for the RSC card */ static int do_rscboard_init(picl_nodehdl_t rooth) { picl_nodehdl_t rscbrdh; picl_nodehdl_t tmph; int err; /* Create the node for the RSC board (if it exists) */ if (ptree_get_node_by_path(platform_frupath[RSC], &tmph) == PICL_SUCCESS) { err = ptree_create_node("rsc-board", "fru", &rscbrdh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(rscbrdh, tmph, SEEPROM_SOURCE); if (err != PICL_SUCCESS) return (err); err = add_void_fda_prop(rscbrdh); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(rooth, rscbrdh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(tmph, rscbrdh, FRU_PARENT); if (err != PICL_SUCCESS) return (err); } return (PICL_SUCCESS); } /* Initializes the FRU nodes for the FCAL backplanes and GBIC card */ static int do_fcal_init(picl_nodehdl_t rooth) { picl_nodehdl_t fcalsloth; picl_nodehdl_t fcalmodh; picl_nodehdl_t fcalgbich; picl_nodehdl_t tmph; int i, err, slotnum; for (i = FCAL0; i <= FCAL1; i++) { /* Create the node for the FCAL backplane slot */ err = ptree_create_node("fcal-backplane-slot", "location", &fcalsloth); if (err != PICL_SUCCESS) return (err); slotnum = i - FCAL0; err = add_slot_prop(fcalsloth, slotnum); if (err != PICL_SUCCESS) return (err); err = add_label_prop(fcalsloth, location_label[i]); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(rooth, fcalsloth); if (err != PICL_SUCCESS) return (err); /* If the FCAL backplane exists, create a node for it */ if (ptree_get_node_by_path(platform_frupath[i], &tmph) == PICL_SUCCESS) { err = ptree_create_node("fcal-backplane", "fru", &fcalmodh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(fcalmodh, tmph, SEEPROM_SOURCE); if (err != PICL_SUCCESS) return (err); err = add_void_fda_prop(fcalmodh); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(fcalsloth, fcalmodh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(tmph, fcalmodh, FRU_PARENT); if (err != PICL_SUCCESS) return (err); } } /* If the FCAL GBIC board exists, create a node for it */ if (ptree_get_node_by_path(platform_frupath[FCALGBIC], &tmph) == PICL_SUCCESS) { err = ptree_create_node("fcal-gbic-board", "fru", &fcalgbich); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(fcalgbich, tmph, SEEPROM_SOURCE); if (err != PICL_SUCCESS) return (err); err = add_void_fda_prop(fcalgbich); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(rooth, fcalgbich); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(tmph, fcalgbich, FRU_PARENT); if (err != PICL_SUCCESS) return (err); } return (PICL_SUCCESS); } /* Initializes the FRU nodes for the PDB and the power supplies */ static int do_power_supplies_init(picl_nodehdl_t rooth) { picl_nodehdl_t powerbrdh; picl_nodehdl_t powersloth; picl_nodehdl_t powermodh; picl_nodehdl_t tmph; int i, err, slotnum; /* Create the node for the PDB (if it exists) */ if (ptree_get_node_by_path(platform_frupath[PDB], &tmph) == PICL_SUCCESS) { err = ptree_create_node("power-dist-board", "fru", &powerbrdh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(powerbrdh, tmph, SEEPROM_SOURCE); if (err != PICL_SUCCESS) return (err); err = add_void_fda_prop(powerbrdh); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(rooth, powerbrdh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(tmph, powerbrdh, FRU_PARENT); if (err != PICL_SUCCESS) return (err); for (i = PS0; i <= PS2; i++) { /* Create the node for the power supply slot */ err = ptree_create_node("power-supply-slot", "location", &powersloth); if (err != PICL_SUCCESS) return (err); slotnum = i - PS0; err = add_slot_prop(powersloth, slotnum); if (err != PICL_SUCCESS) return (err); err = add_label_prop(powersloth, location_label[i]); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(powerbrdh, powersloth); if (err != PICL_SUCCESS) return (err); /* If the PS exists, create a node for it */ if (ptree_get_node_by_path(platform_frupath[i], &tmph) == PICL_SUCCESS) { err = ptree_create_node("power-supply", "fru", &powermodh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(powermodh, tmph, SEEPROM_SOURCE); if (err != PICL_SUCCESS) return (err); err = add_void_fda_prop(powermodh); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(powersloth, powermodh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(tmph, powermodh, FRU_PARENT); if (err != PICL_SUCCESS) return (err); } } } return (PICL_SUCCESS); } /* Initializes the FRU nodes for the motherboard and CPU Memory modules */ static int do_motherboard_init(picl_nodehdl_t rooth) { picl_nodehdl_t sysboardh; picl_nodehdl_t cpumemsloth; picl_nodehdl_t cpumemmodh; picl_nodehdl_t tmph; int i, err, slotnum; /* Create the node for the system board (if it exists) */ if (ptree_get_node_by_path(platform_frupath[SYSBRD], &tmph) == PICL_SUCCESS) { err = ptree_create_node("system-board", "fru", &sysboardh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(sysboardh, tmph, SEEPROM_SOURCE); if (err != PICL_SUCCESS) return (err); err = add_void_fda_prop(sysboardh); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(rooth, sysboardh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(tmph, sysboardh, FRU_PARENT); if (err != PICL_SUCCESS) return (err); for (i = CPUMOD0; i <= CPUMOD3; i++) { /* Create the node for the CPU Memory slot */ err = ptree_create_node("cpu-mem-slot", "location", &cpumemsloth); if (err != PICL_SUCCESS) return (err); slotnum = i - CPUMOD0; err = add_slot_prop(cpumemsloth, slotnum); if (err != PICL_SUCCESS) return (err); err = add_label_prop(cpumemsloth, location_label[i]); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(sysboardh, cpumemsloth); if (err != PICL_SUCCESS) return (err); /* If CPU Mem module exists, create a node for it */ if (ptree_get_node_by_path(platform_frupath[i], &tmph) == PICL_SUCCESS) { err = ptree_create_node("cpu-mem-module", "fru", &cpumemmodh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(cpumemmodh, tmph, SEEPROM_SOURCE); if (err != PICL_SUCCESS) return (err); err = add_void_fda_prop(cpumemmodh); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(cpumemsloth, cpumemmodh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(tmph, cpumemmodh, FRU_PARENT); if (err != PICL_SUCCESS) return (err); err = do_cpu_module_init(cpumemmodh, slotnum); if (err != PICL_SUCCESS) return (err); } } } return (PICL_SUCCESS); } /* Creates the FRU nodes for the CPU Module and associated DIMMs */ static int do_cpu_module_init(picl_nodehdl_t rooth, int slot) { picl_nodehdl_t cpumodh; int i, c, err; for (i = 0; i <= 1; i++) { err = ptree_create_node("cpu-module", "location", &cpumodh); if (err != PICL_SUCCESS) return (err); err = add_slot_prop(cpumodh, i); if (err != PICL_SUCCESS) return (err); c = CPU0_DIMM0 + DIMMS_PER_SLOT + i; err = add_label_prop(cpumodh, location_label[c]); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(rooth, cpumodh); if (err != PICL_SUCCESS) return (err); /* Create the nodes for the memory (if they exist) */ err = do_dimms_init(cpumodh, slot, i); if (err != PICL_SUCCESS) return (err); } return (PICL_SUCCESS); } /* Creates the FRU nodes for the DIMMs on a particular CPU Module */ static int do_dimms_init(picl_nodehdl_t rooth, int slot, int module) { picl_nodehdl_t dimmsloth; picl_nodehdl_t dimmmodh; picl_nodehdl_t tmph; int i, c, l, err; for (i = 0; i < DIMMS_PER_MOD; i++) { /* Create the node for the memory slot */ err = ptree_create_node("dimm-slot", "location", &dimmsloth); if (err != PICL_SUCCESS) return (err); err = add_slot_prop(dimmsloth, i); if (err != PICL_SUCCESS) return (err); c = ((slot * DIMMS_PER_SLOT) + (module * DIMMS_PER_MOD) + i) + CPU0_DIMM0; l = c - (DIMMS_PER_SLOT * slot); err = add_label_prop(dimmsloth, location_label[l]); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(rooth, dimmsloth); if (err != PICL_SUCCESS) return (err); /* If the memory module exists, create a node for it */ if (ptree_get_node_by_path(platform_frupath[c], &tmph) == PICL_SUCCESS) { err = ptree_create_node("dimm-module", "fru", &dimmmodh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(dimmmodh, tmph, SEEPROM_SOURCE); if (err != PICL_SUCCESS) return (err); err = add_void_fda_prop(dimmmodh); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(dimmsloth, dimmmodh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(tmph, dimmmodh, FRU_PARENT); if (err != PICL_SUCCESS) return (err); } } return (PICL_SUCCESS); } /* Creates a "reference" property between two PICL nodes */ static int add_ref_prop(picl_nodehdl_t nodeh, picl_nodehdl_t tmph, char *str) { picl_prophdl_t proph; ptree_propinfo_t propinfo; int err; if (str == NULL) return (PICL_FAILURE); err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t), str, NULL, NULL); if (err != PICL_SUCCESS) return (err); err = ptree_create_and_add_prop(nodeh, &propinfo, &tmph, &proph); if (err != PICL_SUCCESS) return (err); return (PICL_SUCCESS); } /* Creates a "slot" property for a given PICL node */ static int add_slot_prop(picl_nodehdl_t nodeh, int slotnum) { picl_prophdl_t proph; ptree_propinfo_t propinfo; int err; err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_INT, PICL_READ, 4, "Slot", NULL, NULL); if (err != PICL_SUCCESS) return (err); err = ptree_create_and_add_prop(nodeh, &propinfo, &slotnum, &proph); if (err != PICL_SUCCESS) return (err); return (PICL_SUCCESS); } /* Creates a "Label" property for a given PICL node */ static int add_label_prop(picl_nodehdl_t nodeh, char *label) { picl_prophdl_t proph; ptree_propinfo_t propinfo; int err; if (label == NULL) return (PICL_FAILURE); err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, PICL_READ, strlen(label)+1, "Label", NULL, NULL); if (err != PICL_SUCCESS) return (err); err = ptree_create_and_add_prop(nodeh, &propinfo, label, &proph); if (err != PICL_SUCCESS) return (err); return (PICL_SUCCESS); } /* Creates a "FRUDataAvailable" void property for the given PICL node */ static int add_void_fda_prop(picl_nodehdl_t nodeh) { picl_prophdl_t proph; ptree_propinfo_t propinfo; int err; err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_VOID, PICL_READ, 0, "FRUDataAvailable", NULL, NULL); if (err != PICL_SUCCESS) return (err); err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph); if (err != PICL_SUCCESS) return (err); return (PICL_SUCCESS); } /* Creates a "ViewPoints" property -- used for chassis */ static int add_viewpoints_prop(picl_nodehdl_t nodeh, char *string) { picl_prophdl_t proph; ptree_propinfo_t propinfo; int err; if (string == NULL) return (PICL_FAILURE); err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, PICL_READ, strlen(string)+1, "ViewPoints", NULL, NULL); if (err != PICL_SUCCESS) return (err); err = ptree_create_and_add_prop(nodeh, &propinfo, string, &proph); if (err != PICL_SUCCESS) return (err); return (PICL_SUCCESS); } /* Creates and adds all of the frutree nodes */ static int add_all_nodes() { picl_nodehdl_t rooth; picl_nodehdl_t chassish; int err; /* Get the root node of the PICL tree */ err = ptree_get_root(&rooth); if (err != PICL_SUCCESS) { return (err); } /* Create and add the root node of the FRU subtree */ err = ptree_create_and_add_node(rooth, "frutree", "picl", &frutreeh); if (err != PICL_SUCCESS) { syslog(LOG_ERR, CREATE_FRUTREE_FAIL); return (err); } /* Create and add the chassis node */ err = ptree_create_and_add_node(frutreeh, "chassis", "fru", &chassish); if (err != PICL_SUCCESS) { syslog(LOG_ERR, CREATE_CHASSIS_FAIL); return (err); } /* Add ViewPoints prop to chassis node */ err = add_viewpoints_prop(chassish, CHASSIS_VIEWPOINTS); if (err != PICL_SUCCESS) return (err); /* Initialize the FRU nodes for the IO board */ err = do_ioboard_init(chassish); if (err != PICL_SUCCESS) { syslog(LOG_ERR, IOBRD_INIT_FAIL); return (err); } /* Initialize the FRU node for the RSC card */ err = do_rscboard_init(chassish); if (err != PICL_SUCCESS) { syslog(LOG_ERR, RSCBRD_INIT_FAIL); return (err); } /* Initialize the FRU nodes for the FCAL backplanes and GBIC board */ err = do_fcal_init(chassish); if (err != PICL_SUCCESS) { syslog(LOG_ERR, FCAL_INIT_FAIL); return (err); } /* Initialize the FRU nodes for the PDB and the power supplies */ err = do_power_supplies_init(chassish); if (err != PICL_SUCCESS) { syslog(LOG_ERR, PS_INIT_FAIL); return (err); } /* Initialize the FRU nodes for the CPU Memory modules */ err = do_motherboard_init(chassish); if (err != PICL_SUCCESS) { syslog(LOG_ERR, SYSBOARD_INIT_FAIL); return (err); } return (PICL_SUCCESS); } /* Deletes and destroys all PICL nodes for which rooth is a ancestor */ static int remove_all_nodes(picl_nodehdl_t rooth) { picl_nodehdl_t chdh; int err, done = 0; while (!done) { err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh, sizeof (picl_nodehdl_t)); if (err != PICL_PROPNOTFOUND) { (void) remove_all_nodes(chdh); } else { err = ptree_delete_node(rooth); if (err != PICL_SUCCESS) { return (err); } else { (void) ptree_destroy_node(rooth); } done = 1; } } return (PICL_SUCCESS); } /* Searches the list of hotpluggable FRUs, adds the appropriate node(s) */ static int add_hotplug_fru_device() { int i, err, slotnum; /* Check for hotplugged power supplies */ for (i = PS0; i <= PS2; i++) { /* Compare the /platform tree to the frutree */ slotnum = i - PS0; err = is_added_device(platform_frupath[i], frutree_power_supply[slotnum]); if (err != PICL_SUCCESS) continue; /* If they are different, then add a power supply */ err = add_power_supply(slotnum); if (err != PICL_SUCCESS) continue; } /* Check for hotplugged CPU Memory modules */ for (i = CPUMOD0; i <= CPUMOD3; i++) { /* Compare the /platform tree to the frutree */ slotnum = i - CPUMOD0; err = is_added_device(platform_frupath[i], frutree_cpu_module[slotnum]); if (err != PICL_SUCCESS) continue; /* If they are different, then add a CPU Mem module */ err = add_cpu_module(slotnum); if (err != PICL_SUCCESS) continue; } return (PICL_SUCCESS); } /* Searches the list of hotpluggable FRUs, removes the appropriate node(s) */ static int rem_hotplug_fru_device() { int i, err, slotnum; /* Check for hotplugged power supplies */ for (i = PS0; i <= PS2; i++) { /* Compare the /platform tree to the frutree */ slotnum = i - PS0; err = is_removed_device(platform_frupath[i], frutree_power_supply[slotnum]); if (err != PICL_SUCCESS) continue; /* If they are different, then remove a power supply */ err = remove_power_supply(slotnum); if (err != PICL_SUCCESS) continue; } /* Check for hotplugged CPU Memory modules */ for (i = CPUMOD0; i <= CPUMOD3; i++) { /* Compare the /platform tree to the frutree */ slotnum = i - CPUMOD0; err = is_removed_device(platform_frupath[i], frutree_cpu_module[slotnum]); if (err != PICL_SUCCESS) continue; /* If they are different, then remove a CPU Mem module */ err = remove_cpu_module(slotnum); if (err != PICL_SUCCESS) continue; } return (PICL_SUCCESS); } /* * Compare the /platform tree to the /frutree to determine if a * new device has been added */ static int is_added_device(char *plat, char *fru) { int err; picl_nodehdl_t plath, frusloth, frumodh; /* Check for node in the /platform tree */ err = ptree_get_node_by_path(plat, &plath); if (err != PICL_SUCCESS) return (err); /* * The node is in /platform, so find the corresponding slot in * the frutree */ err = ptree_get_node_by_path(fru, &frusloth); if (err != PICL_SUCCESS) return (err); /* * If the slot in the frutree has a child, then return * PICL_FAILURE. This means that the /platform tree and * the frutree are consistent and no action is necessary. * Otherwise return PICL_SUCCESS to indicate that a node needs * to be added to the frutree */ err = ptree_get_propval_by_name(frusloth, PICL_PROP_CHILD, &frumodh, sizeof (picl_nodehdl_t)); if (err == PICL_SUCCESS) return (PICL_FAILURE); return (PICL_SUCCESS); } /* * Compare the /platform tree to the /frutree to determine if a * device has been removed */ static int is_removed_device(char *plat, char *fru) { int err; picl_nodehdl_t plath, frusloth, frumodh; /* Check for node in /platform tree */ err = ptree_get_node_by_path(plat, &plath); if (err == PICL_SUCCESS) return (PICL_FAILURE); /* * The node is not in /platform, so find the corresponding slot in * the frutree */ err = ptree_get_node_by_path(fru, &frusloth); if (err != PICL_SUCCESS) return (err); /* * If the slot in the frutree does not have a child, then return * PICL_FAILURE. This means that the /platform tree and * the frutree are consistent and no action is necessary. * Otherwise return PICL_SUCCESS to indicate that the needs * to be removed from the frutree */ err = ptree_get_propval_by_name(frusloth, PICL_PROP_CHILD, &frumodh, sizeof (picl_nodehdl_t)); if (err != PICL_SUCCESS) return (err); return (PICL_SUCCESS); } static int remove_picl_node(picl_nodehdl_t nodeh) { int err; err = ptree_delete_node(nodeh); if (err != PICL_SUCCESS) return (err); (void) ptree_destroy_node(nodeh); return (PICL_SUCCESS); } /* event completion handler for PICL_FRU_ADDED/PICL_FRU_REMOVED events */ /*ARGSUSED2*/ static void frudr_completion_handler(char *ename, void *earg, size_t size) { picl_nodehdl_t fruh; if (strcmp(ename, PICL_FRU_REMOVED) == 0) { /* * now frudata has been notified that the node is to be * removed, we can actually remove it */ fruh = 0; (void) nvlist_lookup_uint64(earg, PICLEVENTARG_FRUHANDLE, &fruh); if (fruh != 0) { (void) remove_picl_node(fruh); } } nvlist_free(earg); free(earg); free(ename); } /* * Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event */ static void post_frudr_event(char *ename, picl_nodehdl_t parenth, picl_nodehdl_t fruh) { nvlist_t *nvl; char *ev_name; ev_name = strdup(ename); if (ev_name == NULL) return; if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) { free(ev_name); return; } if (parenth != 0L && nvlist_add_uint64(nvl, PICLEVENTARG_PARENTHANDLE, parenth)) { free(ev_name); nvlist_free(nvl); return; } if (fruh != 0L && nvlist_add_uint64(nvl, PICLEVENTARG_FRUHANDLE, fruh)) { free(ev_name); nvlist_free(nvl); return; } if (ptree_post_event(ev_name, nvl, sizeof (nvl), frudr_completion_handler) != 0) { free(ev_name); nvlist_free(nvl); } } /* Hotplug routine used to add a new power supply */ static int add_power_supply(int slotnum) { picl_nodehdl_t powersloth; picl_nodehdl_t powermodh; picl_nodehdl_t tmph; int i, err; /* Find the node for the given power supply slot */ if (ptree_get_node_by_path(frutree_power_supply[slotnum], &powersloth) == PICL_SUCCESS) { i = slotnum + PS0; /* Make sure it's in /platform and create the frutree node */ if (ptree_get_node_by_path(platform_frupath[i], &tmph) == PICL_SUCCESS) { err = ptree_create_node("power-supply", "fru", &powermodh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(powermodh, tmph, SEEPROM_SOURCE); if (err != PICL_SUCCESS) return (err); err = add_void_fda_prop(powermodh); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(powersloth, powermodh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(tmph, powermodh, FRU_PARENT); if (err != PICL_SUCCESS) return (err); /* Post picl-fru-added event */ post_frudr_event(PICL_FRU_ADDED, 0, powermodh); } } return (PICL_SUCCESS); } /* Hotplug routine used to remove an existing power supply */ static int remove_power_supply(int slotnum) { picl_nodehdl_t powersloth; picl_nodehdl_t powermodh; int err; /* Find the node for the given power supply slot */ if (ptree_get_node_by_path(frutree_power_supply[slotnum], &powersloth) == PICL_SUCCESS) { /* Make sure it's got a child, then delete it */ err = ptree_get_propval_by_name(powersloth, PICL_PROP_CHILD, &powermodh, sizeof (picl_nodehdl_t)); if (err != PICL_SUCCESS) { return (err); } err = ptree_delete_node(powermodh); if (err != PICL_SUCCESS) { return (err); } else { (void) ptree_destroy_node(powermodh); } /* Post picl-fru-removed event */ post_frudr_event(PICL_FRU_REMOVED, 0, powermodh); } return (PICL_SUCCESS); } /* Hotplug routine used to add a new CPU Mem Module (with associated DIMMs) */ static int add_cpu_module(int slotnum) { picl_nodehdl_t cpumemsloth; picl_nodehdl_t cpumemmodh; picl_nodehdl_t tmph; int i, err; /* Find the node for the given CPU Memory module slot */ if (ptree_get_node_by_path(frutree_cpu_module[slotnum], &cpumemsloth) == PICL_SUCCESS) { i = slotnum + CPUMOD0; /* Make sure it's in /platform and create the frutree nodes */ if (ptree_get_node_by_path(platform_frupath[i], &tmph) == PICL_SUCCESS) { err = ptree_create_node("cpu-mem-module", "fru", &cpumemmodh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(cpumemmodh, tmph, SEEPROM_SOURCE); if (err != PICL_SUCCESS) return (err); err = add_void_fda_prop(cpumemmodh); if (err != PICL_SUCCESS) return (err); err = ptree_add_node(cpumemsloth, cpumemmodh); if (err != PICL_SUCCESS) return (err); err = add_ref_prop(tmph, cpumemmodh, FRU_PARENT); if (err != PICL_SUCCESS) return (err); } err = do_cpu_module_init(cpumemmodh, slotnum); if (err != PICL_SUCCESS) return (err); } return (PICL_SUCCESS); } /* Hotplug routine used to remove an existing CPU Mem Module */ static int remove_cpu_module(int slotnum) { picl_nodehdl_t cpumemsloth; picl_nodehdl_t cpumemmodh; int err; /* Find the node for the given CPU Memory module slot */ if (ptree_get_node_by_path(frutree_cpu_module[slotnum], &cpumemsloth) == PICL_SUCCESS) { /* Make sure it's got a child, then delete it */ err = ptree_get_propval_by_name(cpumemsloth, PICL_PROP_CHILD, &cpumemmodh, sizeof (picl_nodehdl_t)); if (err != PICL_SUCCESS) { return (err); } err = remove_all_nodes(cpumemmodh); if (err != PICL_SUCCESS) { return (err); } } return (PICL_SUCCESS); }