The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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).