diff options
Diffstat (limited to 'usr/src/lib')
24 files changed, 2574 insertions, 1151 deletions
diff --git a/usr/src/lib/fm/libfmd_log/common/fmd_filter.c b/usr/src/lib/fm/libfmd_log/common/fmd_filter.c index dfc85c9758..b260816275 100644 --- a/usr/src/lib/fm/libfmd_log/common/fmd_filter.c +++ b/usr/src/lib/fm/libfmd_log/common/fmd_filter.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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 * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,6 +29,8 @@ #include <strings.h> #include <libgen.h> +#include <regex.h> +#include <libnvpair.h> #include <fmd_log_impl.h> #include <fmd_log.h> @@ -73,3 +74,27 @@ fmd_log_filter_after(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg) uint64_t nsec = ((struct timeval *)arg)->tv_usec * (NANOSEC / MICROSEC); return (rp->rec_sec == sec ? rp->rec_nsec >= nsec : rp->rec_sec >= sec); } + +/*ARGSUSED*/ +int +fmd_log_filter_nv(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg) +{ + fmd_log_filter_nvarg_t *argt = (fmd_log_filter_nvarg_t *)arg; + char *name = argt->nvarg_name; + char *value = argt->nvarg_value; + regex_t *value_regex = argt->nvarg_value_regex; + nvpair_t *nvp; + int ai; + + /* see if nvlist has named member */ + if (nvlist_lookup_nvpair_embedded_index(rp->rec_nvl, name, + &nvp, &ai, NULL) != 0) + return (0); /* name filter failure */ + + /* check value match for matching nvpair */ + if ((value == NULL) || + (nvpair_value_match_regex(nvp, ai, value, value_regex, NULL) == 1)) + return (1); /* name/value filter pass */ + + return (0); /* value filter failure */ +} diff --git a/usr/src/lib/fm/libfmd_log/common/fmd_log.h b/usr/src/lib/fm/libfmd_log/common/fmd_log.h index 9c98d8236a..be705571b9 100644 --- a/usr/src/lib/fm/libfmd_log/common/fmd_log.h +++ b/usr/src/lib/fm/libfmd_log/common/fmd_log.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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 * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -31,6 +30,7 @@ #include <libnvpair.h> #include <exacct.h> +#include <regex.h> #ifdef __cplusplus extern "C" { @@ -101,10 +101,17 @@ extern fmd_log_rec_f fmd_log_filter_class; /* char *name of event class */ extern fmd_log_rec_f fmd_log_filter_uuid; /* char *uuid of list.suspect */ extern fmd_log_rec_f fmd_log_filter_before; /* struct timeval * latest */ extern fmd_log_rec_f fmd_log_filter_after; /* struct timeval * earliest */ +extern fmd_log_rec_f fmd_log_filter_nv; /* char *namevalue in event */ extern int fmd_log_filter(fmd_log_t *, uint_t, fmd_log_filter_t *, const fmd_log_record_t *); +typedef struct fmd_log_filter_nvarg { + char *nvarg_name; + char *nvarg_value; + regex_t *nvarg_value_regex; +} fmd_log_filter_nvarg_t; + /* * fmd_log_xiter() can be used to perform sophisticated iteration over an fmd * log file such as that required by fmdump(1M). The arguments are as follows: diff --git a/usr/src/lib/fm/libfmd_log/common/mapfile-vers b/usr/src/lib/fm/libfmd_log/common/mapfile-vers index d7ba3e2c45..cecb3d2840 100644 --- a/usr/src/lib/fm/libfmd_log/common/mapfile-vers +++ b/usr/src/lib/fm/libfmd_log/common/mapfile-vers @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -34,6 +34,7 @@ SUNWprivate { fmd_log_filter_after; fmd_log_filter_before; fmd_log_filter_class; + fmd_log_filter_nv; fmd_log_filter_uuid; fmd_log_header; fmd_log_iter; diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h index ba49a8bbb0..11d1090748 100644 --- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h +++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h @@ -82,8 +82,10 @@ extern "C" { #define TOPO_IO_DRIVER "driver" #define TOPO_IO_MODULE "module" #define TOPO_IO_DEV "dev" +#define TOPO_IO_DEVID "devid" #define TOPO_IO_DEV_PATH "devfs-path" #define TOPO_IO_AP_PATH "ap-path" +#define TOPO_IO_PHYS_PATH "phys-path" #define TOPO_PGROUP_PCI "pci" #define TOPO_PCI_VENDID "vendor-id" diff --git a/usr/src/lib/fm/topo/maps/Makefile b/usr/src/lib/fm/topo/maps/Makefile index 1984b1bbf5..5af237b7b8 100644 --- a/usr/src/lib/fm/topo/maps/Makefile +++ b/usr/src/lib/fm/topo/maps/Makefile @@ -45,6 +45,8 @@ sparc_SUBDIRS = sun4u \ i386_SUBDIRS = i86pc \ i386 \ + SUNW,Sun-Fire-X4200-Server \ + SUNW,Sun-Fire-X4200-M2 \ SUNW,Sun-Fire-X4500 \ SUNW,Sun-Fire-X4540 diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Makefile b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Makefile new file mode 100644 index 0000000000..fa4d771486 --- /dev/null +++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Makefile @@ -0,0 +1,41 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" + +# NOTE: The name of the xml file we are building is 'platform' +# specific, but its build is structured as 'arch' specific since +# 'uname -i' on all x86 platforms returns i86pc. + +ARCH = i86pc +CLASS = arch +DTDFILE = +TOPOFILE = Sun-Fire-X4200-M2-hc-topology.xml +SRCDIR = ../SUNW,Sun-Fire-X4200-M2 + +PLATFORM = Sun-Fire-X4200-M2 +TOPOBASE = ../i86pc/i86pc-hc-topology.xml + +include ../Makefile.map diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Sun-Fire-X4200-M2-hc-topology.xmlgen b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Sun-Fire-X4200-M2-hc-topology.xmlgen new file mode 100644 index 0000000000..e8f94d0f65 --- /dev/null +++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-M2/Sun-Fire-X4200-M2-hc-topology.xmlgen @@ -0,0 +1,150 @@ +#!/usr/local/bin/perl +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" + +use Getopt::Std; + +# X4200-M2: platform specific begin +my $sys_supported = { "name" => "Sun-Fire-X4200-M2", + "num_bays" => "4", + "bay_label" => "HD"}; +# X4200-M2: platform specific end + +$IFILE = "filehandle"; +$OFILE = "filehandle"; + +sub Usage() +{ + print STDERR "Usage: xml-gen -p <platform> " . + "-i <input_xml_file> -o <output_xml_file>\n"; +} + +sub calc_nodes +{ +# X4200-M2: platform specific begin + $controller = 0; +# X4200-M2: platform specific end + + for ($bay = 0; $bay < $sys_supported->{"num_bays"}; $bay++) { + +# X4200-M2: platform specific begin + $target = $bay; + + # set hba path, target path, bay path, and attachment point + $hpath = "/pci\@7b,0/pci1022,7458\@11/pci1000,3060\@2"; + $tpath = sprintf("/sd\@%x,0", $target); + $apoint = sprintf(":scsi::dsk/c%dt%dd0", + $controller + 1, $target); +# X4200-M2: platform specific end + + printf OFILE "\n <node instance='%d'>\n\n", $bay; + + printf OFILE + " <propgroup name='protocol' version='1' " . + "name-stability='Private' data-stability='Private' >\n"; + printf OFILE + " <propval name='label' type='string' " . + "value='%s%d' />\n", + $sys_supported->{"bay_label"}, $bay; + printf OFILE + " </propgroup>\n"; + + printf OFILE + " <propgroup name='io' version='1' " . + "name-stability='Private' data-stability='Private' >\n"; + printf OFILE + " <propval name='ap-path' type='string' " . + "value='/devices%s%s' />\n", $hpath, $apoint; + printf OFILE + " </propgroup>\n"; + +# no LED support + + printf OFILE + " <propgroup name='binding' version='1' " . + "name-stability='Private' data-stability='Private' >\n"; + printf OFILE + " <propval name='occupant-path' type='string' " . + "value='%s%s' />\n", $hpath, $tpath; + printf OFILE + " </propgroup>\n"; + + printf OFILE "\n </node>\n\n"; + } +} + +$ok = getopts("p:i:o:h", \%options); +if ($options{'h'}) { + Usage(); + exit (1); +} + +$platform = $options{'p'}; +$input_file = $options{'i'}; +$output_file = $options{'o'}; + +if (!$platform || !$input_file || !$output_file) { + Usage(); + exit (1); +} + +open(IFILE, "< $input_file") || die("$input_file cannot be opened."); +open(OFILE, "> $output_file") || die("$output_file cannot be opened."); +my $in_chassis_range = 0; + +while ($line = <IFILE>) { + chomp($line); + + if ($line =~ /range\s+name\s?=\s?\Wchassis\W/) { + $in_chassis_range = 1; + } + if ($in_chassis_range && ($line =~ /<\/dependents>/)) { + last; + } else { + print OFILE "$line\n"; + } +} + +print OFILE " <!--xml-gen internal storage-->\n"; +printf OFILE " <range name='bay' min='0' max='%d'>\n", + $sys_supported->{"num_bays"}-1; + +calc_nodes(0); + +printf OFILE " <dependents grouping='children'>\n"; +printf OFILE " <range name='disk' min='0' max='0'>\n"; +printf OFILE " <enum-method name='disk' version='1' />\n"; +printf OFILE " </range>\n"; +printf OFILE " </dependents>\n\n"; +printf OFILE " </range>\n"; + +print OFILE "$line\n"; +while ($line = <IFILE>) { + print OFILE $line; +} + +close OFILE; +close IFILE; diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Makefile b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Makefile new file mode 100644 index 0000000000..40cc3f7c5b --- /dev/null +++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Makefile @@ -0,0 +1,41 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" + +# NOTE: The name of the xml file we are building is 'platform' +# specific, but its build is structured as 'arch' specific since +# 'uname -i' on all x86 platforms returns i86pc. + +ARCH = i86pc +CLASS = arch +DTDFILE = +TOPOFILE = Sun-Fire-X4200-Server-hc-topology.xml +SRCDIR = ../SUNW,Sun-Fire-X4200-Server + +PLATFORM = Sun-Fire-X4200 +TOPOBASE = ../i86pc/i86pc-hc-topology.xml + +include ../Makefile.map diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Sun-Fire-X4200-Server-hc-topology.xmlgen b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Sun-Fire-X4200-Server-hc-topology.xmlgen new file mode 100644 index 0000000000..d6bd251c68 --- /dev/null +++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4200-Server/Sun-Fire-X4200-Server-hc-topology.xmlgen @@ -0,0 +1,150 @@ +#!/usr/local/bin/perl +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" + +use Getopt::Std; + +# X4200-Server: platform specific begin +my $sys_supported = { "name" => "Sun-Fire-X4200-Server", + "num_bays" => "4", + "bay_label" => "HD"}; +# X4200-Server: platform specific end + +$IFILE = "filehandle"; +$OFILE = "filehandle"; + +sub Usage() +{ + print STDERR "Usage: xml-gen -p <platform> " . + "-i <input_xml_file> -o <output_xml_file>\n"; +} + +sub calc_nodes +{ +# X4200-Server: platform specific begin + $controller = 0; +# X4200-Server: platform specific end + + for ($bay = 0; $bay < $sys_supported->{"num_bays"}; $bay++) { + +# X4200-Server: platform specific begin + $target = $bay; + + # set hba path, target path, bay path, and attachment point + $hpath = "/pci\@0,0/pci1022,7450\@2/pci1000,3060\@3"; + $tpath = sprintf("/sd\@%x,0", $target); + $apoint = sprintf(":scsi::dsk/c%dt%dd0", + $controller + 1, $target); +# X4200-Server: platform specific end + + printf OFILE "\n <node instance='%d'>\n\n", $bay; + + printf OFILE + " <propgroup name='protocol' version='1' " . + "name-stability='Private' data-stability='Private' >\n"; + printf OFILE + " <propval name='label' type='string' " . + "value='%s%d' />\n", + $sys_supported->{"bay_label"}, $bay; + printf OFILE + " </propgroup>\n"; + + printf OFILE + " <propgroup name='io' version='1' " . + "name-stability='Private' data-stability='Private' >\n"; + printf OFILE + " <propval name='ap-path' type='string' " . + "value='/devices%s%s' />\n", $hpath, $apoint; + printf OFILE + " </propgroup>\n"; + +# no LED support + + printf OFILE + " <propgroup name='binding' version='1' " . + "name-stability='Private' data-stability='Private' >\n"; + printf OFILE + " <propval name='occupant-path' type='string' " . + "value='%s%s' />\n", $hpath, $tpath; + printf OFILE + " </propgroup>\n"; + + printf OFILE "\n </node>\n\n"; + } +} + +$ok = getopts("p:i:o:h", \%options); +if ($options{'h'}) { + Usage(); + exit (1); +} + +$platform = $options{'p'}; +$input_file = $options{'i'}; +$output_file = $options{'o'}; + +if (!$platform || !$input_file || !$output_file) { + Usage(); + exit (1); +} + +open(IFILE, "< $input_file") || die("$input_file cannot be opened."); +open(OFILE, "> $output_file") || die("$output_file cannot be opened."); +my $in_chassis_range = 0; + +while ($line = <IFILE>) { + chomp($line); + + if ($line =~ /range\s+name\s?=\s?\Wchassis\W/) { + $in_chassis_range = 1; + } + if ($in_chassis_range && ($line =~ /<\/dependents>/)) { + last; + } else { + print OFILE "$line\n"; + } +} + +print OFILE " <!--xml-gen internal storage-->\n"; +printf OFILE " <range name='bay' min='0' max='%d'>\n", + $sys_supported->{"num_bays"}-1; + +calc_nodes(0); + +printf OFILE " <dependents grouping='children'>\n"; +printf OFILE " <range name='disk' min='0' max='0'>\n"; +printf OFILE " <enum-method name='disk' version='1' />\n"; +printf OFILE " </range>\n"; +printf OFILE " </dependents>\n\n"; +printf OFILE " </range>\n"; + +print OFILE "$line\n"; +while ($line = <IFILE>) { + print OFILE $line; +} + +close OFILE; +close IFILE; diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen index afb5b1c879..0d58d0b2d0 100644 --- a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen +++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen @@ -23,146 +23,144 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" +#pragma ident "%Z%%M% %I% %E% SMI" # use Getopt::Std; - -my $sys_supported = {"name" => "Sun-Fire-X4500", - "prop_name" => "sfx4500", - "num_bays" => "48"}; - +# X4500: platform specific begin +my $sys_supported = { "name" => "Sun-Fire-X4500", + "prop_name" => "sfx4500", + "num_bays" => "48", + "bay_label" => "HD_ID_"}; +# X4500: platform specific end $IFILE = "filehandle"; $OFILE = "filehandle"; sub Usage() { - print STDERR "Usage: xml-gen -p <platform> -i <input_xml_file> -o <output_xml_file>\n"; + print STDERR "Usage: xml-gen -p <platform> " . + "-i <input_xml_file> -o <output_xml_file>\n"; } +# Define properties associated with LED manipulation. +# We have three LEDs per disk: Present (PRSNT), OK-to-remove (OK2RM), and fault. +# We track the following states (absent present configured unconfigured) via +# the PRSNT/OK2RM LEDs (FAULT LED is maintained separately). sub calc_sfx_prop { my $name = shift; - my $hdd = shift; + my $bay = shift; my $sid = shift; - printf OFILE "\n"; - printf OFILE " <propgroup name='%s-properties'", $name; - printf OFILE " version='1' name-stability='Private'"; - printf OFILE " data-stability='Private' >\n"; - printf OFILE " <propval name='fru-update-action'"; - printf OFILE " type='string' value='ipmi:fru gid=3 hdd=%d' />\n", $hdd; - printf OFILE " <propval name='indicator-name-0'"; - printf OFILE " type='string' value='+PRSNT' />\n"; - printf OFILE " <propval name='indicator-action-0'"; - printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0001' />\n", - $sid; - printf OFILE " <propval name='indicator-name-1'"; - printf OFILE " type='string' value='-PRSNT' />\n"; - printf OFILE " <propval name='indicator-action-1'"; - printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0001' />\n", - $sid; - printf OFILE " <propval name='indicator-name-2'"; - printf OFILE " type='string' value='+OK2RM' />\n"; - printf OFILE " <propval name='indicator-action-2'"; - printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0008' />\n", - $sid; - printf OFILE " <propval name='indicator-name-3'"; - printf OFILE " type='string' value='-OK2RM' />\n"; - printf OFILE " <propval name='indicator-action-3'"; - printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0008' />\n", - $sid; - printf OFILE " <propval name='indicator-name-4'"; - printf OFILE " type='string' value='+FAULT' />\n"; - printf OFILE " <propval name='indicator-action-4'"; - printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0002' />\n", - $sid; - printf OFILE " <propval name='indicator-name-5'"; - printf OFILE " type='string' value='-FAULT' />\n"; - printf OFILE " <propval name='indicator-action-5'"; - printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0002' />\n", - $sid; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-0' type='string' value='absent>present' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-0' type='string' value='+PRSNT&+OK2RM' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-1' type='string' value='present>configured' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-1' type='string' value='+PRSNT&-OK2RM' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-2' type='string' value='configured>unconfigured' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-2' type='string' value='+OK2RM' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-3' type='string' value='unconfigured>configured' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-3' type='string' value='-OK2RM' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-4' type='string' value='unconfigured>absent' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-4' type='string' value='-OK2RM&-PRSNT' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-5' type='string' value='configured>absent' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-5' type='string' value='-OK2RM&-PRSNT' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-6' type='string' value='present>absent' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-6' type='string' value='-OK2RM&-PRSNT' />\n"; - printf OFILE " </propgroup>\n"; - printf OFILE "\n"; + my @names = ( + "+PRSNT", "-PRSNT", + "+OK2RM", "-OK2RM", + "+FAULT", "-FAULT"); + my @masks = ( + "amask=0x0001", "dmask=0x0001", + "amask=0x0008", "dmask=0x0008", + "amask=0x0002", "dmask=0x0002"); + my @states = ( + "absent>present", "present>configured", + "configured>unconfigured", "unconfigured>configured", + "unconfigured>absent", "configured>absent", + "present>absent", "absent>configured"); + my @actions = ( + "+PRSNT&+OK2RM", "+PRSNT&-OK2RM", + "+OK2RM", "-OK2RM", + "-OK2RM&-PRSNT", "-OK2RM&-PRSNT", + "-OK2RM&-PRSNT", "-OK2RM&+PRSNT"); + + printf OFILE "\n"; + printf OFILE + " <propgroup name='%s-properties' version='1' " . + "name-stability='Private' data-stability='Private' >\n", $name; + printf OFILE + " <propval name='fru-update-action' type='string' " . + "value='ipmi:fru gid=3 hdd=%d' />\n", $bay; + + for ($i = 0; $i < 6; $i++) { + printf OFILE + " <propval name='indicator-name-%d' type='string' " . + "value='%s' />\n", $i, $names[$i]; + printf OFILE + " <propval name='indicator-action-%d' " . + "type='string' value='ipmi:state sid=%d %s' />\n", + $i, $sid, $masks[$i]; + } + + for ($i = 0; $i < 8; $i++) { + printf OFILE + " <propval name='indicator-rule-states-%d' " . + "type='string' value='%s' />\n", $i, $states[$i]; + printf OFILE + " <propval name='indicator-rule-actions-%d' " . + "type='string' value='%s' />\n", $i, $actions[$i]; + } + printf OFILE + " </propgroup>\n\n"; } -sub calc_nodes +sub calc_nodes { + +# X4500: platform specific begin my @pci0=(1, 2, 0); my @pci1=(4, 3, 8, 7, 2, 1); +# X4500: platform specific end + + for ($bay = 0; $bay < $sys_supported->{"num_bays"}; $bay++) { - for ($cnt = 0; $cnt < $sys_supported->{"num_bays"}; $cnt++) { - $hdd = $cnt; - $sid = 90 + $cnt; - $d = (($cnt/12) + (($cnt & 1) << 2)); - $index = (($cnt >> 2) % 3); +# X4500: platform specific begin + $sid = 90 + $bay; + $target = (($bay/12) + (($bay & 1) << 2)); + $index = (($bay >> 2) % 3); $p0 = $pci0[$index]; - $index = (($cnt >> 1) % 6); + $index = (($bay >> 1) % 6); $p1 = $pci1[$index]; - printf OFILE "\n"; - printf OFILE " <node instance='%d'>\n", $cnt; - printf OFILE "\n"; - printf OFILE " <propgroup name='protocol'"; - printf OFILE " version='1' name-stability='Private'"; - printf OFILE " data-stability='Private' >\n"; - printf OFILE " <propval name='ASRU' "; - printf OFILE "type='fmri' value="; - printf OFILE "'dev:////pci@%d,0/pci1022,7458@%d", $p0, $p1; - printf OFILE "/pci11ab,11ab\@1' />\n"; - printf OFILE " <propval name='label'"; - printf OFILE " type='string' value='bay%d' />\n", $cnt; - printf OFILE " </propgroup>\n"; - - printf OFILE " <propgroup name='io'"; - printf OFILE " version='1' name-stability='Private'"; - printf OFILE " data-stability='Private' >\n"; - printf OFILE " <propval name='ap-path'"; - printf OFILE " type='string'"; - printf OFILE " value='/devices/pci@%d,0/pci1022,7458@%d", $p0, $p1; - printf OFILE "/pci11ab,11ab\@1:%d' />\n", $d; - printf OFILE " </propgroup>\n"; - - calc_sfx_prop($sys_supported->{"prop_name"}, $hdd, $sid); - printf OFILE " <propgroup name='binding'"; - printf OFILE " version='1' name-stability='Private'"; - printf OFILE " data-stability='Private' >\n"; - printf OFILE " <propval name='occupant-path'"; - printf OFILE " type='string'"; - printf OFILE " value='/pci@%d,0/pci1022,7458@%d", $p0, $p1; - printf OFILE "/pci11ab,11ab\@1/disk@%d,0' />\n", $d; - printf OFILE " </propgroup>\n"; - printf OFILE "\n"; - printf OFILE " </node>\n"; - printf OFILE "\n"; + + # set hba path, target path, bay path, and attachment point + $hpath = sprintf("/pci\@%x,0/pci1022,7458\@%x/pci11ab,11ab\@1", + $p0, $p1); + $tpath = sprintf("/disk\@%x,0", $target); + $apoint = sprintf(":%d", $target); +# X4500: platform specific end + + printf OFILE "\n <node instance='%d'>\n\n", $bay; + + printf OFILE + " <propgroup name='protocol' version='1' " . + "name-stability='Private' data-stability='Private' >\n"; + printf OFILE + " <propval name='label' type='string' " . + "value='%s%d' />\n", + $sys_supported->{"bay_label"}, $bay; + printf OFILE + " </propgroup>\n"; + + printf OFILE + " <propgroup name='io' version='1' " . + "name-stability='Private' data-stability='Private' >\n"; + printf OFILE + " <propval name='ap-path' type='string' " . + "value='/devices%s%s' />\n", $hpath, $apoint; + printf OFILE + " </propgroup>\n"; + +# platform specific LED support + calc_sfx_prop($sys_supported->{"prop_name"}, $bay, $sid); + + printf OFILE + " <propgroup name='binding' version='1' " . + "name-stability='Private' data-stability='Private' >\n"; + printf OFILE + " <propval name='occupant-path' type='string' " . + "value='%s%s' />\n", $hpath, $tpath; + printf OFILE + " </propgroup>\n"; + + printf OFILE "\n </node>\n\n"; } } @@ -170,7 +168,7 @@ $ok = getopts("p:i:o:h", \%options); if ($options{'h'}) { Usage(); exit (1); -} +} $platform = $options{'p'}; $input_file = $options{'i'}; @@ -184,8 +182,10 @@ if (!$platform || !$input_file || !$output_file) { open(IFILE, "< $input_file") || die("$input_file cannot be opened."); open(OFILE, "> $output_file") || die("$output_file cannot be opened."); my $in_chassis_range = 0; + while ($line = <IFILE>) { chomp($line); + if ($line =~ /range\s+name\s?=\s?\Wchassis\W/) { $in_chassis_range = 1; } @@ -195,19 +195,20 @@ while ($line = <IFILE>) { print OFILE "$line\n"; } } -print OFILE " <!--xml-gen internal storage-->\n"; -printf OFILE " <range name='bay' min='0' max='%d'>\n", $sys_supported->{"num_bays"}; + +print OFILE " <!--xml-gen internal storage-->\n"; +printf OFILE " <range name='bay' min='0' max='%d'>\n", + $sys_supported->{"num_bays"}-1; + calc_nodes(0); -printf OFILE " <dependents grouping='children'>\n"; -printf OFILE " <range name='disk' min='0'"; -printf OFILE " max='1'>\n"; -printf OFILE " <enum-method name='disk'"; -printf OFILE " version='1' />\n"; -printf OFILE " </range>\n"; -printf OFILE " </dependents>\n"; -printf OFILE "\n"; -printf OFILE " </range>\n"; +printf OFILE " <dependents grouping='children'>\n"; +printf OFILE " <range name='disk' min='0' max='0'>\n"; +printf OFILE " <enum-method name='disk' version='1' />\n"; +printf OFILE " </range>\n"; +printf OFILE " </dependents>\n\n"; +printf OFILE " </range>\n"; + print OFILE "$line\n"; while ($line = <IFILE>) { print OFILE $line; diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen index 0d49a3c83a..1d1c8a8250 100644 --- a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen +++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen @@ -23,154 +23,143 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" +#pragma ident "%Z%%M% %I% %E% SMI" # use Getopt::Std; - -my $sys_supported = {"name" => "Sun-Fire-X4540", - "prop_name" => "sfx4500", - "num_bays" => "48"}; - +# X4540: platform specific begin +my $sys_supported = { "name" => "Sun-Fire-X4540", + "prop_name" => "sfx4500", + "num_bays" => "48", + "bay_label" => "HD_ID_"}; +# X4540: platform specific end $IFILE = "filehandle"; $OFILE = "filehandle"; sub Usage() { - print STDERR "Usage: xml-gen -p <platform> -i <input_xml_file> -o <output_xml_file>\n"; + print STDERR "Usage: xml-gen -p <platform> " . + "-i <input_xml_file> -o <output_xml_file>\n"; } +# Define properties associated with LED manipulation. +# We have three LEDs per disk: Present (PRSNT), OK-to-remove (OK2RM), and fault. +# We track the following states (absent present configured unconfigured) via +# the PRSNT/OK2RM LEDs (FAULT LED is maintained separately). sub calc_sfx_prop { my $name = shift; - my $hdd = shift; + my $bay = shift; my $sid = shift; - printf OFILE "\n"; - printf OFILE " <propgroup name='%s-properties'", $name; - printf OFILE " version='1' name-stability='Private'"; - printf OFILE " data-stability='Private' >\n"; - printf OFILE " <propval name='fru-update-action'"; - printf OFILE " type='string' value='ipmi:fru gid=3 hdd=%d' />\n", $hdd; - printf OFILE " <propval name='indicator-name-0'"; - printf OFILE " type='string' value='+PRSNT' />\n"; - printf OFILE " <propval name='indicator-action-0'"; - printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0001' />\n", - $sid; - printf OFILE " <propval name='indicator-name-1'"; - printf OFILE " type='string' value='-PRSNT' />\n"; - printf OFILE " <propval name='indicator-action-1'"; - printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0001' />\n", - $sid; - printf OFILE " <propval name='indicator-name-2'"; - printf OFILE " type='string' value='+OK2RM' />\n"; - printf OFILE " <propval name='indicator-action-2'"; - printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0008' />\n", - $sid; - printf OFILE " <propval name='indicator-name-3'"; - printf OFILE " type='string' value='-OK2RM' />\n"; - printf OFILE " <propval name='indicator-action-3'"; - printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0008' />\n", - $sid; - printf OFILE " <propval name='indicator-name-4'"; - printf OFILE " type='string' value='+FAULT' />\n"; - printf OFILE " <propval name='indicator-action-4'"; - printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0002' />\n", - $sid; - printf OFILE " <propval name='indicator-name-5'"; - printf OFILE " type='string' value='-FAULT' />\n"; - printf OFILE " <propval name='indicator-action-5'"; - printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0002' />\n", - $sid; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-0' type='string' value='absent>present' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-0' type='string' value='+PRSNT&+OK2RM' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-1' type='string' value='present>configured' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-1' type='string' value='+PRSNT&-OK2RM' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-2' type='string' value='configured>unconfigured' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-2' type='string' value='+OK2RM' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-3' type='string' value='unconfigured>configured' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-3' type='string' value='-OK2RM' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-4' type='string' value='unconfigured>absent' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-4' type='string' value='-OK2RM&-PRSNT' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-5' type='string' value='configured>absent' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-5' type='string' value='-OK2RM&-PRSNT' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-6' type='string' value='present>absent' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-6' type='string' value='-OK2RM&-PRSNT' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "states-7' type='string' value='absent>configured' />\n"; - printf OFILE " <propval name='indicator-rule-"; - printf OFILE "actions-7' type='string' value='-OK2RM&+PRSNT' />\n"; - printf OFILE " </propgroup>\n"; - printf OFILE "\n"; + my @names = ( + "+PRSNT", "-PRSNT", + "+OK2RM", "-OK2RM", + "+FAULT", "-FAULT"); + my @masks = ( + "amask=0x0001", "dmask=0x0001", + "amask=0x0008", "dmask=0x0008", + "amask=0x0002", "dmask=0x0002"); + my @states = ( + "absent>present", "present>configured", + "configured>unconfigured", "unconfigured>configured", + "unconfigured>absent", "configured>absent", + "present>absent", "absent>configured"); + my @actions = ( + "+PRSNT&+OK2RM", "+PRSNT&-OK2RM", + "+OK2RM", "-OK2RM", + "-OK2RM&-PRSNT", "-OK2RM&-PRSNT", + "-OK2RM&-PRSNT", "-OK2RM&+PRSNT"); + + printf OFILE "\n"; + printf OFILE + " <propgroup name='%s-properties' version='1' " . + "name-stability='Private' data-stability='Private' >\n", $name; + printf OFILE + " <propval name='fru-update-action' type='string' " . + "value='ipmi:fru gid=3 hdd=%d' />\n", $bay; + + for ($i = 0; $i < 6; $i++) { + printf OFILE + " <propval name='indicator-name-%d' type='string' " . + "value='%s' />\n", $i, $names[$i]; + printf OFILE + " <propval name='indicator-action-%d' " . + "type='string' value='ipmi:state sid=%d %s' />\n", + $i, $sid, $masks[$i]; + } + + for ($i = 0; $i < 8; $i++) { + printf OFILE + " <propval name='indicator-rule-states-%d' " . + "type='string' value='%s' />\n", $i, $states[$i]; + printf OFILE + " <propval name='indicator-rule-actions-%d' " . + "type='string' value='%s' />\n", $i, $actions[$i]; + } + printf OFILE + " </propgroup>\n\n"; } -sub calc_nodes +sub calc_nodes { + +# X4540: platform specific begin my @pci0=(0, 0, 0, 0x3c, 0x3c, 0x3c); my @pci1=(0x377, 0x375, 0x376, 0x377, 0x375, 0x376); my @pci2=(0xa, 0xb, 0xf, 0xa, 0xb, 0xf); +# X4540: platform specific end for ($bay = 0; $bay < $sys_supported->{"num_bays"}; $bay++) { - $controller = $bay / 8; - $target = $bay % 8 ; +# X4540: platform specific begin $sid = 90 + $bay; + $target = $bay % 8; + $controller = $bay / 8; - $physdev = "/pci\@" . sprintf("%x", $pci0[$controller]) . - ",0/pci10de," . sprintf("%x", $pci1[$controller]) . - "\@" . sprintf("%x", $pci2[$controller]) . - "/pci1000,1000\@0"; - - printf OFILE "\n"; - printf OFILE " <node instance='%d'>\n", $bay; - printf OFILE "\n"; - printf OFILE " <propgroup name='protocol'"; - printf OFILE " version='1' name-stability='Private'"; - printf OFILE " data-stability='Private' >\n"; - printf OFILE " <propval name='ASRU' "; - printf OFILE "type='fmri' value="; - printf OFILE "'dev:///" . $physdev . "' />\n"; - printf OFILE " <propval name='label'"; - printf OFILE " type='string' value='bay%d' />\n", $bay; - printf OFILE " </propgroup>\n"; - - printf OFILE " <propgroup name='io'"; - printf OFILE " version='1' name-stability='Private'"; - printf OFILE " data-stability='Private' >\n"; - printf OFILE " <propval name='ap-path'"; - printf OFILE " type='string'"; - printf OFILE " value='/devices" . $physdev; - printf OFILE ":scsi::dsk/c%dt%dd0", $controller + 1, $target; - printf OFILE "' />\n"; - printf OFILE " </propgroup>\n"; - + # set hba path, target path, bay path, and attachment point + $hpath = sprintf("/pci\@%x,0/pci10de,%x\@%x/pci1000,1000\@0", + $pci0[$controller], $pci1[$controller], $pci2[$controller]); + $tpath = sprintf("/sd\@%x,0", $target); + $apoint = sprintf(":scsi::dsk/c%dt%dd0", + $controller + 1, $target); +# X4540: platform specific end + + printf OFILE "\n <node instance='%d'>\n\n", $bay; + + printf OFILE + " <propgroup name='protocol' version='1' " . + "name-stability='Private' data-stability='Private' >\n"; + printf OFILE + " <propval name='label' type='string' " . + "value='%s%d' />\n", + $sys_supported->{"bay_label"}, $bay; + printf OFILE + " </propgroup>\n"; + + printf OFILE + " <propgroup name='io' version='1' " . + "name-stability='Private' data-stability='Private' >\n"; + printf OFILE + " <propval name='ap-path' type='string' " . + "value='/devices%s%s' />\n", $hpath, $apoint; + printf OFILE + " </propgroup>\n"; + +# platform specific LED support calc_sfx_prop($sys_supported->{"prop_name"}, $bay, $sid); - printf OFILE " <propgroup name='binding'"; - printf OFILE " version='1' name-stability='Private'"; - printf OFILE " data-stability='Private' >\n"; - printf OFILE " <propval name='occupant-path'"; - printf OFILE " type='string'"; - printf OFILE " value='" . $physdev . "/sd\@%d,0", $target; - printf OFILE "' />\n"; - printf OFILE " </propgroup>\n"; - printf OFILE "\n"; - printf OFILE " </node>\n"; - printf OFILE "\n"; + + printf OFILE + " <propgroup name='binding' version='1' " . + "name-stability='Private' data-stability='Private' >\n"; + printf OFILE + " <propval name='occupant-path' type='string' " . + "value='%s%s' />\n", $hpath, $tpath; + printf OFILE + " </propgroup>\n"; + + printf OFILE "\n </node>\n\n"; } } @@ -178,7 +167,7 @@ $ok = getopts("p:i:o:h", \%options); if ($options{'h'}) { Usage(); exit (1); -} +} $platform = $options{'p'}; $input_file = $options{'i'}; @@ -192,30 +181,33 @@ if (!$platform || !$input_file || !$output_file) { open(IFILE, "< $input_file") || die("$input_file cannot be opened."); open(OFILE, "> $output_file") || die("$output_file cannot be opened."); my $in_chassis_range = 0; + while ($line = <IFILE>) { chomp($line); + if ($line =~ /range\s+name\s?=\s?\Wchassis\W/) { $in_chassis_range = 1; } - if ($in_chassis_range && ($line =~ /\/dependents/)) { + if ($in_chassis_range && ($line =~ /<\/dependents>/)) { last; } else { print OFILE "$line\n"; } } -print OFILE " <!--xml-gen internal storage-->\n"; -printf OFILE " <range name='bay' min='0' max='%d'>\n", $sys_supported->{"num_bays"}; + +print OFILE " <!--xml-gen internal storage-->\n"; +printf OFILE " <range name='bay' min='0' max='%d'>\n", + $sys_supported->{"num_bays"}-1; + calc_nodes(0); -printf OFILE " <dependents grouping='children'>\n"; -printf OFILE " <range name='disk' min='0'"; -printf OFILE " max='1'>\n"; -printf OFILE " <enum-method name='disk'"; -printf OFILE " version='1' />\n"; -printf OFILE " </range>\n"; -printf OFILE " </dependents>\n"; -printf OFILE "\n"; -printf OFILE " </range>\n"; +printf OFILE " <dependents grouping='children'>\n"; +printf OFILE " <range name='disk' min='0' max='0'>\n"; +printf OFILE " <enum-method name='disk' version='1' />\n"; +printf OFILE " </range>\n"; +printf OFILE " </dependents>\n\n"; +printf OFILE " </range>\n"; + print OFILE "$line\n"; while ($line = <IFILE>) { print OFILE $line; diff --git a/usr/src/lib/fm/topo/modules/Makefile.plugin b/usr/src/lib/fm/topo/modules/Makefile.plugin index fd459b0bb5..9ceaf85f45 100644 --- a/usr/src/lib/fm/topo/modules/Makefile.plugin +++ b/usr/src/lib/fm/topo/modules/Makefile.plugin @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -37,9 +37,11 @@ include ../../../../../Makefile.lib # Set PROG and OBJS based on the values of MODULE and SRCS. We expect that # these macros to be defined by the Makefile that is including this file. # -SRCS = $(MODULESRCS:%.c=%.c) +# SHAREDSRCS is used to share sources between multiple libtopo modules. +# +SRCS = $(MODULESRCS:%.c=%.c) $(SHAREDSRCS:%.c=../../common/$(SHAREDMODULE)/%.c) PROG = $(MODULE:%=%.so) -OBJS = $(SRCS:%.c=%.o) +OBJS = $(MODULESRCS:%.c=%.o) $(SHAREDSRCS:%.c=%.o) # # Set ROOTPROG and ROOTCONF based on the values of MODULE, CLASS, and PLATFORMS @@ -84,6 +86,10 @@ $(PROG): $(OBJS) $(APIMAP) $(COMPILE.c) $< $(CTFCONVERT_O) +%.o: ../../common/$(SHAREDMODULE)/%.c + $(COMPILE.c) $< + $(CTFCONVERT_O) + %.o: %.c $(COMPILE.c) $< $(CTFCONVERT_O) diff --git a/usr/src/lib/fm/topo/modules/common/disk/Makefile b/usr/src/lib/fm/topo/modules/common/disk/Makefile index 49002147c7..b4821a6a82 100644 --- a/usr/src/lib/fm/topo/modules/common/disk/Makefile +++ b/usr/src/lib/fm/topo/modules/common/disk/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #pragma ident "%Z%%M% %I% %E% SMI" @@ -27,7 +27,7 @@ MODULE = disk CLASS = common -MODULESRCS = disk.c +MODULESRCS = disk.c disk_common.c include ../../Makefile.plugin diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk.c b/usr/src/lib/fm/topo/modules/common/disk/disk.c index 8253eabb9c..c248e90553 100644 --- a/usr/src/lib/fm/topo/modules/common/disk/disk.c +++ b/usr/src/lib/fm/topo/modules/common/disk/disk.c @@ -18,9 +18,8 @@ * * CDDL HEADER END */ - /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -37,667 +36,103 @@ #include <sys/fm/protocol.h> #include "disk.h" -static int disk_status(topo_mod_t *, tnode_t *, topo_version_t, - nvlist_t *, nvlist_t **); - -/* - * Given a /devices path for a whole disk, appending this extension gives the - * path to a raw device that can be opened. - */ -#if defined(__i386) || defined(__amd64) -#define PHYS_EXTN ":q,raw" -#elif defined(__sparc) || defined(__sparcv9) -#define PHYS_EXTN ":c,raw" -#else -#error Unknown architecture -#endif - static int disk_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, topo_instance_t, void *, void *); static const topo_modops_t disk_ops = { disk_enum, NULL }; -const topo_modinfo_t disk_info = +static const topo_modinfo_t disk_info = {DISK, FM_FMRI_SCHEME_HC, DISK_VERSION, &disk_ops}; -static const topo_pgroup_info_t io_pgroup = - { TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; - -static const topo_pgroup_info_t disk_auth_pgroup = { - FM_FMRI_AUTHORITY, - TOPO_STABILITY_PRIVATE, - TOPO_STABILITY_PRIVATE, -}; - -static const topo_pgroup_info_t storage_pgroup = { - TOPO_STORAGE_PGROUP, - TOPO_STABILITY_PRIVATE, - TOPO_STABILITY_PRIVATE, - 1 -}; - -/* - * Methods for disks. This is used by the disk-transport module to - * generate ereports based off SCSI disk status. - */ -static const topo_method_t disk_methods[] = { - { TOPO_METH_DISK_STATUS, TOPO_METH_DISK_STATUS_DESC, - TOPO_METH_DISK_STATUS_VERSION, TOPO_STABILITY_INTERNAL, - disk_status }, - { NULL } -}; -static di_devlink_handle_t devlink_hdl = NULL; - -/* disk node information */ -typedef struct disk_di_node { - topo_list_t ddn_list; - int ddn_instance; - char *ddn_devid; - di_node_t ddn_node; - char *ddn_lpath; /* logical path */ - char *ddn_dpath; /* device path */ -}disk_di_node_t; - -typedef struct disk_di_nodes { - pthread_mutex_t disk_di_nodes_lock; - topo_list_t disk_di_nodes_list; -}disk_di_nodes_t; - -/* list of devices */ -static disk_di_nodes_t disk_di_nodes; - -/* given a device find it in the global device list */ -static disk_di_node_t * -disk_di_node_match_device(char *device) -{ - disk_di_node_t *dnode; - - (void) pthread_mutex_lock(&disk_di_nodes.disk_di_nodes_lock); - for (dnode = topo_list_next(&(disk_di_nodes.disk_di_nodes_list)); - dnode != NULL; dnode = topo_list_next(dnode)) { - if (dnode->ddn_devid != NULL && - strcmp(device, - dnode->ddn_dpath) == 0) { - (void) pthread_mutex_unlock( - &disk_di_nodes.disk_di_nodes_lock); - return (dnode); - } - } - (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock); - return (NULL); -} - -/* get the disk storage group information */ -static void -disk_storage_info(topo_mod_t *mod, disk_di_node_t *dnode, - char **model, char **manuf, char **serial, char **firm, char **cap) -{ - char *entry; - di_node_t node = dnode->ddn_node; - int64_t *nblocksp; - uint64_t nblocks; - int *dblksizep; - uint_t dblksize; - char lentry[MAXPATHLEN]; - - if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, - INQUIRY_VENDOR_ID, &entry) > 0) { - *manuf = topo_mod_strdup(mod, entry); - } - if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, - INQUIRY_PRODUCT_ID, &entry) > 0) { - *model = topo_mod_strdup(mod, entry); - } - if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, - INQUIRY_REVISION_ID, &entry) > 0) { - *firm = topo_mod_strdup(mod, entry); - } - if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, - INQUIRY_SERIAL_NO, &entry) > 0) { - *serial = topo_mod_strdup(mod, entry); - } - if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, - "device-nblocks", &nblocksp) > 0) { - nblocks = (uint64_t)*nblocksp; - /* - * To save kernel memory, the driver may not - * define "device-dblksize" when its value is - * the default DEV_BSIZE value. - */ - if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, - "device-dblksize", &dblksizep) > 0) - dblksize = (uint_t)*dblksizep; - else - dblksize = DEV_BSIZE; /* default value */ - (void) snprintf(lentry, sizeof (lentry), - "%" PRIu64, nblocks * dblksize); - *cap = topo_mod_strdup(mod, lentry); - } -} - -/* populate the protocol group properties */ -static void -disk_set_proto_props(topo_mod_t *mod, tnode_t *dtn, int pinst) -{ - int err; - nvlist_t *asru = NULL; - char label[32]; - char *func = "disk_set_proto_props"; - nvlist_t *fmri; - disk_di_node_t *dnode; - - /* set the asru */ - dnode = topo_node_getspecific(dtn); - asru = topo_mod_devfmri(mod, FM_DEV_SCHEME_VERSION, - dnode->ddn_dpath, dnode->ddn_devid); - if (topo_node_asru_set(dtn, asru, 0, &err) != 0) { - topo_mod_dprintf(mod, - "%s: topo_node_asru_set error %d\n", - func, err); - nvlist_free(asru); - (void) topo_mod_seterrno(mod, err); - return; - } - nvlist_free(asru); - - (void) snprintf(label, sizeof (label), "HD_ID_%d", pinst); - if (topo_node_label_set(dtn, label, &err) != 0) { - topo_mod_dprintf(mod, "%s: label error %s\n", func, - topo_strerror(err)); - (void) topo_mod_seterrno(mod, err); - return; - } - - /* get the resource property */ - if (topo_node_resource(dtn, &fmri, &err) != 0) { - topo_mod_dprintf(mod, - "%s: topo_node_resource error: %s\n", func, - topo_strerror(err)); - (void) topo_mod_seterrno(mod, err); - return; - } - - /* set the child fru to the same as the resource */ - if (topo_node_fru_set(dtn, fmri, 0, &err) != 0) { - topo_mod_dprintf(mod, - "%s: topo_node_fru_set error: %s\n", func, - topo_strerror(err)); - (void) topo_mod_seterrno(mod, err); - nvlist_free(fmri); - return; - } - nvlist_free(fmri); -} - - -/* - * Set the properties of the disk node which include: - * group: protocol properties: resource, asru, label, fru - * group: authority properties: product-id, chasis-id, server-id - * group: io properties: devfs-path - * group: storage properties: - * - logical-disk, disk-model, disk-manufacturer, serial-number - * - firmware-revision, capacity-in-bytes - */ -static void -disk_set_props(tnode_t *dtn, tnode_t *parent, char *model, char *manuf, - char *serial, char *firm, char *cap, int *err, topo_mod_t *mod) -{ - char *device; - char *ptr, *ptr1; - int inst = topo_node_instance(parent); - disk_di_node_t *dnode; - - dnode = topo_node_getspecific(dtn); - - /* set the protocol group properties */ - disk_set_proto_props(mod, dtn, inst); - - /* create/set the authority group */ - if (topo_pgroup_create(dtn, &disk_auth_pgroup, err) == 0) { - (void) topo_prop_inherit(dtn, FM_FMRI_AUTHORITY, - FM_FMRI_AUTH_PRODUCT, err); - (void) topo_prop_inherit(dtn, FM_FMRI_AUTHORITY, - FM_FMRI_AUTH_CHASSIS, err); - (void) topo_prop_inherit(dtn, FM_FMRI_AUTHORITY, - FM_FMRI_AUTH_SERVER, err); - } - - /* create/set the devfs-path in the io group */ - (void) topo_pgroup_create(dtn, &io_pgroup, err); - - if (topo_prop_get_string(parent, TOPO_BINDING_PGROUP, - TOPO_BINDING_OCCUPANT, &device, err) == 0) { - (void) topo_prop_set_string(dtn, TOPO_PGROUP_IO, - TOPO_IO_DEV_PATH, TOPO_PROP_IMMUTABLE, device, err); - - topo_mod_strfree(mod, device); - } - - /* create the storage group */ - (void) topo_pgroup_create(dtn, &storage_pgroup, err); - - /* set the storage group properties */ - ptr = strrchr(dnode->ddn_lpath, '/'); - ptr1 = strchr(ptr, 's'); - if (ptr1) - *ptr1 = '\0'; - (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, - TOPO_STORAGE_LOGICAL_DISK_NAME, TOPO_PROP_IMMUTABLE, - ptr+1, err); - if (ptr1) - *ptr1 = 's'; - - - /* populate the storage group properties */ - if (model) { - (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, - TOPO_STORAGE_MODEL, TOPO_PROP_IMMUTABLE, model, err); - } - if (manuf) { - (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, - TOPO_STORAGE_MANUFACTURER, TOPO_PROP_IMMUTABLE, manuf, - err); - } - if (serial) { - (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, - TOPO_STORAGE_SERIAL_NUM, TOPO_PROP_IMMUTABLE, serial, err); - } - if (firm) { - (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, - TOPO_STORAGE_FIRMWARE_REV, TOPO_PROP_IMMUTABLE, firm, err); - } - if (cap) { - (void) topo_prop_set_string(dtn, TOPO_STORAGE_PGROUP, - TOPO_STORAGE_CAPACITY, TOPO_PROP_IMMUTABLE, cap, err); - } -} - -/* create the disk topo node */ -/*ARGSUSED*/ -static tnode_t * -disk_tnode_create(topo_mod_t *mod, tnode_t *parent, - const char *name, topo_instance_t i, char *model, char *manuf, - char *serial, char *firm, char *cap, void *priv) -{ - int err, len = 0; - nvlist_t *fmri; - tnode_t *dtn; - char *mm = NULL; - char *s; - nvlist_t *auth = topo_mod_auth(mod, parent); - - if ((s = strchr(model, ' ')) != NULL) { - *s = '-'; - } - len = strlen(manuf) + strlen(model) + 2; - if ((mm = topo_mod_alloc(mod, len)) != NULL) - (void) snprintf(mm, len, "%s-%s", manuf, model); - else - mm = model; - - fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i, - NULL, auth, mm, firm, serial); - - nvlist_free(auth); - - if (mm != model) - topo_mod_free(mod, mm, len); - else if (*s != NULL) - *s = ' '; - - if (fmri == NULL) { - topo_mod_dprintf(mod, - "Unable to make nvlist for %s bind: %s.\n", - name, topo_mod_errmsg(mod)); - return (NULL); - } - - if ((dtn = topo_node_bind(mod, parent, name, i, fmri)) == NULL) { - topo_mod_dprintf(mod, - "topo_node_bind (%s%d/%s%d) failed: %s\n", - topo_node_name(parent), topo_node_instance(parent), - name, i, - topo_strerror(topo_mod_errno(mod))); - nvlist_free(fmri); - return (NULL); - } - nvlist_free(fmri); - topo_node_setspecific(dtn, priv); - - /* add the properties of the disk */ - disk_set_props(dtn, parent, model, manuf, serial, firm, cap, - &err, mod); - - return (dtn); -} - -/*ARGSUSED*/ -static tnode_t * -disk_declare(tnode_t *parent, const char *name, topo_instance_t i, - void *priv, topo_mod_t *mod) -{ - tnode_t *dtn; - int err; - char *func = "disk_declare"; - char *model = NULL, *manuf = NULL, *serial = NULL; - char *cap = NULL, *firm = NULL; - disk_di_node_t *dnode = (disk_di_node_t *)priv; - nvlist_t *fmri; - - disk_storage_info(mod, dnode, - &model, &manuf, &serial, &firm, &cap); - - /* create the node */ - dtn = disk_tnode_create(mod, parent, - name, i, model, manuf, serial, firm, cap, priv); - - topo_mod_strfree(mod, model); - topo_mod_strfree(mod, manuf); - topo_mod_strfree(mod, serial); - topo_mod_strfree(mod, firm); - topo_mod_strfree(mod, cap); - - if (dtn == NULL) { - return (NULL); - } - - /* set the parent fru */ - if (topo_node_resource(parent, &fmri, &err) != 0) { - topo_mod_dprintf(mod, - "%s: topo_node_resource error: %s\n", func, - topo_strerror(err)); - topo_node_unbind(dtn); - return (NULL); - } - if (topo_node_fru_set(parent, fmri, 0, &err) != 0) { - topo_mod_dprintf(mod, "%s topo_node_fru error: %s\n", - func, topo_strerror(err)); - nvlist_free(fmri); - topo_node_unbind(dtn); - return (NULL); - } - - if (topo_method_register(mod, dtn, disk_methods) != 0) { - topo_mod_dprintf(mod, - "topo_method_register failed: %s\n", - topo_strerror(topo_mod_errno(mod))); - nvlist_free(fmri); - topo_node_unbind(dtn); - return (NULL); - } - - nvlist_free(fmri); - - return (dtn); -} - /*ARGSUSED*/ static int -disk_enum(topo_mod_t *mod, tnode_t *rnode, const char *name, - topo_instance_t min, topo_instance_t max, void *arg, void *notused) +disk_enum(topo_mod_t *mod, tnode_t *baynode, + const char *name, topo_instance_t min, topo_instance_t max, + void *arg, void *notused) { - tnode_t *diskn; char *device; int err; - disk_di_node_t *dnode; + nvlist_t *fmri; + topo_list_t *dlistp = topo_mod_getspecific(mod); if (strcmp(name, DISK) != 0) { - topo_mod_dprintf(mod, - "Currently only know how to enumerate %s components.\n", - DISK); + topo_mod_dprintf(mod, "disk_enum: " + "only know how to enumerate %s components.\n", DISK); return (-1); } - if (topo_prop_get_string(rnode, TOPO_BINDING_PGROUP, - TOPO_BINDING_OCCUPANT, &device, &err) != 0) - return (-1); - - if ((dnode = disk_di_node_match_device(device)) == NULL) { - topo_mod_dprintf(mod, - "No occupant found for bay=%d.\n", - topo_node_instance(rnode)); - topo_mod_strfree(mod, device); + /* set the parent fru */ + if (topo_node_resource(baynode, &fmri, &err) != 0) { + topo_mod_dprintf(mod, "disk_enum: " + "topo_node_resource error %s\n", topo_strerror(err)); return (-1); } - - diskn = disk_declare(rnode, name, 0, dnode, mod); - if (diskn == NULL) { - topo_mod_dprintf(mod, "Enumeration of %s failed: %s\n", - DISK, topo_strerror(topo_mod_errno(mod))); - topo_mod_strfree(mod, device); - return (-1); /* mod_errno already set */ + if (topo_node_fru_set(baynode, fmri, 0, &err) != 0) { + topo_mod_dprintf(mod, "disk_enum: " + "topo_node_fru error %s\n", topo_strerror(err)); + nvlist_free(fmri); + return (-1); } - topo_mod_strfree(mod, device); - return (0); -} - -/* - * Query the current disk status. If successful, the disk status is returned as - * an nvlist consisting of at least the following members: - * - * protocol string Supported protocol (currently "scsi") - * - * status nvlist Arbitrary protocol-specific information - * about the current state of the disk. - * - * faults nvlist A list of supported faults. Each - * element of this list is a boolean value. - * An element's existence indicates that - * the drive supports detecting this fault, - * and the value indicates the current - * state of the fault. - * - * <fault-name> nvlist For each fault named in 'faults', a - * nvlist describing protocol-specific - * attributes of the fault. - * - * This method relies on the libdiskstatus library to query this information. - */ -static int -disk_status(topo_mod_t *mod, tnode_t *nodep, topo_version_t vers, - nvlist_t *in_nvl, nvlist_t **out_nvl) -{ - disk_status_t *dsp; - char *devpath, *fullpath; - size_t pathlen; - int err; - nvlist_t *status; - *out_nvl = NULL; - - if (vers != TOPO_METH_DISK_STATUS_VERSION) - return (topo_mod_seterrno(mod, EMOD_VER_NEW)); + nvlist_free(fmri); /* - * If the caller specifies the "path" parameter, then this indicates - * that we should use this instead of deriving it from the topo node - * itself. + * For internal storage, get the path to the occupant from the + * binding group of the bay node */ - if (nvlist_lookup_string(in_nvl, "path", &fullpath) == 0) { - devpath = NULL; - } else { - /* - * Get the /devices path and attempt to open the disk status - * handle. - */ - if (topo_prop_get_string(nodep, TOPO_PGROUP_IO, - TOPO_IO_DEV_PATH, &devpath, &err) != 0) - return (topo_mod_seterrno(mod, EMOD_METHOD_NOTSUP)); - - /* - * Note that sizeof(string) includes the terminating NULL byte - */ - pathlen = strlen(devpath) + sizeof ("/devices") + - sizeof (PHYS_EXTN) - 1; - - if ((fullpath = topo_mod_alloc(mod, pathlen)) == NULL) - return (topo_mod_seterrno(mod, EMOD_NOMEM)); - - (void) snprintf(fullpath, pathlen, "/devices%s%s", devpath, - PHYS_EXTN); - - topo_mod_strfree(mod, devpath); - } - - if ((dsp = disk_status_open(fullpath, &err)) == NULL) { - if (devpath) - topo_mod_free(mod, fullpath, pathlen); - return (topo_mod_seterrno(mod, err == EDS_NOMEM ? - EMOD_NOMEM : EMOD_METHOD_NOTSUP)); - } - - if (devpath) - topo_mod_free(mod, fullpath, pathlen); - - if ((status = disk_status_get(dsp)) == NULL) { - err = (disk_status_errno(dsp) == EDS_NOMEM ? - EMOD_NOMEM : EMOD_METHOD_NOTSUP); - disk_status_close(dsp); - return (topo_mod_seterrno(mod, err)); - } - - *out_nvl = status; - disk_status_close(dsp); - return (0); -} - -/* di_devlink callback for disk_drvinst2devpath */ -static int -disk_drvinst2devpath_devlink_callback(di_devlink_t dl, void *arg) -{ - char **devpathp = (char **)arg; - char *devpath = (char *)di_devlink_path(dl); - - *devpathp = strdup(devpath); - return (DI_WALK_TERMINATE); -} - -static disk_di_node_t * -disk_di_node_add(int *instancep, char *devid, di_node_t node, topo_mod_t *mod) -{ - int mlen; - char *devpath, *minorpath; - char *extn = ":a"; - disk_di_node_t *dnode; - - (void) pthread_mutex_lock(&(disk_di_nodes.disk_di_nodes_lock)); - for (dnode = topo_list_next(&(disk_di_nodes.disk_di_nodes_list)); - dnode != NULL; dnode = topo_list_next(dnode)) { - if (strcmp(dnode->ddn_devid, devid) == 0) { - topo_mod_dprintf(mod, - "disk_node_add - already there %s\n", devid); - (void) pthread_mutex_unlock( - &disk_di_nodes.disk_di_nodes_lock); - return (dnode); /* return existing node */ - } - } - - if ((dnode = topo_mod_alloc(mod, sizeof (disk_di_node_t))) == NULL) { - topo_mod_dprintf(mod, - "disk_node_add - topo_mod_alloc failed\n"); - (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock); - return (NULL); /* return existing node */ + if (topo_prop_get_string(baynode, TOPO_PGROUP_BINDING, + TOPO_BINDING_OCCUPANT, &device, &err) != 0) { + topo_mod_dprintf(mod, "disk_enum: " + "binding error %s\n", topo_strerror(err)); + return (-1); } - dnode->ddn_devid = strdup(devid); - dnode->ddn_instance = *instancep; - dnode->ddn_node = node; - dnode->ddn_dpath = di_devfs_path(node); - - mlen = strlen(dnode->ddn_dpath) + strlen(extn) + 1; - minorpath = topo_mod_alloc(mod, mlen); - (void) snprintf(minorpath, mlen, "%s%s", dnode->ddn_dpath, - extn); - /* walk devlink looking for node that maps to /device path */ - devpath = NULL; - (void) di_devlink_walk(devlink_hdl, "^dsk/", - minorpath, DI_PRIMARY_LINK, - (void *)&devpath, disk_drvinst2devpath_devlink_callback); - topo_mod_free(mod, minorpath, mlen); - dnode->ddn_lpath = devpath; - - topo_list_append(&disk_di_nodes.disk_di_nodes_list, (void *)dnode); - (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock); - - topo_mod_dprintf(mod, - "disk_node_add - adding %s inst: %d\n", - dnode->ddn_devid, *instancep); - *instancep = (*instancep) + 1; - return (dnode); -} - -/*ARGSUSED*/ -static int -disk_walk_di_nodes(di_node_t node, void *arg) -{ - ddi_devid_t devid = NULL; - char *devidstr; - static int instance_devid = 0; - topo_mod_t *mod = (topo_mod_t *)arg; - /* only interested in nodes that have devids */ - devid = (ddi_devid_t)di_devid(node); - if (devid == NULL) - return (DI_WALK_CONTINUE); + /* locate and topo enumerate the disk with that path */ + err = disk_declare_path(mod, baynode, dlistp, device); - /* ... with a string representation of the devid */ - devidstr = devid_str_encode(devid, NULL); - if (devidstr == NULL) - return (DI_WALK_CONTINUE); - - /* create/find the devid scsi topology node */ - (void) disk_di_node_add(&instance_devid, devidstr, node, mod); - devid_str_free(devidstr); - return (DI_WALK_CONTINUE); + topo_mod_strfree(mod, device); + return (err); } /*ARGSUSED*/ int _topo_init(topo_mod_t *mod, topo_version_t version) { - di_node_t devtree; + topo_list_t *dlistp; /* * Turn on module debugging output */ if (getenv("TOPODISKDEBUG") != NULL) topo_mod_setdebug(mod); - topo_mod_dprintf(mod, "initializing %s enumerator\n", DISK); + topo_mod_dprintf(mod, "_topo_init: " + "initializing %s enumerator\n", DISK); if (topo_mod_register(mod, &disk_info, TOPO_VERSION) != 0) { - topo_mod_dprintf(mod, "%s registration failed: %s\n", - DISK, topo_mod_errmsg(mod)); - return (-1); /* mod errno already set */ + topo_mod_dprintf(mod, "_topo_init: " + "%s registration failed: %s\n", DISK, topo_mod_errmsg(mod)); + return (-1); /* mod errno already set */ } - (void) pthread_mutex_init(&disk_di_nodes.disk_di_nodes_lock, NULL); - disk_di_nodes.disk_di_nodes_list.l_next = NULL; - disk_di_nodes.disk_di_nodes_list.l_prev = NULL; - - devtree = di_init("/", DINFOCACHE); - /* we don't get all the nodes with topo_mod_devinfo */ - if (devtree == NULL) { - topo_mod_unregister(mod); - (void) pthread_mutex_destroy(&disk_di_nodes.disk_di_nodes_lock); - topo_mod_dprintf(mod, "topo_mod_devinfo init failed."); + if ((dlistp = topo_mod_zalloc(mod, sizeof (topo_list_t))) == NULL) { + topo_mod_dprintf(mod, "_topo_inti: failed to allocate " + "disk list"); return (-1); } - /* walk the tree to get the devids */ - devlink_hdl = di_devlink_init(NULL, 0); - if (devlink_hdl == DI_NODE_NIL) { + + if (disk_list_gather(mod, dlistp) != 0) { topo_mod_unregister(mod); - (void) pthread_mutex_destroy(&disk_di_nodes.disk_di_nodes_lock); - topo_mod_dprintf(mod, "di_devlink init failed."); + topo_mod_free(mod, dlistp, sizeof (topo_list_t)); + topo_mod_dprintf(mod, "_topo_init: " + "failed to locate disks"); return (-1); } - (void) di_walk_node(devtree, DI_WALK_CLDFIRST, mod, - disk_walk_di_nodes); - if (devlink_hdl != NULL) - (void) di_devlink_fini(&devlink_hdl); + topo_mod_dprintf(mod, "_topo_init: " + "%s enumerator initialized\n", DISK); - topo_mod_dprintf(mod, "%s enumerator initialized\n", DISK); + topo_mod_setspecific(mod, dlistp); return (0); } @@ -705,19 +140,10 @@ _topo_init(topo_mod_t *mod, topo_version_t version) void _topo_fini(topo_mod_t *mod) { - disk_di_node_t *dnode; - - (void) pthread_mutex_lock(&disk_di_nodes.disk_di_nodes_lock); - while ((dnode = topo_list_next(&(disk_di_nodes.disk_di_nodes_list))) - != NULL) { - free(dnode->ddn_lpath); - free(dnode->ddn_dpath); - free(dnode->ddn_devid); - topo_list_delete(&(disk_di_nodes.disk_di_nodes_list), - (void *)dnode); - topo_mod_free(mod, dnode, sizeof (disk_di_node_t)); - } - (void) pthread_mutex_unlock(&disk_di_nodes.disk_di_nodes_lock); - (void) pthread_mutex_destroy(&disk_di_nodes.disk_di_nodes_lock); + topo_list_t *dlistp = topo_mod_getspecific(mod); + disk_list_free(mod, dlistp); + topo_mod_free(mod, dlistp, sizeof (topo_list_t)); topo_mod_unregister(mod); + topo_mod_dprintf(mod, "_topo_fini: " + "%s enumerator uninitialized\n", DISK); } diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk.h b/usr/src/lib/fm/topo/modules/common/disk/disk.h index 2968c3663a..8596945b26 100644 --- a/usr/src/lib/fm/topo/modules/common/disk/disk.h +++ b/usr/src/lib/fm/topo/modules/common/disk/disk.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -29,6 +29,9 @@ #pragma ident "%Z%%M% %I% %E% SMI" +#include <fm/topo_mod.h> +#include <libdevinfo.h> + #ifdef __cplusplus extern "C" { #endif @@ -39,12 +42,8 @@ extern "C" { /* Max. number of devices for thumper */ #define DEVID_MAX 48 -/* Properties for binding group */ -#define TOPO_BINDING_PGROUP "binding" -#define TOPO_BINDING_OCCUPANT "occupant-path" - /* Properties added to the "storage" pgroup: */ -#define TOPO_STORAGE_PGROUP "storage" +#define TOPO_PGROUP_STORAGE "storage" #define TOPO_STORAGE_LOGICAL_DISK_NAME "logical-disk" #define TOPO_STORAGE_MODEL "model" #define TOPO_STORAGE_MANUFACTURER "manufacturer" @@ -52,6 +51,23 @@ extern "C" { #define TOPO_STORAGE_FIRMWARE_REV "firmware-revision" #define TOPO_STORAGE_CAPACITY "capacity-in-bytes" +/* + * Properties for binding group: The binding group required in platform + * specific xml that describes 'bay' nodes containing internal disks. + */ +#define TOPO_PGROUP_BINDING "binding" +#define TOPO_BINDING_OCCUPANT "occupant-path" + +struct topo_list; + +/* Methods shared with the ses module (disk_common.c) */ +extern int disk_list_gather(topo_mod_t *, struct topo_list *); +extern void disk_list_free(topo_mod_t *, struct topo_list *); +extern int disk_declare_path(topo_mod_t *, tnode_t *, + struct topo_list *, const char *); +extern int disk_declare_addr(topo_mod_t *, tnode_t *, + struct topo_list *, const char *); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk_common.c b/usr/src/lib/fm/topo/modules/common/disk/disk_common.c new file mode 100644 index 0000000000..3cc6651d7e --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/disk/disk_common.c @@ -0,0 +1,868 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Functions in this file are shared between the disk and ses enumerators. + * + * A topo_list_t of all disks is returned by a successful disk_list_gather() + * call, and the list is freed by a disk_list_free(). To create a 'disk' topo + * node below a specific 'bay' parent node either disk_declare_path() or + * disk_declare_addr() are called. The caller determines which 'disk' is + * in which 'bay'. A disk's 'label' and 'authority' information come from + * its parent 'bay' node. + */ + +#include <strings.h> +#include <libdevinfo.h> +#include <devid.h> +#include <sys/libdevid.h> +#include <pthread.h> +#include <inttypes.h> +#include <sys/dkio.h> +#include <sys/scsi/scsi_types.h> +#include <fm/topo_mod.h> +#include <fm/topo_list.h> +#include <fm/libdiskstatus.h> +#include <sys/fm/protocol.h> +#include "disk.h" + +/* + * disk node information. + */ +typedef struct disk_di_node { + topo_list_t ddn_list; /* list of disks */ + + /* the following two fields are always defined */ + char *ddn_devid; /* devid of disk */ + char *ddn_dpath; /* path to devinfo (may be vhci) */ + char **ddn_ppath; /* physical path to device (phci) */ + int ddn_ppath_count; + + char *ddn_lpath; /* logical path (public /dev name) */ + + char *ddn_mfg; /* misc information about device */ + char *ddn_model; + char *ddn_serial; + char *ddn_firm; + char *ddn_cap; + + char **ddn_target_port; + int ddn_target_port_count; +} disk_di_node_t; + +/* common callback information for di_walk_node() and di_devlink_walk */ +typedef struct disk_cbdata { + topo_mod_t *dcb_mod; + topo_list_t *dcb_list; + + di_devlink_handle_t dcb_devhdl; + disk_di_node_t *dcb_dnode; /* for di_devlink_walk only */ +} disk_cbdata_t; + +/* + * Given a /devices path for a whole disk, appending this extension gives the + * path to a raw device that can be opened. + */ +#if defined(__i386) || defined(__amd64) +#define PHYS_EXTN ":q,raw" +#elif defined(__sparc) || defined(__sparcv9) +#define PHYS_EXTN ":c,raw" +#else +#error Unknown architecture +#endif + +/* + * Methods for disks. This is used by the disk-transport module to + * generate ereports based off SCSI disk status. + */ +static int disk_status(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); + +static const topo_method_t disk_methods[] = { + { TOPO_METH_DISK_STATUS, TOPO_METH_DISK_STATUS_DESC, + TOPO_METH_DISK_STATUS_VERSION, TOPO_STABILITY_INTERNAL, + disk_status }, + { NULL } +}; + +static const topo_pgroup_info_t io_pgroup = { + TOPO_PGROUP_IO, + TOPO_STABILITY_PRIVATE, + TOPO_STABILITY_PRIVATE, + 1 +}; + +static const topo_pgroup_info_t disk_auth_pgroup = { + FM_FMRI_AUTHORITY, + TOPO_STABILITY_PRIVATE, + TOPO_STABILITY_PRIVATE, + 1 +}; + +static const topo_pgroup_info_t storage_pgroup = { + TOPO_PGROUP_STORAGE, + TOPO_STABILITY_PRIVATE, + TOPO_STABILITY_PRIVATE, + 1 +}; + +/* + * Set the properties of the disk node, from disk_di_node_t data. + * Properties include: + * group: protocol properties: resource, asru, label, fru + * group: authority properties: product-id, chasis-id, server-id + * group: io properties: devfs-path, devid + * group: storage properties: + * - logical-disk, disk-model, disk-manufacturer, serial-number + * - firmware-revision, capacity-in-bytes + */ +static int +disk_set_props(topo_mod_t *mod, tnode_t *parent, + tnode_t *dtn, disk_di_node_t *dnode) +{ + nvlist_t *asru = NULL; + char *label = NULL; + nvlist_t *fmri = NULL; + int err; + + /* form and set the asru */ + if ((asru = topo_mod_devfmri(mod, FM_DEV_SCHEME_VERSION, + dnode->ddn_dpath, dnode->ddn_devid)) == NULL) { + err = ETOPO_FMRI_UNKNOWN; + topo_mod_dprintf(mod, "disk_set_props: " + "asru error %s\n", topo_strerror(err)); + goto error; + } + if (topo_node_asru_set(dtn, asru, 0, &err) != 0) { + topo_mod_dprintf(mod, "disk_set_props: " + "asru_set error %s\n", topo_strerror(err)); + goto error; + } + + /* pull the label property down from our parent 'bay' node */ + if (topo_node_label(parent, &label, &err) != 0) { + topo_mod_dprintf(mod, "disk_set_props: " + "label error %s\n", topo_strerror(err)); + goto error; + } + if (topo_node_label_set(dtn, label, &err) != 0) { + topo_mod_dprintf(mod, "disk_set_props: " + "label_set error %s\n", topo_strerror(err)); + goto error; + } + + /* get the resource fmri, and use it as the fru */ + if (topo_node_resource(dtn, &fmri, &err) != 0) { + topo_mod_dprintf(mod, "disk_set_props: " + "resource error: %s\n", topo_strerror(err)); + goto error; + } + if (topo_node_fru_set(dtn, fmri, 0, &err) != 0) { + topo_mod_dprintf(mod, "disk_set_props: " + "fru_set error: %s\n", topo_strerror(err)); + goto error; + } + + /* create/set the authority group */ + if ((topo_pgroup_create(dtn, &disk_auth_pgroup, &err) != 0) && + (err != ETOPO_PROP_DEFD)) { + topo_mod_dprintf(mod, "disk_set_props: " + "create disk_auth error %s\n", topo_strerror(err)); + goto error; + } + + /* create/set the devfs-path and devid in the io group */ + if (topo_pgroup_create(dtn, &io_pgroup, &err) != 0) { + topo_mod_dprintf(mod, "disk_set_props: " + "create io error %s\n", topo_strerror(err)); + goto error; + } + + if (topo_prop_set_string(dtn, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH, + TOPO_PROP_IMMUTABLE, dnode->ddn_dpath, &err) != 0) { + topo_mod_dprintf(mod, "disk_set_props: " + "set dev error %s\n", topo_strerror(err)); + goto error; + } + + if (topo_prop_set_string(dtn, TOPO_PGROUP_IO, TOPO_IO_DEVID, + TOPO_PROP_IMMUTABLE, dnode->ddn_devid, &err) != 0) { + topo_mod_dprintf(mod, "disk_set_props: " + "set devid error %s\n", topo_strerror(err)); + goto error; + } + + if (dnode->ddn_ppath_count != 0 && + topo_prop_set_string_array(dtn, TOPO_PGROUP_IO, TOPO_IO_PHYS_PATH, + TOPO_PROP_IMMUTABLE, (const char **)dnode->ddn_ppath, + dnode->ddn_ppath_count, &err) != 0) { + topo_mod_dprintf(mod, "disk_set_props: " + "set phys-path error %s\n", topo_strerror(err)); + goto error; + } + + /* create the storage group */ + if (topo_pgroup_create(dtn, &storage_pgroup, &err) != 0) { + topo_mod_dprintf(mod, "disk_set_props: " + "create storage error %s\n", topo_strerror(err)); + goto error; + } + + /* set the storage group public /dev name */ + if (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_LOGICAL_DISK_NAME, TOPO_PROP_IMMUTABLE, + dnode->ddn_lpath, &err) != 0) { + topo_mod_dprintf(mod, "disk_set_props: " + "set disk_name error %s\n", topo_strerror(err)); + goto error; + } + + /* populate other misc storage group properties */ + if (dnode->ddn_mfg && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_MANUFACTURER, TOPO_PROP_IMMUTABLE, + dnode->ddn_mfg, &err) != 0)) { + topo_mod_dprintf(mod, "disk_set_props: " + "set mfg error %s\n", topo_strerror(err)); + goto error; + } + if (dnode->ddn_model && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_MODEL, TOPO_PROP_IMMUTABLE, + dnode->ddn_model, &err) != 0)) { + topo_mod_dprintf(mod, "disk_set_props: " + "set model error %s\n", topo_strerror(err)); + goto error; + } + if (dnode->ddn_serial && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_SERIAL_NUM, TOPO_PROP_IMMUTABLE, + dnode->ddn_serial, &err) != 0)) { + topo_mod_dprintf(mod, "disk_set_props: " + "set serial error %s\n", topo_strerror(err)); + goto error; + } + if (dnode->ddn_firm && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_FIRMWARE_REV, TOPO_PROP_IMMUTABLE, + dnode->ddn_firm, &err) != 0)) { + topo_mod_dprintf(mod, "disk_set_props: " + "set firm error %s\n", topo_strerror(err)); + goto error; + } + if (dnode->ddn_cap && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE, + TOPO_STORAGE_CAPACITY, TOPO_PROP_IMMUTABLE, + dnode->ddn_cap, &err) != 0)) { + topo_mod_dprintf(mod, "disk_set_props: " + "set cap error %s\n", topo_strerror(err)); + goto error; + } + err = 0; + +out: if (fmri) + nvlist_free(fmri); + if (label) + topo_mod_strfree(mod, label); + if (asru) + nvlist_free(asru); + return (err); + +error: err = topo_mod_seterrno(mod, err); + goto out; +} + +/* create the disk topo node */ +static tnode_t * +disk_tnode_create(topo_mod_t *mod, tnode_t *parent, + disk_di_node_t *dnode, const char *name, topo_instance_t i) +{ + int len; + nvlist_t *fmri; + tnode_t *dtn; + char *part = NULL; + char *b = NULL; + nvlist_t *auth; + + /* form 'part=' of fmri as "<mfg>-<model>" */ + if (dnode->ddn_mfg && dnode->ddn_model) { + /* XXX replace first ' ' in the model with a '-' */ + if ((b = strchr(dnode->ddn_model, ' ')) != NULL) + *b = '-'; + len = strlen(dnode->ddn_mfg) + 1 + strlen(dnode->ddn_model) + 1; + if ((part = topo_mod_alloc(mod, len)) != NULL) + (void) snprintf(part, len, "%s-%s", + dnode->ddn_mfg, dnode->ddn_model); + } + + auth = topo_mod_auth(mod, parent); + fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i, NULL, + auth, part ? part : dnode->ddn_model, dnode->ddn_firm, + dnode->ddn_serial); + nvlist_free(auth); + + if (part && (part != dnode->ddn_model)) + topo_mod_free(mod, part, len); + else if (b) + *b = ' '; /* restore blank */ + + if (fmri == NULL) { + topo_mod_dprintf(mod, "disk_tnode_create: " + "hcfmri (%s%d/%s%d) error %s\n", + topo_node_name(parent), topo_node_instance(parent), + name, i, topo_strerror(topo_mod_errno(mod))); + return (NULL); + } + + if ((dtn = topo_node_bind(mod, parent, name, i, fmri)) == NULL) { + topo_mod_dprintf(mod, "disk_tnode_create: " + "bind (%s%d/%s%d) error %s\n", + topo_node_name(parent), topo_node_instance(parent), + name, i, topo_strerror(topo_mod_errno(mod))); + nvlist_free(fmri); + return (NULL); + } + nvlist_free(fmri); + + /* add the properties of the disk */ + if (disk_set_props(mod, parent, dtn, dnode) != 0) { + topo_mod_dprintf(mod, "disk_tnode_create: " + "disk_set_props (%s%d/%s%d) error %s\n", + topo_node_name(parent), topo_node_instance(parent), + name, i, topo_strerror(topo_mod_errno(mod))); + topo_node_unbind(dtn); + return (NULL); + } + return (dtn); +} + +static int +disk_declare(topo_mod_t *mod, tnode_t *parent, disk_di_node_t *dnode) +{ + tnode_t *dtn; + + /* create the disk topo node: one disk per 'bay' */ + dtn = disk_tnode_create(mod, parent, dnode, DISK, 0); + if (dtn == NULL) { + topo_mod_dprintf(mod, "disk_declare: " + "disk_tnode_create error %s\n", + topo_strerror(topo_mod_errno(mod))); + return (-1); + } + + /* register disk_methods against the disk topo node */ + if (topo_method_register(mod, dtn, disk_methods) != 0) { + topo_mod_dprintf(mod, "disk_declare: " + "topo_method_register error %s\n", + topo_strerror(topo_mod_errno(mod))); + topo_node_unbind(dtn); + return (-1); + } + return (0); +} + +int +disk_declare_path(topo_mod_t *mod, tnode_t *parent, topo_list_t *listp, + const char *path) +{ + disk_di_node_t *dnode; + int i; + + /* + * Check for match using physical phci (ddn_ppath). Use + * di_devfs_path_match so generic.vs.non-generic names match. + */ + for (dnode = topo_list_next(listp); dnode != NULL; + dnode = topo_list_next(dnode)) { + if (dnode->ddn_ppath == NULL) + continue; + + for (i = 0; i < dnode->ddn_ppath_count; i++) { + if (di_devfs_path_match(dnode->ddn_ppath[0], path)) + return (disk_declare(mod, parent, dnode)); + } + } + + topo_mod_dprintf(mod, "disk_declare_path: " + "failed to find disk matching path %s", path); + return (0); +} + +int +disk_declare_addr(topo_mod_t *mod, tnode_t *parent, topo_list_t *listp, + const char *addr) +{ + disk_di_node_t *dnode; + int i; + + /* Check for match using addr. */ + for (dnode = topo_list_next(listp); dnode != NULL; + dnode = topo_list_next(dnode)) { + if (dnode->ddn_target_port == NULL) + continue; + + for (i = 0; i < dnode->ddn_target_port_count; i++) { + if (strncmp(dnode->ddn_target_port[i], addr, + strcspn(dnode->ddn_target_port[i], ":")) == 0) + return (disk_declare(mod, parent, dnode)); + } + } + + topo_mod_dprintf(mod, "disk_declare_addr: " + "failed to find disk matching addr %s", addr); + return (0); +} + +/* di_devlink callback for disk_di_node_add */ +static int +disk_devlink_callback(di_devlink_t dl, void *arg) +{ + disk_cbdata_t *cbp = (disk_cbdata_t *)arg; + topo_mod_t *mod = cbp->dcb_mod; + disk_di_node_t *dnode = cbp->dcb_dnode; + const char *devpath; + char *ctds, *slice; + + devpath = di_devlink_path(dl); + if ((dnode == NULL) || (devpath == NULL)) + return (DI_WALK_TERMINATE); + + /* trim the slice off the public name */ + if (((ctds = strrchr(devpath, '/')) != NULL) && + ((slice = strchr(ctds, 's')) != NULL)) + *slice = '\0'; + + /* Establish the public /dev name (no slice) */ + dnode->ddn_lpath = topo_mod_strdup(mod, ctds ? ctds + 1 : devpath); + + if (ctds && slice) + *slice = 's'; + return (DI_WALK_TERMINATE); +} + +static void +disk_di_node_free(topo_mod_t *mod, disk_di_node_t *dnode) +{ + int i; + + /* free the stuff we point to */ + topo_mod_strfree(mod, dnode->ddn_devid); + for (i = 0; i < dnode->ddn_ppath_count; i++) + topo_mod_strfree(mod, dnode->ddn_ppath[i]); + topo_mod_free(mod, dnode->ddn_ppath, + dnode->ddn_ppath_count * sizeof (uintptr_t)); + topo_mod_strfree(mod, dnode->ddn_dpath); + topo_mod_strfree(mod, dnode->ddn_lpath); + + topo_mod_strfree(mod, dnode->ddn_mfg); + topo_mod_strfree(mod, dnode->ddn_model); + topo_mod_strfree(mod, dnode->ddn_serial); + topo_mod_strfree(mod, dnode->ddn_firm); + topo_mod_strfree(mod, dnode->ddn_cap); + + for (i = 0; i < dnode->ddn_target_port_count; i++) + topo_mod_strfree(mod, dnode->ddn_target_port[i]); + topo_mod_free(mod, dnode->ddn_target_port, + dnode->ddn_target_port_count * sizeof (uintptr_t)); + + /* free self */ + topo_mod_free(mod, dnode, sizeof (disk_di_node_t)); +} + +static int +disk_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp) +{ + topo_mod_t *mod = cbp->dcb_mod; + disk_di_node_t *dnode; + di_path_t pnode; + char *path; + int mlen; + char *minorpath; + char *extn = ":a"; + char *s; + int64_t *nblocksp; + uint64_t nblocks; + int *dblksizep; + uint_t dblksize; + char lentry[MAXPATHLEN]; + int pathcount, portcount; + int ret, i; + + /* check for list duplicate using devid search */ + for (dnode = topo_list_next(cbp->dcb_list); + dnode != NULL; dnode = topo_list_next(dnode)) { + if (devid_str_compare(dnode->ddn_devid, devid) == 0) { + topo_mod_dprintf(mod, "disk_di_node_add: " + "already there %s\n", devid); + return (0); + } + } + + if ((dnode = topo_mod_zalloc(mod, sizeof (disk_di_node_t))) == NULL) + return (-1); + + /* Establish the devid. */ + dnode->ddn_devid = topo_mod_strdup(mod, devid); + if (dnode->ddn_devid == NULL) + goto error; + + /* Establish the devinfo dpath */ + if ((path = di_devfs_path(node)) == NULL) { + topo_mod_seterrno(mod, errno); + goto error; + } + + dnode->ddn_dpath = topo_mod_strdup(mod, path); + di_devfs_path_free(path); + if (dnode->ddn_dpath == NULL) + goto error; + + /* + * Establish the physical ppath and target ports. If the device is + * non-mpxio then dpath and ppath are the same, and the target port is a + * property of the device node. + * + * If dpath is a client node under scsi_vhci, then iterate over all + * paths and get their physical paths and target port properrties. + * di_path_client_next_path call below will + * return non-NULL, and ppath is set to the physical path to the first + * pathinfo node. + * + * NOTE: It is possible to get a generic.vs.non-generic path + * for di_devfs_path.vs.di_path_devfs_path like: + * xml: /pci@7b,0/pci1022,7458@11/pci1000,3060@2/sd@2,0 + * pnode: /pci@7b,0/pci1022,7458@11/pci1000,3060@2/disk@2,0 + * To resolve this issue disk_declare_path() needs to use the + * special di_devfs_path_match() interface. + */ + pathcount = portcount = 0; + pnode = NULL; + while ((pnode = di_path_client_next_path(node, pnode)) != NULL) { + if ((ret = di_path_prop_lookup_strings(pnode, + "target-port", &s)) > 0) + portcount += ret; + pathcount++; + } + + if (pathcount == 0) { + if ((dnode->ddn_ppath = + topo_mod_zalloc(mod, sizeof (uintptr_t))) == NULL) + goto error; + + dnode->ddn_ppath_count = 1; + if ((dnode->ddn_ppath[0] = topo_mod_strdup(mod, + dnode->ddn_dpath)) == NULL) + goto error; + + if ((ret = di_prop_lookup_strings(DDI_DEV_T_ANY, node, + "target-port", &s)) > 0) { + if ((dnode->ddn_target_port = topo_mod_zalloc(mod, + ret * sizeof (uintptr_t))) == NULL) + goto error; + + dnode->ddn_target_port_count = ret; + + for (i = 0; i < ret; i++) { + if ((dnode->ddn_target_port[i] = + topo_mod_strdup(mod, s)) == NULL) + goto error; + + s += strlen(s) + 1; + } + } + } else { + if ((dnode->ddn_ppath = topo_mod_zalloc(mod, + pathcount * sizeof (uintptr_t))) == NULL) + goto error; + + dnode->ddn_ppath_count = pathcount; + + if (portcount != 0 && + ((dnode->ddn_target_port = topo_mod_zalloc(mod, + portcount * sizeof (uintptr_t)))) == NULL) + goto error; + + dnode->ddn_target_port_count = portcount; + + pnode = NULL; + pathcount = portcount = 0; + while ((pnode = di_path_client_next_path(node, + pnode)) != NULL) { + if ((path = di_path_devfs_path(pnode)) == NULL) { + topo_mod_seterrno(mod, errno); + goto error; + } + + dnode->ddn_ppath[pathcount] = + topo_mod_strdup(mod, path); + di_devfs_path_free(path); + if (dnode->ddn_ppath[pathcount] == NULL) + goto error; + + if ((ret = di_path_prop_lookup_strings(pnode, + "target-port", &s)) > 0) { + for (i = 0; i < ret; i++) { + if ((dnode->ddn_target_port[portcount] = + topo_mod_strdup(mod, s)) == NULL) + goto error; + + portcount++; + s += strlen(s) + 1; + } + } + + pathcount++; + } + } + + /* + * Find the public /dev name by adding a minor name and using + * di_devlink interface for reverse translation (use devinfo path). + */ + mlen = strlen(dnode->ddn_dpath) + strlen(extn) + 1; + if ((minorpath = topo_mod_alloc(mod, mlen)) == NULL) + goto error; + (void) snprintf(minorpath, mlen, "%s%s", dnode->ddn_dpath, extn); + cbp->dcb_dnode = dnode; + (void) di_devlink_walk(cbp->dcb_devhdl, "^dsk/", minorpath, + DI_PRIMARY_LINK, cbp, disk_devlink_callback); + topo_mod_free(mod, minorpath, mlen); + if (dnode->ddn_lpath == NULL) { + topo_mod_dprintf(mod, "disk_di_node_add: " + "failed to determine logical path"); + goto error; + } + + /* cache various bits of optional information about the disk */ + if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, + INQUIRY_VENDOR_ID, &s) > 0) { + if ((dnode->ddn_mfg = topo_mod_strdup(mod, s)) == NULL) + goto error; + } + if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, + INQUIRY_PRODUCT_ID, &s) > 0) { + if ((dnode->ddn_model = topo_mod_strdup(mod, s)) == NULL) + goto error; + } + if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, + INQUIRY_REVISION_ID, &s) > 0) { + if ((dnode->ddn_firm = topo_mod_strdup(mod, s)) == NULL) + goto error; + } + if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, + INQUIRY_SERIAL_NO, &s) > 0) { + if ((dnode->ddn_serial = topo_mod_strdup(mod, s)) == NULL) + goto error; + } + if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, + "device-nblocks", &nblocksp) > 0) { + nblocks = (uint64_t)*nblocksp; + /* + * To save kernel memory, the driver may not define + * "device-dblksize" when its value is default DEV_BSIZE. + */ + if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, + "device-dblksize", &dblksizep) > 0) + dblksize = (uint_t)*dblksizep; + else + dblksize = DEV_BSIZE; /* default value */ + (void) snprintf(lentry, sizeof (lentry), + "%" PRIu64, nblocks * dblksize); + if ((dnode->ddn_cap = topo_mod_strdup(mod, lentry)) == NULL) + goto error; + } + + topo_mod_dprintf(mod, "disk_di_node_add: " + "adding %s\n", dnode->ddn_devid); + topo_mod_dprintf(mod, " " + " %s\n", dnode->ddn_dpath); + for (i = 0; i < dnode->ddn_ppath_count; i++) { + topo_mod_dprintf(mod, " " + " %s\n", dnode->ddn_ppath[i]); + } + topo_list_append(cbp->dcb_list, dnode); + return (0); + +error: + disk_di_node_free(mod, dnode); + return (-1); +} + +/* di_walk_node callback for disk_list_gather */ +static int +disk_walk_di_nodes(di_node_t node, void *arg) +{ + ddi_devid_t devid = NULL; + char *devidstr; + + /* only interested in nodes that have devids */ + devid = (ddi_devid_t)di_devid(node); + if (devid == NULL) + return (DI_WALK_CONTINUE); + + /* ... with a string representation of the devid */ + devidstr = devid_str_encode(devid, NULL); + if (devidstr == NULL) + return (DI_WALK_CONTINUE); + + /* create/find the devid scsi topology node */ + (void) disk_di_node_add(node, devidstr, arg); + devid_str_free(devidstr); + return (DI_WALK_CONTINUE); +} + +int +disk_list_gather(topo_mod_t *mod, topo_list_t *listp) +{ + di_node_t devtree; + di_devlink_handle_t devhdl; + disk_cbdata_t dcb; + + if ((devtree = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { + topo_mod_dprintf(mod, "disk_list_gather: " + "di_init failed"); + return (-1); + } + + if ((devhdl = di_devlink_init(NULL, 0)) == DI_NODE_NIL) { + topo_mod_dprintf(mod, "disk_list_gather: " + "di_devlink_init failed"); + di_fini(devtree); + return (-1); + } + + dcb.dcb_mod = mod; + dcb.dcb_list = listp; + dcb.dcb_devhdl = devhdl; + + /* walk the devinfo snapshot looking for nodes with devids */ + (void) di_walk_node(devtree, DI_WALK_CLDFIRST, &dcb, + disk_walk_di_nodes); + + (void) di_devlink_fini(&devhdl); + di_fini(devtree); + + return (0); +} + +void +disk_list_free(topo_mod_t *mod, topo_list_t *listp) +{ + disk_di_node_t *dnode; + + while ((dnode = topo_list_next(listp)) != NULL) { + /* order of delete/free is important */ + topo_list_delete(listp, dnode); + disk_di_node_free(mod, dnode); + } +} + +/* + * Query the current disk status. If successful, the disk status is returned + * as an nvlist consisting of at least the following members: + * + * protocol string Supported protocol (currently "scsi") + * + * status nvlist Arbitrary protocol-specific information + * about the current state of the disk. + * + * faults nvlist A list of supported faults. Each + * element of this list is a boolean value. + * An element's existence indicates that + * the drive supports detecting this fault, + * and the value indicates the current + * state of the fault. + * + * <fault-name> nvlist For each fault named in 'faults', a + * nvlist describing protocol-specific + * attributes of the fault. + * + * This method relies on the libdiskstatus library to query this information. + */ +static int +disk_status(topo_mod_t *mod, tnode_t *nodep, topo_version_t vers, + nvlist_t *in_nvl, nvlist_t **out_nvl) +{ + disk_status_t *dsp; + char *devpath, *fullpath; + size_t pathlen; + nvlist_t *status; + int err; + + *out_nvl = NULL; + + if (vers != TOPO_METH_DISK_STATUS_VERSION) + return (topo_mod_seterrno(mod, EMOD_VER_NEW)); + + /* + * If the caller specifies the "path" parameter, then this indicates + * that we should use this instead of deriving it from the topo node + * itself. + */ + if (nvlist_lookup_string(in_nvl, "path", &fullpath) == 0) { + devpath = NULL; + } else { + /* + * Get the /devices path and attempt to open the disk status + * handle. + */ + if (topo_prop_get_string(nodep, TOPO_PGROUP_IO, + TOPO_IO_DEV_PATH, &devpath, &err) != 0) + return (topo_mod_seterrno(mod, EMOD_METHOD_NOTSUP)); + + /* + * Note that sizeof(string) includes the terminating NULL byte + */ + pathlen = strlen(devpath) + sizeof ("/devices") + + sizeof (PHYS_EXTN) - 1; + + if ((fullpath = topo_mod_alloc(mod, pathlen)) == NULL) + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + + (void) snprintf(fullpath, pathlen, "/devices%s%s", devpath, + PHYS_EXTN); + + topo_mod_strfree(mod, devpath); + } + + if ((dsp = disk_status_open(fullpath, &err)) == NULL) { + if (devpath) + topo_mod_free(mod, fullpath, pathlen); + return (topo_mod_seterrno(mod, err == EDS_NOMEM ? + EMOD_NOMEM : EMOD_METHOD_NOTSUP)); + } + + if (devpath) + topo_mod_free(mod, fullpath, pathlen); + + if ((status = disk_status_get(dsp)) == NULL) { + err = (disk_status_errno(dsp) == EDS_NOMEM ? + EMOD_NOMEM : EMOD_METHOD_NOTSUP); + disk_status_close(dsp); + return (topo_mod_seterrno(mod, err)); + } + + *out_nvl = status; + disk_status_close(dsp); + return (0); +} diff --git a/usr/src/lib/libdevinfo/devinfo.c b/usr/src/lib/libdevinfo/devinfo.c index 8c103d2f7a..582aad2156 100644 --- a/usr/src/lib/libdevinfo/devinfo.c +++ b/usr/src/lib/libdevinfo/devinfo.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -855,12 +855,12 @@ int di_walk_minor(di_node_t root, const char *minor_type, uint_t flag, void *arg, int (*minor_callback)(di_node_t, di_minor_t, void *)) { - struct node_list *head; /* node_list for tree walk */ + struct node_list *head; /* node_list for tree walk */ #ifdef DEBUG - char *path = di_devfs_path(root); - DPRINTF((DI_INFO, "walking minor nodes under %s\n", path)); - di_devfs_path_free(path); + char *devfspath = di_devfs_path(root); + DPRINTF((DI_INFO, "walking minor nodes under %s\n", devfspath)); + di_devfs_path_free(devfspath); #endif if (root == NULL) { @@ -877,7 +877,7 @@ di_walk_minor(di_node_t root, const char *minor_type, uint_t flag, void *arg, head->node = root; DPRINTF((DI_INFO, "Start minor walking from node %s\n", - di_node_name(root))); + di_node_name(root))); while (head != NULL) walk_one_minor_list(&head, minor_type, flag, arg, @@ -931,7 +931,7 @@ di_compatible_names(di_node_t node, char **names) } *names = (caddr_t)node + - DI_NODE(node)->compat_names - DI_NODE(node)->self; + DI_NODE(node)->compat_names - DI_NODE(node)->self; c = *names; len = DI_NODE(node)->compat_length; @@ -1130,7 +1130,7 @@ char * di_devfs_minor_path(di_minor_t minor) { di_node_t node; - char *full_path, *name, *path; + char *full_path, *name, *devfspath; int full_path_len; if (minor == DI_MINOR_NIL) { @@ -1140,20 +1140,72 @@ di_devfs_minor_path(di_minor_t minor) name = di_minor_name(minor); node = di_minor_devinfo(minor); - path = di_devfs_path(node); - if (path == NULL) + devfspath = di_devfs_path(node); + if (devfspath == NULL) return (NULL); /* make the full path to the device minor node */ - full_path_len = strlen(path) + strlen(name) + 2; + full_path_len = strlen(devfspath) + strlen(name) + 2; full_path = (char *)calloc(1, full_path_len); if (full_path != NULL) - (void) snprintf(full_path, full_path_len, "%s:%s", path, name); + (void) snprintf(full_path, full_path_len, "%s:%s", + devfspath, name); + + di_devfs_path_free(devfspath); + return (full_path); +} + +/* + * Produce a string representation of path to di_path_t (pathinfo node). This + * string is identical to di_devfs_path had the device been enumerated under + * the pHCI: it has a base path to pHCI, then uses node_name of client, and + * device unit-address of pathinfo node. + */ +char * +di_path_devfs_path(di_path_t path) +{ + di_node_t phci_node; + char *phci_path, *path_name, *path_addr; + char *full_path; + int full_path_len; + + if (path == DI_PATH_NIL) { + errno = EINVAL; + return (NULL); + } - di_devfs_path_free(path); + /* get name@addr for path */ + path_name = di_path_node_name(path); + path_addr = di_path_bus_addr(path); + if ((path_name == NULL) || (path_addr == NULL)) + return (NULL); + + /* base path to pHCI devinfo node */ + phci_node = di_path_phci_node(path); + if (phci_node == NULL) + return (NULL); + phci_path = di_devfs_path(phci_node); + if (phci_path == NULL) + return (NULL); + + /* make the full string representation of path */ + full_path_len = strlen(phci_path) + 1 + strlen(path_name) + + 1 + strlen(path_addr) + 1; + full_path = (char *)calloc(1, full_path_len); + + if (full_path != NULL) + (void) snprintf(full_path, full_path_len, "%s/%s@%s", + phci_path, path_name, path_addr); + di_devfs_path_free(phci_path); return (full_path); } +char * +di_path_client_devfs_path(di_path_t path) +{ + return (di_devfs_path(di_path_client_node(path))); +} + void di_devfs_path_free(char *buf) { @@ -1165,6 +1217,128 @@ di_devfs_path_free(char *buf) free(buf); } +/* + * Return 1 if name is a IEEE-1275 generic name. If new generic + * names are defined, they should be added to this table + */ +static int +is_generic(const char *name, int len) +{ + const char **gp; + + /* from IEEE-1275 recommended practices section 3 */ + static const char *generic_names[] = { + "atm", + "disk", + "display", + "dma-controller", + "ethernet", + "fcs", + "fdc", + "fddi", + "fibre-channel", + "ide", + "interrupt-controller", + "isa", + "keyboard", + "memory", + "mouse", + "nvram", + "pc-card", + "pci", + "printer", + "rtc", + "sbus", + "scanner", + "scsi", + "serial", + "sound", + "ssa", + "tape", + "timer", + "token-ring", + "vme", + 0 + }; + + for (gp = generic_names; *gp; gp++) { + if ((strncmp(*gp, name, len) == 0) && + (strlen(*gp) == len)) + return (1); + } + return (0); +} + +/* + * Determine if two paths below /devices refer to the same device, ignoring + * any generic .vs. non-generic 'name' issues in "[[/]name[@addr[:minor]]]*". + * Return 1 if the paths match. + */ +int +di_devfs_path_match(const char *dp1, const char *dp2) +{ + const char *p1, *p2; + const char *ec1, *ec2; + const char *at1, *at2; + char nc; + int g1, g2; + + /* progress through both strings */ + for (p1 = dp1, p2 = dp2; (*p1 == *p2) && *p1; p1++, p2++) { + /* require match until the start of a component */ + if (*p1 != '/') + continue; + + /* advance p1 and p2 to start of 'name' in component */ + nc = *(p1 + 1); + if ((nc == '\0') || (nc == '/')) + continue; /* skip trash */ + p1++; + p2++; + + /* + * Both p1 and p2 point to beginning of 'name' in component. + * Determine where current component ends: next '/' or '\0'. + */ + ec1 = strchr(p1, '/'); + if (ec1 == NULL) + ec1 = p1 + strlen(p1); + ec2 = strchr(p2, '/'); + if (ec2 == NULL) + ec2 = p2 + strlen(p2); + + /* Determine where name ends based on whether '@' exists */ + at1 = strchr(p1, '@'); + at2 = strchr(p2, '@'); + if (at1 && (at1 < ec1)) + ec1 = at1; + if (at2 && (at2 < ec2)) + ec2 = at2; + + /* + * At this point p[12] point to beginning of name and + * ec[12] point to character past the end of name. Determine + * if the names are generic. + */ + g1 = is_generic(p1, ec1 - p1); + g2 = is_generic(p2, ec2 - p2); + + if (g1 != g2) { + /* + * one generic and one non-generic + * skip past the names in the match. + */ + p1 = ec1; + p2 = ec2; + } else { + if (*p1 != *p2) + break; + } + } + + return ((*p1 == *p2) ? 1 : 0); +} + /* minor data access */ di_minor_t di_minor_next(di_node_t node, di_minor_t minor) @@ -1245,7 +1419,7 @@ dev_t di_minor_devt(di_minor_t minor) { return (makedev(DI_MINOR(minor)->dev_major, - DI_MINOR(minor)->dev_minor)); + DI_MINOR(minor)->dev_minor)); } int @@ -1261,7 +1435,7 @@ di_minor_nodetype(di_minor_t minor) return (NULL); return ((caddr_t)minor - - DI_MINOR(minor)->self + DI_MINOR(minor)->node_type); + DI_MINOR(minor)->self + DI_MINOR(minor)->node_type); } /* @@ -1712,7 +1886,7 @@ di_prop_rawdata(di_prop_t prop, uchar_t **prop_data) * Consolidation private interfaces for accessing I/O multipathing data */ di_path_t -di_path_next_client(di_node_t node, di_path_t path) +di_path_phci_next_path(di_node_t node, di_path_t path) { caddr_t pa; @@ -1733,7 +1907,8 @@ di_path_next_client(di_node_t node, di_path_t path) * Path is NIL; the caller is asking for the first path info node */ if (DI_NODE(node)->multipath_phci != 0) { - DPRINTF((DI_INFO, "phci: returning %p\n", ((caddr_t)node - + DPRINTF((DI_INFO, "phci_next_path: returning %p\n", + ((caddr_t)node - DI_NODE(node)->self + DI_NODE(node)->multipath_phci))); return (DI_PATH((caddr_t)node - DI_NODE(node)->self + DI_NODE(node)->multipath_phci)); @@ -1753,7 +1928,7 @@ di_path_next_client(di_node_t node, di_path_t path) } di_path_t -di_path_next_phci(di_node_t node, di_path_t path) +di_path_client_next_path(di_node_t node, di_path_t path) { caddr_t pa; @@ -1774,7 +1949,8 @@ di_path_next_phci(di_node_t node, di_path_t path) * Path is NIL; the caller is asking for the first path info node */ if (DI_NODE(node)->multipath_client != 0) { - DPRINTF((DI_INFO, "client: returning %p\n", ((caddr_t)node - + DPRINTF((DI_INFO, "client_next_path: returning %p\n", + ((caddr_t)node - DI_NODE(node)->self + DI_NODE(node)->multipath_client))); return (DI_PATH((caddr_t)node - DI_NODE(node)->self + DI_NODE(node)->multipath_client)); @@ -1794,8 +1970,21 @@ di_path_next_phci(di_node_t node, di_path_t path) } /* - * XXX Obsolete wrapper to be removed. Won't work under multilevel. + * XXX Remove the private di_path_(addr,next,next_phci,next_client) interfaces + * below after NWS consolidation switches to using di_path_bus_addr, + * di_path_phci_next_path, and di_path_client_next_path per CR6638521. */ +char * +di_path_addr(di_path_t path, char *buf) +{ + caddr_t pa; /* starting address of map */ + + pa = (caddr_t)path - DI_PATH(path)->self; + + (void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr), + MAXPATHLEN); + return (buf); +} di_path_t di_path_next(di_node_t node, di_path_t path) { @@ -1805,9 +1994,9 @@ di_path_next(di_node_t node, di_path_t path) } if (DI_NODE(node)->multipath_client) { - return (di_path_next_phci(node, path)); + return (di_path_client_next_path(node, path)); } else if (DI_NODE(node)->multipath_phci) { - return (di_path_next_client(node, path)); + return (di_path_phci_next_path(node, path)); } else { /* * The node had multipathing data but didn't appear to be a @@ -1817,6 +2006,19 @@ di_path_next(di_node_t node, di_path_t path) return (DI_PATH_NIL); } } +di_path_t +di_path_next_phci(di_node_t node, di_path_t path) +{ + return (di_path_client_next_path(node, path)); +} +di_path_t +di_path_next_client(di_node_t node, di_path_t path) +{ + return (di_path_phci_next_path(node, path)); +} + + + di_path_state_t di_path_state(di_path_t path) @@ -1825,15 +2027,31 @@ di_path_state(di_path_t path) } char * -di_path_addr(di_path_t path, char *buf) +di_path_node_name(di_path_t path) { - caddr_t pa; /* starting address of map */ + di_node_t client_node; - pa = (caddr_t)path - DI_PATH(path)->self; + /* pathinfo gets node_name from client */ + if ((client_node = di_path_client_node(path)) == NULL) + return (NULL); + return (di_node_name(client_node)); +} - (void) strncpy(buf, (char *)(pa + DI_PATH(path)->path_addr), - MAXPATHLEN); - return (buf); +char * +di_path_bus_addr(di_path_t path) +{ + caddr_t pa = (caddr_t)path - DI_PATH(path)->self; + + if (DI_PATH(path)->path_addr == 0) + return (NULL); + + return ((char *)(pa + DI_PATH(path)->path_addr)); +} + +int +di_path_instance(di_path_t path) +{ + return (DI_PATH(path)->path_instance); } di_node_t @@ -2472,7 +2690,7 @@ di_prom_prop_next(di_prom_handle_t ph, di_node_t node, di_prom_prop_t prom_prop) struct di_prom_handle *p = (struct di_prom_handle *)ph; DPRINTF((DI_TRACE1, "Search next prop for node 0x%p with ph 0x%p\n", - node, p)); + node, p)); /* * paranoid check @@ -2656,7 +2874,7 @@ di_prom_prop_lookup_ints(di_prom_handle_t ph, di_node_t node, } len = di_prop_decode_common((void *)&prop->data, prop->len, - DI_PROP_TYPE_INT, 1); + DI_PROP_TYPE_INT, 1); *prom_prop_data = (int *)((void *)prop->data); return (len); @@ -2905,6 +3123,18 @@ di_node_private_get(di_node_t node) } void +di_path_private_set(di_path_t path, void *data) +{ + DI_PATH(path)->user_private_data = (uintptr_t)data; +} + +void * +di_path_private_get(di_path_t path) +{ + return ((void *)(uintptr_t)DI_PATH(path)->user_private_data); +} + +void di_lnode_private_set(di_lnode_t lnode, void *data) { DI_LNODE(lnode)->user_private_data = (uintptr_t)data; @@ -3028,24 +3258,24 @@ di_link_next_by_lnode(di_lnode_t lnode, di_link_t link, uint_t endpoint) if (DI_LNODE(lnode)->link_out == NULL) return (DI_LINK_NIL); return (DI_LINK((caddr_t)di_all + - DI_LNODE(lnode)->link_out)); + DI_LNODE(lnode)->link_out)); } else { if (DI_LINK(link)->src_link_next == NULL) return (DI_LINK_NIL); return (DI_LINK((caddr_t)di_all + - DI_LINK(link)->src_link_next)); + DI_LINK(link)->src_link_next)); } } else { if (link == DI_LINK_NIL) { if (DI_LNODE(lnode)->link_in == NULL) return (DI_LINK_NIL); return (DI_LINK((caddr_t)di_all + - DI_LNODE(lnode)->link_in)); + DI_LNODE(lnode)->link_in)); } else { if (DI_LINK(link)->tgt_link_next == NULL) return (DI_LINK_NIL); return (DI_LINK((caddr_t)di_all + - DI_LINK(link)->tgt_link_next)); + DI_LINK(link)->tgt_link_next)); } } /* NOTREACHED */ @@ -3084,10 +3314,10 @@ di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg, struct node_list *head; /* node_list for tree walk */ #ifdef DEBUG - char *path = di_devfs_path(root); + char *devfspath = di_devfs_path(root); DPRINTF((DI_INFO, "walking %s link data under %s\n", - (endpoint == DI_LINK_SRC) ? "src" : "tgt", path)); - di_devfs_path_free(path); + (endpoint == DI_LINK_SRC) ? "src" : "tgt", devfspath)); + di_devfs_path_free(devfspath); #endif /* @@ -3108,7 +3338,7 @@ di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, void *arg, head->node = root; DPRINTF((DI_INFO, "Start link data walking from node %s\n", - di_node_name(root))); + di_node_name(root))); while (head != NULL) walk_one_link(&head, endpoint, arg, link_callback); @@ -3149,9 +3379,9 @@ di_walk_lnode(di_node_t root, uint_t flag, void *arg, struct node_list *head; /* node_list for tree walk */ #ifdef DEBUG - char *path = di_devfs_path(root); - DPRINTF((DI_INFO, "walking lnode data under %s\n", path)); - di_devfs_path_free(path); + char *devfspath = di_devfs_path(root); + DPRINTF((DI_INFO, "walking lnode data under %s\n", devfspath)); + di_devfs_path_free(devfspath); #endif /* @@ -3171,7 +3401,7 @@ di_walk_lnode(di_node_t root, uint_t flag, void *arg, head->node = root; DPRINTF((DI_INFO, "Start lnode data walking from node %s\n", - di_node_name(root))); + di_node_name(root))); while (head != NULL) walk_one_lnode(&head, arg, lnode_callback); @@ -3180,18 +3410,17 @@ di_walk_lnode(di_node_t root, uint_t flag, void *arg, } di_node_t -di_lookup_node(di_node_t root, char *path) +di_lookup_node(di_node_t root, char *devfspath) { struct di_all *dap; di_node_t node; - char copy[MAXPATHLEN]; - char *slash, *pname, *paddr; + char *copy, *slash, *pname, *paddr; /* * Path must be absolute and musn't have duplicate slashes */ - if (*path != '/' || strstr(path, "//")) { - DPRINTF((DI_ERR, "Invalid path: %s\n", path)); + if (*devfspath != '/' || strstr(devfspath, "//")) { + DPRINTF((DI_ERR, "Invalid path: %s\n", devfspath)); return (DI_NODE_NIL); } @@ -3206,15 +3435,15 @@ di_lookup_node(di_node_t root, char *path) return (DI_NODE_NIL); } - if (strlcpy(copy, path, sizeof (copy)) >= sizeof (copy)) { - DPRINTF((DI_ERR, "path too long: %s\n", path)); + if ((copy = strdup(devfspath)) == NULL) { + DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath)); return (DI_NODE_NIL); } for (slash = copy, node = root; slash; ) { /* - * Handle path = "/" case as well as trailing '/' + * Handle devfspath = "/" case as well as trailing '/' */ if (*(slash + 1) == '\0') break; @@ -3259,14 +3488,72 @@ di_lookup_node(di_node_t root, char *path) */ if (node == DI_NODE_NIL) { DPRINTF((DI_ERR, "%s@%s: no node\n", pname, paddr)); + free(copy); return (DI_NODE_NIL); } } assert(node != DI_NODE_NIL); + free(copy); return (node); } +di_path_t +di_lookup_path(di_node_t root, char *devfspath) +{ + di_node_t phci_node; + di_path_t path = DI_PATH_NIL; + char *copy, *lastslash; + char *pname, *paddr; + char *path_name, *path_addr; + + if ((copy = strdup(devfspath)) == NULL) { + DPRINTF((DI_ERR, "strdup failed on: %s\n", devfspath)); + return (DI_NODE_NIL); + } + + if ((lastslash = strrchr(copy, '/')) == NULL) { + DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath)); + goto out; + } + + /* stop at pHCI and find the node for the phci */ + *lastslash = '\0'; + phci_node = di_lookup_node(root, copy); + if (phci_node == NULL) { + DPRINTF((DI_ERR, "failed to find component: %s\n", devfspath)); + goto out; + } + + /* set up pname and paddr for last component */ + pname = lastslash + 1; + if ((paddr = strchr(pname, '@')) == NULL) { + DPRINTF((DI_ERR, "failed to find unit-addr: %s\n", devfspath)); + goto out; + } + *paddr++ = '\0'; + + /* walk paths below phci looking for match */ + for (path = di_path_phci_next_path(phci_node, DI_PATH_NIL); + path != DI_PATH_NIL; + path = di_path_phci_next_path(phci_node, path)) { + + /* get name@addr of path */ + path_name = di_path_node_name(path); + path_addr = di_path_bus_addr(path); + if ((path_name == NULL) || (path_addr == NULL)) + continue; + + /* break on match */ + if ((strcmp(pname, path_name) == 0) && + (strcmp(paddr, path_addr) == 0)) + break; + } + +out: free(copy); + return (path); +} + static char * msglevel2str(di_debug_t msglevel) { diff --git a/usr/src/lib/libdevinfo/libdevinfo.h b/usr/src/lib/libdevinfo/libdevinfo.h index 2314ee1c9c..ca745b3b31 100644 --- a/usr/src/lib/libdevinfo/libdevinfo.h +++ b/usr/src/lib/libdevinfo/libdevinfo.h @@ -100,31 +100,32 @@ extern "C" { ((type) == DI_PROP_TYPE_INT64)) /* opaque handles */ - -typedef struct di_node *di_node_t; /* opaque handle to node */ -typedef struct di_minor *di_minor_t; /* opaque handle to minor node */ -typedef struct di_prop *di_prop_t; /* opaque handle to property */ -typedef struct di_prom_prop *di_prom_prop_t; /* opaque handle to prom prop */ -typedef struct di_prom_handle *di_prom_handle_t; /* opaque handle */ -typedef struct di_path *di_path_t; /* opaque handle */ -typedef struct di_path_prop *di_path_prop_t; /* opaque handle */ - +typedef struct di_node *di_node_t; /* node */ +typedef struct di_minor *di_minor_t; /* minor_node */ +typedef struct di_path *di_path_t; /* path_node */ +typedef struct di_link *di_link_t; /* link */ +typedef struct di_lnode *di_lnode_t; /* endpoint */ +typedef struct di_devlink *di_devlink_t; /* devlink */ + +typedef struct di_prop *di_prop_t; /* node property */ +typedef struct di_path_prop *di_path_prop_t; /* path property */ +typedef struct di_prom_prop *di_prom_prop_t; /* prom property */ + +typedef struct di_prom_handle *di_prom_handle_t; /* prom snapshot */ typedef struct di_devlink_handle *di_devlink_handle_t; /* devlink snapshot */ -typedef struct di_devlink *di_devlink_t; /* opaque handle to devlink */ -typedef struct di_link *di_link_t; /* opaque handle to link */ -typedef struct di_lnode *di_lnode_t; /* opaque handle to endpoint */ + /* * Null handles to make handles really opaque */ -#define DI_NODE_NIL NULL -#define DI_LINK_NIL NULL -#define DI_LNODE_NIL NULL -#define DI_MINOR_NIL NULL -#define DI_PROP_NIL NULL +#define DI_NODE_NIL NULL +#define DI_MINOR_NIL NULL +#define DI_PATH_NIL NULL +#define DI_LINK_NIL NULL +#define DI_LNODE_NIL NULL +#define DI_PROP_NIL NULL #define DI_PROM_PROP_NIL NULL #define DI_PROM_HANDLE_NIL NULL -#define DI_PATH_NIL NULL /* * IEEE 1275 properties and other standardized property names @@ -138,92 +139,76 @@ typedef struct di_lnode *di_lnode_t; /* opaque handle to endpoint */ #define DI_PROP_REG "reg" #define DI_PROP_AP_NAMES "ap-names" - /* Interface Prototypes */ /* * Snapshot initialization and cleanup */ -extern di_node_t di_init(const char *phys_path, uint_t flag); -extern void di_fini(di_node_t root); +extern di_node_t di_init(const char *phys_path, uint_t flag); +extern void di_fini(di_node_t root); /* - * tree traversal + * node: traversal, data access, and parameters */ -extern di_node_t di_parent_node(di_node_t node); -extern di_node_t di_sibling_node(di_node_t node); -extern di_node_t di_child_node(di_node_t node); -extern di_node_t di_drv_first_node(const char *drv_name, di_node_t root); -extern di_node_t di_drv_next_node(di_node_t node); -extern di_node_t di_vhci_first_node(di_node_t root); -extern di_node_t di_vhci_next_node(di_node_t node); -extern di_node_t di_phci_first_node(di_node_t vhci_node); -extern di_node_t di_phci_next_node(di_node_t node); +extern int di_walk_node(di_node_t root, uint_t flag, void *arg, + int (*node_callback)(di_node_t node, void *arg)); -/* - * tree walking assistants - */ -extern int di_walk_node(di_node_t root, uint_t flag, void *arg, - int (*node_callback)(di_node_t node, void *arg)); -extern int di_walk_minor(di_node_t root, const char *minortype, uint_t flag, - void *arg, int (*minor_callback)(di_node_t node, di_minor_t minor, - void *arg)); -extern int di_walk_link(di_node_t root, uint_t flag, uint_t endpoint, - void *arg, int (*link_callback)(di_link_t link, void *arg)); -extern int di_walk_lnode(di_node_t root, uint_t flag, - void *arg, int (*lnode_callback)(di_lnode_t lnode, void *arg)); +extern di_node_t di_drv_first_node(const char *drv_name, di_node_t root); +extern di_node_t di_drv_next_node(di_node_t node); -extern void di_node_private_set(di_node_t node, void *data); -extern void *di_node_private_get(di_node_t node); -extern void di_minor_private_set(di_minor_t minor, void *data); -extern void *di_minor_private_get(di_minor_t minor); -extern void di_lnode_private_set(di_lnode_t lnode, void *data); -extern void *di_lnode_private_get(di_lnode_t lnode); -extern void di_link_private_set(di_link_t link, void *data); -extern void *di_link_private_get(di_link_t link); +extern di_node_t di_parent_node(di_node_t node); +extern di_node_t di_sibling_node(di_node_t node); +extern di_node_t di_child_node(di_node_t node); -/* - * generic node parameters - */ -extern char *di_node_name(di_node_t node); -extern char *di_bus_addr(di_node_t node); -extern char *di_binding_name(di_node_t node); -extern int di_compatible_names(di_node_t, char **names); -extern int di_instance(di_node_t node); -extern int di_nodeid(di_node_t node); -extern int di_driver_major(di_node_t node); -extern uint_t di_state(di_node_t node); -extern ddi_node_state_t di_node_state(di_node_t node); -extern ddi_devid_t di_devid(di_node_t node); - -extern char *di_driver_name(di_node_t node); -extern uint_t di_driver_ops(di_node_t node); +extern char *di_node_name(di_node_t node); +extern char *di_bus_addr(di_node_t node); +extern char *di_binding_name(di_node_t node); +extern int di_compatible_names(di_node_t, char **names); +extern int di_instance(di_node_t node); +extern int di_nodeid(di_node_t node); +extern int di_driver_major(di_node_t node); +extern uint_t di_state(di_node_t node); +extern ddi_node_state_t di_node_state(di_node_t node); +extern ddi_devid_t di_devid(di_node_t node); +extern char *di_driver_name(di_node_t node); +extern uint_t di_driver_ops(di_node_t node); -extern char *di_devfs_path(di_node_t node); -extern char *di_devfs_minor_path(di_minor_t minor); +extern void di_node_private_set(di_node_t node, void *data); +extern void *di_node_private_get(di_node_t node); -extern void di_devfs_path_free(char *path_buf); +extern char *di_devfs_path(di_node_t node); +extern char *di_devfs_minor_path(di_minor_t minor); +extern void di_devfs_path_free(char *path_buf); /* - * layering data access + * path_node: traversal, data access, and parameters */ -extern di_link_t di_link_next_by_node(di_node_t node, - di_link_t link, uint_t endpoint); -extern di_link_t di_link_next_by_lnode(di_lnode_t lnode, - di_link_t link, uint_t endpoint); -extern di_lnode_t di_link_to_lnode(di_link_t link, uint_t endpoint); +extern di_path_t di_path_phci_next_path(di_node_t node, di_path_t); +extern di_path_t di_path_client_next_path(di_node_t node, di_path_t); -extern di_lnode_t di_lnode_next(di_node_t node, di_lnode_t lnode); -extern char *di_lnode_name(di_lnode_t lnode); -extern di_node_t di_lnode_devinfo(di_lnode_t lnode); -extern int di_lnode_devt(di_lnode_t lnode, dev_t *devt); +extern di_node_t di_path_phci_node(di_path_t path); +extern di_node_t di_path_client_node(di_path_t path); -extern int di_link_spectype(di_link_t link); +extern char *di_path_node_name(di_path_t path); +extern char *di_path_bus_addr(di_path_t path); +extern int di_path_instance(di_path_t path); +extern di_path_state_t di_path_state(di_path_t path); + +extern char *di_path_devfs_path(di_path_t path); +extern char *di_path_client_devfs_path(di_path_t path); + +extern void di_path_private_set(di_path_t path, void *data); +extern void *di_path_private_get(di_path_t path); /* - * minor data access + * minor_node: traversal, data access, and parameters */ +extern int di_walk_minor(di_node_t root, const char *minortype, + uint_t flag, void *arg, + int (*minor_callback)(di_node_t node, + di_minor_t minor, void *arg)); extern di_minor_t di_minor_next(di_node_t node, di_minor_t minor); + extern di_node_t di_minor_devinfo(di_minor_t minor); extern ddi_minor_type di_minor_type(di_minor_t minor); extern char *di_minor_name(di_minor_t minor); @@ -231,44 +216,109 @@ extern dev_t di_minor_devt(di_minor_t minor); extern int di_minor_spectype(di_minor_t minor); extern char *di_minor_nodetype(di_minor_t node); +extern void di_minor_private_set(di_minor_t minor, void *data); +extern void *di_minor_private_get(di_minor_t minor); + +/* + * node: property access + */ +extern di_prop_t di_prop_next(di_node_t node, di_prop_t prop); + +extern char *di_prop_name(di_prop_t prop); +extern int di_prop_type(di_prop_t prop); +extern dev_t di_prop_devt(di_prop_t prop); + +extern int di_prop_ints(di_prop_t prop, int **prop_data); +extern int di_prop_int64(di_prop_t prop, int64_t **prop_data); +extern int di_prop_strings(di_prop_t prop, char **prop_data); +extern int di_prop_bytes(di_prop_t prop, uchar_t **prop_data); + +extern int di_prop_lookup_bytes(dev_t dev, di_node_t node, + const char *prop_name, uchar_t **prop_data); +extern int di_prop_lookup_ints(dev_t dev, di_node_t node, + const char *prop_name, int **prop_data); +extern int di_prop_lookup_int64(dev_t dev, di_node_t node, + const char *prop_name, int64_t **prop_data); +extern int di_prop_lookup_strings(dev_t dev, di_node_t node, + const char *prop_name, char **prop_data); + /* - * Software property access + * prom_node: property access */ -extern di_prop_t di_prop_next(di_node_t node, di_prop_t prop); -extern dev_t di_prop_devt(di_prop_t prop); -extern char *di_prop_name(di_prop_t prop); -extern int di_prop_type(di_prop_t prop); -extern int di_prop_ints(di_prop_t prop, int **prop_data); -extern int di_prop_int64(di_prop_t prop, int64_t **prop_data); -extern int di_prop_strings(di_prop_t prop, char **prop_data); -extern int di_prop_bytes(di_prop_t prop, uchar_t **prop_data); -extern int di_prop_lookup_ints(dev_t dev, di_node_t node, - const char *prop_name, int **prop_data); -extern int di_prop_lookup_int64(dev_t dev, di_node_t node, - const char *prop_name, int64_t **prop_data); -extern int di_prop_lookup_strings(dev_t dev, di_node_t node, - const char *prop_name, char **prop_data); -extern int di_prop_lookup_bytes(dev_t dev, di_node_t node, - const char *prop_name, uchar_t **prop_data); +extern di_prom_handle_t di_prom_init(void); +extern void di_prom_fini(di_prom_handle_t ph); + +extern di_prom_prop_t di_prom_prop_next(di_prom_handle_t ph, di_node_t node, + di_prom_prop_t prom_prop); + +extern char *di_prom_prop_name(di_prom_prop_t prom_prop); +extern int di_prom_prop_data(di_prom_prop_t prop, + uchar_t **prom_prop_data); + +extern int di_prom_prop_lookup_ints(di_prom_handle_t prom, + di_node_t node, const char *prom_prop_name, + int **prom_prop_data); +extern int di_prom_prop_lookup_strings(di_prom_handle_t prom, + di_node_t node, const char *prom_prop_name, + char **prom_prop_data); +extern int di_prom_prop_lookup_bytes(di_prom_handle_t prom, + di_node_t node, const char *prom_prop_name, + uchar_t **prom_prop_data); /* - * PROM property access + * path_node: property access */ -extern di_prom_handle_t di_prom_init(void); -extern void di_prom_fini(di_prom_handle_t ph); +extern di_path_prop_t di_path_prop_next(di_path_t path, di_path_prop_t prop); + +extern char *di_path_prop_name(di_path_prop_t prop); +extern int di_path_prop_type(di_path_prop_t prop); +extern int di_path_prop_len(di_path_prop_t prop); + +extern int di_path_prop_bytes(di_path_prop_t prop, + uchar_t **prop_data); +extern int di_path_prop_ints(di_path_prop_t prop, + int **prop_data); +extern int di_path_prop_int64s(di_path_prop_t prop, + int64_t **prop_data); +extern int di_path_prop_strings(di_path_prop_t prop, + char **prop_data); + +extern int di_path_prop_lookup_bytes(di_path_t path, + const char *prop_name, uchar_t **prop_data); +extern int di_path_prop_lookup_ints(di_path_t path, + const char *prop_name, int **prop_data); +extern int di_path_prop_lookup_int64s(di_path_t path, + const char *prop_name, int64_t **prop_data); +extern int di_path_prop_lookup_strings(di_path_t path, + const char *prop_name, char **prop_data); + +/* + * layering link/lnode: traversal, data access, and parameters + */ +extern int di_walk_link(di_node_t root, uint_t flag, + uint_t endpoint, void *arg, + int (*link_callback)(di_link_t link, void *arg)); +extern int di_walk_lnode(di_node_t root, uint_t flag, void *arg, + int (*lnode_callback)(di_lnode_t lnode, void *arg)); + +extern di_link_t di_link_next_by_node(di_node_t node, + di_link_t link, uint_t endpoint); +extern di_link_t di_link_next_by_lnode(di_lnode_t lnode, + di_link_t link, uint_t endpoint); +extern di_lnode_t di_lnode_next(di_node_t node, di_lnode_t lnode); +extern char *di_lnode_name(di_lnode_t lnode); -extern di_prom_prop_t di_prom_prop_next(di_prom_handle_t ph, di_node_t node, - di_prom_prop_t prom_prop); +extern int di_link_spectype(di_link_t link); +extern di_lnode_t di_link_to_lnode(di_link_t link, uint_t endpoint); + +extern di_node_t di_lnode_devinfo(di_lnode_t lnode); +extern int di_lnode_devt(di_lnode_t lnode, dev_t *devt); -extern char *di_prom_prop_name(di_prom_prop_t prom_prop); -extern int di_prom_prop_data(di_prom_prop_t prop, uchar_t **prom_prop_data); +extern void di_link_private_set(di_link_t link, void *data); +extern void *di_link_private_get(di_link_t link); +extern void di_lnode_private_set(di_lnode_t lnode, void *data); +extern void *di_lnode_private_get(di_lnode_t lnode); -extern int di_prom_prop_lookup_ints(di_prom_handle_t prom, di_node_t node, - const char *prom_prop_name, int **prom_prop_data); -extern int di_prom_prop_lookup_strings(di_prom_handle_t prom, di_node_t node, - const char *prom_prop_name, char **prom_prop_data); -extern int di_prom_prop_lookup_bytes(di_prom_handle_t prom, di_node_t node, - const char *prom_prop_name, uchar_t **prom_prop_data); /* * Private interfaces @@ -276,12 +326,17 @@ extern int di_prom_prop_lookup_bytes(di_prom_handle_t prom, di_node_t node, * The interfaces and structures below are private to this implementation * of Solaris and are subject to change at any time without notice. * - * Applications and drivers using these interfaces will fail + * Applications and drivers using these interfaces may fail * to run on future releases. */ - extern di_prop_t di_prop_find(dev_t match_dev, di_node_t node, const char *name); +extern int di_devfs_path_match(const char *dp1, const char *dp2); + +extern di_node_t di_vhci_first_node(di_node_t root); +extern di_node_t di_vhci_next_node(di_node_t node); +extern di_node_t di_phci_first_node(di_node_t vhci_node); +extern di_node_t di_phci_next_node(di_node_t node); /* * Interfaces for handling IEEE 1275 and other standardized properties @@ -305,35 +360,14 @@ extern int di_prom_prop_lookup_slot_names(di_prom_handle_t ph, di_node_t node, di_slot_name_t **prop_data); /* - * Interfaces for accessing I/O multipathing data + * XXX Remove the private di_path_(addr,next,next_phci,next_client) interfaces + * below after NWS consolidation switches to using di_path_bus_addr, + * di_path_phci_next_path, and di_path_client_next_path per CR6638521. */ -/* XXX remove di_path_next() after updating NWS consolidation */ +extern char *di_path_addr(di_path_t path, char *buf); extern di_path_t di_path_next(di_node_t node, di_path_t path); extern di_path_t di_path_next_phci(di_node_t node, di_path_t path); extern di_path_t di_path_next_client(di_node_t node, di_path_t path); -extern di_path_state_t di_path_state(di_path_t path); -extern char *di_path_addr(di_path_t path, char *buf); -extern di_node_t di_path_client_node(di_path_t path); -extern void di_path_client_path(di_path_t path, char *buf); -extern di_node_t di_path_phci_node(di_path_t path); -extern void di_path_phci_path(di_path_t path, char *buf); -extern di_path_prop_t di_path_prop_next(di_path_t path, di_path_prop_t prop); -extern char *di_path_prop_name(di_path_prop_t prop); -extern int di_path_prop_type(di_path_prop_t prop); -extern int di_path_prop_len(di_path_prop_t prop); -extern int di_path_prop_bytes(di_path_prop_t prop, uchar_t **prop_data); -extern int di_path_prop_ints(di_path_prop_t prop, int **prop_data); -extern int di_path_prop_int64s(di_path_prop_t prop, int64_t **prop_data); -extern int di_path_prop_strings(di_path_prop_t prop, char **prop_data); -extern int di_path_prop_lookup_bytes(di_path_t path, const char *prop_name, - uchar_t **prop_data); -extern int di_path_prop_lookup_ints(di_path_t path, const char *prop_name, - int **prop_data); -extern int di_path_prop_lookup_int64s(di_path_t path, const char *prop_name, - int64_t **prop_data); -extern int di_path_prop_lookup_strings(di_path_t path, const char *prop_name, - char **prop_data); - /* * Interfaces for private data @@ -436,11 +470,12 @@ extern int di_devperm_login(const char *, uid_t, gid_t, void (*)(char *)); extern int di_devperm_logout(const char *); /* - * Private interface for looking up a node in a snapshot + * Private interface for looking up, by path string, a node/path/minor + * in a snapshot. */ +extern di_path_t di_lookup_path(di_node_t root, char *path); extern di_node_t di_lookup_node(di_node_t root, char *path); - /* * Private hotplug interfaces to be used between cfgadm pci plugin and * devfsadm link generator. diff --git a/usr/src/lib/libdevinfo/mapfile-vers b/usr/src/lib/libdevinfo/mapfile-vers index aa49121009..581729d3e6 100644 --- a/usr/src/lib/libdevinfo/mapfile-vers +++ b/usr/src/lib/libdevinfo/mapfile-vers @@ -25,6 +25,34 @@ # ident "%Z%%M% %I% %E% SMI" # +SUNW_1.4 { + global: + di_path_bus_addr; + di_path_client_devfs_path; + di_path_client_next_path; + di_path_client_node; + di_path_devfs_path; + di_path_instance; + di_path_node_name; + di_path_phci_next_path; + di_path_phci_node; + di_path_private_get; + di_path_private_set; + di_path_prop_bytes; + di_path_prop_int64s; + di_path_prop_ints; + di_path_prop_len; + di_path_prop_lookup_bytes; + di_path_prop_lookup_int64s; + di_path_prop_lookup_ints; + di_path_prop_lookup_strings; + di_path_prop_name; + di_path_prop_next; + di_path_prop_strings; + di_path_prop_type; + di_path_state; +} SUNW_1.3; + SUNW_1.3 { global: di_devfs_minor_path; @@ -80,8 +108,8 @@ SUNW_1.1 { di_minor_nodetype; di_minor_spectype; di_minor_type; - di_nodeid; di_node_name; + di_nodeid; di_parent_node; di_prom_fini; di_prom_init; @@ -123,11 +151,15 @@ SUNWprivate_1.1 { devfs_get_prom_names; devfs_install2target; devfs_load_minor_perm; + devfs_parse_binding_file; devfs_path_to_drv; devfs_read_minor_perm; devfs_resolve_aliases; devfs_rm_minor_perm; devfs_target2install; + devfs_walk_minor_nodes; + device_exists; + di_devfs_path_match; di_devlink_add_link; di_devlink_cache_walk; di_devlink_close; @@ -143,42 +175,34 @@ SUNWprivate_1.1 { di_devlink_type; di_devlink_update; di_devlink_walk; - di_devperm_login; - di_devperm_logout; - di_devname_get_mapinfo; - di_devname_get_mapent; di_devname_action_on_key; + di_devname_get_mapent; + di_devname_get_mapinfo; di_devname_print_mapinfo; - di_driver_private_data; + di_devperm_login; + di_devperm_logout; di_dim_fini; di_dim_init; di_dim_path_dev; di_dim_path_devices; + di_dli_close; + di_dli_name; + di_dli_openr; + di_dli_openw; + di_driver_private_data; + di_flags; di_init_driver; di_init_impl; di_lookup_node; + di_lookup_path; di_minor_devinfo; di_node_state; di_parent_private_data; +# XXX remove: di_path_(addr,next,next_client,next_phci) di_path_addr; - di_path_client_node; di_path_next; di_path_next_client; di_path_next_phci; - di_path_phci_node; - di_path_prop_bytes; - di_path_prop_int64s; - di_path_prop_ints; - di_path_prop_len; - di_path_prop_lookup_bytes; - di_path_prop_lookup_int64s; - di_path_prop_lookup_ints; - di_path_prop_lookup_strings; - di_path_prop_name; - di_path_prop_next; - di_path_prop_strings; - di_path_prop_type; - di_path_state; di_phci_first_node; di_phci_next_node; di_prof_add_dev; @@ -186,37 +210,29 @@ SUNWprivate_1.1 { di_prof_add_map; di_prof_add_symlink; di_prof_commit; - di_prof_init; di_prof_fini; + di_prof_init; + di_prom_prop_lookup_slot_names; + di_prom_prop_slot_names; di_prop_drv_next; + di_prop_find; di_prop_global_next; di_prop_hw_next; + di_prop_lookup_slot_names; di_prop_rawdata; + di_prop_slot_names; di_prop_sys_next; + di_retire_device; + di_retired; + di_slot_names_decode; + di_slot_names_free; + di_unretire_device; di_vhci_first_node; di_vhci_next_node; - di_dli_name; - di_dli_openr; - di_dli_openw; - di_dli_close; - di_slot_names_free; - di_slot_names_decode; - di_prop_slot_names; - di_prom_prop_slot_names; - di_prop_lookup_slot_names; - di_prom_prop_lookup_slot_names; - di_prop_find; - device_exists; finddev_close; finddev_emptydir; finddev_next; finddev_readdir; - di_flags; - di_retire_device; - di_unretire_device; - di_retired; - devfs_parse_binding_file; - devfs_walk_minor_nodes; local: *; }; diff --git a/usr/src/lib/libdiskmgt/common/findevs.c b/usr/src/lib/libdiskmgt/common/findevs.c index 076281693d..81230e6323 100644 --- a/usr/src/lib/libdiskmgt/common/findevs.c +++ b/usr/src/lib/libdiskmgt/common/findevs.c @@ -688,7 +688,7 @@ add_disk2controller(disk_t *diskp, struct search_args *args) /* note: mpxio di_path stuff is all consolidation private */ di_path_t pi = DI_PATH_NIL; - while ((pi = di_path_next_phci(node, pi)) != DI_PATH_NIL) { + while ((pi = di_path_client_next_path(node, pi)) != DI_PATH_NIL) { int cnt; uchar_t *bytes; char str[MAXPATHLEN]; @@ -770,7 +770,8 @@ add_int2array(int p, int **parray) cnt = 0; if (pa != NULL) { - for (; pa[cnt] != -1; cnt++); + for (; pa[cnt] != -1; cnt++) + ; } new_array = (int *)calloc(cnt + 2, sizeof (int *)); @@ -804,7 +805,8 @@ add_ptr2array(void *p, void ***parray) cnt = 0; if (pa != NULL) { - for (; pa[cnt]; cnt++); + for (; pa[cnt]; cnt++) + ; } new_array = (void **)calloc(cnt + 2, sizeof (void *)); diff --git a/usr/src/lib/libnvpair/Makefile.com b/usr/src/lib/libnvpair/Makefile.com index 532a1032cc..4439415f03 100644 --- a/usr/src/lib/libnvpair/Makefile.com +++ b/usr/src/lib/libnvpair/Makefile.com @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -50,6 +50,10 @@ LIBS = $(DYNLIB) $(LINTLIB) # turn off ptr-cast warnings LINTFLAGS64 += -erroff=E_BAD_PTR_CAST_ALIGN +# turn off warning caused by lint bug: not understanding SCNi8 "hhi" +LINTFLAGS += -erroff=E_BAD_FORMAT_STR2 +LINTFLAGS64 += -erroff=E_BAD_FORMAT_STR2 + CFLAGS += $(CCVERBOSE) CPPFLAGS += -D_REENTRANT diff --git a/usr/src/lib/libnvpair/libnvpair.c b/usr/src/lib/libnvpair/libnvpair.c index 58a47f1f06..664a3fff6f 100644 --- a/usr/src/lib/libnvpair/libnvpair.c +++ b/usr/src/lib/libnvpair/libnvpair.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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 * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -28,6 +27,8 @@ #include <unistd.h> #include <strings.h> +#include <sys/types.h> +#include <sys/inttypes.h> #include "libnvpair.h" /* @@ -264,3 +265,347 @@ nvlist_print(FILE *fp, nvlist_t *nvl) { nvlist_print_with_indent(fp, nvl, 0); } + +/* + * Determine if string 'value' matches 'nvp' value. The 'value' string is + * converted, depending on the type of 'nvp', prior to match. For numeric + * types, a radix independent sscanf conversion of 'value' is used. If 'nvp' + * is an array type, 'ai' is the index into the array against which we are + * checking for match. If nvp is of DATA_TYPE_STRING*, the caller can pass + * in a regex_t compilation of value in 'value_regex' to trigger regular + * expression string match instead of simple strcmp(). + * + * Return 1 on match, 0 on no-match, and -1 on error. If the error is + * related to value syntax error and 'ep' is non-NULL, *ep will point into + * the 'value' string at the location where the error exists. + * + * NOTE: It may be possible to move the non-regex_t version of this into + * common code used by library/kernel/boot. + */ +int +nvpair_value_match_regex(nvpair_t *nvp, int ai, + char *value, regex_t *value_regex, char **ep) +{ + char *evalue; + uint_t a_len; + int sr; + + if (ep) + *ep = NULL; + + if ((nvp == NULL) || (value == NULL)) + return (-1); /* error fail match - invalid args */ + + /* make sure array and index combination make sense */ + if ((nvpair_type_is_array(nvp) && (ai < 0)) || + (!nvpair_type_is_array(nvp) && (ai >= 0))) + return (-1); /* error fail match - bad index */ + + /* non-string values should be single 'chunk' */ + if ((nvpair_type(nvp) != DATA_TYPE_STRING) && + (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)) { + value += strspn(value, " \t"); + evalue = value + strcspn(value, " \t"); + if (*evalue) { + if (ep) + *ep = evalue; + return (-1); /* error fail match - syntax */ + } + } + + sr = EOF; + switch (nvpair_type(nvp)) { + case DATA_TYPE_STRING: { + char *val; + + /* check string value for match */ + if (nvpair_value_string(nvp, &val) == 0) { + if (value_regex) { + if (regexec(value_regex, val, + (size_t)0, NULL, 0) == 0) + return (1); /* match */ + } else { + if (strcmp(value, val) == 0) + return (1); /* match */ + } + } + break; + } + case DATA_TYPE_STRING_ARRAY: { + char **val_array; + + /* check indexed string value of array for match */ + if ((nvpair_value_string_array(nvp, &val_array, &a_len) == 0) && + (ai < a_len)) { + if (value_regex) { + if (regexec(value_regex, val_array[ai], + (size_t)0, NULL, 0) == 0) + return (1); + } else { + if (strcmp(value, val_array[ai]) == 0) + return (1); + } + } + break; + } + case DATA_TYPE_BYTE: { + uchar_t val, val_arg; + + /* scanf uchar_t from value and check for match */ + sr = sscanf(value, "%c", &val_arg); + if ((sr == 1) && (nvpair_value_byte(nvp, &val) == 0) && + (val == val_arg)) + return (1); + break; + } + case DATA_TYPE_BYTE_ARRAY: { + uchar_t *val_array, val_arg; + + + /* check indexed value of array for match */ + sr = sscanf(value, "%c", &val_arg); + if ((sr == 1) && + (nvpair_value_byte_array(nvp, &val_array, &a_len) == 0) && + (ai < a_len) && + (val_array[ai] == val_arg)) + return (1); + break; + } + case DATA_TYPE_INT8: { + int8_t val, val_arg; + + /* scanf int8_t from value and check for match */ + sr = sscanf(value, "%"SCNi8, &val_arg); + if ((sr == 1) && + (nvpair_value_int8(nvp, &val) == 0) && + (val == val_arg)) + return (1); + break; + } + case DATA_TYPE_INT8_ARRAY: { + int8_t *val_array, val_arg; + + /* check indexed value of array for match */ + sr = sscanf(value, "%"SCNi8, &val_arg); + if ((sr == 1) && + (nvpair_value_int8_array(nvp, &val_array, &a_len) == 0) && + (ai < a_len) && + (val_array[ai] == val_arg)) + return (1); + break; + } + case DATA_TYPE_UINT8: { + uint8_t val, val_arg; + + /* scanf uint8_t from value and check for match */ + sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg); + if ((sr == 1) && + (nvpair_value_uint8(nvp, &val) == 0) && + (val == val_arg)) + return (1); + break; + } + case DATA_TYPE_UINT8_ARRAY: { + uint8_t *val_array, val_arg; + + /* check indexed value of array for match */ + sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg); + if ((sr == 1) && + (nvpair_value_uint8_array(nvp, &val_array, &a_len) == 0) && + (ai < a_len) && + (val_array[ai] == val_arg)) + return (1); + break; + } + case DATA_TYPE_INT16: { + int16_t val, val_arg; + + /* scanf int16_t from value and check for match */ + sr = sscanf(value, "%"SCNi16, &val_arg); + if ((sr == 1) && + (nvpair_value_int16(nvp, &val) == 0) && + (val == val_arg)) + return (1); + break; + } + case DATA_TYPE_INT16_ARRAY: { + int16_t *val_array, val_arg; + + /* check indexed value of array for match */ + sr = sscanf(value, "%"SCNi16, &val_arg); + if ((sr == 1) && + (nvpair_value_int16_array(nvp, &val_array, &a_len) == 0) && + (ai < a_len) && + (val_array[ai] == val_arg)) + return (1); + break; + } + case DATA_TYPE_UINT16: { + uint16_t val, val_arg; + + /* scanf uint16_t from value and check for match */ + sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg); + if ((sr == 1) && + (nvpair_value_uint16(nvp, &val) == 0) && + (val == val_arg)) + return (1); + break; + } + case DATA_TYPE_UINT16_ARRAY: { + uint16_t *val_array, val_arg; + + /* check indexed value of array for match */ + sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg); + if ((sr == 1) && + (nvpair_value_uint16_array(nvp, &val_array, &a_len) == 0) && + (ai < a_len) && + (val_array[ai] == val_arg)) + return (1); + break; + } + case DATA_TYPE_INT32: { + int32_t val, val_arg; + + /* scanf int32_t from value and check for match */ + sr = sscanf(value, "%"SCNi32, &val_arg); + if ((sr == 1) && + (nvpair_value_int32(nvp, &val) == 0) && + (val == val_arg)) + return (1); + break; + } + case DATA_TYPE_INT32_ARRAY: { + int32_t *val_array, val_arg; + + /* check indexed value of array for match */ + sr = sscanf(value, "%"SCNi32, &val_arg); + if ((sr == 1) && + (nvpair_value_int32_array(nvp, &val_array, &a_len) == 0) && + (ai < a_len) && + (val_array[ai] == val_arg)) + return (1); + break; + } + case DATA_TYPE_UINT32: { + uint32_t val, val_arg; + + /* scanf uint32_t from value and check for match */ + sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg); + if ((sr == 1) && + (nvpair_value_uint32(nvp, &val) == 0) && + (val == val_arg)) + return (1); + break; + } + case DATA_TYPE_UINT32_ARRAY: { + uint32_t *val_array, val_arg; + + /* check indexed value of array for match */ + sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg); + if ((sr == 1) && + (nvpair_value_uint32_array(nvp, &val_array, &a_len) == 0) && + (ai < a_len) && + (val_array[ai] == val_arg)) + return (1); + break; + } + case DATA_TYPE_INT64: { + int64_t val, val_arg; + + /* scanf int64_t from value and check for match */ + sr = sscanf(value, "%"SCNi64, &val_arg); + if ((sr == 1) && + (nvpair_value_int64(nvp, &val) == 0) && + (val == val_arg)) + return (1); + break; + } + case DATA_TYPE_INT64_ARRAY: { + int64_t *val_array, val_arg; + + /* check indexed value of array for match */ + sr = sscanf(value, "%"SCNi64, &val_arg); + if ((sr == 1) && + (nvpair_value_int64_array(nvp, &val_array, &a_len) == 0) && + (ai < a_len) && + (val_array[ai] == val_arg)) + return (1); + break; + } + case DATA_TYPE_UINT64: { + uint64_t val_arg, val; + + /* scanf uint64_t from value and check for match */ + sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg); + if ((sr == 1) && + (nvpair_value_uint64(nvp, &val) == 0) && + (val == val_arg)) + return (1); + break; + } + case DATA_TYPE_UINT64_ARRAY: { + uint64_t *val_array, val_arg; + + /* check indexed value of array for match */ + sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg); + if ((sr == 1) && + (nvpair_value_uint64_array(nvp, &val_array, &a_len) == 0) && + (ai < a_len) && + (val_array[ai] == val_arg)) + return (1); + break; + } + case DATA_TYPE_BOOLEAN_VALUE: { + boolean_t val, val_arg; + + /* scanf boolean_t from value and check for match */ + sr = sscanf(value, "%"SCNi32, &val_arg); + if ((sr == 1) && + (nvpair_value_boolean_value(nvp, &val) == 0) && + (val == val_arg)) + return (1); + break; + } + case DATA_TYPE_BOOLEAN_ARRAY: { + boolean_t *val_array, val_arg; + + /* check indexed value of array for match */ + sr = sscanf(value, "%"SCNi32, &val_arg); + if ((sr == 1) && + (nvpair_value_boolean_array(nvp, + &val_array, &a_len) == 0) && + (ai < a_len) && + (val_array[ai] == val_arg)) + return (1); + break; + } + case DATA_TYPE_HRTIME: + case DATA_TYPE_NVLIST: + case DATA_TYPE_NVLIST_ARRAY: + case DATA_TYPE_BOOLEAN: + case DATA_TYPE_UNKNOWN: + default: + /* + * unknown/unsupported data type + */ + return (-1); /* error fail match */ + } + + /* + * check to see if sscanf failed conversion, return approximate + * pointer to problem + */ + if (sr != 1) { + if (ep) + *ep = value; + return (-1); /* error fail match - syntax */ + } + + return (0); /* fail match */ +} + +int +nvpair_value_match(nvpair_t *nvp, int ai, char *value, char **ep) +{ + return (nvpair_value_match_regex(nvp, ai, value, NULL, ep)); +} diff --git a/usr/src/lib/libnvpair/libnvpair.h b/usr/src/lib/libnvpair/libnvpair.h index d1d25ea70e..e655e0d406 100644 --- a/usr/src/lib/libnvpair/libnvpair.h +++ b/usr/src/lib/libnvpair/libnvpair.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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 * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -32,12 +31,15 @@ #include <sys/nvpair.h> #include <stdlib.h> #include <stdio.h> +#include <regex.h> #ifdef __cplusplus extern "C" { #endif void nvlist_print(FILE *, nvlist_t *); +int nvpair_value_match(nvpair_t *, int, char *, char **); +int nvpair_value_match_regex(nvpair_t *, int, char *, regex_t *, char **); #ifdef __cplusplus } diff --git a/usr/src/lib/libnvpair/mapfile-vers b/usr/src/lib/libnvpair/mapfile-vers index 50252d220f..fb80a984b1 100644 --- a/usr/src/lib/libnvpair/mapfile-vers +++ b/usr/src/lib/libnvpair/mapfile-vers @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -147,6 +147,10 @@ SUNWprivate_1.1 { nvlist_lookup_hrtime; nvlist_print; nvpair_value_hrtime; + nvpair_type_is_array; + nvlist_lookup_nvpair_embedded_index; + nvpair_value_match; + nvpair_value_match_regex; local: *; }; |