/*
* 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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* platform independent module to manage nodes under frutree
*/
/*
* This file has the frutree initialization code:
* 1) parse the config file to create all locations in the chassis
* 2) probe each location to find fru and probe the fru recursively to
* create locations, port nodes
* 3) handle hotswap picl events (dr_ap_state_change, dr_req)
* - update the frutree
* - send out picl-state-change, picl-condition-events
* 4) Monitor the port nodes state and condition
*/
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <limits.h>
#include <syslog.h>
#include <pthread.h>
#include <thread.h>
#include <libintl.h>
#include <sys/systeminfo.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <ctype.h>
#include <time.h>
#include <poll.h>
#include <assert.h>
#include <libnvpair.h>
#include <alloca.h>
#include <stdarg.h>
#include <config_admin.h>
#include <libdevinfo.h>
#include <synch.h>
#include <picl.h>
#include <picltree.h>
#include <picldefs.h>
#include <picld_pluginutil.h>
#include <libfru.h>
#include <ptree_impl.h>
#include "piclfrutree.h"
#pragma init(piclfrutree_register)
/*
* following values are tunables that can be changed using
* environment variables
*/
/* Hash table structure */
typedef struct frutree_hash_elm {
void *nodep;
typedef struct {
int hash_size;
typedef struct {
void *data;
} hashdata_t;
typedef enum {
} action_t;
typedef struct {
void *data;
typedef struct event_queue {
typedef struct {
typedef struct remove_list {
typedef struct {
static int piclevent_pending = 0;
static void *dr_thread(void *);
static int fini_called = 0;
static void *monitor_node_status(void *);
static ev_queue_t *remove_from_queue(void);
/*
* location states.
*/
static char *loc_state[] = {
};
/*
* fru states.
*/
static char *fru_state[] = {
};
/*
* fru condition.
*/
static char *fru_cond[] = {
};
/*
* port states.
*/
static char *port_state[] = {
};
/*
* port condition.
*/
static char *port_cond[] = {
};
/* mapping between libcfgadm error codes to picl error codes */
{CFGA_OK, PICL_SUCCESS},
};
/* local functions */
static void piclfrutree_register(void);
static void piclfrutree_init(void);
static void piclfrutree_fini(void);
static void * init_thread(void *);
static void frutree_wd_evhandler(const char *, const void *, size_t, void *);
static void frutree_dr_apstate_change_evhandler(const char *, const void *,
size_t, void *);
static void frutree_dr_req_evhandler(const char *, const void *,
size_t, void *);
static void frutree_cpu_state_change_evhandler(const char *, const void *,
size_t, void *);
static void init_queue(void);
static void frutree_get_env();
static picl_errno_t hash_init(void);
static void hash_destroy();
static picl_errno_t initialize_frutree();
static int is_autoconfig_enabled(char *);
static picl_errno_t post_piclevent(const char *, char *, char *,
/* External functions */
extern int kstat_port_state(frutree_port_type_t, char *, int);
extern int kstat_port_cond(frutree_port_type_t, char *, int);
extern picl_errno_t get_scsislot_name(char *, char *, char *);
extern picl_errno_t scsi_info_init();
extern void scsi_info_fini();
/* Plugin initialization */
"SUNW_piclfrutree",
};
/* ptree entry points */
static void
piclfrutree_register(void)
{
(void) picld_plugin_register(&frutree_reg_info);
}
static void
piclfrutree_init(void)
{
fini_called = 0;
/* read the environment variables */
return;
}
if (hash_init() != PICL_SUCCESS) {
return;
}
if (initialize_frutree() != PICL_SUCCESS) {
return;
}
/* initialize the event queue */
(void) init_queue();
return;
}
/* register for picl events */
PICL_SUCCESS) {
return;
}
return;
}
PICL_SUCCESS) {
return;
}
return;
}
}
static void
piclfrutree_fini(void)
{
void *exitval;
fini_called = 1;
/* unregister event handlers */
/* flush the event queue */
(void) pthread_mutex_lock(&ev_mutex);
event = remove_from_queue();
while (event) {
event = remove_from_queue();
}
(void) pthread_cond_broadcast(&ev_cond);
(void) pthread_mutex_unlock(&ev_mutex);
(void) pthread_cancel(tid);
(void) pthread_cancel(monitor_tid);
(void) pthread_cancel(init_threadID);
hash_destroy();
(void) ptree_delete_node(frutreeh);
(void) ptree_destroy_node(frutreeh);
piclevent_pending = 0;
}
/* read the ENVIRONMENT variables and initialize tunables */
static void
{
char *val;
int intval = 0;
/* read frutree debug flag value */
errno = 0;
if (errno == 0) {
}
}
/* read poll timeout value */
errno = 0;
if (errno == 0) {
}
}
/* read drwait time value */
errno = 0;
if (errno == 0) {
}
}
}
/*
* callback function for ptree_walk_tree_class to get the
* node handle of node
* matches a node with same class and name
*/
static int
{
return (PICL_INVALIDARG);
sizeof (name))) != PICL_SUCCESS) {
return (rc);
}
return (PICL_WALK_TERMINATE);
}
return (PICL_WALK_CONTINUE);
}
/* queue implementation (used to queue hotswap events) */
static void
init_queue(void)
{
queue_head = NULL;
queue_tail = NULL;
}
/* add an event to the queue */
static int
{
return (PICL_NOSPACE);
if (queue_head == NULL) {
} else {
}
return (PICL_SUCCESS);
}
static ev_queue_t *
remove_from_queue(void)
{
if (queue_head == NULL)
return (NULL);
event = queue_head;
if (queue_head == NULL)
queue_tail = NULL;
return (event);
}
/*
* event handler for watchdog expiry event (picl-state-change) event on
* watchdog-timer node
*/
/* ARGSUSED */
static void
void *cookie)
{
return;
return;
}
return;
}
&wd_nodehdl) == -1) {
return;
}
&wd_state) != 0) {
return;
}
return;
}
/* if the event is not of watchdog-timer, return */
return;
}
/* frutree plugin handles only watchdog expiry events */
return;
}
PICL_SUCCESS) {
return;
}
/* if action is none, dont do anything */
return;
}
/* find the CPU nodehdl */
return;
}
return;
}
NO_WAIT)) != PICL_SUCCESS) {
}
}
/*
* event handler for dr_ap_state_change event
* - determine the event type and queue it in dr_queue to handle it
*/
/* ARGSUSED */
static void
{
return;
strlen(PICLEVENT_DR_AP_STATE_CHANGE)) != 0) {
return;
}
return;
}
return;
}
return;
}
/* check for empty strings */
return;
}
/* get the location name */
} else {
name++;
}
/* find the loc object */
return;
}
return;
}
return;
}
return;
}
(void) pthread_mutex_lock(&ev_mutex);
(void) pthread_mutex_unlock(&ev_mutex);
return;
}
(void) pthread_cond_signal(&ev_cond);
(void) pthread_mutex_unlock(&ev_mutex);
return;
}
(void) pthread_mutex_lock(&ev_mutex);
(void) pthread_mutex_unlock(&ev_mutex);
return;
}
(void) pthread_cond_signal(&ev_cond);
(void) pthread_mutex_unlock(&ev_mutex);
return;
}
return;
}
/* handle DR_RESERVED_ATTR HINT */
/* check if this is a fru event */
/* get the child fru information */
PICL_SUCCESS) {
}
}
return;
}
if (frup->dr_in_progress) {
/* dr in progress, neglect the event */
return;
}
return;
}
if (state_changed) {
}
(void) pthread_mutex_lock(&ev_mutex);
(void) pthread_mutex_unlock(&ev_mutex);
return;
}
(void) pthread_cond_signal(&ev_cond);
(void) pthread_mutex_unlock(&ev_mutex);
return;
}
/* check if this event is related to location */
if (locp->dr_in_progress) {
/* dr in progress, neglect the event */
return;
}
return;
}
if (state_changed) { /* location state has changed */
(void) pthread_mutex_lock(&ev_mutex);
(void) pthread_mutex_unlock(&ev_mutex);
return;
}
(void) pthread_cond_signal(&ev_cond);
(void) pthread_mutex_unlock(&ev_mutex);
return;
}
/* duplicate event */
}
/*
* Event handler for dr_req event
*/
/* ARGSUSED */
static void
void *cookie)
{
return;
return;
}
return;
}
return;
}
&dr_req) == -1) {
return;
}
return;
}
/* get the location name */
} else {
name++;
}
return;
}
return;
}
return;
}
/* find the fru object */
return;
}
return;
}
} else {
return;
}
(void) pthread_mutex_lock(&ev_mutex);
(void) pthread_mutex_unlock(&ev_mutex);
return;
}
(void) pthread_cond_signal(&ev_cond);
(void) pthread_mutex_unlock(&ev_mutex);
}
/*
* Event handler for cpu_state_change event
*/
/* ARGSUSED */
static void
{
return;
strlen(PICLEVENT_CPU_STATE_CHANGE)) != 0) {
return;
}
return;
}
return;
}
return;
}
return;
}
return;
}
} else {
return;
}
(void) pthread_mutex_lock(&ev_mutex);
(void) pthread_mutex_unlock(&ev_mutex);
return;
}
(void) pthread_cond_signal(&ev_cond);
(void) pthread_mutex_unlock(&ev_mutex);
}
static void
{
cmd[0] = '\0';
}
/*
* Find the node in platform tree with given devfs-path.
* ptree_find_node is getting a node with devfs-path /pci@1f,0/pci@1,1
* when we want to find node with /pci@1f,0/pci@1. The fix
* is required in libpicltree. For now use ptree_walk_tree_by_class
* to find the node.
*/
static int
{
void *vbuf;
return (PICL_INVALIDARG);
&proph) != PICL_SUCCESS) {
return (PICL_WALK_CONTINUE);
}
return (PICL_WALK_CONTINUE);
}
return (PICL_WALK_CONTINUE);
return (PICL_WALK_CONTINUE);
}
/* compare the devfs_path */
return (PICL_WALK_TERMINATE);
}
return (PICL_WALK_CONTINUE);
}
/*
* Find the reference node in /platform tree
* return : 0 - if node is not found
*/
static picl_nodehdl_t
{
void *vbuf;
/*
* for fru node, get the devfspath and bus-addr of
* its parent.
*/
return (0);
}
return (0);
}
} else {
return (0);
}
return (0);
}
return (0);
}
/* find the node with same devfs-path */
return (0);
}
return (0);
/* traverse thru childeren and find the reference node */
&refhdl, sizeof (picl_nodehdl_t));
while (rc == PICL_SUCCESS) {
&refhdl, sizeof (picl_nodehdl_t));
/*
* compare the bus_addr or Unit address
* format of bus_addr can be either (1,3 or 0x6)
*/
&proph) != PICL_SUCCESS) {
PICL_PROP_UNIT_ADDRESS, &proph) !=
PICL_SUCCESS) {
continue;
}
}
continue;
}
continue;
continue;
}
return (nodehdl);
}
} else {
return (nodehdl);
}
}
}
return (0);
}
/* Hash Table Management */
static void
{
return;
}
switch (type) {
case FRU_TYPE:
break;
case LOC_TYPE:
break;
case PORT_TYPE:
break;
}
}
/*
* Initialize the hash table
*/
static picl_errno_t
hash_init(void)
{
int i;
sizeof (frutree_hashelm_t *) * HASH_TABLE_SIZE);
return (PICL_NOSPACE);
}
/* initialize each entry in hashtable */
for (i = 0; i < node_hash_table.hash_size; ++i) {
}
return (PICL_SUCCESS);
}
/*
* Destroy the hash table
*/
static void
hash_destroy(void)
{
int i;
return;
}
/* loop thru each linked list in the table and free */
for (i = 0; i < node_hash_table.hash_size; ++i) {
}
}
}
/*
* Add an entry to the hash table
*/
static picl_errno_t
{
int indx;
return (PICL_NOTINITIALIZED);
}
return (PICL_NOSPACE);
}
if (frutree_debug & HASHTABLE) {
}
/* first element for this index */
return (PICL_SUCCESS);
}
return (PICL_SUCCESS);
}
/*
* Remove a hash entry from the table
*/
static picl_errno_t
{
int i;
return (PICL_NOTINITIALIZED);
}
/* check that the hash chain is not empty */
return (PICL_NODENOTFOUND);
}
/* search hash chain for entry to be removed */
while (cur) {
} else {
}
if (frutree_debug & HASHTABLE) {
nodeid);
}
return (PICL_SUCCESS);
}
}
/* entry was not found */
return (PICL_NODENOTFOUND);
}
/*
* Lookup a handle in the table
*/
static picl_errno_t
{
int i;
return (PICL_NOTINITIALIZED);
}
return (PICL_INVALIDHANDLE);
}
return (PICL_NODENOTFOUND);
}
while (el) {
return (PICL_SUCCESS);
}
}
return (PICL_NODENOTFOUND);
}
/* create and initialize data structure for a loc node */
static picl_errno_t
{
char *name_copy;
return (PICL_NOSPACE);
}
/* allocate the data */
return (PICL_NOSPACE);
}
/* make a copy of the name */
return (PICL_NOSPACE);
}
/* initialize the data */
return (PICL_SUCCESS);
}
/* create and initialize data structure for a fru node */
static picl_errno_t
{
char *name_copy;
return (PICL_NOSPACE);
}
/* allocate the data */
return (PICL_NOSPACE);
}
/* make a copy of the name */
return (PICL_NOSPACE);
}
/* initialize the data */
return (PICL_SUCCESS);
}
/* create and initialize data structure for a port node */
static picl_errno_t
{
char *name_copy;
return (PICL_NOSPACE);
}
/* allocate the data */
return (PICL_NOSPACE);
}
/* make a copy of the name */
return (PICL_NOSPACE);
}
/* initialize the data */
return (PICL_SUCCESS);
}
/*
* utility routine to create table entries
*/
static picl_errno_t
{
/* first column is class */
NULLWRITE)) != PICL_SUCCESS) {
return (rc);
}
&prophdl[0])) != PICL_SUCCESS) {
return (rc);
}
/* second column is reference property */
NULLWRITE)) != PICL_SUCCESS) {
return (rc);
}
return (rc);
}
/* add row to table */
return (rc);
}
return (PICL_SUCCESS);
}
/*
* Utility routine to create picl property
*/
static picl_errno_t
int (*readfn)(ptree_rarg_t *, void *),
int (*writefn)(ptree_warg_t *, const void *),
{
return (PICL_FAILURE);
}
if (ptype == PICL_PTYPE_TABLE) {
!= PICL_SUCCESS) {
return (rc);
}
}
PICL_SUCCESS) { /* property already exists */
return (rc);
}
if (rc != PICL_SUCCESS) {
return (rc);
}
if (rc != PICL_SUCCESS) {
return (rc);
}
return (PICL_SUCCESS);
}
/*
* create frutree node, chassis node
*/
static picl_errno_t
{
/* Get the root of the PICL tree */
return (rc);
}
/* create /frutree node */
return (rc);
}
/* create chassis node */
&chassish)) != PICL_SUCCESS) {
return (rc);
}
/* Allocate fru data */
PICL_SUCCESS) {
(void) ptree_destroy_node(chassish);
return (rc);
}
/* initialise chassis handle and parent handle */
/* Add the chassis node to the tree */
(void) ptree_destroy_node(chassish);
return (rc);
}
/* create chassis state property */
(void) ptree_delete_node(chassish);
(void) ptree_destroy_node(chassish);
return (rc);
}
sizeof (ap_status_time), PICL_PROP_STATUS_TIME,
(void) ptree_delete_node(chassish);
(void) ptree_destroy_node(chassish);
return (rc);
}
/* save chassis info in hashtable */
(void *)datap)) != PICL_SUCCESS) {
(void) ptree_delete_node(chassish);
(void) ptree_destroy_node(chassish);
return (rc);
}
return (PICL_SUCCESS);
}
/*
* Read the temporary property created by platform specific
* plugin to get the config file name.
*/
static picl_errno_t
{
return (rc);
}
sizeof (file_name))) != PICL_SUCCESS) {
return (rc);
}
/* delete the tmp prop created by platform specific plugin */
(void) ptree_delete_prop(proph);
(void) ptree_destroy_prop(proph);
return (PICL_SUCCESS);
}
/*
* Read the cfgadm data and get the latest information
*/
static picl_errno_t
{
int nlist;
char * const *p = &ap_id;
return (PICL_INVALIDARG);
}
if (ap_list_err != CFGA_OK) {
}
return (PICL_SUCCESS);
}
/*
* syncup with cfgadm data and read latest location state information
*/
static picl_errno_t
{
int i = 0;
PICL_PROP_STATE, (void *)valbuf,
PICL_PROPNAMELEN_MAX)) != PICL_SUCCESS) {
return (rc);
}
/* if there is a change in state, update the internal value */
PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
sizeof (ap_status_time))) != PICL_SUCCESS) {
}
return (PICL_SUCCESS);
}
}
}
return (PICL_SUCCESS);
return (PICL_SUCCESS);
}
/* get the info from the libcfgadm interface */
return (PICL_NOSPACE);
}
sizeof (slot_type))) != PICL_SUCCESS) {
return (rc1);
}
return (rc);
}
/* this is a scsi location */
if (rc != PICL_NODENOTFOUND) {
return (rc);
}
/*
* for scsi locations, if node is not found,
* consider location state as empty
*/
PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
sizeof (ap_status_time))) != PICL_SUCCESS) {
}
}
return (PICL_SUCCESS);
}
switch (list->ap_r_state) {
case CFGA_STAT_CONNECTED:
}
break;
case CFGA_STAT_DISCONNECTED:
}
break;
case CFGA_STAT_EMPTY:
}
break;
default:
}
}
PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
sizeof (ap_status_time))) != PICL_SUCCESS) {
}
}
/* update the autoconfig flag */
case 1:
break;
case 0:
default:
break;
}
return (PICL_SUCCESS);
}
/*
* volatile callback function to return the state value for a location
*/
static int
{
return (PICL_INVALIDARG);
}
PICL_SUCCESS) {
return (rc);
}
return (PICL_FAILURE);
}
/* return the cached value */
return (PICL_SUCCESS);
}
/* return the cached value */
return (rc);
}
/* if there is a state change, handle the event */
if (state_change) {
} else {
/* loc state changed */
}
(void) pthread_mutex_lock(&ev_mutex);
(void) pthread_mutex_unlock(&ev_mutex);
} else {
(void) pthread_cond_signal(&ev_cond);
(void) pthread_mutex_unlock(&ev_mutex);
}
}
return (PICL_SUCCESS);
}
/*
* syncup with cfgadm data and read latest fru state information
*/
static picl_errno_t
{
int i;
PICL_PROP_STATE, (void *)valbuf,
PICL_PROPNAMELEN_MAX)) != PICL_SUCCESS) {
return (rc);
}
/* if there is a change in state, update the internal value */
PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
sizeof (ap_status_time))) != PICL_SUCCESS) {
if (rc == PICL_PROPNOTFOUND) {
(void) create_property(
sizeof (ap_status_time),
NULL, &ap_status_time);
} else {
}
}
return (PICL_SUCCESS);
}
}
}
return (PICL_SUCCESS);
return (PICL_SUCCESS);
}
return (rc);
}
PICL_SUCCESS) {
return (rc);
}
return (PICL_FAILURE);
}
return (PICL_NOSPACE);
}
return (rc);
}
switch (list->ap_o_state) {
case CFGA_STAT_CONFIGURED:
}
break;
case CFGA_STAT_UNCONFIGURED:
}
break;
default:
}
break;
}
/* update the fru_type property */
}
}
PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
sizeof (ap_status_time))) != PICL_SUCCESS) {
}
}
return (PICL_SUCCESS);
}
/*
* syncup with cfgadm data and read latest fru condition information
*/
static picl_errno_t
{
int i = 0;
PICL_PROP_CONDITION, (void *)valbuf,
PICL_PROPNAMELEN_MAX)) != PICL_SUCCESS) {
return (rc);
}
/*
* if there is a change in condition, update the
* internal value
*/
PICL_PROP_CONDITION_TIME, (void *)&ap_cond_time,
sizeof (ap_cond_time))) != PICL_SUCCESS) {
rc);
}
return (PICL_SUCCESS);
}
}
}
return (PICL_SUCCESS);
return (PICL_SUCCESS);
}
return (rc);
}
PICL_SUCCESS) {
return (rc);
}
return (PICL_FAILURE);
}
return (PICL_NOSPACE);
}
return (rc);
}
case CFGA_COND_OK:
}
break;
case CFGA_COND_FAILING:
}
break;
case CFGA_COND_FAILED:
case CFGA_COND_UNUSABLE:
}
break;
default:
}
}
PICL_PROP_CONDITION_TIME, (void *)&ap_cond_time,
sizeof (ap_cond_time))) != PICL_SUCCESS) {
}
}
return (PICL_SUCCESS);
}
/*
* Volatile callback function to read fru state
*/
static int
{
return (PICL_INVALIDARG);
}
PICL_SUCCESS) {
return (rc);
}
return (PICL_FAILURE);
}
/* return the cached value, if dr is in progress */
if (frup->dr_in_progress) {
return (PICL_SUCCESS);
}
/* return the cached value */
return (rc);
}
/* if there is a state change, handle the event */
if (state_change) {
}
(void) pthread_mutex_lock(&ev_mutex);
(void) pthread_mutex_unlock(&ev_mutex);
} else {
(void) pthread_cond_signal(&ev_cond);
(void) pthread_mutex_unlock(&ev_mutex);
}
}
return (PICL_SUCCESS);
}
/*
* Volatile callback function to read fru condition
*/
static int
{
return (PICL_INVALIDARG);
}
PICL_SUCCESS) {
return (rc);
}
return (PICL_FAILURE);
}
/* return the cached value, if dr is in progress */
if (frup->dr_in_progress) {
return (PICL_SUCCESS);
}
/* return the cached value */
return (rc);
}
if (cond_changed) {
(void) pthread_mutex_lock(&ev_mutex);
(void) pthread_mutex_unlock(&ev_mutex);
} else {
(void) pthread_cond_signal(&ev_cond);
(void) pthread_mutex_unlock(&ev_mutex);
}
}
/* if there is a condition change, post picl event */
return (PICL_SUCCESS);
}
static void
{
return;
}
}
/*
* traverse the /platform tree in PICL tree to create logical devices table
*/
static picl_errno_t
{
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
/* traverse thru platform tree and add entries to Devices table */
return (PICL_NODENOTFOUND);
}
/* create Devices table property */
PICL_SUCCESS) {
return (rc);
}
return (rc);
}
PICL_SUCCESS) {
return (rc);
}
/* create Environment devices table property */
PICL_SUCCESS) {
return (rc);
}
/* probe using platform tree info */
device)) != PICL_SUCCESS) {
return (rc);
}
return (PICL_SUCCESS);
}
/*
* create temp conf file to pass it to picld util lib to create
* nodes under the fru
*/
static picl_errno_t
{
int fd;
return (PICL_SUCCESS);
}
/* create the configuration file for the fru */
return (PICL_FAILURE);
}
}
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
/* traverse thru each cache entry and append to conf file */
return (PICL_FAILURE);
}
}
/* create child nodes for fru using the conffile created */
conffile)) != PICL_SUCCESS) {
return (rc);
}
return (rc);
}
return (PICL_SUCCESS);
}
/*
* probes libdevinfo and create the port nodes under a fru
* probes for any scsi devices under a fru
*/
static picl_errno_t
{
return (PICL_FAILURE);
}
return (rc);
}
sizeof (frutree_device_args_t));
return (PICL_NOSPACE);
}
}
/*
* if parent has NULL probe-path, skip probing this fru
* probe only child locations (if present).
* if probe-path is not present use devfs-path as path for
* probing the fru.
*/
probe_path, sizeof (probe_path));
if (rc != PICL_SUCCESS) {
if (!devfs_path[0]) { /* devfspath is also not present */
return (PICL_SUCCESS); /* nothing to probe */
} else {
/* use devfs-path as path for probing */
PICL_SUCCESS) {
return (rc);
}
}
} else {
/* NULL path, skip probing this fru */
if (strlen(probe_path) == 0) {
return (rc);
} else {
/* valid probe-path */
PICL_SUCCESS) {
return (rc);
}
}
}
/* children present already, no need to probe libdevinfo */
&child, sizeof (picl_nodehdl_t));
return (rc);
}
/* now create the scsi nodes for this fru */
return (rc);
}
return (PICL_SUCCESS);
}
return (rc);
}
return (rc);
}
/* no need to probe further for scsi frus */
return (PICL_SUCCESS);
}
sizeof (frutree_device_args_t));
return (PICL_NOSPACE);
}
PICL_SUCCESS) {
return (rc);
}
return (rc);
}
}
/* now create the scsi nodes for this fru */
return (rc);
}
return (PICL_SUCCESS);
}
/*
* callback function for ptree_walk_tree_by_class,
* used to update hashtable during DR_HINT_REMOVE event
*/
/*ARGSUSED*/
static int
{
return (rc);
}
return (PICL_WALK_CONTINUE);
}
/*
* routine to handle DR_HINT_REMOVE
*/
static picl_errno_t
{
return (PICL_FAILURE);
}
return (rc);
}
PICL_SUCCESS) {
return (rc);
}
return (PICL_SUCCESS);
}
/* remove State and Condition props for all the nodes under fru */
/*ARGSUSED*/
static int
{
&proph) == PICL_SUCCESS) {
(void) ptree_delete_prop(proph);
(void) ptree_destroy_prop(proph);
}
&proph) == PICL_SUCCESS) {
(void) ptree_delete_prop(proph);
(void) ptree_destroy_prop(proph);
}
return (rc);
}
&proph) == PICL_SUCCESS) {
(void) ptree_delete_prop(proph);
(void) ptree_destroy_prop(proph);
}
&proph) == PICL_SUCCESS) {
(void) ptree_delete_prop(proph);
(void) ptree_destroy_prop(proph);
}
/* delete devices table */
&proph) == PICL_SUCCESS) {
(void) ptree_delete_prop(proph);
(void) ptree_destroy_prop(proph);
}
}
return (PICL_WALK_CONTINUE);
}
/*
* traverse thru each node fru node and do cleanup
*/
static picl_errno_t
{
return (PICL_FAILURE);
}
/* delete devices table */
&proph) == PICL_SUCCESS) {
(void) ptree_delete_prop(proph);
(void) ptree_destroy_prop(proph);
}
/* delete Environment devices table */
&proph) == PICL_SUCCESS) {
(void) ptree_delete_prop(proph);
(void) ptree_destroy_prop(proph);
}
return (rc);
}
/* remove all the fru nodes under the child locations */
while (retval == PICL_SUCCESS) {
return (rc);
}
continue;
}
/* if the child location has fru, delete the fru */
continue;
}
/* child is present under the location */
PICL_SUCCESS) {
return (rc);
}
(void) handle_fru_remove(child_frup);
}
return (PICL_SUCCESS);
}
/*
* create the properties under the fru
*/
static picl_errno_t
{
/* create state props */
PICL_SUCCESS) {
}
sizeof (ap_status_time), PICL_PROP_STATUS_TIME,
}
return (rc);
}
/* create condition props */
PICL_SUCCESS) {
}
sizeof (ap_status_time), PICL_PROP_CONDITION_TIME,
&ap_status_time)) != PICL_SUCCESS) {
}
return (rc);
}
/* create admin lock prop */
PICL_SUCCESS) {
}
return (rc);
}
/*
* calls libcfgadm API to do a connect on a location
*/
static picl_errno_t
{
return (PICL_FAILURE);
}
}
if (frutree_debug & PERF_DATA) {
}
if (frutree_debug & PERF_DATA) {
}
if (ap_list_err != CFGA_OK) {
/* release mutex before updating state */
}
/* wakeup threads sleeping on this condition */
return (PICL_SUCCESS);
}
}
PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
sizeof (ap_status_time))) != PICL_SUCCESS) {
}
/* wakeup threads sleeping on this condition */
}
return (PICL_SUCCESS);
}
/*
* calls libcfgadm API to do a disconnect on a location
*/
static picl_errno_t
{
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
/* get the child fru information */
PICL_SUCCESS) {
}
}
return (PICL_SUCCESS);
}
}
return (PICL_FAILURE);
}
}
if (frutree_debug & PERF_DATA) {
}
if (frutree_debug & PERF_DATA) {
}
if (ap_list_err != CFGA_OK) {
/* release mutex before updating state */
}
return (PICL_SUCCESS);
}
}
PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
sizeof (ap_status_time))) != PICL_SUCCESS) {
}
}
return (PICL_SUCCESS);
}
/*
* Handle DR_INCOMING_RES event
*/
static void
{
return;
}
/* update the fru condition */
if (cond_changed) {
}
}
}
}
/*
* call libcfgadm API to configure a fru
* (Handle DR_INCOMING_RES event)
*/
static picl_errno_t
{
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
return (rc);
}
PICL_SUCCESS) {
return (rc);
}
return (PICL_FAILURE);
}
/* wait for sometime for location to get connected */
}
return (PICL_FAILURE);
}
}
if (frutree_debug & PERF_DATA) {
}
if (frutree_debug & PERF_DATA) {
}
if (ap_list_err != CFGA_OK) {
/* release mutex before updating state */
}
/* update the fru condition */
if (state_change) {
rc);
}
}
}
PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
sizeof (ap_status_time))) != PICL_SUCCESS) {
}
}
/* update the fru condition */
if (cond_changed) {
}
}
/* send the state change event */
}
return (PICL_SUCCESS);
}
/*
* Handle DR_OUTGOING_RES event
* (call libcfgadm API to unconfigure a fru)
*/
static picl_errno_t
{
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
}
}
if (frutree_debug & PERF_DATA) {
}
if (frutree_debug & PERF_DATA) {
}
if (ap_list_err != CFGA_OK) {
/*
* call configure again (workaround for
* ENUM# to get generated for next attempt)
*/
/* release mutex before updating state */
if (state_change) {
rc);
}
}
}
}
PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
sizeof (ap_status_time))) != PICL_SUCCESS) {
}
/* wakeup threads sleeping on this condition */
/* update the fru condition */
}
if (state_change) {
}
}
}
return (PICL_SUCCESS);
}
/* creates fru nodes with basic properties and sends out intializing events */
static int
{
return (PICL_SUCCESS);
}
/* check if fru is present or not */
&child, sizeof (picl_nodehdl_t));
if (rc == PICL_SUCCESS) {
}
/* create fru node */
if (fru_present == B_FALSE) {
&fruh)) != PICL_SUCCESS) {
return (rc);
}
}
/* initialize internal data structures */
return (rc);
}
*child_frupp = frup;
(void) ptree_destroy_node(fruh);
return (rc);
}
sizeof (slot_type))) == PICL_SUCCESS) {
sizeof (apid_type));
}
}
/* create fru type property */
PICL_SUCCESS) {
}
if (fru_present == B_FALSE) {
PICL_SUCCESS) {
(void) ptree_destroy_node(fruh);
(void) hash_remove_entry(fruh);
return (rc);
}
}
return (PICL_SUCCESS);
}
return (rc);
}
return (PICL_SUCCESS);
}
static picl_errno_t
{
int instance;
sizeof (port_type));
sizeof (port_type));
sizeof (port_type));
} else {
return (PICL_FAILURE);
}
return (rc);
}
/* load the driver */
if (instance < 0) {
}
return (rc);
}
/* get either bus address or unit address */
sizeof (bus_addr))) != PICL_SUCCESS) {
sizeof (bus_addr))) != PICL_SUCCESS) {
return (rc);
}
}
return (rc);
}
return (PICL_NOSPACE);
}
/* update the cache buffer in PICL configuration format */
"\n%s %s%d %s\n"
"\t%s %s %s %s 0 \"%s %d\"\n"
"\t%s %s %s %s 0 \"%s\"\n"
"\t%s %s %s %s 1 %d\n"
"\t%s %s %s %s 0 \"%s\"\n"
"\t%s %s %s %s 0 \"%s\"\n"
"%s\n",
"ENDNODE");
return (PICL_SUCCESS);
}
/* ARGSUSED */
static int
{
return (PICL_INVALIDARG);
}
return (PICL_WALK_CONTINUE);
}
/* add reference handle to Devices table */
/* add to Environment Devices table */
if (device->env_tblhdl) {
class);
}
}
return (PICL_WALK_CONTINUE);
}
/* compare the classname and create the cache entry for the child */
sizeof (name)) != PICL_SUCCESS) {
return (PICL_WALK_CONTINUE);
}
}
return (PICL_WALK_CONTINUE);
}
/* add cache to the linked list */
} else { /* 2nd node */
}
}
return (PICL_WALK_CONTINUE);
}
/*
* determine the state manager for this node
*/
static picl_errno_t
{
return (PICL_SUCCESS);
(void *)valbuf, PICL_PROPNAMELEN_MAX);
return (PICL_SUCCESS);
}
/* get the info from the libcfgadm interface */
return (PICL_NOSPACE);
}
} else {
sizeof (slot_type))) != PICL_SUCCESS) {
return (rc);
}
/*
* for scsi locations, if cfgadm ap is
* not present, then consider it as device
* not present
*/
} else {
/*
* devices like PMC card doesnt showup in cfgadm
*/
}
}
return (PICL_SUCCESS);
}
/*
* Initialize the location node.(create all the props)
*/
static picl_errno_t
{
/* check if it is a CPU location node or not */
strlen(SANIBEL_PICLNODE_CPU)) == 0) {
}
}
/*
* Algorithm:
* if "State" prop is already created (node is managed by other plugin)
* does nothing
* else if cfgadm ap is found
* creates State prop and intializes it
* else
* find the nodes using libdevinfo under a given path
* at given geoaddr
* if node is found
* mark node state a connected
* else
* mark node state a empty
*/
(void) get_loc_type(locp);
return (PICL_SUCCESS);
}
/*
* in case of scsi locations,, loc state will be connected
* no need to check again if the fru is present using libdevinfo
*/
} else {
}
}
}
/* create state property */
return (rc);
}
/* create location StatusTime prop. */
PICL_SUCCESS) {
return (rc);
}
return (rc);
}
return (PICL_SUCCESS);
}
static frutree_port_type_t
{
return (port_type);
}
sizeof (device_type)) == PICL_SUCCESS) {
} else if (strcmp(device_type,
SANIBEL_SERIAL_PORT) == 0) {
} else if (strcmp(device_type,
SANIBEL_PARALLEL_PORT) == 0) {
}
}
return (port_type);
}
/* volatile callback function to get port condition */
static int
{
return (PICL_INVALIDARG);
}
PICL_SUCCESS) {
return (rc);
}
return (PICL_FAILURE);
}
if (port_type == UNKNOWN_PORT) {
return (PICL_SUCCESS);
}
return (rc);
}
return (PICL_SUCCESS);
}
/* volatile callback function to get port state */
static int
{
return (PICL_INVALIDARG);
}
PICL_SUCCESS) {
return (rc);
}
return (PICL_FAILURE);
}
if (port_type == UNKNOWN_PORT) {
return (PICL_SUCCESS);
}
return (rc);
}
return (PICL_SUCCESS);
}
/*
* Creates State and Condition property for a port node
*/
static picl_errno_t
{
void *vbuf;
return (PICL_FAILURE);
}
/* traverse thru platform tree and add entries to Devices table */
if (refhdl != 0) {
/* create Devices table property */
sizeof (picl_prophdl_t), PICL_PROP_DEVICES,
&tblhdl)) != PICL_SUCCESS) {
return (rc);
}
/* walk down the subtree and populate Devices */
sizeof (class))) != PICL_SUCCESS) {
return (rc);
}
PICL_SUCCESS) {
return (rc);
}
(void *)&device)) != PICL_SUCCESS) {
return (rc);
}
&proph)) != PICL_SUCCESS) {
return (rc);
}
PICL_SUCCESS) {
return (rc);
}
return (PICL_NOSPACE);
return (rc);
}
return (rc);
}
PICL_SUCCESS) {
return (rc);
}
return (PICL_NOSPACE);
return (rc);
}
} else {
/* this node is created using libdevinfo or conf file */
return (rc);
}
}
/* create state and condition properties */
return (rc);
}
PICL_SUCCESS) {
return (rc);
}
PICL_SUCCESS) {
return (rc);
}
PICL_SUCCESS) {
return (rc);
}
return (PICL_SUCCESS);
}
/*
* This routine dynamically determines the scsi name (using libcfgadm)
* that corresponds to the node specified in configuration file
*/
static picl_errno_t
{
return (PICL_INVALIDARG);
}
return (PICL_FAILURE);
}
sizeof (devfs_path))) != PICL_SUCCESS) {
return (rc);
}
sizeof (bus_addr))) != PICL_SUCCESS) {
return (rc);
}
/* find the dynamic ap_id from libcfgadm */
name)) != PICL_SUCCESS) {
/* if rc is NODENOTFOUND, then slot is empty */
if (rc != PICL_NODENOTFOUND) {
return (rc);
} else {
return (PICL_SUCCESS);
}
}
/* node name is same, so dont change anything */
return (PICL_SUCCESS);
}
sizeof (geo_addr))) != PICL_SUCCESS) {
geo_addr = 0;
}
sizeof (label))) != PICL_SUCCESS) {
return (rc);
}
/* Now recreate the node with new name */
&nodeh)) != PICL_SUCCESS) {
return (rc);
}
/* add all the properties now */
label);
bus_addr);
&geo_addr);
return (rc);
}
/* save data in hash table */
return (rc);
}
return (PICL_SUCCESS);
}
/*
* find the child nodes under a fru and initialize them
*/
static int
{
return (PICL_INVALIDARG);
}
return (rc);
}
return (PICL_WALK_CONTINUE);
sizeof (class))) != PICL_SUCCESS) {
return (rc);
}
sizeof (name))) != PICL_SUCCESS) {
return (rc);
}
/* initialize internal data structure */
return (PICL_WALK_CONTINUE);
}
/* save data in hash table */
sizeof (slot_type))) != PICL_SUCCESS) {
return (PICL_WALK_CONTINUE);
} else {
/*
* this rountine finds the valid cfgadm
* ap_id name for a given node and
* creates a new node with that name.
* If the node name is changed, the present
* node must be added to the list of nodes
* to be deleted from tree after ptree walk.
*/
&node_changed);
if (node_changed) {
/*
* add this node to list of nodes
* to be removed
*/
sizeof (delete_list_t));
return (PICL_NOSPACE);
}
} else { /* add 2 front */
}
}
}
}
return (PICL_WALK_CONTINUE);
}
/* if location is empty, done */
return (PICL_WALK_CONTINUE);
}
/* create the fru node and initialize it */
PICL_SUCCESS) {
return (PICL_WALK_CONTINUE);
}
/*
* if fru is already configured, create the
* subtree under the child fru
*/
/* initialize the fru_path */
PICL_SUCCESS) {
}
}
return (PICL_WALK_CONTINUE);
}
}
return (PICL_WALK_CONTINUE);
}
/* traverse thru all locations under fru and initiate connects */
static int
{
return (PICL_INVALIDARG);
}
return (rc);
}
return (PICL_WALK_CONTINUE);
PICL_SUCCESS) {
return (PICL_WALK_CONTINUE);
}
return (PICL_WALK_CONTINUE);
}
/* if loc is not connected, do a connect operation */
if (locp->autoconfig_enabled) {
}
}
return (PICL_WALK_CONTINUE);
}
/*
* Initializes the subtree under a FRU
*/
static picl_errno_t
{
return (PICL_INVALIDARG);
}
/*
* this routine creates internal data structures for
* all the children under this fru and initializes them
*/
(void *)&arg)) != PICL_SUCCESS) {
return (rc);
}
/* traverse thru delete_nodes_list and delete the nodes from tree */
while (curr) {
}
/*
* dont post events during intialization (for other FRUs)
* chassis intialization will take care of posting events
* for complete frutree
*/
(post_picl_events == B_TRUE)) {
PICL_SUCCESS) {
"posting picl events(error=%d)", rc);
}
}
}
/* initiate connects */
return (rc);
}
return (PICL_SUCCESS);
}
/*ARGSUSED*/
static int
{
int rc;
return (PICL_WALK_CONTINUE);
}
PICL_SUCCESS) {
return (PICL_WALK_CONTINUE);
}
}
return (PICL_WALK_CONTINUE);
}
}
}
return (PICL_WALK_CONTINUE);
}
}
}
return (PICL_WALK_CONTINUE);
}
return (PICL_WALK_CONTINUE);
}
/*
* This function is a utility function that calls the
* appropriate call back function for the all the nodes under
* the specified root node.
* future additions can be done by defining new action and callback.
*/
static picl_errno_t
{
int rc;
switch (action) {
case INIT_FRU:
break;
case CREATE_DEVICES_ENTRIES:
break;
case POST_EVENTS:
break;
default:
return (PICL_INVALIDARG);
}
func_ptr)) != PICL_SUCCESS) {
return (rc);
}
return (PICL_SUCCESS);
}
static picl_errno_t
{
(void) ptree_update_propval_by_name(chassish,
PICL_PROP_STATUS_TIME, (void *)&ap_status_time,
sizeof (ap_status_time))) != PICL_SUCCESS) {
}
}
return (PICL_SUCCESS);
}
static picl_errno_t
{
PICL_SUCCESS) {
return (rc);
}
PICL_SUCCESS) {
return (rc);
}
/* create the nodes in conf file under chassis node */
conf_file)) != PICL_SUCCESS) {
/* update chassis state to unconfigured */
(void) frutree_update_chassis_state(
return (rc);
}
/* update chassis state to configuring */
(void) frutree_update_chassis_state(
if (scsi_info_init() != PICL_SUCCESS) {
/* update chassis state to unconfigured */
(void) frutree_update_chassis_state(
return (PICL_FAILURE);
}
/* traverse thru all the nodes under chassis, initialize them */
/* update chassis state to unconfigured */
(void) frutree_update_chassis_state(
return (rc);
}
/* free the memory used during initialization */
/* start node monitoring thread */
NULL) != 0) {
" monitoring thread");
}
/* update chassis state to configured */
(void) frutree_update_chassis_state(
return (PICL_SUCCESS);
}
/* ARGSUSED */
static void *
{
if (get_configuration_file() != PICL_SUCCESS) {
return (NULL);
}
rc);
}
return (NULL);
}
/* ARGSUSED */
static void
{
if (frutree_debug & EV_COMPLETION) {
strlen(PICLEVENT_STATE_CHANGE)) == 0) {
strlen(PICLEVENT_CONDITION_CHANGE)) == 0) {
}
&fruhdl);
}
}
(void) mutex_lock(&piclevent_mutex);
piclevent_pending = 0;
(void) cond_broadcast(&piclevent_completed_cv);
(void) mutex_unlock(&piclevent_mutex);
}
{
return (PICL_INVALIDARG);
}
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
return (PICL_NOSPACE);
}
strlen(PICLEVENT_STATE_CHANGE)) == 0) {
strlen(PICLEVENT_CONDITION_CHANGE)) == 0) {
} else {
return (PICL_INVALIDARG);
}
return (PICL_FAILURE);
}
strlen(PICLEVENT_CONDITION_CHANGE)) == 0) {
NULL)) {
return (PICL_FAILURE);
}
} else { /* state change event */
/* if there is a last state, add it to nvlist */
if (nvlist_add_string(nvl,
return (PICL_FAILURE);
}
}
}
return (PICL_FAILURE);
}
(void) mutex_lock(&piclevent_mutex);
while (piclevent_pending) {
(void) cond_wait(&piclevent_completed_cv,
}
piclevent_pending = 1;
(void) mutex_unlock(&piclevent_mutex);
event_completion_handler)) != PICL_SUCCESS) {
(void) mutex_lock(&piclevent_mutex);
piclevent_pending = 0;
(void) mutex_unlock(&piclevent_mutex);
return (rc);
}
if (frutree_debug) {
} else {
}
}
if (wait) { /* wait for the event to be handled */
(void) mutex_lock(&piclevent_mutex);
while (piclevent_pending) {
(void) cond_timedwait(&piclevent_completed_cv,
&piclevent_mutex, &to);
}
(void) mutex_unlock(&piclevent_mutex);
}
return (PICL_SUCCESS);
}
/*
* return values
* -1 : error
* 0 : not enabled
* 1 : enabled
*/
/* ARGSUSED */
static int
{
return (1);
}
static picl_errno_t
{
/* get the info from the libcfgadm interface */
return (PICL_NOSPACE);
}
return (PICL_SUCCESS);
}
return (PICL_NODENOTFOUND);
}
/*
* handles DR_INCOMING_RES on chassis node
* (refresh piclfrutree tree)
*/
static int
{
return (PICL_INVALIDARG);
}
return (rc);
}
return (PICL_WALK_CONTINUE);
PICL_SUCCESS) {
return (PICL_WALK_CONTINUE);
}
/* if the location has child fru, get its information */
/* get the child fru information */
PICL_SUCCESS) {
}
}
/* for each location, update the state */
/* check if cfgadm ap_id is present */
if (rc == PICL_SUCCESS) {
if (child_frup) {
(void) update_fru_state(child_frup,
}
}
}
if (state_changed) {
case LOC_STATE_CONNECTED:
case LOC_STATE_DISCONNECTED:
/* handle fru insertion */
} else {
/* handle loc state change */
}
break;
case LOC_STATE_EMPTY:
/* handle fru removal */
/* post piclevent to update led */
} else {
/* disconnected fru is removed */
}
break;
default:
return (PICL_WALK_CONTINUE);
} /* end of switch */
(void) pthread_mutex_lock(&ev_mutex);
(void) pthread_mutex_unlock(&ev_mutex);
return (PICL_WALK_CONTINUE);
}
(void) pthread_cond_signal(&ev_cond);
(void) pthread_mutex_unlock(&ev_mutex);
return (PICL_WALK_CONTINUE);
} else {
/* connect the disconnect locations */
}
return (PICL_WALK_CONTINUE);
}
}
/* post picl event for child fru */
if (child_frup == NULL) {
return (PICL_WALK_CONTINUE);
}
/* update the state */
if (state_changed) {
}
}
/* update the condition */
if (cond_changed) {
rc);
}
}
return (PICL_WALK_CONTINUE);
}
static picl_errno_t
{
return (PICL_INVALIDARG);
}
/* initial probe/initialization */
/* create a thread to do the initialization */
NULL) != 0) {
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
/*
* 1. update the state of all the nodes in chassis
* 2. handle all the state changes accordingly
*/
return (rc);
}
return (PICL_SUCCESS);
}
static picl_errno_t
{
return (PICL_SUCCESS);
}
/* do any cleanups here */
}
PICL_PROPNAMELEN_MAX)) != PICL_SUCCESS) {
}
(void) handle_fru_unconfigure(frup);
}
return (PICL_SUCCESS);
}
static picl_errno_t
{
return (PICL_FAILURE);
return (PICL_FAILURE);
}
return (rc);
}
return (rc);
}
PICL_SUCCESS) {
return (rc);
}
/*
* update the location state also, as this could be
* user initiated connect operation
*/
if (state_changed)
}
case CPU_ONLINE:
flags |= CFGA_FLAG_FORCE;
if (locp->autoconfig_enabled) {
}
}
break;
} /*FALLTHRU*/
/* do configure now */
case CONFIGURE_FRU: /* dr_incoming_res */
break;
}
}
return (PICL_SUCCESS);
}
/* handles all dr related events */
static picl_errno_t
{
case CPU_ONLINE:
case CONFIGURE_FRU:
return (NULL);
}
(void) configuration_fn((void *)arg);
break;
case CPU_OFFLINE:
flags |= CFGA_FLAG_FORCE;
break;
}
break;
}
}
break;
case UNCONFIGURE_FRU: /* dr_outgoing_res */
break;
}
(void) handle_chassis_unconfigure(frup);
break;
}
break;
}
}
break;
}
PICL_SUCCESS) {
break;
}
/* check the autoconfig flag */
break;
}
}
break;
case HANDLE_CONFIGURE: /* basic hotswap operation */
break;
}
break;
case HANDLE_UNCONFIGURE: /* basic hotswap operation */
/* cleanup the internal data structures */
break;
}
}
/* update the fru condition */
if (state_changed) {
}
}
}
break;
case HANDLE_LOCSTATE_CHANGE: /* basic hotswap operation */
/* posts state change events of location */
break;
}
}
/* wakeup threads sleeping on this condition */
}
/* if the location has child fru, get its information */
/* get the child fru information */
PICL_SUCCESS) {
}
}
/* update the child fru state and handle any state changes */
if (child_frup == NULL) {
break;
}
PICL_SUCCESS) {
break;
}
if (state_changed == B_FALSE) {
/*
* if there is no change in state, check for condition
* changes.
* if there is a state change, handling state change
* will take care of condition changes also.
*/
if (cond_changed == B_FALSE) {
break;
}
}
break;
}
/* add to queue to handle the fru state change */
}
(void) pthread_mutex_lock(&ev_mutex);
(void) pthread_mutex_unlock(&ev_mutex);
break;
}
(void) pthread_cond_signal(&ev_cond);
(void) pthread_mutex_unlock(&ev_mutex);
break;
case HANDLE_INSERT: /* dr_apstate_change (HINT_INSERT) */
break;
}
/* if the location has child fru, get its information */
/* get the child fru information */
PICL_SUCCESS) {
}
}
if (child_frup) {
/*
* if previous state is not empty, it could be a
* hint insert to retry connects
*/
if (state_changed) {
WAIT)) != PICL_SUCCESS) {
}
}
if (cond_changed == B_TRUE) {
}
}
if (!locp->autoconfig_enabled) {
break;
}
}
}
break;
}
break;
}
}
if (locp->autoconfig_enabled) {
}
}
break;
case HANDLE_REMOVE: /* dr_apstate_change (HINT_REMOVE) */
break;
}
break; /* discard the spurious event */
}
/* if the location has child fru, get its information */
/* get the child fru information */
PICL_SUCCESS) {
}
}
break;
}
/*
* frutree need to post this event before handling the
* fru remove, so that other plugins (like frudata) can
* do the cleanup
*/
}
}
break;
case POST_COND_EVENT:
break;
}
}
default:
break;
}
return (PICL_SUCCESS);
}
/*ARGSUSED*/
static void*
{
for (;;) {
if (fini_called)
break;
(void) pthread_mutex_lock(&ev_mutex);
while (queue_head == NULL) {
}
event = remove_from_queue();
(void) pthread_mutex_unlock(&ev_mutex);
while (event) {
(void) pthread_mutex_lock(&ev_mutex);
event = remove_from_queue();
(void) pthread_mutex_unlock(&ev_mutex);
}
}
return (NULL);
}
static picl_errno_t
{
return (PICL_INVALIDARG);
}
if (port_type == UNKNOWN_PORT) {
return (PICL_SUCCESS);
}
switch (state) {
case 0:
/* DOWN */
}
break;
case 1:
/* UP */
}
break;
default:
/* UNKNOWN */
}
}
if (post_ev && state_changed) {
sizeof (uint64_t))) != PICL_SUCCESS) {
}
}
}
switch (cond) {
case 0:
}
break;
case 1:
}
break;
case 2:
}
break;
case 3:
}
break;
default:
}
}
if (post_ev && cond_changed) {
sizeof (uint64_t))) != PICL_SUCCESS) {
}
}
}
return (PICL_SUCCESS);
}
/*
* monitor port nodes and scsi nodes under a fru
*/
static int
{
return (PICL_INVALIDARG);
}
return (PICL_WALK_CONTINUE);
}
return (PICL_WALK_CONTINUE);
sizeof (class))) != PICL_SUCCESS) {
return (PICL_WALK_CONTINUE);
}
PICL_SUCCESS) {
return (PICL_WALK_CONTINUE);
}
sizeof (slot_type)) != PICL_SUCCESS) {
return (PICL_WALK_CONTINUE);
}
return (PICL_WALK_CONTINUE);
}
if (state_changed) {
}
}
}
return (PICL_WALK_CONTINUE);
}
/* This routine monitors only port node, scsi nodes */
/* ARGSUSED */
static int
{
PICL_SUCCESS) {
return (PICL_WALK_CONTINUE);
}
if (frup->dr_in_progress) {
return (PICL_WALK_CONTINUE);
}
/* get the parent information to determine if it is scsi slot or not */
return (PICL_WALK_CONTINUE);
}
sizeof (slot_type)) != PICL_SUCCESS) {
return (PICL_WALK_CONTINUE);
}
/* scsi fru */
if (state_changed) {
}
}
if (cond_changed) {
rc);
}
}
return (PICL_WALK_CONTINUE);
}
return (PICL_WALK_CONTINUE);
}
(void) ptree_walk_tree_by_class(chassish,
return (PICL_WALK_CONTINUE);
}
/* ARGSUSED */
static void *
{
int err;
do
{
(void) pthread_mutex_lock(&monitor_mutex);
(void) pthread_mutex_unlock(&monitor_mutex);
(void) ptree_walk_tree_by_class(chassish,
}
} while (fini_called == 0);
return (NULL);
}
{
int i = 0;
return (PICL_FAILURE);
}
/* check if the location is already created */
return (PICL_SUCCESS);
}
}
/* create the location node and all its properties */
&nodeh)) != PICL_SUCCESS) {
return (rc);
}
PICL_SUCCESS) {
}
}
}
&geo_addr)) != PICL_SUCCESS) {
}
PICL_SUCCESS) {
}
(void) ptree_destroy_node(nodeh);
return (rc);
}
/* save the node in hashtable */
return (rc);
}
/* save data in hash table */
PICL_SUCCESS) {
return (rc);
}
}
return (rc);
}
/* if location is empty, done */
}
return (PICL_SUCCESS);
}
/* create the fru node and initilize it */
return (rc);
}
/* post picl event on location (frudata is consumer for these events) */
}
/* derive the fru_type from name */
fru_type[i] = '\0';
break;
}
++i;
}
PICL_SUCCESS) {
}
}
/* post picl state change event on fru state */
}
/* for scsi FRUs we need not probe further */
return (PICL_SUCCESS);
}
/*
* recursive search in the subtree
*/
/*ARGSUSED*/
const char *path)
{
return (B_TRUE);
}
}
return (B_FALSE);
}