pi_subr.c revision fc33347812f84907261f6fd501e2409da108b8d8
/*
* 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
*/
/*
*/
/*
* Subroutines used by various components of the Sun4v PI enumerator
*/
#include <sys/systeminfo.h>
#include <string.h>
#include <strings.h>
#include <fm/topo_mod.h>
#include <libnvpair.h>
#include "pi_impl.h"
/* max pci path = 256 */
/* max pci path + child + minor */
static const topo_pgroup_info_t sys_pgroup = {
1
};
static const topo_pgroup_info_t auth_pgroup = {
1
};
/*
* Search the PRI for MDE nodes using md_scan_dag. Using this routine
* consolodates similar searches used in a few places within the sun4vpi
* enumerator.
*
* The routine returns the number of nodes found, or -1. If the node array
* is non-NULL on return, then it must be freed:
* topo_mod_free(mod, nodes, nsize);
*
*/
int
{
int result;
int total_mdenodes;
/* Prepare to scan the PRI using the start string and given arc */
/* Allocate an array to hold the results of the scan */
/* We have no memory. Set an error code and return failure */
*nsize = 0;
return (-1);
}
if (result <= 0) {
/* No nodes found. Free the node array before returning */
*nsize = 0;
}
return (result);
}
/*
* Determine if this node should be skipped by finding the topo-skip property.
*/
int
{
int result;
/*
* These parameters are required. Tell the caller to skip
* all nodes.
*/
return (1);
}
skip = 0; /* do not skip by default */
if (result != 0) {
/*
* There is no topo-skip property. Assume we are not skipping
* the mde node.
*/
skip = 0;
}
/*
* If skip is present and non-zero we want to skip this node. We
* return 1 to indicate this.
*/
if (skip != 0) {
return (1);
}
return (0);
}
/*
* Build a device path without device names (PRI like) from a devinfo
* node. Return the PRI like path.
*
* The string must be freed with topo_mod_strfree()
*/
char *
{
int i, j, rv;
int depth = 0;
/* loop through collecting bus addresses */
do {
/* stop at '/' */
break;
}
if (depth < MAX_DIPATH_DEPTH) {
di_bus_addr(dnode));
++depth;
} else {
"long (%d)\n", depth);
return (NULL);
}
/* prepend '/@' to each bus address */
for (i = (depth - 1), j = 0; i >= 0; --i, j++) {
if (rv < 0) {
return (NULL);
}
}
/*
* Build the path from the bus addresses.
*/
for (i = 1; i < depth; i++) {
}
for (i = 0; i < depth; i++) {
}
}
}
return (path);
}
/*
* Get the product serial number (the ID as far as the topo authority is
* concerned) either from the current node, if it is of type 'product', or
* search for a product node in the PRI.
*
* The string must be freed with topo_mod_strfree()
*/
char *
{
int result;
int idx;
int num_nodes;
char *type;
/*
* This is a product node. We need only search for the serial
* number property on this node to return the ID.
*/
&id);
return (NULL);
id);
}
/*
* Search the PRI for nodes of type MD_STR_COMPONENT and find the
* first element with type of MD_STR_PRODUCT. This node
* will contain the MD_STR_SERIAL_NUMBER property to use as the
* product-sn.
*/
/* We did not find any component nodes */
return (NULL);
}
idx = 0;
/*
* This is a product node. Get the serial number
* property from the node.
*/
if (result != 0)
"failed to read %s from node_0x%llx\n",
}
/* Search the next node, if necessary */
idx++;
}
/* Everything is freed up and it's time to return the product-sn */
return (NULL);
}
}
/*
* Get the chassis serial number (the ID as far as the topo authority is
* concerned) either from the current node, if it is of type 'chassis', or
* search for a chassis node in the PRI.
*
* The string must be freed with topo_mod_strfree()
*/
char *
{
int result;
int idx;
int num_nodes;
/*
* This is a chassis node. We need only search for the serial
* number property on this node to return the ID.
*/
&id);
return (NULL);
}
}
}
/*
* Search the PRI for nodes of type MD_STR_COMPONENT and find the
* first element with topo-hc-type of MD_STR_CHASSIS. This node
* will contain the MD_STR_SERIAL_NUMBER property to use as the
* chassis-id.
*/
/* We did not find any chassis nodes */
return (NULL);
}
idx = 0;
/*
* This is a chassis node. Get the serial number
* property from the node.
*/
if (result != 0) {
"failed to read %s from node_0x%llx\n",
}
}
/* Search the next node, if necessary */
idx++;
}
/* Everything is freed up and it's time to return the platform-id */
return (NULL);
}
}
/*
* Determine if the node is a FRU by checking for the existance and non-zero
* value of the 'fru' property on the mde node.
*/
int
{
int result;
return (-1);
}
fru = 0;
*is_fru = 0;
if (result != 0) {
/* The node is not a FRU. */
return (-1);
}
if (fru != 0) {
*is_fru = 1;
}
return (0);
}
/*
* Get the id property value from the given PRI node
*/
int
{
int result;
id = 0;
if (result != 0) {
/*
* There is no id property.
*/
return (-1);
}
return (0);
}
/*
* If the given MDE node is a FRU return the 'nac' property, if it exists,
* to use as the label.
*
* The string must be freed with topo_mod_strfree()
*/
char *
{
int result;
int is_fru;
/*
* The disk enumerator will set the "bay" node as a FRU and
* expect the label from the PRI. The "fru" property can not
* be set because hostconfig has no way to set the S/N, P/N,
* etc.. in the PRI.
*/
/* This node is not a FRU. It has no label */
return (NULL);
}
}
/*
* The node is a FRU. Get the NAC name to use as a label.
*/
/* No NAC label. Return NULL */
return (NULL);
}
/* Return a copy of the label */
}
/*
* Return the "lun" property.
*/
int
{
int lun;
int *buf;
unsigned char *chbuf;
/* look for pathinfo property */
while ((di_path_prop =
if (strcmp("lun",
di_path_prop_name(di_path_prop)) == 0) {
goto found;
}
}
}
/* look for devinfo property */
di_prop != DI_PROP_NIL;
continue;
}
goto found;
}
}
di_path_prop == DI_PROP_NIL)) {
return (-1);
}
return (lun);
}
/*
* Return the complete part number string to the caller. The complete part
* number is made up of the part number attribute concatenated with the dash
* number attribute of the mde node.
*
* The string must be freed with topo_mod_strfree()
*/
char *
{
int result;
if (result != 0) {
}
if (result != 0) {
}
if (bufsize == 1) {
return (NULL);
}
/* Construct the part number from the part and dash values */
}
return (buf);
}
/*
* Return the path string to the caller.
*
* The string must be freed with topo_mod_strfree()
*/
char *
{
int result;
int i = 0;
char *buffree;
char *token;
char *lastp;
/*
* Get the path property from PRI; should look something
* like "/@600/@0".
*/
return (NULL);
}
return (NULL);
}
/*
* Grab the address(es) from the path property.
*/
if (++i < MAX_PATH_DEPTH) {
} else {
"too long (%d)\n", i);
return (NULL);
}
}
} else {
return (NULL);
}
max_addrs = ++i;
/*
* Construct the path to look something like "/pci@600/pci@0".
*/
for (i = 0; i < max_addrs; i++) {
if (result < 0) {
return (NULL);
}
}
/* put the parts together */
for (i = 1; i < max_addrs; i++) {
}
/*
* Cleanup
*/
for (i = 0; i < max_addrs; i++) {
}
}
}
return (path);
}
/*
* Get the product ID from the 'platform' node in the PRI
*
* The string must be freed with topo_mod_strfree()
*/
char *
{
int result;
/*
* Search the PRI for nodes of type MD_STR_PLATFORM, which contains
* the product-id in it's MD_STR_NAME property.
*/
/* We did not find any platform nodes */
return (NULL);
}
result);
/*
* There should only be 1 platform node, so we will always
* use the first if we find any at all.
*/
/* Everything is freed up and it's time to return the platform-id */
return (NULL);
}
}
/*
* If the phy pointer is NULL just return the number of 'phy_number' properties
* from the PRI; otherwise pass the 'phy_number' property values back to the
* caller.
*
* The caller is responsible for managing allocated memory.
*/
int
{
int result;
int nphy;
if (result != 0) {
/* no phy_number property */
"node_0x%llx has no phy_number property\n",
return (-1);
}
}
return (nphy);
}
/*
*/
int
{
int phy;
int *buf;
unsigned char *chbuf;
/* look for pathinfo property */
while ((di_path_prop =
if (strcmp("phy-num",
di_path_prop_name(di_path_prop)) == 0) {
goto found;
}
}
}
/* look for devinfo property */
di_prop != DI_PROP_NIL;
strlen("phy-num")) == 0) {
continue;
}
goto found;
}
}
di_path_prop == DI_PROP_NIL)) {
return (-1);
}
return (phy);
}
/*
* Return the revision string to the caller.
*
* The string must be freed with topo_mod_strfree()
*/
char *
{
int result;
return (NULL);
}
}
/*
* Return the serial number string to the caller.
*
* The string must be freed with topo_mod_strfree()
*/
char *
{
int result;
char buf[MAXNAMELEN];
/* Is this a uint64_t type serial number? */
&sn);
if (result != 0) {
/* No. We have failed to find a serial number */
return (NULL);
}
/* Convert the acquired value to a string */
if (result < 0) {
return (NULL);
}
}
}
/*
* Get the server hostname (the ID as far as the topo authority is
* concerned) from sysinfo and return a copy to the caller.
*
* The string must be freed with topo_mod_strfree()
*/
char *
{
int result;
char hostname[MAXNAMELEN];
/* Everything is freed up and it's time to return the platform-id */
if (result == -1) {
return (NULL);
}
}
/*
* Return the "target-port" property.
*
* The string must be freed with topo_mod_strfree()
*/
char *
{
char *tport;
/* look for pathinfo property */
while ((di_path_prop =
if (strcmp("target-port",
di_path_prop_name(di_path_prop)) == 0) {
(void) di_path_prop_strings(di_path_prop,
&tport);
goto found;
}
}
}
/* look for devinfo property */
di_prop != DI_PROP_NIL;
continue;
}
goto found;
}
}
di_path_prop == DI_PROP_NIL)) {
return (NULL);
}
tport);
}
/*
* Get the hc scheme name for the given node.
*
* The string must be freed with topo_mod_strfree()
*/
char *
{
int result;
char *hc_name;
/*
* Request the hc name from the node.
*/
"failed to get property %s from node_0x%llx\n",
return (NULL);
}
/* Return a copy of the type string */
}
/*
* Calculate the authority information for a node. Inherit the data if
* possible, but always create an appropriate property group.
*/
int
{
int result;
int err;
return (-1);
}
/*
* We failed to create the property group and it was not
* already defined. Set the err code and return failure.
*/
return (-1);
}
/* Get the authority information already available from the parent */
/*
* Set the authority data, inheriting it if possible, but creating it
* if necessary.
*/
/* product-id */
&val);
/*
* No product information in the parent node or auth
* list. Find the product information in the PRI.
*/
"name not found for node_0x%llx\n",
}
} else {
/*
* Dup the string. If we cannot find it in the auth
* nvlist we will need to free it, so this lets us
* have a single code path.
*/
}
/*
* We continue even if the product information is not available
* to enumerate as much as possible.
*/
&err);
if (result != 0) {
/* Preserve the error and continue */
"set property %s (%d) : %s\n",
topo_strerror(err));
}
}
}
/* product-sn */
&val);
/*
* No product-sn information in the parent node or auth
* list. Find the product-sn information in the PRI.
*/
"name not found for node_0x%llx\n",
}
} else {
/*
* Dup the string. If we cannot find it in the auth
* nvlist we will need to free it, so this lets us
* have a single code path.
*/
}
/*
* We continue even if the product information is not available
* to enumerate as much as possible.
*/
&err);
if (result != 0) {
/* Preserve the error and continue */
"set property %s (%d) : %s\n",
topo_strerror(err));
}
}
}
/* chassis-id */
&val);
/*
* No product information in the parent node or auth
* list. Find the product information in the PRI.
*/
"name not found for node_0x%llx\n",
}
} else {
/*
* Dup the string. If we cannot find it in the auth
* nvlist we will need to free it, so this lets us
* have a single code path.
*/
}
/*
* We continue even if the product information is not available
* to enumerate as much as possible.
*/
&err);
if (result != 0) {
/* Preserve the error and continue */
"set property %s (%d) : %s\n",
topo_strerror(err));
}
}
}
/* server-id */
&val);
/*
* No product information in the parent node or auth
* list. Find the product information in the PRI.
*/
"name not found for node_0x%llx\n",
}
} else {
/*
* Dup the string. If we cannot find it in the auth
* nvlist we will need to free it, so this lets us
* have a single code path.
*/
}
/*
* We continue even if the product information is not available
* to enumerate as much as possible.
*/
&err);
if (result != 0) {
/* Preserve the error and continue */
"set property %s (%d) : %s\n",
topo_strerror(err));
}
}
}
return (0);
}
/*
* Calculate a generic FRU for the given node. If the node is not a FRU,
* then inherit the FRU data from the nodes parent.
*/
int
{
int result;
int err;
int is_fru;
char *part;
char *rev;
char *serial;
return (-1);
}
/*
* Determine if this node is a FRU
*/
/* This node is not a FRU. Inherit from parent and return */
return (0);
}
/*
* This node is a FRU. Create an FMRI.
*/
}
/* Set the FRU, whether NULL or not */
if (result != 0) {
}
return (result);
}
int
{
int result;
int err;
char *label;
return (-1);
}
/*
* Get the label, if any, from the mde node and apply it as the label
* for this topology node. Note that a NULL label will inherit the
* label from topology node's parent.
*/
if (result != 0) {
}
return (result);
}
/*
* Calculate the system information for a node. Inherit the data if
* possible, but always create an appropriate property group.
*/
int
{
int result;
int err;
char isa[MAXNAMELEN];
return (-1);
}
/*
* We failed to create the property group and it was not
* already defined. Set the err code and return failure.
*/
return (-1);
}
&err);
isa[0] = '\0';
if (result == -1) {
/* Preserve the error and continue */
"read SI_ARCHITECTURE: %d\n", errno);
}
if (result != 0) {
/* Preserve the error and continue */
"set property %s (%d) : %s\n",
}
}
}
TOPO_PROP_MACHINE, &err);
if (result == -1) {
/* Preserve the error and continue */
"read uname: %d\n", errno);
}
if (result != 0) {
/* Preserve the error and continue */
"set property %s (%d) : %s\n",
}
}
}
return (0);
}
tnode_t *
{
int result;
"cannot bind for node_0x%llx instance %d type %s\n",
return (NULL);
}
/* Bind this node to the parent */
"failed to bind node_0x%llx instance %d: %s\n",
return (NULL);
}
/*
* We have bound the node. Now decorate it with an appropriate
* FRU and label (which may be inherited from the parent).
*
* The disk enumerator requires that 'bay' nodes not set their
* fru property.
*/
if (result != 0) {
/*
* Though we have failed to set the FRU FMRI we still
* continue. The module errno is set by the called
* routine, so we report the problem and move on.
*/
"failed to set FRU FMRI for node_0x%llx\n",
}
}
if (result != 0) {
/*
* Though we have failed to set the label, we still continue.
* The module errno is set by the called routine, so we report
* the problem and move on.
*/
}
if (result != 0) {
/*
* Though we have failed to set the authority, we still
* continue. The module errno is set by the called routine, so
* we report the problem and move on.
*/
}
if (result != 0) {
/*
* Though we have failed to set the system group, we still
* continue. The module errno is set by the called routine, so
* we report the problem and move on.
*/
}
return (t_node);
}