2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A
2N/A/*
2N/A * Subroutines used by various components of the Sun4v PI enumerator
2N/A */
2N/A
2N/A#include <sys/types.h>
2N/A#include <sys/systeminfo.h>
2N/A#include <sys/utsname.h>
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <sys/fm/protocol.h>
2N/A#include <fm/topo_mod.h>
2N/A#include <fm/topo_hc.h>
2N/A#include <sys/mdesc.h>
2N/A#include <libnvpair.h>
2N/A
2N/A#include "pi_impl.h"
2N/A
2N/Astatic const topo_pgroup_info_t sys_pgroup = {
2N/A TOPO_PGROUP_SYSTEM,
2N/A TOPO_STABILITY_PRIVATE,
2N/A TOPO_STABILITY_PRIVATE,
2N/A 1
2N/A};
2N/A
2N/Astatic const topo_pgroup_info_t auth_pgroup = {
2N/A FM_FMRI_AUTHORITY,
2N/A TOPO_STABILITY_PRIVATE,
2N/A TOPO_STABILITY_PRIVATE,
2N/A 1
2N/A};
2N/A
2N/A
2N/A/*
2N/A * Search the PRI for MDE nodes using md_scan_dag. Using this routine
2N/A * consolodates similar searches used in a few places within the sun4vpi
2N/A * enumerator.
2N/A *
2N/A * The routine returns the number of nodes found, or -1. If the node array
2N/A * is non-NULL on return, then it must be freed:
2N/A * topo_mod_free(mod, nodes, nsize);
2N/A *
2N/A */
2N/Aint
2N/Api_find_mdenodes(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_start,
2N/A char *type_str, char *arc_str, mde_cookie_t **nodes, size_t *nsize)
2N/A{
2N/A int result;
2N/A int total_mdenodes;
2N/A
2N/A mde_str_cookie_t start_cookie;
2N/A mde_str_cookie_t arc_cookie;
2N/A
2N/A /* Prepare to scan the PRI using the start string and given arc */
2N/A total_mdenodes = md_node_count(mdp);
2N/A start_cookie = md_find_name(mdp, type_str);
2N/A arc_cookie = md_find_name(mdp, arc_str);
2N/A
2N/A /* Allocate an array to hold the results of the scan */
2N/A *nsize = sizeof (mde_cookie_t) * total_mdenodes;
2N/A *nodes = topo_mod_zalloc(mod, *nsize);
2N/A if (*nodes == NULL) {
2N/A /* We have no memory. Set an error code and return failure */
2N/A *nsize = 0;
2N/A (void) topo_mod_seterrno(mod, EMOD_NOMEM);
2N/A return (-1);
2N/A }
2N/A
2N/A result = md_scan_dag(mdp, mde_start, start_cookie, arc_cookie, *nodes);
2N/A if (result <= 0) {
2N/A /* No nodes found. Free the node array before returning */
2N/A topo_mod_free(mod, *nodes, *nsize);
2N/A *nodes = NULL;
2N/A *nsize = 0;
2N/A }
2N/A
2N/A return (result);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Determine if this node should be skipped by finding the topo-skip property.
2N/A */
2N/Aint
2N/Api_skip_node(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
2N/A{
2N/A int result;
2N/A uint64_t skip;
2N/A
2N/A if (mod == NULL || mdp == NULL) {
2N/A /*
2N/A * These parameters are required. Tell the caller to skip
2N/A * all nodes.
2N/A */
2N/A return (1);
2N/A }
2N/A
2N/A skip = 0; /* do not skip by default */
2N/A result = md_get_prop_val(mdp, mde_node, MD_STR_TOPO_SKIP, &skip);
2N/A if (result != 0) {
2N/A /*
2N/A * There is no topo-skip property. Assume we are not skipping
2N/A * the mde node.
2N/A */
2N/A skip = 0;
2N/A }
2N/A
2N/A /*
2N/A * If skip is present and non-zero we want to skip this node. We
2N/A * return 1 to indicate this.
2N/A */
2N/A if (skip != 0) {
2N/A return (1);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Build a device path without device names (PRI like) from a devinfo
2N/A * node. Return the PRI like path.
2N/A *
2N/A * The string must be freed with topo_mod_strfree()
2N/A */
2N/Achar *
2N/Api_get_dipath(topo_mod_t *mod, di_node_t p_dnode)
2N/A{
2N/A int i, j, rv;
2N/A int depth = 0;
2N/A char **bus_addr = NULL;
2N/A char **dev_path = NULL;
2N/A char *path = NULL;
2N/A char *di_path = NULL;
2N/A size_t path_len = 0;
2N/A boolean_t depth_found = B_FALSE;
2N/A di_node_t dnode = p_dnode;
2N/A
2N/Aagain:
2N/A /* loop through collecting bus addresses */
2N/A do {
2N/A /* stop at '/' */
2N/A di_path = di_devfs_path(dnode);
2N/A if (strcmp(di_path, "/") == 0) {
2N/A di_devfs_path_free(di_path);
2N/A break;
2N/A }
2N/A di_devfs_path_free(di_path);
2N/A
2N/A if (depth_found) {
2N/A bus_addr[depth] = topo_mod_strdup(mod,
2N/A di_bus_addr(dnode));
2N/A }
2N/A ++depth;
2N/A } while ((dnode = di_parent_node(dnode)) != DI_NODE_NIL);
2N/A
2N/A if (!depth_found) {
2N/A bus_addr = (char **)topo_mod_zalloc(mod,
2N/A sizeof (char *) * depth);
2N/A dev_path = (char **)topo_mod_zalloc(mod,
2N/A sizeof (char *) * depth);
2N/A if (bus_addr == NULL || dev_path == NULL) {
2N/A topo_mod_dprintf(mod, "pi_get_dipath: no memory\n");
2N/A goto out;
2N/A }
2N/A
2N/A depth_found = B_TRUE;
2N/A dnode = p_dnode;
2N/A depth = 0;
2N/A goto again;
2N/A }
2N/A
2N/A /* prepend '/@' to each bus address */
2N/A for (i = (depth - 1), j = 0; i >= 0; --i, j++) {
2N/A int len = strlen(bus_addr[i]) + strlen("/@") + 1;
2N/A path_len += len;
2N/A dev_path[j] = (char *)topo_mod_alloc(mod, len);
2N/A rv = snprintf(dev_path[j], len, "/@%s", bus_addr[i]);
2N/A if (rv < 0) {
2N/A topo_mod_dprintf(mod,
2N/A "pi_get_dipath: snprintf failed\n");
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Build the path from the bus addresses.
2N/A */
2N/A path_len -= (depth - 1); /* leave room for one null char */
2N/A path = (char *)topo_mod_alloc(mod, path_len);
2N/A if (path == NULL) {
2N/A topo_mod_dprintf(mod, "pi_get_dipath: no memory for path\n");
2N/A goto out;
2N/A }
2N/A path = strcpy(path, dev_path[0]);
2N/A
2N/A for (i = 1; i < depth; i++) {
2N/A path = strncat(path, dev_path[i], strlen(dev_path[i]) + 1);
2N/A }
2N/A
2N/A topo_mod_dprintf(mod, "pi_get_dipath: path (%s)\n", path);
2N/Aout:
2N/A for (i = 0; i < depth; i++) {
2N/A if (bus_addr[i] != NULL) {
2N/A topo_mod_strfree(mod, bus_addr[i]);
2N/A }
2N/A if (dev_path[i] != NULL) {
2N/A topo_mod_strfree(mod, dev_path[i]);
2N/A }
2N/A }
2N/A if (bus_addr != NULL) {
2N/A topo_mod_free(mod, bus_addr, sizeof (char *) * depth);
2N/A }
2N/A if (dev_path != NULL) {
2N/A topo_mod_free(mod, dev_path, sizeof (char *) * depth);
2N/A }
2N/A
2N/A return (path);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Get the product serial number (the ID as far as the topo authority is
2N/A * concerned) either from the current node, if it is of type 'product', or
2N/A * search for a product node in the PRI.
2N/A *
2N/A * The string must be freed with topo_mod_strfree()
2N/A */
2N/Achar *
2N/Api_get_productsn(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
2N/A{
2N/A int result;
2N/A int idx;
2N/A int num_nodes;
2N/A char *id = NULL;
2N/A char *type;
2N/A size_t size;
2N/A mde_cookie_t *nodes = NULL;
2N/A
2N/A topo_mod_dprintf(mod, "pi_get_productsn: enter\n");
2N/A
2N/A result = md_get_prop_str(mdp, mde_node, MD_STR_TYPE, &type);
2N/A if (result == 0 && strcmp(type, MD_STR_PRODUCT) == 0) {
2N/A /*
2N/A * This is a product node. We need only search for the serial
2N/A * number property on this node to return the ID.
2N/A */
2N/A result = md_get_prop_str(mdp, mde_node, MD_STR_SERIAL_NUMBER,
2N/A &id);
2N/A if (result != 0 || id == NULL || strlen(id) == 0)
2N/A return (NULL);
2N/A
2N/A topo_mod_dprintf(mod, "pi_get_productsn: product-sn = %s\n",
2N/A id);
2N/A return (topo_mod_strdup(mod, id));
2N/A }
2N/A
2N/A /*
2N/A * Search the PRI for nodes of type MD_STR_COMPONENT and find the
2N/A * first element with type of MD_STR_PRODUCT. This node
2N/A * will contain the MD_STR_SERIAL_NUMBER property to use as the
2N/A * product-sn.
2N/A */
2N/A num_nodes = pi_find_mdenodes(mod, mdp, MDE_INVAL_ELEM_COOKIE,
2N/A MD_STR_COMPONENT, MD_STR_FWD, &nodes, &size);
2N/A if (num_nodes <= 0 || nodes == NULL) {
2N/A /* We did not find any component nodes */
2N/A return (NULL);
2N/A }
2N/A topo_mod_dprintf(mod, "pi_get_productsn: found %d %s nodes\n",
2N/A num_nodes, MD_STR_COMPONENT);
2N/A
2N/A idx = 0;
2N/A while (id == NULL && idx < num_nodes) {
2N/A result = md_get_prop_str(mdp, nodes[idx], MD_STR_TYPE, &type);
2N/A if (result == 0 && strcmp(type, MD_STR_PRODUCT) == 0) {
2N/A /*
2N/A * This is a product node. Get the serial number
2N/A * property from the node.
2N/A */
2N/A result = md_get_prop_str(mdp, nodes[idx],
2N/A MD_STR_SERIAL_NUMBER, &id);
2N/A if (result != 0)
2N/A topo_mod_dprintf(mod, "pi_get_productsn: "
2N/A "failed to read %s from node_0x%llx\n",
2N/A MD_STR_SERIAL_NUMBER,
2N/A (uint64_t)nodes[idx]);
2N/A }
2N/A /* Search the next node, if necessary */
2N/A idx++;
2N/A }
2N/A topo_mod_free(mod, nodes, size);
2N/A
2N/A /* Everything is freed up and it's time to return the product-sn */
2N/A if (result != 0 || id == NULL || strlen(id) == 0) {
2N/A return (NULL);
2N/A }
2N/A topo_mod_dprintf(mod, "pi_get_productsn: product-sn %s\n", id);
2N/A
2N/A return (topo_mod_strdup(mod, id));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Get the chassis serial number (the ID as far as the topo authority is
2N/A * concerned) either from the current node, if it is of type 'chassis', or
2N/A * search for a chassis node in the PRI.
2N/A *
2N/A * The string must be freed with topo_mod_strfree()
2N/A */
2N/Achar *
2N/Api_get_chassisid(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
2N/A{
2N/A int result;
2N/A int idx;
2N/A int num_nodes;
2N/A char *id = NULL;
2N/A char *hc_name = NULL;
2N/A size_t chassis_size;
2N/A mde_cookie_t *chassis_nodes = NULL;
2N/A
2N/A topo_mod_dprintf(mod, "pi_get_chassis: enter\n");
2N/A
2N/A hc_name = pi_get_topo_hc_name(mod, mdp, mde_node);
2N/A if (hc_name != NULL && strcmp(hc_name, MD_STR_CHASSIS) == 0) {
2N/A topo_mod_strfree(mod, hc_name);
2N/A
2N/A /*
2N/A * This is a chassis node. We need only search for the serial
2N/A * number property on this node to return the ID.
2N/A */
2N/A result = md_get_prop_str(mdp, mde_node, MD_STR_SERIAL_NUMBER,
2N/A &id);
2N/A if (result != 0 || id == NULL || strlen(id) == 0) {
2N/A return (NULL);
2N/A }
2N/A topo_mod_dprintf(mod, "pi_get_chassis: chassis-id = %s\n", id);
2N/A return (topo_mod_strdup(mod, id));
2N/A }
2N/A if (hc_name != NULL) {
2N/A topo_mod_strfree(mod, hc_name);
2N/A }
2N/A
2N/A /*
2N/A * Search the PRI for nodes of type MD_STR_COMPONENT and find the
2N/A * first element with topo-hc-type of MD_STR_CHASSIS. This node
2N/A * will contain the MD_STR_SERIAL_NUMBER property to use as the
2N/A * chassis-id.
2N/A */
2N/A num_nodes = pi_find_mdenodes(mod, mdp, MDE_INVAL_ELEM_COOKIE,
2N/A MD_STR_COMPONENT, MD_STR_FWD, &chassis_nodes, &chassis_size);
2N/A if (num_nodes <= 0 || chassis_nodes == NULL) {
2N/A /* We did not find any chassis nodes */
2N/A return (NULL);
2N/A }
2N/A topo_mod_dprintf(mod, "pi_get_chassisid: found %d %s nodes\n",
2N/A num_nodes, MD_STR_COMPONENT);
2N/A
2N/A idx = 0;
2N/A while (id == NULL && idx < num_nodes) {
2N/A hc_name = pi_get_topo_hc_name(mod, mdp, chassis_nodes[idx]);
2N/A if (hc_name != NULL && strcmp(hc_name, MD_STR_CHASSIS) == 0) {
2N/A /*
2N/A * This is a chassis node. Get the serial number
2N/A * property from the node.
2N/A */
2N/A result = md_get_prop_str(mdp, chassis_nodes[idx],
2N/A MD_STR_SERIAL_NUMBER, &id);
2N/A if (result != 0) {
2N/A topo_mod_dprintf(mod, "pi_get_chassisid: "
2N/A "failed to read %s from node_0x%llx\n",
2N/A MD_STR_SERIAL_NUMBER,
2N/A (uint64_t)chassis_nodes[idx]);
2N/A }
2N/A }
2N/A topo_mod_strfree(mod, hc_name);
2N/A
2N/A /* Search the next node, if necessary */
2N/A idx++;
2N/A }
2N/A topo_mod_free(mod, chassis_nodes, chassis_size);
2N/A
2N/A /* Everything is freed up and it's time to return the chassis-sn */
2N/A if (result != 0 || id == NULL || strlen(id) == 0) {
2N/A return (NULL);
2N/A }
2N/A topo_mod_dprintf(mod, "pi_get_chassis: chassis-id %s\n", id);
2N/A
2N/A return (topo_mod_strdup(mod, id));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Determine if the node is a FRU by checking for the existance and non-zero
2N/A * value of the 'fru' property on the mde node.
2N/A */
2N/Aint
2N/Api_get_fru(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, int *is_fru)
2N/A{
2N/A int result;
2N/A uint64_t fru;
2N/A
2N/A if (mod == NULL || mdp == NULL || is_fru == NULL) {
2N/A return (-1);
2N/A }
2N/A fru = 0;
2N/A *is_fru = 0;
2N/A
2N/A result = md_get_prop_val(mdp, mde_node, MD_STR_FRU, &fru);
2N/A if (result != 0) {
2N/A /* The node is not a FRU. */
2N/A return (-1);
2N/A }
2N/A if (fru != 0) {
2N/A *is_fru = 1;
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Get the id property value from the given PRI node
2N/A */
2N/Aint
2N/Api_get_instance(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
2N/A topo_instance_t *ip)
2N/A{
2N/A int result;
2N/A uint64_t id;
2N/A
2N/A id = 0;
2N/A result = md_get_prop_val(mdp, mde_node, MD_STR_ID, &id);
2N/A if (result != 0) {
2N/A /*
2N/A * There is no id property.
2N/A */
2N/A topo_mod_dprintf(mod, "node_0x%llx has no id property\n",
2N/A (uint64_t)mde_node);
2N/A return (-1);
2N/A }
2N/A *ip = id;
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * If the given MDE node is a FRU return the 'nac' property, if it exists,
2N/A * to use as the label.
2N/A *
2N/A * The string must be freed with topo_mod_strfree()
2N/A */
2N/Achar *
2N/Api_get_label(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
2N/A{
2N/A int result;
2N/A int is_fru;
2N/A char *lp = NULL;
2N/A char *hc_name = pi_get_topo_hc_name(mod, mdp, mde_node);
2N/A
2N/A /*
2N/A * The disk enumerator will set the "bay" node as a FRU and
2N/A * expect the label from the PRI. The "fru" property can not
2N/A * be set because hostconfig has no way to set the S/N, P/N,
2N/A * etc.. in the PRI.
2N/A */
2N/A if (strncmp(hc_name, BAY, strlen(BAY)) != 0) {
2N/A result = pi_get_fru(mod, mdp, mde_node, &is_fru);
2N/A if (result != 0 || is_fru == 0) {
2N/A /* This node is not a FRU. It has no label */
2N/A topo_mod_strfree(mod, hc_name);
2N/A return (NULL);
2N/A }
2N/A }
2N/A topo_mod_strfree(mod, hc_name);
2N/A
2N/A /*
2N/A * The node is a FRU. Get the NAC name to use as a label.
2N/A */
2N/A result = md_get_prop_str(mdp, mde_node, MD_STR_NAC, &lp);
2N/A if (result != 0 || lp == NULL || strlen(lp) == 0) {
2N/A /* No NAC label. Return NULL */
2N/A return (NULL);
2N/A }
2N/A
2N/A /* Return a copy of the label */
2N/A return (topo_mod_strdup(mod, lp));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Return the "lun" property.
2N/A */
2N/Aint
2N/Api_get_lun(topo_mod_t *mod, di_node_t node)
2N/A{
2N/A int lun;
2N/A int *buf;
2N/A unsigned char *chbuf;
2N/A di_prop_t di_prop = DI_PROP_NIL;
2N/A di_path_t dpath = DI_PATH_NIL;
2N/A di_path_prop_t di_path_prop = DI_PROP_NIL;
2N/A
2N/A /* look for pathinfo property */
2N/A while ((dpath = di_path_phci_next_path(node, dpath)) != DI_PATH_NIL) {
2N/A while ((di_path_prop =
2N/A di_path_prop_next(dpath, di_path_prop)) != DI_PROP_NIL) {
2N/A if (strcmp("lun",
2N/A di_path_prop_name(di_path_prop)) == 0) {
2N/A (void) di_path_prop_ints(di_path_prop, &buf);
2N/A bcopy(buf, &lun, sizeof (int));
2N/A goto found;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* look for devinfo property */
2N/A for (di_prop = di_prop_next(node, DI_PROP_NIL);
2N/A di_prop != DI_PROP_NIL;
2N/A di_prop = di_prop_next(node, di_prop)) {
2N/A if (strncmp("lun", di_prop_name(di_prop),
2N/A strlen(di_prop_name(di_prop))) == 0) {
2N/A if (di_prop_bytes(di_prop, &chbuf) < sizeof (uint_t)) {
2N/A continue;
2N/A }
2N/A bcopy(chbuf, &lun, sizeof (uint_t));
2N/A goto found;
2N/A }
2N/A }
2N/A
2N/A if (di_prop == DI_PROP_NIL && (dpath == DI_PATH_NIL ||
2N/A di_path_prop == DI_PROP_NIL)) {
2N/A return (-1);
2N/A }
2N/Afound:
2N/A topo_mod_dprintf(mod, "pi_get_lun: lun = (%d)\n", lun);
2N/A return (lun);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Return the complete part number string to the caller. The complete part
2N/A * number is made up of the part number attribute concatenated with the dash
2N/A * number attribute of the mde node.
2N/A *
2N/A * The string must be freed with topo_mod_strfree()
2N/A */
2N/Achar *
2N/Api_get_part(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
2N/A{
2N/A int result;
2N/A size_t bufsize;
2N/A char *buf = NULL;
2N/A char *part = NULL;
2N/A char *dash = NULL;
2N/A
2N/A result = md_get_prop_str(mdp, mde_node, MD_STR_PART_NUMBER, &part);
2N/A if (result != 0) {
2N/A part = NULL;
2N/A }
2N/A result = md_get_prop_str(mdp, mde_node, MD_STR_DASH_NUMBER, &dash);
2N/A if (result != 0) {
2N/A dash = NULL;
2N/A }
2N/A bufsize = 1 + (part ? strlen(part) : 0) + (dash ? strlen(dash) : 0);
2N/A if (bufsize == 1) {
2N/A return (NULL);
2N/A }
2N/A
2N/A /* Construct the part number from the part and dash values */
2N/A buf = topo_mod_alloc(mod, bufsize);
2N/A if (buf != NULL) {
2N/A (void) snprintf(buf, bufsize, "%s%s", (part ? part : ""),
2N/A (dash ? dash : ""));
2N/A }
2N/A
2N/A return (buf);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Return the path string to the caller.
2N/A *
2N/A * The string must be freed with topo_mod_strfree()
2N/A */
2N/Achar *
2N/Api_get_path(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
2N/A{
2N/A int result;
2N/A int i = 0;
2N/A size_t max_addrs = 0;
2N/A size_t path_len = 0;
2N/A size_t buf_len;
2N/A char *propbuf = NULL;
2N/A char *buf = NULL;
2N/A char *buffree = NULL;
2N/A char *path = NULL;
2N/A char *token;
2N/A char **dev_addr = NULL;
2N/A char **dev_path = NULL;
2N/A char *lastp;
2N/A
2N/A /*
2N/A * Get the path property from PRI; should look something
2N/A * like "/@600/@0".
2N/A */
2N/A result = md_get_prop_str(mdp, mde_node, MD_STR_PATH, &propbuf);
2N/A if (result != 0 || propbuf == NULL || strlen(propbuf) == 0) {
2N/A topo_mod_dprintf(mod, "pi_get_path: failed to get path\n");
2N/A goto out;
2N/A }
2N/A buf_len = strlen(propbuf) + 1;
2N/A buf = topo_mod_alloc(mod, buf_len);
2N/A if (buf == NULL) {
2N/A topo_mod_dprintf(mod, "pi_get_path: no memory\n");
2N/A goto out;
2N/A }
2N/A (void) strcpy(buf, propbuf);
2N/A
2N/A /* count the path depth */
2N/A if ((token = strtok_r(buf, "/@", &lastp)) != NULL) {
2N/A ++max_addrs;
2N/A while ((token = strtok_r(NULL, "/@", &lastp)) != NULL) {
2N/A ++max_addrs;
2N/A }
2N/A }
2N/A if (max_addrs == 0) {
2N/A topo_mod_dprintf(mod, "pi_get_path: bad path\n");
2N/A goto out;
2N/A }
2N/A
2N/A /* allocate pointers */
2N/A dev_addr = (char **)topo_mod_zalloc(mod, sizeof (char *) * max_addrs);
2N/A dev_path = (char **)topo_mod_zalloc(mod, sizeof (char *) * max_addrs);
2N/A if (dev_addr == NULL || dev_path == NULL) {
2N/A topo_mod_dprintf(mod, "pi_get_path: no path memory\n");
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * Grab the address(es) from the path property.
2N/A */
2N/A (void) strcpy(buf, propbuf);
2N/A buffree = buf; /* strtok_r is destructive */
2N/A if ((token = strtok_r(buf, "/@", &lastp)) != NULL) {
2N/A dev_addr[i] = topo_mod_strdup(mod, token);
2N/A while ((token = strtok_r(NULL, "/@", &lastp)) != NULL) {
2N/A ++i;
2N/A dev_addr[i] = topo_mod_strdup(mod, token);
2N/A }
2N/A } else {
2N/A topo_mod_dprintf(mod, "pi_get_path: path wrong\n");
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * Construct the path to look something like "/pci@600/pci@0".
2N/A */
2N/A for (i = 0; i < max_addrs; i++) {
2N/A int len = strlen(dev_addr[i]) + strlen("/pci@") + 1;
2N/A path_len += len;
2N/A dev_path[i] = (char *)topo_mod_alloc(mod, len);
2N/A if (dev_path[i] == NULL) {
2N/A topo_mod_dprintf(mod,
2N/A "pi_get_path: no memory for dev_path[%d]\n", i);
2N/A goto out;
2N/A }
2N/A result = snprintf(dev_path[i], len, "/pci@%s", dev_addr[i]);
2N/A if (result < 0) {
2N/A topo_mod_dprintf(mod,
2N/A "pi_get_path: snprintf failed\n");
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A path_len -= (i - 1); /* leave room for one null char */
2N/A path = (char *)topo_mod_alloc(mod, path_len);
2N/A path = strcpy(path, dev_path[0]);
2N/A
2N/A /* put the parts together */
2N/A for (i = 1; i < max_addrs; i++) {
2N/A path = strncat(path, dev_path[i], strlen(dev_path[i]) + 1);
2N/A }
2N/A
2N/A topo_mod_dprintf(mod, "pi_get_path: path = (%s)\n", path);
2N/Aout:
2N/A /*
2N/A * Cleanup
2N/A */
2N/A for (i = 0; i < max_addrs; i++) {
2N/A if (dev_addr[i] != NULL) {
2N/A topo_mod_free(mod, dev_addr[i],
2N/A strlen(dev_addr[i]) + 1);
2N/A }
2N/A if (dev_path[i] != NULL) {
2N/A topo_mod_free(mod, dev_path[i],
2N/A strlen(dev_path[i]) + 1);
2N/A }
2N/A }
2N/A if (dev_addr != NULL) {
2N/A topo_mod_free(mod, dev_addr, sizeof (char *) * max_addrs);
2N/A }
2N/A if (dev_path != NULL) {
2N/A topo_mod_free(mod, dev_path, sizeof (char *) * max_addrs);
2N/A }
2N/A if (buffree != NULL) {
2N/A topo_mod_free(mod, buffree, buf_len);
2N/A }
2N/A return (path);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Get the product ID and serial number from the 'platform' node in the PRI
2N/A *
2N/A * Strings must be freed with topo_mod_strfree()
2N/A */
2N/Avoid
2N/Api_get_platform(topo_mod_t *mod, md_t *mdp, char **name, char **serial)
2N/A{
2N/A int result;
2N/A char *id = NULL;
2N/A size_t platform_size;
2N/A mde_cookie_t *platform_nodes = NULL;
2N/A
2N/A topo_mod_dprintf(mod, "pi_get_platform: enter\n");
2N/A
2N/A /*
2N/A * Search the PRI for nodes of type MD_STR_PLATFORM, which contains
2N/A * the product-id in it's MD_STR_NAME property.
2N/A */
2N/A result = pi_find_mdenodes(mod, mdp, MDE_INVAL_ELEM_COOKIE,
2N/A MD_STR_PLATFORM, MD_STR_FWD, &platform_nodes, &platform_size);
2N/A if (result <= 0 || platform_nodes == NULL) {
2N/A /* We did not find any platform nodes */
2N/A topo_mod_dprintf(mod, "pi_get_platform: no platform node\n");
2N/A return;
2N/A }
2N/A topo_mod_dprintf(mod, "pi_get_platform: found %d platform nodes\n",
2N/A result);
2N/A
2N/A /*
2N/A * There should only be 1 platform node, so we will always
2N/A * use the first if we find any at all.
2N/A */
2N/A result = md_get_prop_str(mdp, platform_nodes[0], MD_STR_NAME, &id);
2N/A if (result == 0 && id != NULL && strlen(id) != 0) {
2N/A *name = topo_mod_strdup(mod, id);
2N/A } else {
2N/A *name = NULL;
2N/A }
2N/A
2N/A *serial = pi_get_serial(mod, mdp, platform_nodes[0]);
2N/A topo_mod_dprintf(mod, "pi_get_platform: name %s serial %s\n",
2N/A *name ? *name : "NULL", *serial ? *serial : "NULL");
2N/A
2N/A /* free platform node(s) */
2N/A topo_mod_free(mod, platform_nodes, platform_size);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * If the phy pointer is NULL just return the number of 'phy_number' properties
2N/A * from the PRI; otherwise pass the 'phy_number' property values back to the
2N/A * caller.
2N/A *
2N/A * The caller is responsible for managing allocated memory.
2N/A */
2N/Aint
2N/Api_get_priphy(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, uint8_t *phyp)
2N/A{
2N/A int result;
2N/A uint8_t *phy_num;
2N/A int nphy;
2N/A
2N/A result = md_get_prop_data(mdp, mde_node, MD_STR_PHY_NUMBER,
2N/A &phy_num, &nphy);
2N/A if (result != 0) {
2N/A /* no phy_number property */
2N/A topo_mod_dprintf(mod,
2N/A "node_0x%llx has no phy_number property\n",
2N/A (uint64_t)mde_node);
2N/A return (-1);
2N/A }
2N/A
2N/A if (phyp != NULL) {
2N/A bcopy(phy_num, phyp, nphy);
2N/A }
2N/A return (nphy);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Return "phy-num" devinfo/pathinfo property.
2N/A */
2N/Aint
2N/Api_get_phynum(topo_mod_t *mod, di_node_t node)
2N/A{
2N/A int phy;
2N/A int *buf;
2N/A unsigned char *chbuf;
2N/A di_prop_t di_prop = DI_PROP_NIL;
2N/A di_path_t dpath = DI_PATH_NIL;
2N/A di_path_prop_t di_path_prop = DI_PROP_NIL;
2N/A
2N/A
2N/A /* look for pathinfo property */
2N/A while ((dpath = di_path_phci_next_path(node, dpath)) != DI_PATH_NIL) {
2N/A while ((di_path_prop =
2N/A di_path_prop_next(dpath, di_path_prop)) != DI_PROP_NIL) {
2N/A if (strcmp("phy-num",
2N/A di_path_prop_name(di_path_prop)) == 0) {
2N/A (void) di_path_prop_ints(di_path_prop, &buf);
2N/A bcopy(buf, &phy, sizeof (int));
2N/A goto found;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* look for devinfo property */
2N/A for (di_prop = di_prop_next(node, DI_PROP_NIL);
2N/A di_prop != DI_PROP_NIL;
2N/A di_prop = di_prop_next(node, di_prop)) {
2N/A if (strncmp("phy-num", di_prop_name(di_prop),
2N/A strlen("phy-num")) == 0) {
2N/A if (di_prop_bytes(di_prop, &chbuf) < sizeof (uint_t)) {
2N/A continue;
2N/A }
2N/A bcopy(chbuf, &phy, sizeof (uint_t));
2N/A goto found;
2N/A }
2N/A }
2N/A
2N/A if (di_prop == DI_PROP_NIL && (dpath == DI_PATH_NIL ||
2N/A di_path_prop == DI_PROP_NIL)) {
2N/A return (-1);
2N/A }
2N/Afound:
2N/A topo_mod_dprintf(mod, "pi_get_phynum: phy = %d\n", phy);
2N/A return (phy);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Return the revision string to the caller.
2N/A *
2N/A * The string must be freed with topo_mod_strfree()
2N/A */
2N/Achar *
2N/Api_get_revision(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
2N/A{
2N/A int result;
2N/A char *rp = NULL;
2N/A
2N/A result = md_get_prop_str(mdp, mde_node, MD_STR_REVISION_NUMBER, &rp);
2N/A if (result != 0 || rp == NULL || strlen(rp) == 0) {
2N/A return (NULL);
2N/A }
2N/A
2N/A return (topo_mod_strdup(mod, rp));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Return the serial number string to the caller.
2N/A *
2N/A * The string must be freed with topo_mod_strfree()
2N/A */
2N/Achar *
2N/Api_get_serial(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
2N/A{
2N/A int result;
2N/A uint64_t sn;
2N/A char *sp = NULL;
2N/A char buf[MAXNAMELEN];
2N/A
2N/A result = md_get_prop_str(mdp, mde_node, MD_STR_SERIAL_NUMBER, &sp);
2N/A if (result != 0 || sp == NULL || strlen(sp) == 0) {
2N/A /* Is this a uint64_t type serial number? */
2N/A result = md_get_prop_val(mdp, mde_node, MD_STR_SERIAL_NUMBER,
2N/A &sn);
2N/A if (result != 0) {
2N/A /* try "serial#" */
2N/A result = md_get_prop_val(mdp, mde_node,
2N/A "serial#", &sn);
2N/A if (result != 0) {
2N/A /* failed to find a serial number */
2N/A return (NULL);
2N/A }
2N/A }
2N/A topo_mod_dprintf(mod, "pi_get_serial: node_0x%llx numeric "
2N/A "serial number %llx\n", (uint64_t)mde_node, sn);
2N/A
2N/A /* Convert the acquired value to a string */
2N/A result = snprintf(buf, sizeof (buf), "%llu", sn);
2N/A if (result < 0) {
2N/A return (NULL);
2N/A }
2N/A sp = buf;
2N/A }
2N/A topo_mod_dprintf(mod, "pi_get_serial: node_0x%llx = %s\n",
2N/A (uint64_t)mde_node, (sp == NULL ? "NULL" : sp));
2N/A
2N/A return (topo_mod_strdup(mod, sp));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Get the server hostname (the ID as far as the topo authority is
2N/A * concerned) from sysinfo and return a copy to the caller.
2N/A *
2N/A * The string must be freed with topo_mod_strfree()
2N/A */
2N/Achar *
2N/Api_get_serverid(topo_mod_t *mod)
2N/A{
2N/A int result;
2N/A char hostname[MAXNAMELEN];
2N/A
2N/A topo_mod_dprintf(mod, "pi_get_serverid: enter\n");
2N/A
2N/A result = sysinfo(SI_HOSTNAME, hostname, sizeof (hostname));
2N/A /* Everything is freed up and it's time to return the platform-id */
2N/A if (result == -1) {
2N/A return (NULL);
2N/A }
2N/A topo_mod_dprintf(mod, "pi_get_serverid: hostname = %s\n", hostname);
2N/A
2N/A return (topo_mod_strdup(mod, hostname));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Return the "target-port" property.
2N/A *
2N/A * The string must be freed with topo_mod_strfree()
2N/A */
2N/Achar *
2N/Api_get_target_port(topo_mod_t *mod, di_node_t node)
2N/A{
2N/A char *tport;
2N/A di_prop_t di_prop = DI_PROP_NIL;
2N/A di_path_t dpath = DI_PATH_NIL;
2N/A di_path_prop_t di_path_prop = DI_PROP_NIL;
2N/A
2N/A /* look for pathinfo property */
2N/A while ((dpath = di_path_phci_next_path(node, dpath)) != DI_PATH_NIL) {
2N/A while ((di_path_prop =
2N/A di_path_prop_next(dpath, di_path_prop)) != DI_PROP_NIL) {
2N/A if (strcmp("target-port",
2N/A di_path_prop_name(di_path_prop)) == 0) {
2N/A (void) di_path_prop_strings(di_path_prop,
2N/A &tport);
2N/A goto found;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* look for devinfo property */
2N/A for (di_prop = di_prop_next(node, DI_PROP_NIL);
2N/A di_prop != DI_PROP_NIL;
2N/A di_prop = di_prop_next(node, di_prop)) {
2N/A if (strcmp("target-port", di_prop_name(di_prop)) == 0) {
2N/A if (di_prop_strings(di_prop, &tport) < 0) {
2N/A continue;
2N/A }
2N/A goto found;
2N/A }
2N/A }
2N/A
2N/A if (di_prop == DI_PROP_NIL && (dpath == DI_PATH_NIL ||
2N/A di_path_prop == DI_PROP_NIL)) {
2N/A return (NULL);
2N/A }
2N/Afound:
2N/A topo_mod_dprintf(mod, "pi_get_target_port: 'target-port' = (%s)\n",
2N/A tport);
2N/A return (topo_mod_strdup(mod, tport));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Get the hc scheme name for the given node.
2N/A *
2N/A * The string must be freed with topo_mod_strfree()
2N/A */
2N/Achar *
2N/Api_get_topo_hc_name(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
2N/A{
2N/A int result;
2N/A char *hc_name;
2N/A
2N/A /*
2N/A * Request the hc name from the node.
2N/A */
2N/A hc_name = NULL;
2N/A result = md_get_prop_str(mdp, mde_node, MD_STR_TOPO_HC_NAME, &hc_name);
2N/A if (result != 0 || hc_name == NULL) {
2N/A topo_mod_dprintf(mod,
2N/A "failed to get property %s from node_0x%llx\n",
2N/A MD_STR_TOPO_HC_NAME, (uint64_t)mde_node);
2N/A return (NULL);
2N/A }
2N/A
2N/A /* Return a copy of the type string */
2N/A return (topo_mod_strdup(mod, hc_name));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Calculate the authority information for a node. Inherit the data if
2N/A * possible, but always create an appropriate property group.
2N/A */
2N/Aint
2N/Api_set_auth(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
2N/A tnode_t *t_parent, tnode_t *t_node)
2N/A{
2N/A int result;
2N/A int err;
2N/A nvlist_t *auth;
2N/A
2N/A if (mod == NULL || mdp == NULL || t_parent == NULL || t_node == NULL) {
2N/A return (-1);
2N/A }
2N/A
2N/A if ((topo_pgroup_create(t_node, &auth_pgroup, &err) != 0) &&
2N/A (err != ETOPO_PROP_DEFD)) {
2N/A /*
2N/A * We failed to create the property group and it was not
2N/A * already defined. Set the err code and return failure.
2N/A */
2N/A (void) topo_mod_seterrno(mod, err);
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * Set the authority data.
2N/A *
2N/A * Continue even if some authority information is not available
2N/A * to enumerate as much as possible.
2N/A */
2N/A auth = topo_mod_auth(mod, t_parent);
2N/A result = topo_node_set_auth_chassis(mod, auth, t_node);
2N/A if (result != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "pi_set_auth: failed to set chassis authority "
2N/A "for node_0x%llx\n", (uint64_t)mde_node);
2N/A }
2N/A
2N/A nvlist_free(auth);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Calculate a generic FRU for the given node. If the node is not a FRU,
2N/A * then inherit the FRU data from the nodes parent.
2N/A */
2N/Aint
2N/Api_set_frufmri(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
2N/A const char *name, topo_instance_t inst, tnode_t *t_parent, tnode_t *t_node)
2N/A{
2N/A int result;
2N/A int err;
2N/A int is_fru;
2N/A char *part;
2N/A char *rev;
2N/A char *serial;
2N/A nvlist_t *auth = NULL;
2N/A nvlist_t *frufmri = NULL;
2N/A
2N/A if (t_node == NULL || mod == NULL || mdp == NULL) {
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * Determine if this node is a FRU
2N/A */
2N/A result = pi_get_fru(mod, mdp, mde_node, &is_fru);
2N/A if (result != 0 || is_fru == 0) {
2N/A /* This node is not a FRU. Inherit from parent and return */
2N/A (void) topo_node_fru_set(t_node, NULL, 0, &result);
2N/A return (0);
2N/A }
2N/A
2N/A /*
2N/A * This node is a FRU. Create an FMRI.
2N/A */
2N/A part = pi_get_part(mod, mdp, mde_node);
2N/A rev = pi_get_revision(mod, mdp, mde_node);
2N/A serial = pi_get_serial(mod, mdp, mde_node);
2N/A auth = topo_mod_auth(mod, t_parent);
2N/A frufmri = topo_mod_hcfmri(mod, t_parent, FM_HC_SCHEME_VERSION, name,
2N/A inst, NULL, auth, part, rev, serial);
2N/A if (frufmri == NULL) {
2N/A topo_mod_dprintf(mod, "failed to create FRU: %s\n",
2N/A topo_strerror(topo_mod_errno(mod)));
2N/A }
2N/A nvlist_free(auth);
2N/A topo_mod_strfree(mod, part);
2N/A topo_mod_strfree(mod, rev);
2N/A topo_mod_strfree(mod, serial);
2N/A
2N/A /* Set the FRU, whether NULL or not */
2N/A result = topo_node_fru_set(t_node, frufmri, 0, &err);
2N/A if (result != 0) {
2N/A (void) topo_mod_seterrno(mod, err);
2N/A }
2N/A nvlist_free(frufmri);
2N/A
2N/A return (result);
2N/A}
2N/A
2N/A
2N/Aint
2N/Api_set_label(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, tnode_t *t_node)
2N/A{
2N/A int result;
2N/A int err;
2N/A char *label;
2N/A
2N/A if (mod == NULL || mdp == NULL) {
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * Get the label, if any, from the mde node and apply it as the label
2N/A * for this topology node. Note that a NULL label will inherit the
2N/A * label from topology node's parent.
2N/A */
2N/A label = pi_get_label(mod, mdp, mde_node);
2N/A result = topo_node_label_set(t_node, label, &err);
2N/A topo_mod_strfree(mod, label);
2N/A if (result != 0) {
2N/A (void) topo_mod_seterrno(mod, err);
2N/A topo_mod_dprintf(mod, "pi_set_label: failed with label %s "
2N/A "on node_0x%llx: %s\n", (label == NULL ? "NULL" : label),
2N/A (uint64_t)mde_node, topo_strerror(err));
2N/A }
2N/A
2N/A return (result);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Calculate the system information for a node. Inherit the data if
2N/A * possible, but always create an appropriate property group.
2N/A */
2N/Aint
2N/Api_set_system(topo_mod_t *mod, tnode_t *t_node)
2N/A{
2N/A int result;
2N/A int err;
2N/A struct utsname uts;
2N/A char isa[MAXNAMELEN];
2N/A
2N/A if (mod == NULL || t_node == NULL) {
2N/A return (-1);
2N/A }
2N/A
2N/A result = topo_pgroup_create(t_node, &sys_pgroup, &err);
2N/A if (result != 0 && err != ETOPO_PROP_DEFD) {
2N/A /*
2N/A * We failed to create the property group and it was not
2N/A * already defined. Set the err code and return failure.
2N/A */
2N/A (void) topo_mod_seterrno(mod, err);
2N/A return (-1);
2N/A }
2N/A
2N/A result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
2N/A &err);
2N/A if (result != 0 && err != ETOPO_PROP_DEFD) {
2N/A isa[0] = '\0';
2N/A result = sysinfo(SI_ARCHITECTURE, isa, sizeof (isa));
2N/A if (result == -1) {
2N/A /* Preserve the error and continue */
2N/A topo_mod_dprintf(mod, "pi_set_system: failed to "
2N/A "read SI_ARCHITECTURE: %d\n", errno);
2N/A }
2N/A if (strnlen(isa, MAXNAMELEN) > 0) {
2N/A result = topo_prop_set_string(t_node,
2N/A TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
2N/A TOPO_PROP_IMMUTABLE, isa, &err);
2N/A if (result != 0) {
2N/A /* Preserve the error and continue */
2N/A (void) topo_mod_seterrno(mod, err);
2N/A topo_mod_dprintf(mod, "pi_set_auth: failed to "
2N/A "set property %s (%d) : %s\n",
2N/A TOPO_PROP_ISA, err, topo_strerror(err));
2N/A }
2N/A }
2N/A }
2N/A
2N/A result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM,
2N/A TOPO_PROP_MACHINE, &err);
2N/A if (result != 0 && err != ETOPO_PROP_DEFD) {
2N/A result = uname(&uts);
2N/A if (result == -1) {
2N/A /* Preserve the error and continue */
2N/A (void) topo_mod_seterrno(mod, errno);
2N/A topo_mod_dprintf(mod, "pi_set_system: failed to "
2N/A "read uname: %d\n", errno);
2N/A }
2N/A if (strnlen(uts.machine, sizeof (uts.machine)) > 0) {
2N/A result = topo_prop_set_string(t_node,
2N/A TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE,
2N/A TOPO_PROP_IMMUTABLE, uts.machine, &err);
2N/A if (result != 0) {
2N/A /* Preserve the error and continue */
2N/A (void) topo_mod_seterrno(mod, err);
2N/A topo_mod_dprintf(mod, "pi_set_auth: failed to "
2N/A "set property %s (%d) : %s\n",
2N/A TOPO_PROP_MACHINE, err, topo_strerror(err));
2N/A }
2N/A }
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Obtain high level authority from PRI "component" nodes, create nvlist
2N/A * which is held in the topo snapshot handle.
2N/A *
2N/A * system authority - component node, type="product"
2N/A * component System authority - component node, type="system"
2N/A * chassis authority - component node, type="chassis"
2N/A */
2N/Avoid
2N/Api_set_topo_auth_impl(topo_mod_t *mod, md_t *mdp, mde_cookie_t cookie,
2N/A nvlist_t *nvl, int auth_type)
2N/A{
2N/A int rv;
2N/A char *mfg = NULL;
2N/A char *name = NULL;
2N/A char *part = NULL;
2N/A char *serial = NULL;
2N/A
2N/A /* Manufacturer */
2N/A rv = md_get_prop_str(mdp, cookie, MD_STR_MANUFACTURER, &mfg);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod, "pi_set_topo_auth_impl: failed to read "
2N/A "%s from node_0x%llx\n", MD_STR_MANUFACTURER, cookie);
2N/A }
2N/A /* name */
2N/A rv = md_get_prop_str(mdp, cookie, MD_STR_NAME, &name);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod, "pi_set_topo_auth_impl: failed to read "
2N/A "%s from node_0x%llx\n", MD_STR_NAME, cookie);
2N/A }
2N/A
2N/A /* part number */
2N/A rv = md_get_prop_str(mdp, cookie, MD_STR_PART_NUMBER, &part);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod, "pi_set_topo_auth_impl: failed to read "
2N/A "%s from node_0x%llx\n", MD_STR_PART_NUMBER, cookie);
2N/A }
2N/A
2N/A /* serial number */
2N/A rv = md_get_prop_str(mdp, cookie, MD_STR_SERIAL_NUMBER,
2N/A &serial);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod, "pi_set_topo_auth_impl: failed to read "
2N/A "%s from node_0x%llx\n", MD_STR_SERIAL_NUMBER, cookie);
2N/A }
2N/A
2N/A /* set no values to default values */
2N/A if (mfg == NULL || *mfg == '\0')
2N/A mfg = TOPO_AUTH_UNKNOWN;
2N/A if (name == NULL || *name == '\0')
2N/A name = TOPO_AUTH_UNKNOWN;
2N/A if (part == NULL || *part == '\0')
2N/A part = TOPO_AUTH_UNKNOWN;
2N/A if (serial == NULL || *serial == '\0')
2N/A serial = TOPO_AUTH_UNKNOWN;
2N/A
2N/A topo_mod_dprintf(mod, "pi_set_topo_auth_impl: auth type(%d) "
2N/A "manufacturer(%s) name(%s) part(%s) serial(%s)\n", auth_type,
2N/A mfg ? mfg : "NULL", name ? name : "NULL",
2N/A part ? part : "NULL", serial ? serial : "NULL");
2N/A
2N/A topo_mod_auth_set_nvl(mod, &nvl, auth_type, mfg, name, part, serial);
2N/A}
2N/A
2N/A/*
2N/A * Set the product/system/chassis identity information in the topo handle
2N/A * structures. The values are taken from the PRI.
2N/A */
2N/Aint
2N/Api_set_topo_auth(topo_mod_t *mod, uint32_t version)
2N/A{
2N/A int i;
2N/A int rv;
2N/A int ncomp;
2N/A int sys_done = 0;
2N/A int sc_done = 0;
2N/A int ch_done = 0;
2N/A size_t csize;
2N/A nvlist_t *nvl;
2N/A pi_enum_t pi;
2N/A char *type = NULL;
2N/A mde_cookie_t *component;
2N/A
2N/A /* get PRI */
2N/A rv = pi_ldompri_open(mod, &pi, version);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod,
2N/A "pi_set_topo_auth: failed to get PRI\n");
2N/A return (-1);
2N/A }
2N/A
2N/A /* find the "component" nodes */
2N/A ncomp = pi_find_mdenodes(mod, pi.mdp, MDE_INVAL_ELEM_COOKIE,
2N/A MD_STR_COMPONENT, MD_STR_FWD, &component, &csize);
2N/A if (ncomp <= 0 || component == NULL) {
2N/A /* no "component" PRI nodes found */
2N/A topo_mod_dprintf(mod,
2N/A "pi_set_topo_auth: no components PRI nodes\n");
2N/A pi_ldompri_close(mod, &pi);
2N/A return (-1);
2N/A }
2N/A
2N/A /* allocate the topo authority nvlist */
2N/A rv = topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod, "i_set_topo_auth: "
2N/A "failed to xalloc topo auth nvlist\n");
2N/A topo_mod_free(mod, component, csize);
2N/A pi_ldompri_close(mod, &pi);
2N/A return (-1);
2N/A }
2N/A rv = nvlist_add_uint8(nvl, FM_VERSION, FM_FMRI_AUTH_VERSION);
2N/A if (rv != 0) {
2N/A topo_mod_dprintf(mod, "i_set_topo_auth: "
2N/A "failed to set FM_VERSION\n");
2N/A nvlist_free(nvl);
2N/A topo_mod_free(mod, component, csize);
2N/A pi_ldompri_close(mod, &pi);
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * Search through the PRI for 'component' "type=product",
2N/A * "type=system", and "type=chassis" nodes which contain the
2N/A * identity strings.
2N/A */
2N/A for (i = 0; i < ncomp; i++) {
2N/A rv = md_get_prop_str(pi.mdp, component[i], MD_STR_TYPE, &type);
2N/A if (rv == 0) {
2N/A if (strcmp(type, MD_STR_PRODUCT) == 0) {
2N/A pi_set_topo_auth_impl(mod, pi.mdp, component[i],
2N/A nvl, FM_FMRI_AUTH_TYPE_SYSTEM);
2N/A ++sys_done;
2N/A } else if (strcmp(type, MD_STR_SYSTEM) == 0) {
2N/A pi_set_topo_auth_impl(mod, pi.mdp, component[i],
2N/A nvl, FM_FMRI_AUTH_TYPE_SYS_COMP);
2N/A ++sc_done;
2N/A } else if (strcmp(type, MD_STR_CHASSIS) == 0) {
2N/A pi_set_topo_auth_impl(mod, pi.mdp, component[i],
2N/A nvl, FM_FMRI_AUTH_TYPE_CHASSIS);
2N/A ++ch_done;
2N/A }
2N/A } else {
2N/A topo_mod_dprintf(mod, "pi_set_topo_auth: failed to "
2N/A "read %s from node_0x%llx\n", MD_STR_TYPE,
2N/A component[i]);
2N/A }
2N/A }
2N/A topo_mod_free(mod, component, csize);
2N/A
2N/A /*
2N/A * Older PRIs don't contain the product and/or system component
2N/A * nodes; do it the old fashion way.
2N/A *
2N/A * Since the required PRI nodes to differentiate system and component
2N/A * system data are absent - set them to the same values.
2N/A */
2N/A if (!sys_done || !sc_done) {
2N/A char *prod_name = NULL, *prod_sn = NULL;
2N/A char *str = NULL, *s1 = NULL, *s2 = NULL;
2N/A
2N/A if (sys_done) {
2N/A /* use product name/sn from the product node */
2N/A if ((nvlist_lookup_string(nvl,
2N/A FM_FMRI_AUTH_V1_SYSTEM_NM, &s1) == 0) &&
2N/A s1 != NULL &&
2N/A (strncmp(s1, TOPO_AUTH_UNKNOWN,
2N/A strlen(TOPO_AUTH_UNKNOWN)) != 0))
2N/A prod_name = topo_mod_strdup(mod, s1);
2N/A if ((nvlist_lookup_string(nvl,
2N/A FM_FMRI_AUTH_V1_SYSTEM_SN,
2N/A &s2) == 0) && s2 != NULL &&
2N/A (strncmp(s2, TOPO_AUTH_UNKNOWN,
2N/A strlen(TOPO_AUTH_UNKNOWN)) != 0))
2N/A prod_sn = topo_mod_strdup(mod, s2);
2N/A }
2N/A
2N/A if (prod_name == NULL || prod_sn == NULL) {
2N/A char *s1 = NULL, *s2 = NULL;
2N/A /* use product name/sn from the platform node */
2N/A pi_get_platform(mod, pi.mdp, &s1, &s2);
2N/A if (prod_name == NULL)
2N/A prod_name = topo_mod_strdup(mod, s1);
2N/A if (prod_sn == NULL)
2N/A prod_sn = topo_mod_strdup(mod, s2);
2N/A if (s1 != NULL)
2N/A topo_mod_strfree(mod, s1);
2N/A if (s2 != NULL)
2N/A topo_mod_strfree(mod, s2);
2N/A }
2N/A
2N/A topo_mod_dprintf(mod, "pi_set_topo_auth: set sys/comp "
2N/A "from platform node name(%s) serial(%s)\n",
2N/A prod_name ? prod_name : "NULL",
2N/A prod_sn ? prod_sn : "NULL");
2N/A topo_mod_auth_set_nvl(mod, &nvl, FM_FMRI_AUTH_TYPE_SYSTEM,
2N/A TOPO_AUTH_UNKNOWN, prod_name, TOPO_AUTH_UNKNOWN, prod_sn);
2N/A topo_mod_auth_set_nvl(mod, &nvl, FM_FMRI_AUTH_TYPE_SYS_COMP,
2N/A TOPO_AUTH_UNKNOWN, prod_name, TOPO_AUTH_UNKNOWN, prod_sn);
2N/A
2N/A /* if chassis name is "unknown" set to the product name */
2N/A if ((nvlist_lookup_string(nvl, FM_FMRI_AUTH_V1_CHASSIS_NM,
2N/A &str) == 0) && ((str == NULL) ||
2N/A (strcmp(str, TOPO_AUTH_UNKNOWN) == 0))) {
2N/A topo_mod_dprintf(mod,
2N/A "pi_set_topo_auth: set %s from prod_name (%s)\n",
2N/A FM_FMRI_AUTH_V1_CHASSIS_NM, prod_name);
2N/A (void) nvlist_add_string(nvl,
2N/A FM_FMRI_AUTH_V1_CHASSIS_NM, prod_name);
2N/A }
2N/A
2N/A if (prod_name != NULL) {
2N/A topo_mod_strfree(mod, prod_name);
2N/A }
2N/A if (prod_sn != NULL) {
2N/A topo_mod_strfree(mod, prod_sn);
2N/A }
2N/A }
2N/A
2N/A /* copy the nvlist to the topo handle */
2N/A topo_mod_auth_set_th(mod, nvl);
2N/A
2N/A /* free the nvlist */
2N/A nvlist_free(nvl);
2N/A
2N/A /* close up the PRI connection */
2N/A pi_ldompri_close(mod, &pi);
2N/A return (0);
2N/A}
2N/A
2N/A
2N/Atnode_t *
2N/Api_node_bind(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
2N/A tnode_t *t_parent, const char *hc_name, topo_instance_t inst,
2N/A nvlist_t *fmri)
2N/A{
2N/A int result;
2N/A tnode_t *t_node;
2N/A
2N/A if (t_parent == NULL) {
2N/A topo_mod_dprintf(mod,
2N/A "cannot bind for node_0x%llx instance %d type %s\n",
2N/A (uint64_t)mde_node, inst, hc_name);
2N/A return (NULL);
2N/A }
2N/A
2N/A /* Bind this node to the parent */
2N/A t_node = topo_node_bind(mod, t_parent, hc_name, inst, fmri);
2N/A if (t_node == NULL) {
2N/A topo_mod_dprintf(mod,
2N/A "failed to bind node_0x%llx instance %d: %s\n",
2N/A (uint64_t)mde_node, (uint32_t)inst,
2N/A topo_strerror(topo_mod_errno(mod)));
2N/A return (NULL);
2N/A }
2N/A topo_mod_dprintf(mod, "bound node_0x%llx instance %d type %s\n",
2N/A (uint64_t)mde_node, inst, hc_name);
2N/A
2N/A /*
2N/A * We have bound the node. Now decorate it with an appropriate
2N/A * FRU and label (which may be inherited from the parent).
2N/A *
2N/A * The disk enumerator requires that 'bay' nodes not set their
2N/A * fru property.
2N/A */
2N/A if (strncmp(hc_name, BAY, strlen(BAY)) != 0) {
2N/A result = pi_set_frufmri(mod, mdp, mde_node, hc_name, inst,
2N/A t_parent, t_node);
2N/A if (result != 0) {
2N/A /*
2N/A * Though we have failed to set the FRU FMRI we still
2N/A * continue. The module errno is set by the called
2N/A * routine, so we report the problem and move on.
2N/A */
2N/A topo_mod_dprintf(mod,
2N/A "failed to set FRU FMRI for node_0x%llx\n",
2N/A (uint64_t)mde_node);
2N/A }
2N/A }
2N/A
2N/A result = pi_set_label(mod, mdp, mde_node, t_node);
2N/A if (result != 0) {
2N/A /*
2N/A * Though we have failed to set the label, we still continue.
2N/A * The module errno is set by the called routine, so we report
2N/A * the problem and move on.
2N/A */
2N/A topo_mod_dprintf(mod, "failed to set label for node_0x%llx\n",
2N/A (uint64_t)mde_node);
2N/A }
2N/A
2N/A result = pi_set_auth(mod, mdp, mde_node, t_parent, t_node);
2N/A if (result != 0) {
2N/A /*
2N/A * Though we have failed to set the authority, we still
2N/A * continue. The module errno is set by the called routine, so
2N/A * we report the problem and move on.
2N/A */
2N/A topo_mod_dprintf(mod, "failed to set authority for "
2N/A "node_0x%llx\n", (uint64_t)mde_node);
2N/A }
2N/A
2N/A result = pi_set_system(mod, t_node);
2N/A if (result != 0) {
2N/A /*
2N/A * Though we have failed to set the system group, we still
2N/A * continue. The module errno is set by the called routine, so
2N/A * we report the problem and move on.
2N/A */
2N/A topo_mod_dprintf(mod, "failed to set system for node_0x%llx\n",
2N/A (uint64_t)mde_node);
2N/A }
2N/A
2N/A return (t_node);
2N/A}