/*
* 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
* 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 2001-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* PICL plug-in that creates the FRU Hierarchy for the
* SUNW,Sun-Fire-480R (Cherrystone) platform
*/
#include <stdio.h>
#include <string.h>
#include <libintl.h>
#include <libnvpair.h>
#include <syslog.h>
#include <picl.h>
#include <picltree.h>
#include <picldefs.h>
/*
* Plugin registration entry points
*/
static void picl_frutree_register(void);
static void picl_frutree_init(void);
static void picl_frutree_fini(void);
#pragma init(picl_frutree_register)
/*
* Log message texts
*/
/*
* Viewpoints property field used by SunMC
*/
/*
* Ref prop values
*/
/*
* List of all the FRU locations in the platform_frupath[] array, and
* location_label[] array
*/
#define PS0 0
/*
* Local variables
*/
"SUNW_Cherrystone_frutree",
};
/*
* List of all the FRUs in the /platform tree with SEEPROMs
*/
static char *platform_frupath[] = {
NULL};
/*
* List of Labels for FRU locations (uses the #define's from above)
*/
static char *location_label[] = {
"0", /* PS0 */
"1", /* PS1 */
NULL, /* RSC */
NULL, /* DISKBACKPLANE */
NULL, /* PDB */
NULL, /* CENTERPLANE */
NULL, /* IOBRD */
"A", /* CPUMOD0 */
"B", /* CPUMOD1 */
"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",
NULL};
/* PICL handle for the root node of the "frutree" */
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_centerplane_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_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);
/*
* This function is executed as part of .init when the plugin is
* dlopen()ed
*/
static void
{
(void) picld_plugin_register(&my_reg_info);
}
/*
* This function is the init entry point of the plugin.
* It initializes the /frutree tree
*/
static void
{
int err;
err = add_all_nodes();
if (err != PICL_SUCCESS) {
(void) remove_all_nodes(frutreeh);
return;
}
/* Register the event handler routine */
}
/*
* This function is the fini entry point of the plugin
*/
static void
picl_frutree_fini(void)
{
/* Unregister the event handler routine */
(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
void *cookie)
{
/* Check for and add any hotplugged device(s) */
(void) add_hotplug_fru_device();
/* Check for and remove any hotplugged device(s) */
(void) rem_hotplug_fru_device();
}
}
/* Initializes the FRU nodes for the IO board */
static int
{
int err;
/* Create the node for the IO board (if it exists) */
PICL_SUCCESS) {
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
}
return (PICL_SUCCESS);
}
/* Initializes the FRU node for the RSC card */
static int
{
int err;
/* Create the node for the RSC board (if it exists) */
PICL_SUCCESS) {
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
}
return (PICL_SUCCESS);
}
/* Initializes the FRU nodes for the FCAL backplaned */
static int
{
int err;
/* Create the node for the FCAL backplane slot */
"location", &fcalsloth);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
/* If the FCAL backplane exists, create a node for it */
PICL_SUCCESS) {
&fcalmodh);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
}
return (PICL_SUCCESS);
}
/* Initializes the FRU nodes for the PDB and the power supplies */
static int
{
/* Create the node for the PDB (if it exists) */
PICL_SUCCESS) {
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
/* Create the node for the power supply slot */
"location", &powersloth);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
/* If the PS exists, create a node for it */
&tmph) == PICL_SUCCESS) {
"fru", &powermodh);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
}
}
}
return (PICL_SUCCESS);
}
/* Initializes the FRU nodes for the centerplane and CPU Memory modules */
static int
{
/* Create the node for the system board (if it exists) */
PICL_SUCCESS) {
&sysboardh);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
/* Create the node for the CPU Memory slot */
&cpumemsloth);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
/* If CPU Mem module exists, create a node for it */
&tmph) == PICL_SUCCESS) {
"fru", &cpumemmodh);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
}
}
}
return (PICL_SUCCESS);
}
/* Creates the FRU nodes for the CPU Module and associated DIMMs */
static int
{
int i, c, err;
for (i = 0; i <= 1; i++) {
&cpumodh);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
c = CPU0_DIMM0 + DIMMS_PER_SLOT + i;
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
/* Create the nodes for the memory (if they exist) */
if (err != PICL_SUCCESS)
return (err);
}
return (PICL_SUCCESS);
}
/* Creates the FRU nodes for the DIMMs on a particular CPU Module */
static int
{
int i, c, l, err;
for (i = 0; i < DIMMS_PER_MOD; i++) {
/* Create the node for the memory slot */
&dimmsloth);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
c = ((slot * DIMMS_PER_SLOT) +
l = c - (DIMMS_PER_SLOT * slot);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
/* If the memory module exists, create a node for it */
PICL_SUCCESS) {
&dimmmodh);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
}
}
return (PICL_SUCCESS);
}
/* Creates a "reference" property between two PICL nodes */
static int
{
int err;
return (PICL_FAILURE);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
return (PICL_SUCCESS);
}
/* Creates a "slot" property for a given PICL node */
static int
{
int err;
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
return (PICL_SUCCESS);
}
/* Creates a "Label" property for a given PICL node */
static int
{
int err;
return (PICL_FAILURE);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
return (PICL_SUCCESS);
}
/* Creates a "FRUDataAvailable" void property for the given PICL node */
static int
{
int err;
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
return (PICL_SUCCESS);
}
/* Creates a "ViewPoints" property -- used for chassis */
static int
{
int err;
return (PICL_FAILURE);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
return (PICL_SUCCESS);
}
/* Creates and adds all of the frutree nodes */
static int
{
int err;
/* Get the root node of the PICL tree */
if (err != PICL_SUCCESS) {
return (err);
}
/* Create and add the root node of the FRU subtree */
if (err != PICL_SUCCESS) {
return (err);
}
/* Create and add the chassis node */
if (err != PICL_SUCCESS) {
return (err);
}
/* Add ViewPoints prop to chassis node */
if (err != PICL_SUCCESS)
return (err);
/* Initialize the FRU nodes for the IO board */
if (err != PICL_SUCCESS) {
return (err);
}
/* Initialize the FRU node for the RSC card */
if (err != PICL_SUCCESS) {
return (err);
}
/* Initialize the FRU nodes for the DISK backplane */
if (err != PICL_SUCCESS) {
return (err);
}
/* Initialize the FRU nodes for the PDB and the power supplies */
if (err != PICL_SUCCESS) {
return (err);
}
/* Initialize the FRU nodes for the CPU Memory modules */
if (err != PICL_SUCCESS) {
return (err);
}
return (PICL_SUCCESS);
}
/* Deletes and destroys all PICL nodes for which rooth is a ancestor */
static int
{
while (!done) {
sizeof (picl_nodehdl_t));
if (err != PICL_PROPNOTFOUND) {
(void) remove_all_nodes(chdh);
} else {
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
{
/* Check for hotplugged power supplies */
/* Compare the /platform tree to the frutree */
if (err != PICL_SUCCESS)
continue;
/* If they are different, then add a power supply */
if (err != PICL_SUCCESS)
continue;
}
return (PICL_SUCCESS);
}
/* Searches the list of hotpluggable FRUs, removes the appropriate node(s) */
static int
{
/* Check for hotplugged power supplies */
/* Compare the /platform tree to the frutree */
if (err != PICL_SUCCESS)
continue;
/* If they are different, then remove a power supply */
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
{
int err;
/* Check for node in the /platform tree */
if (err != PICL_SUCCESS)
return (err);
/*
* The node is in /platform, so find the corresponding slot in
* the frutree
*/
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
*/
&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
{
int err;
/* Check for node in /platform tree */
if (err == PICL_SUCCESS)
return (PICL_FAILURE);
/*
* The node is not in /platform, so find the corresponding slot in
* the frutree
*/
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
*/
&frumodh, sizeof (picl_nodehdl_t));
if (err != PICL_SUCCESS)
return (err);
return (PICL_SUCCESS);
}
static int
{
int err;
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 */
static void
{
/*
* now frudata has been notified that the node is to be
* removed, we can actually remove it
*/
(void) nvlist_lookup_uint64(earg,
(void) remove_picl_node(fruh);
}
}
}
/*
* Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event
*/
static void
{
char *ev_name;
return;
return;
}
if (parenth != 0L &&
return;
}
if (fruh != 0L &&
return;
}
frudr_completion_handler) != 0) {
}
}
/* Hotplug routine used to add a new power supply */
static int
{
int i, err;
/* Find the node for the given power supply slot */
&powersloth) == PICL_SUCCESS) {
/* Make sure it's in /platform and create the frutree node */
PICL_SUCCESS) {
&powermodh);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
/* Post picl-fru-added event */
}
}
return (PICL_SUCCESS);
}
/* Hotplug routine used to remove an existing power supply */
static int
{
int err;
/* Find the node for the given power supply slot */
&powersloth) == PICL_SUCCESS) {
/* Make sure it's got a child, then delete it */
&powermodh, sizeof (picl_nodehdl_t));
if (err != PICL_SUCCESS) {
return (err);
}
if (err != PICL_SUCCESS) {
return (err);
}
(void) ptree_destroy_node(powermodh);
/* Post picl-fru-removed event */
}
return (PICL_SUCCESS);
}