/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
*/
/*
* Snapshot Library Interfaces
*
* Consumers of topology data may use the interfaces in this file to open,
* snapshot and close a topology exported by FMRI scheme (hc, mem and cpu)
* builtin plugins and their helper modules. A topology handle is obtained
* by calling topo_open(). Upon a successful return, the caller may use this
* handle to open a new snapshot. Each snapshot is assigned a Universally
* Unique Identifier that in a future enchancement to the libtopo API will be
* a previously captured snapshot. topo_snap_hold() will capture the current
* system topology. All consumers of the topo_hdl_t argument will be
* blocked from accessing the topology trees until the snapshot completes.
*
* A snapshot may be cleared by calling topo_snap_rele(). As with
* topo_snap_hold(), all topology accesses are blocked until the topology
* trees have been released and deallocated.
*
* Walker Library Interfaces
*
* Once a snapshot has been taken with topo_snap_hold(), topo_hdl_t holders
* may initiate topology tree walks on a scheme-tree basis. topo_walk_init()
* will initiate the data structures required to walk any one one of the
* FMRI scheme trees. The walker data structure, topo_walk_t, is an opaque
* handle passed to topo_walk_step to begin the walk. At each node in the
* topology tree, a callback function is called with access to the node at
* which our current walk falls. The callback function is passed in during
* calls to topo_walk_init() and used throughout the walk_step of the
* scheme tree. At any time, the callback may terminate the walk by returning
* TOPO_WALK_TERMINATE or TOPO_WALK_ERR. TOPO_WALK_NEXT will continue the walk.
*
* The type of walk through the tree may be sibling first or child first by
* respectively passing in TOPO_WALK_SIBLING or TOPO_WALK_CHILD to
* the topo_walk_step() function. Topology nodes
* associated with an outstanding walk are held in place and will not be
* deallocated until the walk through that node completes.
*
* Once the walk has terminated, the walking process should call
* topo_walk_fini() to clean-up resources created in topo_walk_init()
* and release nodes that may be still held.
*/
#include <alloca.h>
#include <ctype.h>
#include <pthread.h>
#include <limits.h>
#include <assert.h>
#include <fcntl.h>
#include <smbios.h>
#include <sys/systeminfo.h>
#include <unistd.h>
#include <zone.h>
#include <topo_alloc.h>
#include <topo_builtin.h>
#include <topo_string.h>
#include <topo_error.h>
#include <topo_subr.h>
static void topo_snap_destroy(topo_hdl_t *);
static topo_hdl_t *
{
}
return (NULL);
}
static void
{
char *product;
char *bufp;
int noclean = 0;
/* get SMBIOS handle */
/* determine product name */
if (shp &&
(unsigned char **)&bufp) != -1)) {
}
noclean = 1;
}
/*
* Cleanup the product name we found. Note that
* topo_cleanup_auth_str imposes a MAXNAMELEN limit
*/
}
}
{
char *dbflags;
char *dbout;
if (version != TOPO_VERSION)
/*
* Install default allocators
*/
/*
* Set-up system information and search paths for modules
* and topology map files
*/
} else {
int len;
char *rpath;
} else {
}
}
/* setup sysinfo based authority */
platform[0] = '\0';
isa[0] = '\0';
"%s: failed to load builtin modules: %s\n",
}
return (thp);
}
void
{
/*
* Clean-up snapshot
*/
/*
* Clean-up trees
*/
}
/*
* Unload all plugins
*/
}
static char *
{
*errp = ETOPO_HDL_UUID;
"%s: th_uuid should be NULL\n", __func__);
return (NULL);
}
/*
* If we're loading a topo snapshot rather than generating
* a new one from scratch, then thp->th_snap_dir will be
* non-null and the name of a sub-directory under the top
* level topo snapshots directory.
*/
/*
* If we're not loading a topo snapshot then generate a uuid,
* otherwise, one will be read in from the snapshot.
* We also don't need the devinfo or prominfo handles
* when loading a snapshot since those are only used
* by enumerators.
*/
if (load_snapshot == B_FALSE) {
== NULL) {
*errp = ETOPO_NOMEM;
"allocate uuid\n", __func__);
return (NULL);
}
/*
* Use uuid_generate_time() if debug option is set.
*/
"%s: using uuid_generate_time(), time=0x%lx(%s)\n",
} else {
}
if (need_force) {
"%s: taking a DINFOFORCE snapshot\n", __func__);
} else {
}
/*
* the /dev links are probed by the disk enumerator and the ses
* enumetator to find /dev public name for a device that the
* enumerator is interested in. The devlink handle used to
* be acquired in disk_common.c but /dev links are only probed
* for the devices that are pulled from the devinfo snapshot
* taken above so it is okay to acquire the handle here since
* the /dev link repository will include the same set of
* the devices as the devinfo snapshot.
*
* NOTE from disk_common.c:
* Until we can clean up (i.e. remove) topo dependencies
* on /dev public names, we ensure that name creation has
* completed by passing the DI_MAKE_LINK flag. Doing this
* lets us ignore EC_DEV_ADD and EC_DEV_REMOVE events
* in fmd_dr.c code.
*/
} else {
}
if (topo_tree_enum_all(thp) < 0) {
/*
* Note that nothing returns ETOPO_ENUM_FATAL today.
*/
"enumeration error\n", __func__);
*errp = ETOPO_ENUM_FATAL;
return (NULL);
} else {
"enumeration error\n", __func__);
}
}
"%s: failed to refresh IPMI sdr repository: %s\n",
}
"%s: enumeration failed, th_uuid is NULL\n", __func__);
return (NULL);
}
"%s: unable to allocate ustr\n", __func__);
*errp = ETOPO_NOMEM;
return (NULL);
}
/*
* Create topo handle authority if enumerator has not.
*/
__func__);
}
return (ustr);
}
/*ARGSUSED*/
static char *
{
return ((char *)uuid);
}
/*ARGSUSED*/
static int
{
int err;
/*
* If the facility enumeration method fails, note the failure,
* but continue on with the walk.
*/
&err) != 0) {
"%s: facility enumeration method failed on "
}
}
return (TOPO_WALK_NEXT);
}
/*
* Return snapshot id
*/
char *
{
char *ret;
return (ret);
}
char *
{
char *ret;
return (NULL);
if (uuid)
/* In global zone, bracket snapshot with di_cromk_begin/end. */
if (thp->th_cromk_hdl) {
}
return (NULL);
}
if (getzoneid())
return (ret);
/* global zone: walk and invoke facility enumeration methods. */
if (twp) {
}
if (thp->th_cromk_hdl) {
}
return (ret);
}
/*ARGSUSED*/
static int
{
return (TOPO_WALK_NEXT);
return (TOPO_WALK_NEXT);
}
static void
{
int i;
/*
* Clean-up tree nodes from the bottom-up
*/
}
/*
* Tidy-up the root node
*/
}
}
}
/*
* Clean-up our cached devinfo, devlink, prom tree, and smbios handles.
*/
}
}
}
}
}
}
void
{
return;
}
{
/*
* Hold the root node and start walk at the first
* child node
*/
return (NULL);
return (wp);
}
}
return (NULL);
}
static int
{
int status;
"%s: TOPO_WALK_TERMINATE for %s=%d\n",
return (TOPO_WALK_TERMINATE);
}
"%s: walk through node %s=%d to %s=%d\n", __func__,
if (bottomup == 1)
else
return (status);
}
static int
{
int status;
"%s: TOPO_WALK_TERMINATE for %s=%d\n", __func__,
return (TOPO_WALK_TERMINATE);
}
"%s: through sibling node %s=%d to %s=%d\n", __func__,
if (bottomup == 1)
else
return (status);
}
int
{
int status;
return (TOPO_WALK_TERMINATE);
else
return (status);
}
int
{
int status;
return (status);
}
int
{
int status;
return (TOPO_WALK_ERR);
}
/*
* No more nodes to walk
*/
"%s: walk terminated\n", __func__);
return (TOPO_WALK_TERMINATE);
}
else
/*
* Walker callback says we're done
*/
if (status != TOPO_WALK_NEXT) {
return (status);
}
if (flag == TOPO_WALK_CHILD)
else
/*
* No more nodes in this hash, skip to next node hash by stepping
* to next sibling (child-first walk) or next child (sibling-first
* walk).
*/
if (status == TOPO_WALK_TERMINATE) {
if (flag == TOPO_WALK_CHILD)
else
}
return (status);
}
void
{
return;
}
int
{
int status;
return (TOPO_WALK_ERR);
return (TOPO_WALK_ERR);
}
/*
* End of the line
*/
"%s: walk terminated\n", __func__);
return (TOPO_WALK_TERMINATE);
}
"%s: %s through node %s=%d\n", __func__,
if (flag == TOPO_WALK_CHILD)
else
/*
* At a leaf, run the callback
*/
if (status == TOPO_WALK_TERMINATE) {
!= TOPO_WALK_NEXT) {
return (status);
}
}
/*
* Try next child or sibling
*/
if (status == TOPO_WALK_NEXT) {
if (flag == TOPO_WALK_CHILD)
else
}
return (status);
}
{
}
{
}
{
}
{
}
/*
* Load in a saved topology snapshot.
*/
char *
{
char *ustr;
__func__);
*errp = ETOPO_HDL_INVAL;
return (NULL);
}
__func__);
*errp = ETOPO_HDL_INVAL;
return (NULL);
}
return (ustr);
}
{
}
void
{
/* fmd(1M) is about to exit, call di_cromk_cleanup(). */
}