fru_data.c revision 161c3e5a3e36266bace5970ff96ffec158570b08
/*
* 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"
#include <picl.h>
#include <syslog.h>
#include <strings.h>
#include <alloca.h>
#include <pthread.h>
#include <synch.h>
#include <limits.h>
#include <ctype.h>
#include <unistd.h>
#include <picltree.h>
#include <signal.h>
#include <sys/systeminfo.h>
#include <libnvpair.h>
#include "fru_tag.h"
#include "fru_data_impl.h"
#include "fru_data.h"
#include "picld_pluginutil.h"
static void frudata_plugin_init(void);
static void frudata_plugin_fini(void);
/*
* Locking Stragtegy :
* calling thread should hold the cont_tbl_lock during the course
* of container table lookup. release the cont_tbl_lock on lookup
* failure or on the condition wait.
*
* thread holding the container object rwlock should release lock
* and signal to unblock threads blocked on the condition variable
* upon i/o completion.
*
*/
packet_t *, container_tbl_t *);
static picld_plugin_reg_t frudata_reg_info = {
"SUNW_piclfrudata",
frudata_plugin_init, /* init entry point */
frudata_plugin_fini /* cleanup entry point */
};
/* initialization function */
static void
frudata_plugin_register(void)
{
/* register plugin with daemon */
}
}
static int
map_access_err(int err)
{
switch (err) {
case ENFILE :
return (PICL_PROPEXISTS);
case EAGAIN :
return (PICL_NOSPACE);
case EPERM :
return (PICL_PERMDENIED);
case EEXIST :
return (PICL_PROPEXISTS);
default :
return (PICL_FAILURE);
}
}
/*
* unlock_container_lock() should be always called by the thread holding the
* container object lock. it will signal block thread waiting on the condition
* variable.
*/
static void
{
(void) pthread_mutex_lock(&cont_tbl_lock);
(void) pthread_mutex_unlock(&cont_tbl_lock);
}
/* volatile callback read routine */
/* ARGSUSED */
static int
{
return (PICL_SUCCESS);
}
/*
* called to get hash object for specified node and object type from
* hash table.
*/
static container_tbl_t *
{
int index_to_hash;
int retval = PICL_SUCCESS;
picl_nodehdl_t parenthdl = 0;
switch (object_type) {
case SECTION_NODE:
&parenthdl, sizeof (picl_nodehdl_t));
break;
case SEGMENT_NODE:
&parenthdl, sizeof (picl_nodehdl_t));
&parenthdl, sizeof (picl_nodehdl_t));
break;
case CONTAINER_NODE :
break;
default :
return (NULL);
}
if (retval != PICL_SUCCESS) {
return (NULL);
}
return (next_hash);
}
}
return (NULL);
}
static int
{
/* if write operation */
if (operation == PICL_WRITE) {
}
/* read operation */
}
/*
* lock the container table, do lookup for the container object
* in the container table. if container object found try to lock
* the container object, if lock on container object is busy wait
* on condition variable till the thread holding the container
* object lock signal it.
*/
static container_tbl_t *
{
(void) pthread_mutex_lock(&cont_tbl_lock);
}
(void) pthread_mutex_unlock(&cont_tbl_lock);
return (cont_obj);
}
static hash_obj_t *
{
int index_to_hash;
return (next_hash);
}
}
return (NULL);
}
/*
* called to add newly created container hash table into container hash table.
*
*/
static void
{
int cnt;
int index_to_hash;
/* initialize the bucket of this container hash table. */
hash_ptr++;
}
}
}
static void
{
int index_to_hash;
}
}
static container_tbl_t *
{
return (NULL);
}
return (NULL);
}
return (cont_tbl);
}
/*
* called to allocate container node object for container property and a
* container table.
*/
static hash_obj_t *
{
/* open the container (call fruaccess) */
if (acc_hdl == (container_hdl_t)0) {
return (NULL);
}
/* allocate container node object */
return (NULL);
}
/* allocate container hash object */
return (NULL);
}
return (hash_obj);
}
/*
* called to allocate node object for section node.
*/
static hash_obj_t *
{
/* allocate section node object */
return (NULL);
}
/* allocate section hash object */
return (NULL);
}
return (hash_obj);
}
/*
* called to allocate segment node object.
*/
static hash_obj_t *
{
/* allocate segment node object */
return (NULL);
}
/* allocate segment hash object */
return (NULL);
}
/* fruaccess handle */
/* picl node handle */
return (hash_obj);
}
/*
* called to allocate node object for packet.
*/
static hash_obj_t *
{
/* allocate packet node object */
return (NULL);
}
/* allocate packet hash object */
return (NULL);
}
/* fruaccess handle */
return (hash_obj);
}
/* add new section hash object to the section list */
static void
{
return;
}
;
}
}
/* add new segment hash object to the existing list */
static void
{
return;
}
;
}
}
/*
* called to add packet node object to the existing packet list.
*/
static void
{
return;
}
;
}
}
/*
* free the packet hash list.
*/
static void
{
/* packet hash object list */
}
} else {
}
}
}
}
/*
* free the segment hash node object.
*/
static void
{
/* segment hash object list */
return;
}
/* find the segment hash from the segment list to be deleted. */
} else {
} else {
break;
}
}
return;
}
}
} else {
}
}
}
/*
* Description : frudata_delete_segment is called when volatile property
* delete_segment under class segment is accessed.
*
* Arguments : ptree_warg_t is holds node handle of segment node and property
* handle of delete_segment property.
*/
/* ARGSUSED */
static int
{
int retval;
int num_of_segment;
int num_of_pkt;
int pkt_cnt;
int count;
if (!cont_tbl) {
return (PICL_FAILURE);
}
/* segment hash */
return (PICL_FAILURE);
}
/* fruaccess segment handle */
/* call fruaccess to get new section handle */
== -1) {
return (map_access_err(errno));
}
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
/* get section node handle */
/* get section hash */
return (PICL_FAILURE);
}
/* call fruaccess with new section handle */
if (num_of_segment <= 0) {
return (PICL_SUCCESS);
}
if (seg_buffer == NULL) {
return (PICL_FAILURE);
}
/* get all the segments */
if (retval == -1) {
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
/* rebuild the segment list */
continue;
}
continue;
}
if (num_of_pkt <= 0) {
continue;
}
return (PICL_FAILURE);
}
if (retval == -1) {
continue;
}
continue;
}
/* rebuild the packet list */
}
break;
}
}
/* updated with new section handle */
return (PICL_SUCCESS);
}
/*
* Description : frudata_read_payload is called when volatile property
* payload is read.
*
* Arguments : ptree_rarg_t holds node handle of the table property.
* and property handle of the payload cell.
* p_buf contains payload data when function returns.
*
* Returns : PICL_SUCCESS on success.
* PICL_FAILURE on failure.
*/
static int
{
int num_bytes;
if (!cont_tbl) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
/*
* Description : frudata_write_payload is called when payload property cell
* is accessed.
*
* Arguments : ptree_warg_t holds node handle of the packet-table.
* and property handle of the payload cell.
* p_buf contains payload data.
*
* Returns : PICL_SUCCESS on success.
*
*/
static int
{
int retval;
if (!cont_tbl) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
if (retval == -1) {
return (map_access_err(errno));
}
return (PICL_SUCCESS);
}
/*
* callback volatile function is called when tag volatile property
* is accessed. this routine holds a read lock over the hash table
* and do a lookup over the property handle i.e property handle of
* the tag property passed in rarg parameter.
* tag value is copied into the buffer (void *buf).
*/
static int
{
int retval;
if (!cont_tbl) {
return (PICL_FAILURE);
}
if (retval != PICL_SUCCESS) {
return (retval);
}
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
/*
* Description : create_packet_table() is called by fru_delete_packet_row(),
* to create a packet-table volatile property. it's called after
* deleting the packet-table. fru_delete_packet_row() calls
* frudata_read_packet_table() to add rows into the table.
*/
static int
{
int retval;
if (retval != PICL_SUCCESS) {
return (retval);
}
&prophdl);
if (retval != PICL_SUCCESS) {
return (retval);
}
/* hold the table handle */
return (PICL_SUCCESS);
}
/*
* Description : frudata_delete_packet is called when write operation is
* performed on tag volatile property.
*
*
* Arguments : ptree_warg_t holds node handle to the segment node.
* and property handle of the tag cell in the packet table to be
* deleted.
* buf contains the tag data + plus DELETE_KEY_TAG
*
* Returns : PICL_SUCCESS on success
*
*/
static int
{
int count = 0;
int retval;
int num_of_pkt;
if (!cont_tbl) {
return (PICL_FAILURE);
}
/* get the payload property handle */
if (retval != PICL_SUCCESS) {
return (retval);
}
/* do lookup on payload property handle */
if (pkt_hash_obj == NULL) {
return (PICL_FAILURE);
}
/* verify the tag */
return (PICL_FAILURE);
}
/* call fruaccess module */
if (retval == -1) {
return (map_access_err(errno));
}
/* delete the packet table */
&tblhdl);
if (retval != PICL_SUCCESS) {
return (retval);
}
if (retval != PICL_SUCCESS) {
return (retval);
}
if (retval != PICL_SUCCESS) {
return (retval);
}
cont_tbl);
if (seg_hash_obj == NULL) {
return (PICL_FAILURE);
}
/* free all packet hash object */
/* recreate the packet table */
if (retval != PICL_SUCCESS) {
return (retval);
}
if (num_of_pkt == -1) {
return (PICL_FAILURE);
}
if (num_of_pkt == 0) {
return (PICL_SUCCESS);
}
return (PICL_FAILURE);
}
if (retval == -1) {
return (PICL_FAILURE);
}
/* rebuild the packet hash object */
cont_tbl);
}
&num_of_pkt, sizeof (uint32_t));
return (PICL_SUCCESS);
}
/*
* called from frudata_delete_packet(), frudata_add_packet(),
* frudata_read_packet() callback routine to add packet into
* the packet table. it also create hash node object for each
* individual packet and add the object to the packet list.
*/
static int
{
int retval;
int paylen;
/* tag property node */
if (paylen < 0) {
return (PICL_FAILURE);
}
if (retval != PICL_SUCCESS) {
return (retval);
}
/* payload property node */
if (retval != PICL_SUCCESS) {
return (retval);
}
return (PICL_FAILURE);
}
prophdl);
if (retval != PICL_SUCCESS) {
return (retval);
}
if (tagtype == -1) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
/*
* called from frudata_read_segment() callback routine. it's called after
* creating the packet table under class segment. this routine reads the
* segment data to get total number of packets in the segments and add
* the tag and payload data into the table. it calls add_row_to_table
* routine to add individual row into the packet table.
*/
static int
{
int cnt;
int retval;
int num_of_pkt;
return (PICL_FAILURE);
}
/* get the access handle */
/* get total number of packets */
if (num_of_pkt < 0) {
return (map_access_err(errno));
}
if (num_of_pkt == 0) {
return (0);
}
/* allocate buffer */
return (0);
}
/* get all the packet into the packet buffer */
if (retval == -1) {
return (0);
}
/* add payload and tag into the table. */
cont_tbl);
}
}
return (0);
}
/*
* Description : frudata_add_packet is called when add-packet volatile
* property is accessed.
*
* Arguments : ptree_warg_t holds node handle of the segment node and
* property handle of add-packet property.
* p_buf- contains packet data to be added.
*
* Return : PICL_SUCCESS on success.
*
*/
/* ARGSUSED */
static int
{
int paylen;
int retval;
int num_of_pkt;
int cnt;
if (!cont_tbl) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
if (tagtype == -1) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
if (paylen == -1) {
return (PICL_FAILURE);
}
if (retval == -1) {
return (map_access_err(errno));
}
if (retval != PICL_SUCCESS) {
return (retval);
}
if (retval != PICL_SUCCESS) {
return (retval);
}
if (num_of_pkt == -1) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
if (retval == -1) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
}
&num_of_pkt, sizeof (uint32_t));
return (PICL_SUCCESS);
}
static void
{
(void) ptree_delete_node(nodeh);
(void) ptree_destroy_node(nodeh);
}
/*
* called by frudata_read_segment() and fru_data_add_segment() callback routine.
* it's called to create a segment node and all it's property beneith the
* segment node in the picl tree.
*/
static int
{
int retval;
return (PICL_FAILURE);
}
!= PICL_SUCCESS) {
return (PICL_FAILURE);
}
/* create property node */
/* descriptor property */
&prophdl) != PICL_SUCCESS) {
return (PICL_FAILURE);
}
/* offset property */
&prophdl) != PICL_SUCCESS) {
return (PICL_FAILURE);
}
/* length property */
&prophdl) != PICL_SUCCESS) {
return (PICL_FAILURE);
}
/* Number of Tags */
!= PICL_SUCCESS) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
if (retval != PICL_SUCCESS) {
return (PICL_FAILURE);
}
if (protection == 0) { /* to be added only read/write section */
/* delete segment volatile property */
!= PICL_SUCCESS) {
return (PICL_FAILURE);
}
/* add packet volatile property */
!= PICL_SUCCESS) {
return (PICL_FAILURE);
}
}
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
if (retval != 0) {
return (PICL_SUCCESS);
}
return (PICL_SUCCESS);
}
/*
* Description :frudata_read_segment is called when num_segment volatile
* property is accessed.
*
* Arguments : ptree_rarg_t contains node handle of the section node.
* and property node of num_segments.
* void * will hold number of segment.
*
* Returns : PICL_SUCCESS on success.
* PICL_FAILURE on failure.
*/
static int
{
int num_of_segment;
int cnt;
int retval;
if (!cont_tbl) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
if (num_of_segment < 0) {
*(int *)buf = 0;
return (PICL_FAILURE);
}
if (num_of_segment == 0) {
*(int *)buf = 0;
return (PICL_SUCCESS);
}
*(int *)buf = 0;
return (PICL_SUCCESS);
}
if (retval == -1) {
*(int *)buf = 0;
return (PICL_SUCCESS);
}
continue;
}
/* if opaque segment don't create segment node */
continue;
}
}
}
/* return number of segment in the section */
return (PICL_SUCCESS);
}
/*
* Description : frudata_add_segment is called when volatile property
* add_segment under class node section is accessed.
*
* Arguments : ptree_warg_t holds node handle for the section node.
* property handle for the add_segment property.
*
* Returns : PICL_SUCCESS on success.
* PICL_FAILURE on failure.
*/
static int
{
int retval;
int cnt;
int num_of_segment;
/* initialize segment_t */
return (PICL_PERMDENIED);
}
if (!cont_tbl) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
/* call fruaccess module, get the new section handle. */
if (retval == -1) {
return (map_access_err(errno));
}
/* call access module with new section handle */
return (PICL_FAILURE);
}
if (retval == -1) {
return (PICL_FAILURE);
}
/* rebuild segment list */
return (PICL_FAILURE);
}
continue;
}
/* if opaque segment don't create segment node */
continue;
}
}
/* update with new section handle */
return (PICL_SUCCESS);
}
/*
* called from frudata_write_section() callback routine to create
* section node and all the property under class section. it also
* allocate hash node object for each section in the container and
* add the section node object in the section list.
*/
static int
{
char sec_name[SECNAMESIZE];
!= PICL_SUCCESS) {
return (PICL_FAILURE);
}
/* offset */
&prophdl) != PICL_SUCCESS) {
return (PICL_FAILURE);
}
/* length */
&prophdl) != PICL_SUCCESS) {
return (PICL_FAILURE);
}
/* protected */
&prophdl) != PICL_SUCCESS) {
return (PICL_FAILURE);
}
!= PICL_SUCCESS) {
return (PICL_FAILURE);
}
if (section->protection == 0) {
!= PICL_SUCCESS) {
return (PICL_FAILURE);
}
}
return (PICL_FAILURE);
}
/* lookup for container handle */
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
/*
* Description :frudata_write_section is called when volatile container
* property is accessed. it reads the section table associated
* with the specified node handle(container) in ptree_rarg_t.
* it calls search_root_node to search the node handle to open the
* device associated with the node handle. it creates section
* node and it's associated property. it also creates
* volatile property num_segments.
*
* Argument : ptree_rarg_t : contains node handle of fru container the
* container.
* property handle of the container.
*
* Return : PICL_SUCCESS on success.
*
*/
/* ARGSUSED */
static int
{
int retval;
int num_of_section;
int count;
(void) pthread_mutex_lock(&cont_tbl_lock);
/*
* if lookup succeed return from this function with PICL_SUCCESS
* because first write operation has already occurred on this container,
* it also means that the container has been already initialzed.
*/
(void) pthread_mutex_unlock(&cont_tbl_lock);
return (PICL_SUCCESS);
}
/*
* lookup failed that means this is first write on the
* container property. allocate a new container hash table for this
* new container and add to the cont_tbl hash table.
*/
(void) pthread_mutex_unlock(&cont_tbl_lock);
return (map_access_err(errno));
}
(void) pthread_mutex_unlock(&cont_tbl_lock);
return (map_access_err(errno));
}
/* add container table object to container table */
/* add the hash object to container hash table. */
}
(void) pthread_mutex_unlock(&cont_tbl_lock);
/* fruaccess handle */
if (num_of_section == -1) {
return (PICL_FAILURE);
}
if (retval == -1) {
return (PICL_FAILURE);
}
}
return (PICL_SUCCESS);
}
/* create container and add-segment property */
static int
{
int retval;
/* create a property */
return (retval);
}
/* search for FRUDataAvailable and create container and add segment property */
static void
{
int retval;
&chldhdl, sizeof (picl_nodehdl_t))) {
if (retval != PICL_SUCCESS)
return;
/* Does it have a FRUDataAvailable property */
if (retval == PICL_SUCCESS) {
(void) create_container_prop(chldhdl);
}
/* Traverse tree recursively */
(void) create_frudata_props(chldhdl);
}
}
/*
* Search for the frutree config file from the platform specific
* directory to the common directory.
*
* The size of outfilename must be PATH_MAX
*/
static int
get_config_file(char *outfilename)
{
return (0);
}
}
return (0);
}
}
return (0);
}
return (-1);
}
/*
* called from delete_frudata_props(), this routine delete the section node
* and free's the section hash object. it calls free_segment_node() to
* delete segment node beneath it.
*/
static void
{
}
}
} else {
}
}
/* delete & destroy section node */
}
/*
* called from delete_frudata_props(), this routine free's the container
* hash object.
*/
static void
{
}
} else {
}
}
}
/*
* called from frudata_event_handler() to free the corresponding hash object
* of the removed fru.
*/
static void
{
(void) pthread_mutex_lock(&cont_tbl_lock);
(void) pthread_mutex_unlock(&cont_tbl_lock);
return;
}
/* remove the container object from the container table */
(void) pthread_mutex_unlock(&cont_tbl_lock);
/*
* progress to complete. don't free the container
* hash before all I/O is complete.
*/
return;
}
/* walk through the section list */
}
}
/*
* called when there is any state-change in location, fru, port nodes.
* this event handler handles only location state-changes.
*/
/* ARGSUSED */
static void
{
int rc;
char *present_state, *last_state;
char name[PICL_PROPNAMELEN_MAX];
return;
return;
}
&loch) == -1) {
return;
}
sizeof (name)) != PICL_SUCCESS) {
return;
}
/* handle only location events */
return;
}
&present_state)) {
return;
}
&fruh, sizeof (picl_nodehdl_t));
if (rc != PICL_SUCCESS) {
return;
}
/* fru removed */
return;
}
&last_state)) {
return;
}
/* fru added */
&proph);
if (rc != PICL_SUCCESS) {
if (fru_is_data_available(fruh) == 0) {
return;
}
/* create the property */
if (rc != PICL_SUCCESS) {
return;
}
if (rc != PICL_SUCCESS) {
return;
}
}
(void) create_container_prop(fruh);
}
}
/*
* called when event is posted when is fru is either added or removed from
* the picltree.
*/
/* ARGSUSED */
static void
{
int retval;
char fullfilename[PATH_MAX];
if (retval != PICL_SUCCESS) {
return;
}
/* free the hash object */
/*
* reparse the configuration file to create
* FRUDevicePath Prop.
*/
(void) get_config_file(fullfilename);
if (retval != PICL_SUCCESS) {
return;
}
if (retval != PICL_SUCCESS) {
return;
}
/* create container property */
}
}
/*
* Function : plugin_init() is called by daemon. this routine is specified
* while registering with daemon. it performs the initialization
* of plugin module.
*/
static void
frudata_plugin_init(void)
{
int retval;
int count;
char fullfilename[PATH_MAX];
if (retval != PICL_SUCCESS) {
return;
}
(void) ptree_register_handler(PICL_FRU_ADDED,
(void) pthread_mutex_lock(&cont_tbl_lock);
}
(void) pthread_mutex_unlock(&cont_tbl_lock);
(void) get_config_file(fullfilename);
if (retval != PICL_SUCCESS) {
return;
}
}
static void
{
}
}
static void
{
}
}
static void
{
}
}
/*
* called from frudata_plugin_fini() this routine walks through
* the hash table to free each and very hash object in the hash table.
*/
static void
free_hash_table(void)
{
int cnt;
while (container_table[cnt]) {
(void) pthread_mutex_lock(&cont_tbl_lock);
(void) pthread_mutex_unlock(&cont_tbl_lock);
break;
}
(void) pthread_mutex_unlock(&cont_tbl_lock);
/*
* progress to complete. don't free the container
* hash until all I/O is complete.
*/
break;
}
}
}
}
}
/*
* called by the daemon and perform frudata cleanup. hold the write lock
* over the entire hash table to free each and every hash object.
*/
static void
frudata_plugin_fini(void)
{
}