NAME
Solaris::DeviceTree::Node - Abstract base class for all device nodes
DESCRIPTION
This class acts as an abstract base class for subclasses of Solaris::DeviceTree to provide methods of general use returning default values for attributes and properties for nodes and supply tree traversal and searching methods. It should not be necessary to instantiate objects of this class directly.
SYNOPSIS
Tree traversal:
$parent = $node->parent_node
@childs = $node->child_nodes
$root = $node->root_node
@siblings = $node->sibling_nodes
Value access:
$path = $node->devfs_path
$nodename = $node->node_name
$bindingname = $node->binding_name
$drivername = $node->driver_name
$busaddr = $node->bus_addr
$instance = $node->instance
@compat = $node->compatible_names
%ops = $node->driver_ops
if( $node->is_pseudo_node ) ...
if( $node->is_sid_node ) ...
if( $node->is_prom_node ) ...
$nodeid = $node->nodeid
%state = $node->state
$props = $node->props; $props->{'myprop'}->...
$pprops = $node->prom_props; $pprops->{'mypprop'}->...
$minors = $node->minor_nodes; $minors->[0]->...
$ctrl = $node->controller
$target = $node->target
$lun = $node->lun
$slice = $node->slice
$rmt = $node->rmt
Derived value access:
$prop = $node->find_prop( devfs_path => '/aliases', prop_name => 'disk' )
$solaris_path = $node->solaris_path
Node type detection:
if( $node->is_network_node ) ...
if( $node->is_block_node ) ...
if( $node->is_controller_node ) ...
Node selection:
@network_nodes = $node->network_nodes
@block_nodes = $node->block_nodes
@controller_nodes = $node->controller_nodes
$node = $node->find_nodes( devfs_path => '/pci@1f,0/pci@1f,2000' );
@nodes = $node->find_nodes( func => sub { $_->is_network_node } );
METHODS
The following methods are available:
parent_node
Returns the parent node for this node. If this is the root node undef
is returned.
child_nodes
This method returns a list with all children.
root_node
Returns the root node of the tree.
sibling_nodes
Returns the list of siblings for this object. A sibling is a child from our parent, but not ourselves.
devfs_path
Returns the physical path assocatiated with this node. Default is undef
.
node_name
Returns the name of the node used in the pysical path. Default is undef
.
binding_name
Returns the binding name of the driver for the node. Default is undef
.
driver_name
Returns the driver name for the node. Default is undef
.
bus_addr
Returns the address on the bus for this node. Default is undef
.
instance
Returns the instance number of the bound driver for this node. Default is undef
.
compatible_names
Returns the list of device which are compatible to this node. Default is the empty list.
driver_ops
Returns a hash which keys indicate which driver entry points are supported by the driver bound to this node. This is done to allow writing of something like if( exists $ops{'STREAM'} ) ...
. Default is the empty list.
is_pseudo_node =head2 is_sid_node =head2 is_prom_node
Returns true
if this is a pseudo / SID / PROM node. The default is false
.
nodeid
Returns the type of the node differing between pseudo, SID, etc. Default is undef
.
state
Returns a hash which keys indicate the state in which the bound driver is. Default is the empty list.
props
Returns a reference to the properties associated with this node. Default is undef
.
prom_props
Returns a reference to the PROM properties associated with this node. Default is undef
.
minor_nodes
Returns a reference to a list containing the minor nodes associated to this node. Default is undef
.
solaris_device
This method returns the name of the associated Solaris device. This is currently something like
c0t0d0s0 for a disk device
hme0 for a network device
or undef
if no corresponding Solaris device could be found.
controller
Returns the controller number which is associated to this node. Default is undef
.
target
Returns the target number which is associated to this node. Default is undef
.
lun
Returns the logical unit number which is associated to this node. Default is undef
.
slice
Returns the slice number which is associated to this node. Default is undef
.
rmt
Returns the tape number which is associated to this node. Default is undef
.
is_network_node
This method returns true if the node represents a network card.
is_block_node
This method returns true if the node represents a block device (which is essentially a disk).
is_controller_node
This method returns true if the node represents a controller device.
network_nodes
This method returns all nodes for network cards in the tree.
block_nodes
This method returns all nodes for disks in the tree.
controller_nodes
This method returns all nodes for controller devices.
find_nodes
This method returns nodes matching certain criteria. Currently it is possible to match against a physical path or to specify a subroutine where the node is returned if the subroutine returns true. As in Perl grep $_
is locally bound to the node being checked.
In a scalar context the method returns only the first node found. In an array context the method returns all matching nodes.
Examples:
$node = $node->find_nodes( devfs_path => '/pci@1f,0/pci@1f,2000' );
@nodes = $node->find_nodes( func => sub { $_->is_network_node } );
find_prop
This method picks a node by criteria from the devicetree and then selects either a property or a prom property depending on the options given. At least one of
prop_name
prom_prop_name
must be specified. All options valid for find_nodes are also applicable to this method.
Example:
$prop = $node->find_prop( devfs_path => '/aliases', prop_name => 'disk' )
find_minor_node( name => ':a' );
This method finds the minor node with the specified name.
#=head2 prom_path # #This method converts between a Solaris device path and an OBP device path. # #The conversion is quite complex. As a first step the IOCTLS # # OPROMDEV2PROMNAME (OIOC | 15) /* Convert devfs path to prom path */ # OPROMPROM2DEVNAME (OIOC | 16) /* Convert prom path to devfs path */ # #from the openeepr
driver accessed through /dev/openprom
might be taken. #However, some older machines are not aware of that. It would #be optimal to use devfs_dev_to_prom_name
from libdevinfo(3devinfo), but that one is #a static function and reprogramming that one is *not* fun. # #=cut
# This method takes an obp path in an OBP::Path object and returns a # solaris path. # In other words: a path containing only prom nodes is transformed to # a path containing pseudo nodes. # $promPath is a reference to an OBP::Path::Component array # This method returns an OBP::Path object. The returned object might or # might not point to a node in the obp tree. sub solaris_path { my ($this, $promPath) = @_; $promPath = new OBP::Path( string => $promPath ) if( !ref( $promPath ) ); return $promPath if( @{$promPath->components} == 0 );
my $pc; # leftmost path component, the one to check against
$pc = shift @{$promPath->components};
#print "Matching ", $pc->string, " ", $this->devfsPath, "\n"; my @children = $this->children( nodename => $pc->node, busaddress => $pc->busaddress ); if( @children == 0 ) { # no direct match found # Check if we have a transfer node.
# The mapping might or might not lead to different pathes.
# Examples:
# Ultra 10 IDE disk: disk -> dad
# ATAPI cdrom: cdrom -> sd
# SCSI disk: disk -> sd
# Ultra 1: SCSI disk: sd -> sd
@children = $this->children(
nodename => $pc->node, busaddr => undef, instance => undef );
if( @children == 0 ) {
# No transfer node found. Because we can't find the next node in the
# device tree we guess that the path stays the same and return what we have.
return new OBP::Path( components => [ $pc, @{$promPath->components} ] );
} elsif( @children == 1 ) {
# we found the transfer node. Continue with the node specified in the
# driverName attribute but leave the address and args (if any) the same.
my $transferNode = $children[ 0 ];
my @target = $this->children(
nodename => $transferNode->driverName, busaddress => $pc->busaddress );
if( @target == 0 ) {
# We have a transfer node but no node to continue. Return the corrected
# node and leave the rest as is.
return new OBP::Path( components => [
new OBP::Path::Component(
node => $transferNode->driverName,
adr => $pc->adr,
subadr => $pc->subadr,
arg => $pc->arg,
),
@{$promPath->components}
] );
} elsif( @target == 1 ) {
# Everything fine. Prepend the found note after node transferal to
# the result of the continued search.
my $contnode = $target[ 0 ];
return new OBP::Path( components => [
new OBP::Path::Component( string => $contnode->nodeName . "@" . $contnode->busAddress . ( defined $pc->arg ? ':' . $pc->arg : '' ) ),
@{$contnode->solarisPath( $promPath )->components}
] );
} else {
warn "Found more than one node after node transfer. This should not happen.";
}
} else {
# This is a very ugly situation. We have a valid prefix and we don't
# know yet how to continue correctly. Both might be valid Solaris pathes.
# It is unfortunately possible (is it?) that one path can be continued
# and the other can not. So all pathes should be tried and compared here.
# -> TODO
warn " Found more than one transfer node:\n " .
join( "\n ", map { $_->devfsPath } @children ) . "\n";
my $match = $children[ 0 ];
return new OBP::Path( components => [ $pc, @{$match->solarisPath( $promPath )->components} ] );
}
} elsif( @children == 1 ) {
# found exact match. Continue with the next node.
my $match = $children[ 0 ];
return new OBP::Path( components => [ $pc, @{$match->solarisPath( $promPath )->components} ] );
} else {
# -> TODO: Wildcard match
warn "Wildcard match. Just taking the first match.";
my $match = $children[ 0 ];
return new OBP::Path( components => [ $pc, @{$match->solarisPath( $promPath )->components} ] );
}
}
AUTHOR
Copyright 1999-2003 Dagobert Michelsen.
SEE ALSO
Solaris::DeviceTree::Libdevinfo, Solaris::DeviceTree::PathToInst, Solaris::DeviceTree::Filesystem, eeprom(1m).