/*
* 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
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* PICL plug-in that creates device tree nodes for all platforms
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <stdlib.h>
#include <assert.h>
#include <alloca.h>
#include <unistd.h>
#include <stropts.h>
#include <syslog.h>
#include <libdevinfo.h>
#include <fcntl.h>
#include <picl.h>
#include <picltree.h>
#include <sys/processor.h>
#include <kstat.h>
#include <dirent.h>
#include <libintl.h>
#include <pthread.h>
#include <libnvpair.h>
#include <sys/systeminfo.h>
#include <sys/openpromio.h>
#include "picldevtree.h"
/*
* Plugin registration entry points
*/
static void picldevtree_register(void);
static void picldevtree_init(void);
static void picldevtree_fini(void);
#pragma init(picldevtree_register)
/*
* Log message texts
*/
#define PICL_EVENT_DROPPED \
gettext("SUNW_picldevtree '%s' event dropped.\n")
/*
* Macro to get PCI device id (from IEEE 1275 spec)
*/
/*
* Local variables
*/
"SUNW_picldevtree",
};
/*
* Debug enabling environment variable
*/
static int picldevtree_debug = 0;
/* MAX_NAMEVAL_SIZE */
{ "SUNW,bpp", PICL_CLASS_PARALLEL},
{ "parallel", PICL_CLASS_PARALLEL},
{ "floppy", PICL_CLASS_FLOPPY},
{ "memory", PICL_CLASS_MEMORY},
{ "ebus", PICL_CLASS_EBUS},
{ "i2c", PICL_CLASS_I2C},
{ "usb", PICL_CLASS_USB},
{ "isa", PICL_CLASS_ISA},
{ "dma", PICL_CLASS_DMA},
{ "keyboard", PICL_CLASS_KEYBOARD},
{ "mouse", PICL_CLASS_MOUSE},
{ "fan-control", PICL_CLASS_FAN_CONTROL},
{ "sc", PICL_CLASS_SYSTEM_CONTROLLER},
{ "dimm", PICL_CLASS_SEEPROM},
{ "dimm-fru", PICL_CLASS_SEEPROM},
{ "cpu", PICL_CLASS_SEEPROM},
{ "cpu-fru", PICL_CLASS_SEEPROM},
{ "flashprom", PICL_CLASS_FLASHPROM},
{ "temperature", PICL_CLASS_TEMPERATURE_DEVICE},
{ "motherboard", PICL_CLASS_SEEPROM},
{ "motherboard-fru", PICL_CLASS_SEEPROM},
{ "motherboard-fru-prom", PICL_CLASS_SEEPROM},
{ "pmu", PICL_CLASS_PMU},
{ "sound", PICL_CLASS_SOUND},
{ "firewire", PICL_CLASS_FIREWIRE},
{ "i2c-at34c02", PICL_CLASS_SEEPROM},
{ "hardware-monitor", PICL_CLASS_HARDWARE_MONITOR},
{ "", ""}
};
/* MAX_NAMEVAL_SIZE */
{ "cpus", PICL_CLASS_I86CPUS},
{ "cpu", PICL_CLASS_CPU},
{ "memory", PICL_CLASS_MEMORY},
{ "asy", PICL_CLASS_SERIAL},
{ "", ""}
};
{ "reg", PICL_PTYPE_BYTEARRAY},
{ "device_type", PICL_PTYPE_CHARSTRING},
{ "ranges", PICL_PTYPE_BYTEARRAY},
{ "status", PICL_PTYPE_CHARSTRING},
{ "compatible", PICL_PTYPE_CHARSTRING},
{ "interrupts", PICL_PTYPE_BYTEARRAY},
{ "model", PICL_PTYPE_CHARSTRING},
{ "address", PICL_PTYPE_BYTEARRAY},
{ "vendor-id", PICL_PTYPE_UNSIGNED_INT},
{ "device-id", PICL_PTYPE_UNSIGNED_INT},
{ "revision-id", PICL_PTYPE_UNSIGNED_INT},
{ "class-code", PICL_PTYPE_UNSIGNED_INT},
{ "min-grant", PICL_PTYPE_UNSIGNED_INT},
{ "max-latency", PICL_PTYPE_UNSIGNED_INT},
{ "devsel-speed", PICL_PTYPE_UNSIGNED_INT},
{ "subsystem-id", PICL_PTYPE_UNSIGNED_INT},
{ "subsystem-vendor-id", PICL_PTYPE_UNSIGNED_INT},
{ "assigned-addresses", PICL_PTYPE_BYTEARRAY},
{ "configuration#", PICL_PTYPE_UNSIGNED_INT},
{ "assigned-address", PICL_PTYPE_UNSIGNED_INT},
{ "#address-cells", PICL_PTYPE_UNSIGNED_INT},
{ "#size-cells", PICL_PTYPE_UNSIGNED_INT},
{ "clock-frequency", PICL_PTYPE_UNSIGNED_INT},
{ "scsi-initiator-id", PICL_PTYPE_UNSIGNED_INT},
{ "differential", PICL_PTYPE_UNSIGNED_INT},
{ "idprom", PICL_PTYPE_BYTEARRAY},
{ "bus-range", PICL_PTYPE_BYTEARRAY},
{ "alternate-reg", PICL_PTYPE_BYTEARRAY},
{ "power-consumption", PICL_PTYPE_BYTEARRAY},
{ "slot-names", PICL_PTYPE_BYTEARRAY},
{ "burst-sizes", PICL_PTYPE_UNSIGNED_INT},
{ "up-burst-sizes", PICL_PTYPE_UNSIGNED_INT},
{ "slot-address-bits", PICL_PTYPE_UNSIGNED_INT},
{ "eisa-slots", PICL_PTYPE_BYTEARRAY},
{ "dma", PICL_PTYPE_BYTEARRAY},
{ "slot-names-index", PICL_PTYPE_UNSIGNED_INT},
{ "pnp-csn", PICL_PTYPE_UNSIGNED_INT},
{ "pnp-data", PICL_PTYPE_BYTEARRAY},
{ "description", PICL_PTYPE_CHARSTRING},
{ "pnp-id", PICL_PTYPE_CHARSTRING},
{ "max-frame-size", PICL_PTYPE_UNSIGNED_INT},
{ "address-bits", PICL_PTYPE_UNSIGNED_INT},
{ "local-mac-address", PICL_PTYPE_BYTEARRAY},
{ "mac-address", PICL_PTYPE_BYTEARRAY},
{ "character-set", PICL_PTYPE_CHARSTRING},
{ "available", PICL_PTYPE_BYTEARRAY},
{ "port-wwn", PICL_PTYPE_BYTEARRAY},
{ "node-wwn", PICL_PTYPE_BYTEARRAY},
{ "width", PICL_PTYPE_UNSIGNED_INT},
{ "linebytes", PICL_PTYPE_UNSIGNED_INT},
{ "height", PICL_PTYPE_UNSIGNED_INT},
{ "banner-name", PICL_PTYPE_CHARSTRING},
{ "reset-reason", PICL_PTYPE_CHARSTRING},
{ "implementation#", PICL_PTYPE_UNSIGNED_INT},
{ "version#", PICL_PTYPE_UNSIGNED_INT},
{ "icache-size", PICL_PTYPE_UNSIGNED_INT},
{ "icache-line-size", PICL_PTYPE_UNSIGNED_INT},
{ "icache-associativity", PICL_PTYPE_UNSIGNED_INT},
{ "l1-icache-size", PICL_PTYPE_UNSIGNED_INT},
{ "l1-icache-line-size", PICL_PTYPE_UNSIGNED_INT},
{ "l1-icache-associativity", PICL_PTYPE_UNSIGNED_INT},
{ "#itlb-entries", PICL_PTYPE_UNSIGNED_INT},
{ "dcache-size", PICL_PTYPE_UNSIGNED_INT},
{ "dcache-line-size", PICL_PTYPE_UNSIGNED_INT},
{ "dcache-associativity", PICL_PTYPE_UNSIGNED_INT},
{ "l1-dcache-size", PICL_PTYPE_UNSIGNED_INT},
{ "l1-dcache-line-size", PICL_PTYPE_UNSIGNED_INT},
{ "l1-dcache-associativity", PICL_PTYPE_UNSIGNED_INT},
{ "#dtlb-entries", PICL_PTYPE_UNSIGNED_INT},
{ "ecache-size", PICL_PTYPE_UNSIGNED_INT},
{ "ecache-line-size", PICL_PTYPE_UNSIGNED_INT},
{ "ecache-associativity", PICL_PTYPE_UNSIGNED_INT},
{ "l2-cache-size", PICL_PTYPE_UNSIGNED_INT},
{ "l2-cache-line-size", PICL_PTYPE_UNSIGNED_INT},
{ "l2-cache-associativity", PICL_PTYPE_UNSIGNED_INT},
{ "l2-cache-sharing", PICL_PTYPE_BYTEARRAY},
{ "mask#", PICL_PTYPE_UNSIGNED_INT},
{ "manufacturer#", PICL_PTYPE_UNSIGNED_INT},
{ "sparc-version", PICL_PTYPE_UNSIGNED_INT},
{ "version", PICL_PTYPE_CHARSTRING},
{ "cpu-model", PICL_PTYPE_UNSIGNED_INT},
{ "memory-layout", PICL_PTYPE_BYTEARRAY},
{ "#interrupt-cells", PICL_PTYPE_UNSIGNED_INT},
{ "interrupt-map", PICL_PTYPE_BYTEARRAY},
{ "interrupt-map-mask", PICL_PTYPE_BYTEARRAY}
};
static int builtin_map_size = 0;
static int snapshot_stale;
/*
* UnitAddress mapping table
*/
{NULL, encode_default_unitaddr, 0}
};
/*
* The mc event completion handler.
* The arguments are event name buffer and a packed nvlist buffer
* with the size specifying the size of unpacked nvlist. These
* buffers are deallcoated here.
*
* Also, if a memory controller node is being removed then destroy the
* PICL subtree associated with that memory controller.
*/
static void
{
(void) nvlist_lookup_uint64(unpack_nvl,
if (picldevtree_debug)
"picldevtree: destroying_node:%llx\n",
mch);
(void) ptree_destroy_node(mch);
}
}
}
/*
* Functions to post memory controller change event
*/
static int
{
char *pack_buf;
char *ev_name;
return (-1);
return (-1);
}
return (-1);
}
if (picldevtree_debug)
"picldevtree: posting MC event ename:%s nodeh:%llx\n",
return (-1);
}
return (0);
}
/*
* Lookup a name in the name to class map tables
*/
static int
{
int i;
/*
* check name to class mapping in conf file
*/
return (0);
}
}
/*
* check name to class mapping in builtin table
*/
if (builtin_map_ptr == NULL)
return (-1);
for (i = 0; i < builtin_map_size; ++i)
return (0);
}
return (-1);
}
/*
* Lookup a prop name in the pname to class map table
*/
static int
{
int i;
for (i = 0; i < PNAME_MAP_SIZE; ++i)
return (0);
}
return (-1);
}
/*
* Return the number of strings in the buffer
*/
static int
{
int count;
char *lastnull;
char *nullptr;
count = 1;
count++;
return (count);
}
/*
* Return 1 if the node has a "reg" property
*/
static int
{
int *pdata;
int dret;
if (dret > 0)
return (1);
if (!ph)
return (0);
return (dret < 0 ? 0 : 1);
}
/*
* This function copies a PROM node's device_type property value into the
* buffer given by outbuf. The buffer size is PICL_CLASSNAMELEN_MAX.
*
* We reclassify device_type 'fru-prom' to PICL class 'seeprom'
* for FRUID support.
*/
static int
{
char *pdata;
char *pdatap;
int dret;
int i;
&pdata);
if (dret <= 0) {
if (!ph)
return (-1);
&pdata);
if (dret <= 0) {
return (-1);
}
}
if (dret != 1) {
/*
* multiple strings
*/
for (i = 0; i < (dret - 1); ++i) {
pdatap++;
}
}
/*
* Use PICL 'seeprom' class for fru-prom device types
*/
} else {
}
return (0);
}
/*
* Get the minor node name in the class buffer passed
*/
static int
{
char *mi_nodetype;
char *mi_name;
/* get minor node type */
if (mi_node == DI_MINOR_NIL)
return (-1);
return (-1);
return (0);
}
/*
* convert the string to the picl class for non-peudo nodes
*/
return (-1);
char *colon;
return (-1);
++colon;
} else { /* unrecognized type, return name */
return (-1);
}
return (0);
}
/*
* Derive PICL class using the compatible property of the node
* We use the map table to map compatible property value to
* class.
*/
static int
{
char *pdata;
char *pdatap;
int dret;
int i;
&pdata);
if (dret <= 0) {
if (!ph)
return (-1);
&pdata);
if (dret <= 0) {
return (-1);
}
}
for (i = 0; i < dret; ++i) {
return (0);
pdatap++;
}
return (-1);
}
/*
* For a given device node find the PICL class to use. Returns NULL
* for non device node
*/
static int
{
/*
* discard place holder nodes
*/
return (-1);
return (0);
}
return (0); /* return device_type value */
}
return (0); /* derive class using compatible prop */
}
return (0); /* derive class using name prop */
return (0);
}
}
/*
* Add a table property containing nrows with one column
*/
static int
unsigned int nrows)
{
int err;
unsigned int i;
unsigned int j;
int len;
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
(void) ptree_destroy_prop(proph);
return (PICL_FAILURE);
}
for (j = 0; j < nrows; ++j) {
if (err != PICL_SUCCESS)
break;
if (err != PICL_SUCCESS)
break;
&proprow[j]);
if (err != PICL_SUCCESS)
break;
}
if (err != PICL_SUCCESS) {
for (i = 0; i < j; ++i)
(void) ptree_destroy_prop(proprow[i]);
(void) ptree_delete_prop(proph);
(void) ptree_destroy_prop(proph);
return (err);
}
return (PICL_SUCCESS);
}
/*
* return 1 if this node has this property with the given value
*/
static int
const char *pval)
{
char *pvalbuf;
int err;
int len;
return (0);
return (0); /* not string prop */
return (0);
return (1); /* prop match */
return (0);
}
/*
* This function recursively searches the tree for a node that has
* the specified string property name and value
*/
static int
{
int err;
sizeof (picl_nodehdl_t))) {
if (err != PICL_SUCCESS)
return (err);
return (PICL_SUCCESS);
}
return (PICL_SUCCESS);
}
return (PICL_FAILURE);
}
/*
* check if this is a string prop
* If the length is less than or equal to 4, assume it's not a string list.
* If there is any non-ascii or non-print char, it's not a string prop
* If \0 is in the first char or any two consecutive \0's exist,
* it's a bytearray prop.
* Return value: 0 means it's not a string prop, 1 means it's a string prop
*/
static int
{
int i;
int lastindex;
switch (len) {
case 1:
return (0);
return (1);
case 2:
case 3:
case 4:
for (i = 0; i < lastindex; i++)
return (0);
return (1);
default:
if (len <= 0)
return (0);
for (i = 0; i < len; i++) {
if (pdata[i] != '\0')
return (0);
/*
* if the null char is in the first char
* or two consecutive nulls' exist,
* it's a bytearray prop
*/
if ((i == 0) || ((i - prevnull) == 1))
return (0);
prevnull = i;
}
}
break;
}
return (1);
}
/*
* This function counts the number of strings in the value buffer pdata
* and creates a property.
* If there is only one string in the buffer, pdata, a charstring property
* type is created and added.
* If there are more than one string in the buffer, pdata, then a table
* of charstrings is added.
*/
static int
int retval)
{
int err;
int strcount;
char *strdat;
/*
* append the null char at the end of string when there is
* no null terminator
*/
retval++;
} else {
}
/*
* If it's a string list, create a table prop
*/
if (strcount > 1) {
if (err != PICL_SUCCESS)
return (err);
} else {
NULL);
if (err != PICL_SUCCESS)
return (err);
}
return (PICL_SUCCESS);
}
/*
* Add the OBP properties as properties of the PICL node
*/
static int
{
char *pname;
unsigned char *pdata;
int retval;
int err;
if (!ph)
return (PICL_FAILURE);
if (retval < 0) {
return (PICL_SUCCESS);
}
if (retval == 0) {
if (err != PICL_SUCCESS) {
return (err);
}
NULL);
continue;
}
/*
* Get the prop type from pname map table
*/
if (type == PICL_PTYPE_CHARSTRING) {
if (err != PICL_SUCCESS) {
return (err);
}
continue;
}
if (err != PICL_SUCCESS) {
return (err);
}
switch (retval) {
case sizeof (uint8_t):
/*FALLTHROUGH*/
case sizeof (uint16_t):
/*FALLTHROUGH*/
case sizeof (uint32_t):
break;
default:
break;
}
if (err != PICL_SUCCESS) {
return (err);
}
} else {
retval);
if (err != PICL_SUCCESS) {
return (err);
}
}
}
return (PICL_SUCCESS);
}
static void
{
}
static void
{
if (len == 1)
else
}
static void
{
if (len == 1) {
} else {
}
}
static void
{
}
static const char *
{
switch (st) {
case DI_PATH_STATE_ONLINE:
return ("online");
case DI_PATH_STATE_STANDBY:
return ("standby");
case DI_PATH_STATE_OFFLINE:
return ("offline");
case DI_PATH_STATE_FAULT:
return ("faulted");
}
return ("unknown");
}
/*
* This function is the volatile property handler for the multipath node
* "State" property. It must locate the associated devinfo node in order to
* determine the current state. Since the devinfo node can have multiple
* paths the devfs_path is used to locate the correct path.
*/
static int
{
int err;
/*
* The parent node represents the vHCI.
*/
sizeof (picl_nodehdl_t));
if (err != PICL_SUCCESS) {
return (PICL_SUCCESS);
}
/*
* The PICL_PROP_DEVFS_PATH property will be used to locate the
* devinfo node for the vHCI driver.
*/
sizeof (devfs_path));
if (err != PICL_SUCCESS) {
return (PICL_SUCCESS);
}
/*
* Find the di_node for the vHCI driver. It will be used to scan
* the path information nodes.
*/
if (di_root == DI_NODE_NIL) {
return (PICL_SUCCESS);
}
if (di_node == DI_NODE_NIL) {
return (PICL_SUCCESS);
}
/*
* The devfs_path will be used below to match the
* proper path information node.
*/
devfs_path, sizeof (devfs_path));
if (err != PICL_SUCCESS) {
return (PICL_SUCCESS);
}
/*
* Scan the path information nodes looking for the matching devfs
* path. When found obtain the state information.
*/
char *di_path;
if (phci_node == DI_PATH_NIL)
continue;
if (di_path) {
continue;
}
break;
}
}
return (PICL_SUCCESS);
}
static void
{
int di_ptype;
char *di_val;
int *idata;
char *sdata;
unsigned char *bdata;
int len;
switch (di_ptype) {
case DI_PROP_TYPE_BOOLEAN:
break;
case DI_PROP_TYPE_INT:
case DI_PROP_TYPE_INT64:
if (len < 0)
/* Received error, so ignore prop */
break;
break;
case DI_PROP_TYPE_STRING:
if (len <= 0)
break;
break;
case DI_PROP_TYPE_BYTE:
if (len < 0)
break;
break;
case DI_PROP_TYPE_UNKNOWN:
/*
* Unknown type, we'll try and guess what it should be.
*/
len);
break;
}
if (len > 0) {
break;
}
if (len > 0)
else if (len == 0)
di_val);
break;
case DI_PROP_TYPE_UNDEF_IT:
break;
default:
break;
}
}
/*
* Add nodes for path information (PSARC/1999/647, PSARC/2008/437)
*/
static void
{
int err;
int instance;
char *di_val;
if (phci_node == DI_PATH_NIL)
continue;
if (err != PICL_SUCCESS)
continue;
NULL);
if (di_val) {
(void) ptree_init_propinfo(&propinfo,
(void) ptree_create_and_add_prop(nodeh,
}
}
}
}
/*
* Add properties provided by libdevinfo
*/
static void
{
int instance;
char *di_val;
int di_ptype;
char *sdata;
unsigned char *bdata;
int *idata;
int len;
if (di_val) {
NULL);
}
if (di_val) {
NULL);
}
if (di_val) {
NULL);
}
if (di_val) {
NULL);
}
di_prop != DI_PROP_NIL;
switch (di_ptype) {
case DI_PROP_TYPE_BOOLEAN:
break;
case DI_PROP_TYPE_INT:
if (len < 0)
/* Received error, so ignore prop */
break;
break;
case DI_PROP_TYPE_STRING:
if (len < 0)
break;
break;
case DI_PROP_TYPE_BYTE:
if (len < 0)
break;
break;
case DI_PROP_TYPE_UNKNOWN:
/*
* Unknown type, we'll try and guess what it should be.
*/
len);
break;
}
if (len > 0) {
break;
}
if (len > 0)
else if (len == 0)
di_val);
break;
case DI_PROP_TYPE_UNDEF_IT:
break;
default:
break;
}
}
}
/*
* This function creates the /obp node in the PICL tree for OBP nodes
* without a device type class.
*/
static int
{
int err;
PICL_CLASS_PICL, &tmph);
if (err != PICL_SUCCESS)
return (err);
return (PICL_SUCCESS);
}
/*
* This function creates the /platform node in the PICL tree and
* its properties. It sets the "platform-name" property to the
* platform name
*/
static int
{
int err;
char *nodename;
return (PICL_FAILURE);
err = 0;
if (err < 0)
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
return (PICL_SUCCESS);
}
/*
* This function creates a node in /obp tree for the libdevinfo handle.
*/
static int
{
int err;
char *nodename;
return (PICL_FAILURE);
return (PICL_FAILURE);
return (PICL_FAILURE);
if (err != PICL_SUCCESS)
return (err);
return (PICL_SUCCESS);
}
/*
* This function creates a PICL node in /platform tree for a device
*/
static int
{
int err;
if (err != PICL_SUCCESS)
return (err);
return (err);
}
/*
* Create a subtree of "picl" class nodes in /obp for these nodes
*/
static int
{
int err;
if (err != PICL_SUCCESS)
return (err);
return (PICL_SUCCESS);
}
/*
* Process the libdevinfo device tree and create nodes in /platform or /obp
* PICL tree.
*
* This routine traverses the immediate children of "dinode" device and
* determines the node class for that child. If it finds a valid class
* name, then it builds a PICL node under /platform subtree and calls itself
* recursively to construct the subtree for that child node. Otherwise, if
* the parent_class is NULL, then it constructs a node and subtree under /obp
* subtree.
*
* Note that we skip the children nodes that don't have a valid class name
* and the parent_class is non NULL to prevent creation of any placeholder
* nodes (such as sd,...).
*/
static int
{
char *nodename;
int err;
err = PICL_SUCCESS;
continue;
if (err == 0) {
if (err != PICL_SUCCESS)
return (err);
} else if (parent_class == NULL)
else
continue;
/*
* if parent_class is non NULL, skip the children nodes
* that don't have a valid device class - eliminates
* placeholder nodes (sd,...) from being created.
*/
}
return (err);
}
/*
* This function is called from the event handler called from the daemon
* on PICL events.
*
* This routine traverses the children of the "dinode" device and
* creates a PICL node for each child not found in the PICL tree and
* invokes itself recursively to create a subtree for the newly created
* child node. It also checks if the node being created is a meory
* controller. If so, it posts PICLEVENT_MC_ADDED PICL event to the PICL
* framework.
*/
static int
{
char *nodename;
char *path_buf;
char *strp;
int gotit;
int err;
continue;
continue;
}
if (err < 0) {
continue;
}
/*
* this is quite complicated - both path_buf and any nodes
* already in the picl tree may, or may not, have the
* @<unit_addr> at the end of their names. So we must
* take path_buf and work out what the device path would
* be both with and without the unit_address, then search
* the picl tree for both forms.
*/
/*
* This is an unattached node - so the path is not
* unique. Need to find out which node it is.
* Find the unit_address from the OBP or devinfo
* properties.
*/
if (err != PICL_SUCCESS)
return (err);
sizeof (unitaddr));
if (err != PICL_SUCCESS)
return (err);
(void) ptree_destroy_node(chdh);
path_buf);
} else {
/*
* this is an attached node - so the path is unique
*/
path_buf);
path_buf);
*strp++ = '\0';
strp);
}
/*
* first look for node with unit address in devfs_path
*/
&nh) == PICL_SUCCESS) {
/*
* node already there - there's nothing we need to do
*/
if (picldevtree_debug > 1)
"update_subtree: path:%s node exists\n",
path_buf);
continue;
}
/*
* now look for node without unit address in devfs_path.
* This might be just one out of several
* nodes - need to check all siblings
*/
return (err);
gotit = 0;
while (err == PICL_SUCCESS) {
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
gotit = 1;
break;
}
}
if (err != PICL_SUCCESS)
break;
}
if (gotit) {
/*
* node already there - there's nothing we need to do
*/
if (picldevtree_debug > 1)
"update_subtree: path:%s node exists\n",
path_buf);
continue;
}
&chdh) == PICL_SUCCESS) {
if (picldevtree_debug)
"picldevtree: added node:%s path:%s\n",
}
}
}
return (PICL_SUCCESS);
}
/*
* Check for a stale OBP node. EINVAL is returned from the openprom(7D) driver
* if the nodeid stored in the snapshot is not valid.
*/
static int
{
errno = 0;
snapshot_stale = 1;
return (DI_WALK_TERMINATE);
}
return (DI_WALK_CONTINUE);
}
/*
* Walk the snapshot and check the OBP properties of each node.
*/
static int
{
snapshot_stale = 0;
return (snapshot_stale);
}
/*
* This function processes the data from libdevinfo and creates nodes
* in the PICL tree.
*/
static int
{
int err;
/*
* Use DINFOCACHE so that we obtain all attributes for all
* of all drivers). Once the (on-disk) cache file is built, it
* exists over a reboot and can be read into memory at a very
* low cost.
*/
return (PICL_FAILURE);
return (PICL_FAILURE);
/*
* Check if the snapshot cache contains stale OBP nodeid references.
* If it does release the snapshot and obtain a live snapshot from the
* kernel.
*/
if (is_snapshot_stale(di_root)) {
DI_NODE_NIL) {
return (PICL_FAILURE);
}
}
/*
* create platform PICL node using di_root node
*/
if (err != PICL_SUCCESS) {
return (PICL_FAILURE);
}
if (err != PICL_SUCCESS) {
return (PICL_FAILURE);
}
if (ph) {
}
return (err);
}
/*
* This function returns the integer property value
*/
static int
{
int err;
sizeof (int));
return (err);
}
/*
* This function returns the port ID (or CPU ID in the case of CMP cores)
* of the specific CPU node handle. If upa_portid exists, return its value.
*/
static int
{
int err;
if (err == PICL_SUCCESS)
return (err);
if (err == PICL_SUCCESS)
return (err);
}
return (PICL_FAILURE);
}
/*
* This function is the volatile read access function of CPU state
* property
*/
static int
{
int id;
int err;
if (err != PICL_SUCCESS)
return (err);
case P_ONLINE:
break;
case P_OFFLINE:
break;
case P_NOINTR:
break;
case P_SPARE:
break;
case P_FAULTED:
break;
case P_POWEROFF:
break;
default:
break;
}
return (PICL_SUCCESS);
}
/*
* This function is the volatile read access function of CPU processor_type
* property
*/
static int
{
int id;
int err;
if (err != PICL_SUCCESS)
return (err);
}
return (PICL_SUCCESS);
}
/*
* This function is the volatile read access function of CPU fputypes
* property
*/
static int
{
int id;
int err;
if (err != PICL_SUCCESS)
return (err);
}
return (PICL_SUCCESS);
}
/*
* This function is the volatile read access function of CPU StateBegin
* property. To minimize overhead, use kstat_chain_update() to refresh
* the kstat header info as opposed to invoking kstat_open() every time.
*/
static int
{
int err;
int cpu_id;
if (err != PICL_SUCCESS)
return (err);
(void) pthread_mutex_lock(&kc_mutex);
kc = kstat_open();
(void) kstat_close(kc);
kc = kstat_open();
}
(void) pthread_mutex_unlock(&kc_mutex);
return (PICL_FAILURE);
}
/* Get the state_begin from kstat */
(void) pthread_mutex_unlock(&kc_mutex);
return (PICL_FAILURE);
}
if (kn) {
err = PICL_SUCCESS;
} else
err = PICL_FAILURE;
(void) pthread_mutex_unlock(&kc_mutex);
return (err);
}
/*
* This function adds CPU information to the CPU nodes
*/
/* ARGSUSED */
static int
{
int err;
int cpu_id;
if (err != PICL_SUCCESS)
return (PICL_WALK_CONTINUE);
/*
* Check to make sure that the CPU is still present, i.e. that it
* has not been DR'ed out of the system.
*/
if (picldevtree_debug)
"picldevtree: cpu %d (%llx) does not exist - "
(void) ptree_destroy_node(cpuh);
return (PICL_WALK_CONTINUE);
}
if (err != PICL_SUCCESS)
return (PICL_WALK_CONTINUE);
return (PICL_WALK_CONTINUE);
}
/*
* This function sets up the "ID" property in every CPU nodes
* and adds processor info
*/
static int
{
int err;
return (err);
}
/*
* This function format's the manufacture's information for FFB display
* devices
*/
static void
{
/*
* Format the manufacturer's info. Note a small inconsistency we
* have to work around - Brooktree has it's part number in decimal,
* while Mitsubishi has it's part number in hex.
*/
case MANF_BROOKTREE:
break;
case MANF_MITSUBISHI:
break;
default:
"JED code %d, Part num 0x%x, version %d",
}
}
/*
* If it's an ffb device, open ffb devices and return PICL_SUCCESS
*/
static int
{
char *devp;
int err;
int tmpfd;
/* Get the devfs_path of the ffb devices */
sizeof (devfs_path));
if (err != PICL_SUCCESS)
return (err);
/* Get the device node name */
return (PICL_FAILURE);
*devp = '\0';
++devp;
/*
* Check if device node name has the ffb string
* If not, assume it's not a ffb device.
*/
return (PICL_FAILURE);
/*
* Get the parent path of the ffb device node.
*/
/*
* Since we don't know ffb's minor nodename,
* we need to search all the devices under its
* parent dir by comparing the node name
*/
return (PICL_FAILURE);
if (tmpfd < 0)
continue;
return (PICL_SUCCESS);
}
}
return (PICL_FAILURE);
}
/*
* This function recursively searches the tree for ffb display devices
* and add ffb config information
*/
static int
{
int err;
int fd;
int board_rev;
&nodeh, sizeof (picl_nodehdl_t))) {
if (err != PICL_SUCCESS)
return (err);
if ((err == PICL_SUCCESS) &&
if ((err == PICL_SUCCESS) &&
(void) ptree_init_propinfo(&pinfo,
sizeof (int), PICL_PROP_FFB_BOARD_REV,
(void) ptree_init_propinfo(&pinfo,
(void) ptree_init_propinfo(&pinfo,
NULL);
}
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
static conf_entries_t *
{
return (NULL);
}
return (el);
}
/*
* Reading config order: platform, common
*/
static conf_entries_t *
{
char *nametok;
char *classtok;
return (list);
return (list);
continue;
continue;
continue;
break;
return (list);
}
/*
* Add it to the end of list
*/
else {
}
}
return (list);
}
/*
* Process the devtree conf file and set up the conf_name_class_map list
*/
static void
{
}
}
}
static void
}
}
/*
* Reading config order: platform, common
*/
static asr_conf_entries_t *
{
char *nametok;
char *classtok;
char *statustok;
char *addresstok;
char *propstok;
return (list);
return (list);
continue;
continue;
continue;
continue;
if (addresstok == NULL)
continue;
/*
* props are optional
*/
break;
else
break;
}
/*
* Add it to the end of list
*/
else {
}
}
return (list);
}
/*
* Process the asr conf file
*/
static void
{
}
}
}
/*
* This function reads the export file list from ASR
*/
static int
{
int d;
int listsize;
if (d < 0)
return (0);
(void) close(d);
return (0);
}
listsize);
(void) close(d);
return (0);
}
(void) close(d);
return (0);
}
if (*exportlist == NULL) {
(void) close(d);
return (0);
}
(void) close(d);
return (1);
}
/*
* Parses properties string, fills in triplet structure with first
* type, name, val triplet and returns pointer to next property.
* Returns NULL if no valid triplet found
* CAUTION: drops \0 characters over separator characters: if you
* want to parse the string twice, you'll have to take a copy.
*/
static char *
{
char *prop_name;
char *prop_val;
char *prop_next;
return (NULL);
*prop_name++ = '\0';
return (NULL);
*prop_val++ = '\0';
return (prop_val - 1);
*prop_next++ = '\0';
return (prop_next);
}
static int
{
int err;
if (err != PICL_SUCCESS)
return (err);
return (err);
}
static void
{
char *next;
char *prop_string;
int val;
int err;
return;
/*
* see if the required child node already exists
*/
sizeof (picl_nodehdl_t))) {
if (err != PICL_SUCCESS)
break;
(void *)nodename, PICL_PROPNAMELEN_MAX);
if (err != PICL_SUCCESS)
break;
continue;
/*
* found a candidate child node
*/
if (unitaddr) {
/*
* does it match the required unit address?
*/
if (err == PICL_PROPNOTFOUND)
continue;
if (err != PICL_SUCCESS)
break;
continue;
}
next = "";
} else if (props_copy == NULL) {
if (props_copy == NULL)
return;
next = props_copy;
}
&proph);
if (err != PICL_SUCCESS)
break;
if (err != PICL_SUCCESS)
break;
err = PICL_FAILURE;
case PICL_PTYPE_INT:
case PICL_PTYPE_UNSIGNED_INT:
break;
sizeof (val));
if (err != PICL_SUCCESS)
break;
err = PICL_FAILURE;
break;
case PICL_PTYPE_CHARSTRING:
break;
if (prop_string == NULL)
break;
(void *)prop_string,
if (err != PICL_SUCCESS) {
break;
}
err = PICL_FAILURE;
break;
default:
break;
}
if (err != PICL_SUCCESS) {
break;
}
}
break;
}
}
if (props_copy)
if (found) {
/*
* does the pre-existing node have a status property?
*/
if (err == PICL_PROPNOTFOUND)
if (err != PICL_SUCCESS)
return;
return;
}
/*
* more urgent status now, so replace existing value
*/
if (err != PICL_SUCCESS)
return;
(void) ptree_delete_prop(proph);
(void) ptree_destroy_prop(proph);
if (err != PICL_SUCCESS)
return;
return;
}
/*
* typical case, node needs adding together with a set of properties
*/
PICL_SUCCESS) {
if (unitaddr) {
(void) ptree_init_propinfo(&propinfo,
(void) ptree_init_propinfo(&propinfo,
}
/*
* only handle int and string properties for
* simplicity
*/
(void) ptree_init_propinfo(&propinfo,
(void) ptree_create_and_add_prop(chdh,
} else {
(void) ptree_init_propinfo(&propinfo,
(void) ptree_create_and_add_prop(chdh,
}
}
}
}
static void
{
char *asrexport;
int asrexportlen;
asr_conf_entries_t *c = NULL;
int i;
char *key;
char *child;
char *unitaddr;
int disabled;
return;
if (conf_name_asr_map == NULL)
return;
i = 0;
while (i < asrexportlen) {
if (i >= asrexportlen)
break;
/*
* next byte tells us whether failed by diags or manually
* disabled
*/
i++;
if (i >= asrexportlen)
break;
/*
* only type 1 supported
*/
if (asrexport[i] != 1)
break;
i++;
if (i >= asrexportlen)
break;
/*
* next two bytes give size of reason string
*/
i += count + 2;
if (i > asrexportlen)
break;
/*
* now look for key in conf file info
*/
c = conf_name_asr_map;
while (c != NULL) {
*child++ = '\0';
if (unitaddr)
*unitaddr++ = '\0';
c->props);
} else {
c->props);
}
}
c = c->next;
}
}
}
/*
* This function adds information to the /platform node
*/
static int
{
int err;
return (PICL_FAILURE);
&proph);
if (err != PICL_SUCCESS)
return (err);
&proph);
if (err != PICL_SUCCESS)
return (err);
&proph);
if (err != PICL_SUCCESS)
return (err);
&proph);
if (err != PICL_SUCCESS)
return (err);
&proph);
return (err);
}
/*
* Get first 32-bit value from the reg property
*/
static int
{
int err;
return (err);
if (err != PICL_SUCCESS)
return (err);
return (PICL_FAILURE);
return (PICL_FAILURE);
if (err != PICL_SUCCESS)
return (err);
return (PICL_SUCCESS);
}
/*
* Get device ID from the reg property
*/
static int
{
int err;
if (err != PICL_SUCCESS)
return (err);
return (PICL_SUCCESS);
}
/*
* add Slot property for children of SBUS node
*/
/* ARGSUSED */
static int
{
int err;
sizeof (picl_nodehdl_t))) {
if (err != PICL_SUCCESS)
return (err);
continue;
}
return (PICL_WALK_CONTINUE);
}
/*
* This function creates a Slot property for SBUS child nodes
* which can be correlated with the slot they are plugged into
* on the motherboard.
*/
static int
{
int err;
return (err);
}
/*
*/
/* ARGSUSED */
static int
{
int err;
sizeof (picl_nodehdl_t))) {
if (err != PICL_SUCCESS)
return (err);
continue;
}
return (PICL_WALK_CONTINUE);
}
/*
* which can be correlated with the slot they are plugged into
* on the motherboard.
*/
static void
{
}
/*
* Default UnitAddress encode function
*/
static int
{
int i, len;
/*
* Encode UnitAddress as %a,%b,%c,...,%n
*/
if (addrcells < 1)
return (-1);
}
/*
* UnitAddress encode function where the last component is not printed
* unless non-zero.
*/
static int
{
int retval;
/*
* Encode UnitAddress as %a,%b,%c,...,%n where the last component
* is printed only if non-zero.
*/
else
return (retval);
}
/*
* UnitAddress encode function for SCSI class of devices
*/
static int
{
/*
* #address-cells Format
* 2 second component printed only if non-zero
*
* 4 regprop: phys_hi phys_lo lun_hi lun_lo
* UnitAddr: w<phys_hi><phys_lo>,<lun_lo>
*/
if (addrcells == 2) {
} else if (addrcells == 4) {
regprop[3]);
} else
retval = -1;
return (retval);
}
/*
* UnitAddress encode function for UPA devices
*/
static int
{
int len;
if (addrcells != 2)
return (-1);
}
/*
* UnitAddress encode function for GPTWO, JBUS devices
*/
static int
{
if (addrcells != 2)
return (-1);
if (hi & 0x400) {
} else {
}
}
/*
* UnitAddress encode function for PCI devices
*/
static int
{
typedef struct {
p:1, /* prefetchable */
t:1, /* address region aliases */
pci_addrcell_t *p;
int len;
if (addrcells != 3)
return (-1);
p = (pci_addrcell_t *)regprop;
switch (p->ss) {
case 0: /* Config */
if (p->fn)
else
break;
case 1: /* IO */
p->phys_lo);
break;
case 2: /* Mem32 */
p->phys_lo);
break;
case 3: /* Mem64 */
break;
}
}
/*
* Get #address-cells property value
*/
static uint_t
{
/*
* Get #address-cells property. If not present, use default value.
*/
if (err == PICL_SUCCESS)
if (err == PICL_SUCCESS) {
} else
} else
return (addrcells);
}
/*
* Get UnitAddress mapping entry for a node
*/
static unitaddr_map_t *
{
int err;
/*
* Get my classname and locate a function to translate "reg" prop
* into "UnitAddress" prop for my children.
*/
sizeof (clname));
if (err != PICL_SUCCESS)
break;
return (uamap);
}
/*
* Add UnitAddress property to the specified node
*/
static int
{
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (PICL_FAILURE);
return (PICL_FAILURE);
return (PICL_FAILURE);
addrcells) != 0) {
return (PICL_FAILURE);
}
if (err == PICL_SUCCESS)
return (err);
}
/*
* work out UnitAddress property of the specified node
*/
static int
{
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
return (PICL_FAILURE);
return (PICL_FAILURE);
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
/*
* Add UnitAddress property to all children of the specified node
*/
static int
{
int err;
/*
* Get #address-cells and unit address mapping entry for my
* node's class
*/
/*
* Add UnitAddress property to my children and their subtree
*/
sizeof (picl_nodehdl_t));
while (err == PICL_SUCCESS) {
(void) add_unitaddr_prop_to_subtree(chdh);
sizeof (picl_nodehdl_t));
}
return (PICL_SUCCESS);
}
static int
{
char *regbuf;
/*
* check if the #size-cells of the platform node is 2
*/
sizeof (pval));
if (err == PICL_PROPNOTFOUND)
else if (err != PICL_SUCCESS)
return (err);
/*
* don't know how to handle other vals
*/
if (pval != SUPPORTED_NUM_CELL_SIZE)
return (PICL_FAILURE);
if (err != PICL_SUCCESS)
return (err);
/*
* Get the REG property to calculate the size of memory
*/
if (err != PICL_SUCCESS)
return (err);
if (err != PICL_SUCCESS)
return (err);
return (PICL_FAILURE);
if (err != PICL_SUCCESS)
return (err);
memsize = 0;
if (err == PICL_SUCCESS) {
return (err);
}
/*
* Add the size property
*/
return (err);
}
/*
* This function is executed as part of .init when the plugin is
* dlopen()ed
*/
static void
picldevtree_register(void)
{
picldevtree_debug = 1;
(void) picld_plugin_register(&my_reg_info);
}
/*
* This function is the init entry point of the plugin.
* It initializes the /platform tree based on libdevinfo
*/
static void
picldevtree_init(void)
{
int err;
return;
} else {
builtin_map_size = 0;
}
if (err != PICL_SUCCESS) {
return;
}
return;
}
if (err != PICL_SUCCESS)
return;
(void) add_unitaddr_prop_to_subtree(plafh);
(void) update_memory_size_prop(plafh);
(void) setup_cpus(plafh);
(void) add_ffb_config_info(plafh);
(void) add_platform_info(plafh);
(void) set_sbus_slot(plafh);
}
/*
* This function is the fini entry point of the plugin
*/
static void
picldevtree_fini(void)
{
/* First unregister the event handlers */
}
/*
* This function is the event handler of this plug-in.
*
* It processes the following events:
*
* PICLEVENT_SYSEVENT_DEVICE_ADDED
* PICLEVENT_SYSEVENT_DEVICE_REMOVED
* PICLEVENT_CPU_STATE_CHANGE
* PICLEVENT_DR_AP_STATE_CHANGE
*/
/* ARGSUSED */
static void
void *cookie)
{
char *devfs_path;
return;
(void) setup_cpus(plafh);
if (picldevtree_debug > 1)
return;
}
return;
}
if (picldevtree_debug)
goto done;
}
char *strp;
char *nodename;
int err;
/* If the node already exist, then nothing else to do here */
return;
/* Skip if unable to find parent PICL node handle */
*strp = '\0';
return;
}
/*
* If parent is the root node
*/
ph = di_prom_init();
if (devnode == DI_NODE_NIL) {
}
return;
}
}
return;
}
if (err < 0) {
}
return;
}
if (err != PICL_SUCCESS) {
}
return;
}
(void) add_unitaddr_prop_to_subtree(nodeh);
}
goto done;
}
/* kludge ... try without bus-addr first */
char *p;
*strp = '\0';
if (devnode != DI_NODE_NIL)
*strp = '@';
}
}
/* Get parent devnode */
*++strp = '\0';
if (devnode == DI_NODE_NIL)
return;
ph = di_prom_init();
(void) add_unitaddr_prop_to_subtree(parh);
if (ph) {
}
char *strp;
/*
* if final element of path doesn't have a unit address
* then it is not uniquely identifiable - cannot remove
*/
return;
/* skip if can't find the node */
return;
return;
if (picldevtree_debug)
"picldevtree: deleted node nodeh:%llx\n", nodeh);
} else
(void) ptree_destroy_node(nodeh);
}
done:
(void) setup_cpus(plafh);
(void) add_ffb_config_info(plafh);
(void) set_sbus_slot(plafh);
if (picldevtree_debug > 1)
}