changeset 10652:9d0aff74d6fd

PSARC/2008/687 T11 Storage Management HBA API(SM-HBA) 6795795 Provide management utility for SAS Gen-2(SAS-2 compliant) HBAs. 6795797 Provide SM-HBA wrapper library for SAS Gen-2(SAS-2 compliant) HBAs. 6795800 Provide SM-HBA Vendor Specific Library for Sun SAS-2 HBAs.
author Hyon Kim <Hyon.Kim@Sun.COM>
date Fri, 25 Sep 2009 16:43:29 -0700
parents 6e737c28ebe6
children e0ceed15cf0a
files usr/src/cmd/Makefile usr/src/cmd/sasinfo/Makefile usr/src/cmd/sasinfo/printAttrs.c usr/src/cmd/sasinfo/printAttrs.h usr/src/cmd/sasinfo/sasinfo-list.c usr/src/cmd/sasinfo/sasinfo.c usr/src/cmd/sasinfo/sasinfo.h usr/src/common/cmdparse/cmdparse.c usr/src/lib/Makefile usr/src/lib/libsecdb/exec_attr.txt usr/src/lib/smhba/Makefile usr/src/lib/smhba/Makefile.com usr/src/lib/smhba/THIRDPARTYLICENSE usr/src/lib/smhba/THIRDPARTYLICENSE.descrip usr/src/lib/smhba/amd64/Makefile usr/src/lib/smhba/common/SMHBAAPILIB.c usr/src/lib/smhba/common/llib-lSMHBAAPI usr/src/lib/smhba/common/mapfile-vers usr/src/lib/smhba/common/smhba.conf usr/src/lib/smhba/common/smhbaapi.h usr/src/lib/smhba/common/vendorsmhbaapi.h usr/src/lib/smhba/i386/Makefile usr/src/lib/smhba/sparc/Makefile usr/src/lib/smhba/sparcv9/Makefile usr/src/lib/sun_sas/Makefile usr/src/lib/sun_sas/Makefile.com usr/src/lib/sun_sas/amd64/Makefile usr/src/lib/sun_sas/common/SMHBA_RegisterLibrary.c usr/src/lib/sun_sas/common/Sun_sasCloseAdapter.c usr/src/lib/sun_sas/common/Sun_sasFreeLibrary.c usr/src/lib/sun_sas/common/Sun_sasGetAdapterAttributes.c usr/src/lib/sun_sas/common/Sun_sasGetAdapterName.c usr/src/lib/sun_sas/common/Sun_sasGetAdapterPortAttributes.c usr/src/lib/sun_sas/common/Sun_sasGetDiscoveredPortAttributes.c usr/src/lib/sun_sas/common/Sun_sasGetLUNStatistics.c usr/src/lib/sun_sas/common/Sun_sasGetNumberOfAdapters.c usr/src/lib/sun_sas/common/Sun_sasGetNumberOfPorts.c usr/src/lib/sun_sas/common/Sun_sasGetPersistentBinding.c usr/src/lib/sun_sas/common/Sun_sasGetPhyStatistics.c usr/src/lib/sun_sas/common/Sun_sasGetPortAttributesByWWN.c usr/src/lib/sun_sas/common/Sun_sasGetPortType.c usr/src/lib/sun_sas/common/Sun_sasGetProtocolStatistics.c usr/src/lib/sun_sas/common/Sun_sasGetSASPhyAttributes.c usr/src/lib/sun_sas/common/Sun_sasGetTargetMapping.c usr/src/lib/sun_sas/common/Sun_sasGetVendorLibraryAttributes.c usr/src/lib/sun_sas/common/Sun_sasGetVersion.c usr/src/lib/sun_sas/common/Sun_sasLoadLibrary.c usr/src/lib/sun_sas/common/Sun_sasOpenAdapter.c usr/src/lib/sun_sas/common/Sun_sasRefreshAdapterConfiguration.c usr/src/lib/sun_sas/common/Sun_sasRefreshInformation.c usr/src/lib/sun_sas/common/Sun_sasScsiInquiry.c usr/src/lib/sun_sas/common/Sun_sasScsiReadCapacity.c usr/src/lib/sun_sas/common/Sun_sasScsiReportLUNs.c usr/src/lib/sun_sas/common/Sun_sasSendSMPPassThru.c usr/src/lib/sun_sas/common/Sun_sasSetPersistentBinding.c usr/src/lib/sun_sas/common/devlink_disco.c usr/src/lib/sun_sas/common/devtree_device_disco.c usr/src/lib/sun_sas/common/devtree_hba_disco.c usr/src/lib/sun_sas/common/devtree_phy_disco.c usr/src/lib/sun_sas/common/event.c usr/src/lib/sun_sas/common/log.c usr/src/lib/sun_sas/common/mapfile-vers usr/src/lib/sun_sas/common/sun_sas.c usr/src/lib/sun_sas/common/sun_sas.h usr/src/lib/sun_sas/common/verify.c usr/src/lib/sun_sas/i386/Makefile usr/src/lib/sun_sas/sparc/Makefile usr/src/lib/sun_sas/sparcv9/Makefile usr/src/pkgdefs/SUNWsmhba/prototype_com usr/src/pkgdefs/SUNWsmhba/prototype_i386 usr/src/pkgdefs/SUNWsmhba/prototype_sparc usr/src/pkgdefs/SUNWsmhbar/pkginfo.tmpl usr/src/pkgdefs/SUNWsmhbar/prototype_com
diffstat 73 files changed, 17717 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/Makefile	Fri Sep 25 18:10:09 2009 -0400
+++ b/usr/src/cmd/Makefile	Fri Sep 25 16:43:29 2009 -0700
@@ -353,6 +353,7 @@
 	runat		\
 	sa		\
 	saf		\
+	sasinfo		\
 	savecore	\
 	sbdadm		\
 	script		\
@@ -686,6 +687,7 @@
 	rmformat	\
 	rmmount		\
 	rmvolmgr	\
+	sasinfo		\
 	sbdadm		\
 	scadm		\
 	script		\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sasinfo/Makefile	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,83 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.cmd
+
+COMMONBASE = ../../common
+
+PROG = sasinfo
+PRODUCT = $(PROG)
+
+$(ROOT_PROG_LINK) := FILEMODE = 0555
+
+LOCAL_OBJS = sasinfo.o sasinfo-list.o printAttrs.o
+COMMON_OBJS = cmdparse.o
+LOCAL_SRCS = $(LOCAL_OBJS:%.o=%.c)
+COMMON_SRCS = $(COMMON_OBJS:%.o=$(COMMONBASE)/cmdparse/%.c)
+OBJS = $(LOCAL_OBJS) $(COMMON_OBJS)
+SRCS = $(LOCAL_SRCS) $(COMMON_SRCS)
+POFILE = sasinfo_all.po
+POFILES = $(LOCAL_OBJS:%.o=%.po)
+
+
+LDLIBS += -lSMHBAAPI
+
+INCS += -I.
+INCS += -I$(SRC)/lib/smhba/common
+INCS += -I$(SRC)/lib/hbaapi/common
+INCS += -I$(COMMONBASE)/cmdparse
+
+CPPFLAGS += -D_LARGEFILE64_SOURCE=1 -D_REENTRANT $(INCS)
+$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
+
+LINTFLAGS += -erroff=E_NAME_USED_NOT_DEF2
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+	$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+	$(POST_PROCESS)
+
+cmdparse.o: $(COMMONBASE)/cmdparse/cmdparse.c
+	$(COMPILE.c) -o $@ $(COMMONBASE)/cmdparse/cmdparse.c
+	$(POST_PROCESS_O)
+
+install: all $(ROOTUSRSBINPROG)
+
+$(POFILE): $(POFILES)
+	$(RM) $@
+	cat $(POFILES) > $@
+
+clean:
+	$(RM) $(OBJS)
+
+lint:	lint_SRCS
+
+check:	$(CHKMANIFEST)
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sasinfo/printAttrs.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,582 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <ctype.h>
+#include <printAttrs.h>
+
+static SAS_STATE hbastatus_string[] = {
+	HBA_STATUS_OK,				"Okay",
+	HBA_STATUS_ERROR,			"Error",
+	HBA_STATUS_ERROR_NOT_SUPPORTED,		"Not Supported",
+	HBA_STATUS_ERROR_INVALID_HANDLE,	"Invalid Handle",
+	HBA_STATUS_ERROR_ARG,			"Argument Error",
+	HBA_STATUS_ERROR_ILLEGAL_WWN,		"Illegal WWN",
+	HBA_STATUS_ERROR_ILLEGAL_INDEX,		"Illegal Index",
+	HBA_STATUS_ERROR_MORE_DATA,		"Not Enough Buffer for Data",
+	HBA_STATUS_ERROR_STALE_DATA,		"Stale Data",
+	HBA_STATUS_SCSI_CHECK_CONDITION,	"SCSI Check Condition",
+	HBA_STATUS_ERROR_BUSY,			"Busy",
+	HBA_STATUS_ERROR_TRY_AGAIN,		"Try Again",
+	HBA_STATUS_ERROR_UNAVAILABLE,		"Unavailable",
+	HBA_STATUS_ERROR_ELS_REJECT,		"ELS Reject",
+	HBA_STATUS_ERROR_INVALID_LUN,		"Invalid LUN",
+	HBA_STATUS_ERROR_INCOMPATIBLE,		"Request Incompatible",
+	HBA_STATUS_ERROR_AMBIGUOUS_WWN,		"Ambiguous WWN",
+	HBA_STATUS_ERROR_LOCAL_BUS,		"Local Bus Error",
+	HBA_STATUS_ERROR_LOCAL_TARGET,		"Local Target Error",
+	HBA_STATUS_ERROR_LOCAL_LUN,		"Local LUN Error",
+	HBA_STATUS_ERROR_LOCAL_SCSIID_BOUND,	"Local SCSIID Bound",
+	HBA_STATUS_ERROR_TARGET_FCID,		"Target FCID Error",
+	HBA_STATUS_ERROR_TARGET_NODE_WWN,	"Target Node WWN Error",
+	HBA_STATUS_ERROR_TARGET_PORT_WWN,	"Target Port WWN Error",
+	HBA_STATUS_ERROR_TARGET_LUN,		"Target LUN Error",
+	HBA_STATUS_ERROR_TARGET_LUID,		"Target LUID Error",
+	HBA_STATUS_ERROR_NO_SUCH_BINDING,	"No Such Binding",
+	HBA_STATUS_ERROR_NOT_A_TARGET,		"Not a Target",
+	HBA_STATUS_ERROR_UNSUPPORTED_FC4,	"Unsupported FC4",
+	HBA_STATUS_ERROR_INCAPABLE,		"Incapable",
+	HBA_STATUS_ERROR_TARGET_BUSY,		"Target Busy",
+	HBA_STATUS_ERROR_NOT_LOADED,		"Not Loaded",
+	HBA_STATUS_ERROR_ALREADY_LOADED,	"Alreday Loaded",
+	HBA_STATUS_ERROR_ILLEGAL_FCID,		"Illegal FCID",
+	HBA_STATUS_ERROR_NOT_ASCSIDEVICE,	"Not a SCSI Device",
+	HBA_STATUS_ERROR_INVALID_PROTOCOL_TYPE,	"Invalid Protocol Type",
+	HBA_STATUS_ERROR_BAD_EVENT_TYPE,	"Bad Event Type",
+	-1,					NULL
+};
+
+SAS_STATE porttype_string[] = {
+	HBA_PORTTYPE_UNKNOWN,		"UNKNOWN",
+	HBA_PORTTYPE_OTHER,		"OTHER",
+	HBA_PORTTYPE_NOTPRESENT,	"NOT Present",
+	HBA_PORTTYPE_SASDEVICE,		"SAS Device",
+	HBA_PORTTYPE_SATADEVICE,	"SATA Device",
+	HBA_PORTTYPE_SASEXPANDER, 	"SAS Expander",
+	-1,				NULL,
+};
+
+SAS_STATE portstate_string[] = {
+	HBA_PORTSTATE_UNKNOWN,		"unknown",
+	HBA_PORTSTATE_ONLINE,		"online",
+	HBA_PORTSTATE_OFFLINE,		"offline",
+	HBA_PORTSTATE_BYPASSED,		"bypassed",
+	HBA_PORTSTATE_DIAGNOSTICS,	"diagnostics",
+	HBA_PORTSTATE_LINKDOWN,		"link Down",
+	HBA_PORTSTATE_ERROR,		"port Error",
+	HBA_PORTSTATE_LOOPBACK,		"loopback",
+	HBA_PORTSTATE_DEGRADED,		"degraded",
+	-1,				NULL,
+};
+
+static SAS_STATE phystate_string[] = {
+	HBA_SASSTATE_UNKNOWN,		"unknown",
+	HBA_SASSTATE_DISABLED,		"disabled",
+	HBA_SASSTATE_FAILED,		"failed",
+	HBA_SASSTATE_SATASPINUP,	"sata-spinup",
+	HBA_SASSTATE_SATAPORTSEL,	"sata-portselector",
+	HBA_SASSPEED_1_5GBIT,		"1.5Gbit",
+	HBA_SASSPEED_3GBIT,		"3Gbit",
+	HBA_SASSPEED_6GBIT,		"6Gbit",
+	-1,				NULL,
+};
+
+static SAS_STATE dtype_string[] = {
+	DTYPE_DIRECT,			"Disk Device",
+	DTYPE_SEQUENTIAL,		"Tape Device",
+	DTYPE_PRINTER,			"Printer Device",
+	DTYPE_PROCESSOR,		"Processor Device",
+	DTYPE_WORM,			"WORM Device",
+	DTYPE_RODIRECT,			"CD/DVD Device",
+	DTYPE_SCANNER,			"Scanner Device",
+	DTYPE_OPTICAL,			"Optical Memory Device",
+	DTYPE_CHANGER,			"Medium Changer Device",
+	DTYPE_COMM,			"Communications Device",
+	DTYPE_ARRAY_CTRL,		"Storage Array Controller Device",
+	DTYPE_ESI,			"Enclosure Services Device",
+	DTYPE_RBC,			"Simplified Direct-access Device",
+	DTYPE_OCRW,			"Optical Card Reader/Writer Device",
+	DTYPE_BCC,			"Bridge Controller Commands",
+	DTYPE_OSD,			"Object-based Storage Device",
+	DTYPE_ADC,			"Automation/Drive Interface",
+	DTYPE_WELLKNOWN,		"Well Known Logical Unit",
+	DTYPE_UNKNOWN,			"Unknown Device",
+	-1,				NULL
+};
+
+static char *getPhyStateString(HBA_UINT32 key, phystat_type phyt);
+
+char *
+getIndentSpaces(int number)
+{
+	int 		i = 0;
+	/* the maximum indent with terminator '\0' */
+	static char	ret[MAXINDENT+1];
+
+	if (number > MAXINDENT)
+		number = MAXINDENT;
+
+	for (i = 0; i < number; i++) {
+		ret[i] = ' ';
+	}
+	ret[i] = '\0';
+	return (ret);
+}
+
+char *
+getStateString(HBA_UINT32 key, SAS_STATE *stat_string)
+{
+	static char ret[64];
+	while (stat_string->key != -1) {
+		if (stat_string->key == key) {
+			return ((char *)stat_string->value);
+		}
+		stat_string++;
+	}
+	(void *) sprintf(ret, "Undefined value (%d)", key);
+	return (ret);
+}
+
+static char *
+getPhyStateString(HBA_UINT32 key, phystat_type phyt)
+{
+	int i = 0, len = 0, match = 0;
+	HBA_UINT32 physpeed[] = {
+		HBA_SASSPEED_1_5GBIT,
+		HBA_SASSPEED_3GBIT,
+		HBA_SASSPEED_6GBIT
+	};
+
+	len = sizeof (physpeed) / sizeof (HBA_UINT32);
+	for (i = 0; i < len; i++) {
+		if (key == physpeed[i]) {
+			match = 1;
+			break;
+		}
+	}
+
+	if (match == 1) {
+		if (phyt == PHY_STATE)
+			return ("enabled");
+		else
+			return (getStateString(key, phystate_string));
+	} else {
+		if (phyt == PHY_STATE)
+			return (getStateString(key, phystate_string));
+		else
+			return ("not available");
+	}
+}
+
+char *
+getHBAStatus(HBA_STATUS key)
+{
+	return (getStateString(key, hbastatus_string));
+}
+
+/*
+ * return device type description
+ *
+ * Arguments:
+ *	dType - Device type returned from Standard INQUIRY
+ * Returns:
+ *	char string description for device type
+ */
+char *
+getDTypeString(uchar_t dType)
+{
+	return (getStateString((dType & DTYPE_MASK), dtype_string));
+}
+
+uint64_t
+wwnConversion(uchar_t *wwn)
+{
+	uint64_t tmp;
+	(void *) memcpy(&tmp, wwn, sizeof (uint64_t));
+	return (ntohll(tmp));
+}
+
+/*
+ * prints out HBA information
+ */
+void
+printHBAInfo(SMHBA_ADAPTERATTRIBUTES *attrs, int pflag, int numberOfPorts,
+    const char *adapterName)
+{
+
+	(void *) fprintf(stdout, "%s %s\n", "HBA Name:", adapterName);
+
+	if (pflag & PRINT_VERBOSE) {
+		(void *) fprintf(stdout, "%s%s %s\n",
+		    getIndentSpaces(4), "Manufacturer:",
+		    attrs->Manufacturer[0] == 0?
+		    "not available":attrs->Manufacturer);
+		(void *) fprintf(stdout, "%s%s %s\n",
+		    getIndentSpaces(4), "Model: ",
+		    attrs->Model[0] == 0? "not available":attrs->Model);
+		(void *) fprintf(stdout, "%s%s %s\n",
+		    getIndentSpaces(4),
+		    "Firmware Version:",
+		    attrs->FirmwareVersion[0] == 0? "not available":
+		    attrs->FirmwareVersion);
+		(void *) fprintf(stdout, "%s%s %s\n",
+		    getIndentSpaces(4),
+		    "FCode/BIOS Version:",
+		    attrs->OptionROMVersion[0] == 0? "not available":
+		    attrs->OptionROMVersion);
+		(void *) fprintf(stdout, "%s%s %s\n",
+		    getIndentSpaces(4),
+		    "Serial Number:",
+		    attrs->SerialNumber[0] == 0? "not available":
+		    attrs->SerialNumber);
+		(void *) fprintf(stdout, "%s%s %s\n",
+		    getIndentSpaces(4),
+		    "Driver Name:",
+		    attrs->DriverName[0] == 0? "not available":
+		    attrs->DriverName);
+		(void *) fprintf(stdout, "%s%s %s\n",
+		    getIndentSpaces(4),
+		    "Driver Version:",
+		    attrs->DriverVersion[0] == 0? "not available":
+		    attrs->DriverVersion);
+		(void *) fprintf(stdout, "%s%s %d\n",
+		    getIndentSpaces(4),
+		    "Number of HBA Ports:",
+		    numberOfPorts);
+	}
+}
+
+/*
+ * prints out all the HBA port information
+ */
+void
+printHBAPortInfo(SMHBA_PORTATTRIBUTES *port,
+    SMHBA_ADAPTERATTRIBUTES *attrs, int pflag) {
+
+	if ((port == NULL) || (attrs == NULL)) {
+		return;
+	}
+
+	(void *) fprintf(stdout, "%s%s %s\n",
+	    getIndentSpaces(2),
+	    "HBA Port Name:",
+	    port->OSDeviceName);
+
+	if (!(pflag & PRINT_VERBOSE)) {
+		return;
+	}
+
+	if (port->PortType != HBA_PORTTYPE_SASDEVICE)
+		return;
+
+	(void *) fprintf(stdout, "%s%s %s\n",
+	    getIndentSpaces(4),
+	    "Type:",
+	    getStateString(port->PortType, porttype_string));
+	(void *) fprintf(stdout, "%s%s %s\n",
+	    getIndentSpaces(4),
+	    "State:",
+	    getStateString(port->PortState, portstate_string));
+
+	(void *) fprintf(stdout, "%s%s %016llx\n",
+	    getIndentSpaces(4),
+	    "Local SAS Address:",
+	    wwnConversion(port->PortSpecificAttribute.SASPort->\
+	    LocalSASAddress.wwn));
+
+	(void *) fprintf(stdout, "%s%s %016llx\n",
+	    getIndentSpaces(4),
+	    "Attached SAS Address:",
+	    wwnConversion(port->PortSpecificAttribute.SASPort->\
+	    AttachedSASAddress.wwn));
+
+	(void *) fprintf(stdout, "%s%s %d\n",
+	    getIndentSpaces(4),
+	    "Number of Phys:",
+	    port->PortSpecificAttribute.SASPort->NumberofPhys);
+}
+
+void
+printHBAPortPhyInfo(SMHBA_SAS_PHY *phyinfo)
+{
+	if (phyinfo == NULL)
+		return;
+
+	(void *) fprintf(stdout, "%s%s %u\n",
+	    getIndentSpaces(6),
+	    "Identifier:",
+	    phyinfo->PhyIdentifier);
+
+	(void *) fprintf(stdout, "%s%s %s\n",
+	    getIndentSpaces(8),
+	    "State: ",
+	    getPhyStateString(phyinfo->NegotiatedLinkRate, PHY_STATE));
+	(void *) fprintf(stdout, "%s%s %s/%s\n",
+	    getIndentSpaces(8),
+	    "HardwareLinkRate(Min/Max):",
+	    getPhyStateString(phyinfo->HardwareMinLinkRate, PHY_SPEED),
+	    getPhyStateString(phyinfo->HardwareMaxLinkRate, PHY_SPEED));
+	(void *) fprintf(stdout, "%s%s %s/%s\n",
+	    getIndentSpaces(8),
+	    "ProgrammedLinkRate(Min/Max):",
+	    getPhyStateString(phyinfo->ProgrammedMinLinkRate, PHY_SPEED),
+	    getPhyStateString(phyinfo->ProgrammedMaxLinkRate, PHY_SPEED));
+	(void *) fprintf(stdout, "%s%s %s\n",
+	    getIndentSpaces(8),
+	    "NegotiatedLinkRate:",
+	    getPhyStateString(phyinfo->NegotiatedLinkRate, PHY_SPEED));
+}
+
+void
+printHBAPortPhyStatistics(SMHBA_SASPHYSTATISTICS *phystat)
+{
+	if (phystat == NULL)
+		return;
+
+	(void *) fprintf(stdout, "%s%s\n",
+	    getIndentSpaces(8),
+	    "Link Error Statistics:");
+	(void *) fprintf(stdout, "%s%s %llu\n",
+	    getIndentSpaces(12),
+	    "Invalid Dword:",
+	    phystat->InvalidDwordCount);
+	(void *) fprintf(stdout, "%s%s %llu\n",
+	    getIndentSpaces(12),
+	    "Running Disparity Error:",
+	    phystat->RunningDisparityErrorCount);
+	(void *) fprintf(stdout, "%s%s %llu\n",
+	    getIndentSpaces(12),
+	    "Loss of Dword Sync:",
+	    phystat->LossofDwordSyncCount);
+	(void *) fprintf(stdout, "%s%s %llu\n",
+	    getIndentSpaces(12),
+	    "Reset Problem:",
+	    phystat->PhyResetProblemCount);
+}
+
+/*
+ * print the OS device name for the logical-unit object
+ *
+ * Arguments:
+ *	devListWalk - OS device path info
+ *	verbose - boolean indicating whether to display additional info
+ *
+ * returns:
+ * 	0 - we're good.
+ * 	>0 - we met issues.
+ */
+int
+printTargetPortInfo(targetPortList_t *TPListWalk, int pflag)
+{
+	targetPortConfig_t	*configList;
+	targetPortMappingData_t	*mapList;
+	int			count, i;
+	int			ret = 0;
+
+	(void *) fprintf(stdout, "Target Port SAS Address: %016llx\n",
+	    wwnConversion(TPListWalk->sasattr.LocalSASAddress.wwn));
+	if ((pflag & PRINT_VERBOSE) || (pflag & PRINT_TARGET_SCSI)) {
+		(void *) fprintf(stdout, "%sType: %s\n", getIndentSpaces(4),
+		    getStateString(TPListWalk->targetattr.PortType,
+		    porttype_string));
+		for (configList = TPListWalk->configEntry;
+		    configList != NULL; configList = configList->next) {
+			(void *) fprintf(stdout, "%sHBA Port Name: %s\n",
+			    getIndentSpaces(4), configList->hbaPortName);
+			if (wwnConversion(configList->expanderSASAddr.wwn) !=
+			    0) {
+				if (configList->expanderValid) {
+					(void *) fprintf(stdout,
+					    "%sExpander Device SAS Address:"
+					    " %016llx",
+					    getIndentSpaces(8),
+					    wwnConversion(configList->
+					    expanderSASAddr.wwn));
+				} else {
+					(void *) fprintf(stdout,
+					    "%sExpander Device SAS Address:"
+					    " %016llx (Failed to Validate"
+					    " Attached Port.)",
+					    getIndentSpaces(8),
+					    wwnConversion(configList->
+					    expanderSASAddr.wwn));
+					ret++;
+				}
+			} else {
+				if (configList->expanderValid) {
+					(void *) fprintf(stdout,
+					    "%sExpander Device SAS Address: %s",
+					    getIndentSpaces(8),
+					    "None (direct attached)");
+				} else {
+					(void *) fprintf(stdout,
+					    "%sExpander Device SAS Address: %s",
+					    getIndentSpaces(8),
+					    "None (Failed to Get"
+					    " Attached Port)");
+				}
+			}
+			(void *) fprintf(stdout, "\n");
+			if (pflag & PRINT_TARGET_SCSI) {
+
+				if (configList->reportLUNsFailed) {
+					(void *) fprintf(stdout,
+					    "%s %016llx\n",
+					    gettext("Error: Failed to get "
+					    "ReportLun Data on"),
+					    wwnConversion(TPListWalk->
+					    sasattr.LocalSASAddress.wwn));
+					ret++;
+					continue;
+				}
+
+				for (mapList = configList->map;
+				    mapList != NULL; mapList = mapList->next) {
+					(void *) fprintf(stdout, "%sLUN : %d\n",
+					    getIndentSpaces(12),
+					    mapList->osLUN);
+					if (mapList->mappingExist) {
+						(void *) fprintf(stdout,
+						    "%sOS Device Name : %s\n",
+						    getIndentSpaces(14),
+						    (mapList->osDeviceName[0] ==
+						    '\0') ?  "Not avaialble" :
+						    mapList->osDeviceName);
+					} else {
+						(void *) fprintf(stdout,
+						    "%sOS Device Name : %s\n",
+						    getIndentSpaces(14), "No "
+						    "matching OS Device "
+						    "found.");
+						ret++;
+					}
+		/* indentation changed here */
+		if (mapList->inquiryFailed) {
+			(void *) fprintf(stdout, "%s %s LUN %d\n",
+			    gettext("Error: Failed to get Inquiry Data on"),
+			    mapList->osDeviceName, mapList->osLUN);
+			ret++;
+		} else {
+			(void *) fprintf(stdout, "%sVendor: ",
+			    getIndentSpaces(14));
+			for (count = sizeof (mapList->inq_vid), i = 0;
+			    i < count; i++) {
+				if (isprint(mapList->inq_vid[i]))
+					(void *) fprintf(stdout, "%c",
+					    mapList->inq_vid[i]);
+			}
+
+			(void *) fprintf(stdout, "\n%sProduct: ",
+			    getIndentSpaces(14));
+			for (count = sizeof (mapList->inq_pid), i = 0;
+			    i < count; i++) {
+				if (isprint(mapList->inq_pid[i]))
+					(void *) fprintf(stdout, "%c",
+					    mapList->inq_pid[i]);
+			}
+
+			(void *) fprintf(stdout, "\n%sDevice Type: %s\n",
+			    getIndentSpaces(14),
+			    getDTypeString(mapList->inq_dtype));
+		}
+		/* indentation changed back */
+				}
+			}
+		}
+	}
+	return (ret);
+}
+
+/*
+ * print the OS device name for the logical-unit object
+ *
+ * Arguments:
+ *	devListWalk - OS device path info
+ *	verbose - boolean indicating whether to display additional info
+ *
+ * returns:
+ * 	0 - we're good.
+ * 	>0 - we met issues.
+ */
+int
+printOSDeviceNameInfo(discoveredDevice *devListWalk, boolean_t verbose)
+{
+	portList		*portElem;
+	tgtPortWWNList		*tgtWWNList;
+	int			i, count;
+	int			ret = 0;
+
+	(void *) fprintf(stdout, "OS Device Name: %s\n",
+	    devListWalk->OSDeviceName);
+	if (verbose == B_TRUE) {
+		for (portElem = devListWalk->HBAPortList;
+		    portElem != NULL; portElem = portElem->next) {
+			(void *) fprintf(stdout, "%sHBA Port Name: ",
+			    getIndentSpaces(4));
+			(void *) fprintf(stdout, "%s", portElem->portName);
+			for (tgtWWNList = portElem->tgtPortWWN;
+			    tgtWWNList != NULL; tgtWWNList = tgtWWNList->next) {
+				(void *) fprintf(stdout,
+				    "\n%sTarget Port SAS Address: ",
+				    getIndentSpaces(8));
+				(void *) fprintf(stdout, "%016llx",
+				    wwnConversion(tgtWWNList->portWWN.wwn));
+				(void *) fprintf(stdout, "\n%sLUN: %u",
+				    getIndentSpaces(12),
+				    tgtWWNList->scsiOSLun);
+			}
+			(void *) fprintf(stdout, "\n");
+		}
+
+		if (devListWalk->inquiryFailed) {
+			(void *) fprintf(stdout, "%s %s\n",
+			    gettext("Error: Failed to get Inquiry data "
+			    "on device"), devListWalk->OSDeviceName);
+			ret++;
+		} else {
+			(void *) fprintf(stdout, "%sVendor: ",
+			    getIndentSpaces(4));
+			for (count = sizeof (devListWalk->VID), i = 0;
+			    i < count; i++) {
+				if (isprint(devListWalk->VID[i]))
+					(void *) fprintf(stdout, "%c",
+					    devListWalk->VID[i]);
+			}
+
+			(void *) fprintf(stdout, "\n%sProduct: ",
+			    getIndentSpaces(4));
+			for (count = sizeof (devListWalk->PID), i = 0;
+			    i < count; i++) {
+				if (isprint(devListWalk->PID[i]))
+					(void *) fprintf(stdout, "%c",
+					    devListWalk->PID[i]);
+			}
+
+			(void *) fprintf(stdout, "\n%sDevice Type: %s\n",
+			    getIndentSpaces(4),
+			    getDTypeString(devListWalk->dType));
+		}
+	}
+	return (ret);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sasinfo/printAttrs.h	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,72 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_PRINTATTRS_H
+#define	_PRINTATTRS_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sasinfo.h>
+
+typedef enum {
+	PHY_STATE,
+	PHY_SPEED
+} phystat_type;
+
+typedef struct state_string {
+	int	key;
+	char	*value;
+} SAS_STATE;
+
+extern SAS_STATE porttype_string[];
+extern SAS_STATE portstate_string[];
+
+#define	MAXINDENT	64
+
+char *getHBAStatus(HBA_STATUS hbaStatus);
+uint64_t wwnConversion(uchar_t *wwn);
+void printHBAInfo(SMHBA_ADAPTERATTRIBUTES *attrs, int pflag, int numberOfPorts,
+    const char *adapterName);
+void printHBAPortInfo(SMHBA_PORTATTRIBUTES *port,
+    SMHBA_ADAPTERATTRIBUTES *attrs, int pflag);
+void printHBAPortPhyInfo(SMHBA_SAS_PHY *phyinfo);
+void printHBAPortPhyStatistics(SMHBA_SASPHYSTATISTICS *phystat);
+extern void
+printLogicalUnit(int pflag, SMHBA_TARGETMAPPING *map);
+extern int
+printOSDeviceNameInfo(discoveredDevice *devListWalk, boolean_t verbose);
+extern int
+printTargetPortInfo(targetPortList_t *TPListWalk, int pflag);
+extern char *getStateString(HBA_UINT32 key, SAS_STATE *stat_string);
+extern char *getIndentSpaces(int number);
+extern char *getDTypeString(uchar_t dType);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PRINTATTRS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sasinfo/sasinfo-list.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,2799 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <printAttrs.h>
+#include <smhbaapi.h>
+
+#define	TABLEN	2
+typedef struct inputArgs {
+	int 		wwnCount;
+	char 		**wwn_argv;
+	uint64_t 	portWWN;
+	char		*hbaName;
+	int		pflag;
+	int		*wwn_flag;
+} inputArg_t;
+
+typedef struct tgt_mapping {
+	SMHBA_SCSIENTRY	tgtentry;
+	uchar_t		inq_vid[8];
+	uchar_t		inq_pid[16];
+	uchar_t		inq_dtype;
+	struct tgt_mapping *next;
+}tgt_mapping;
+
+/*
+ * Remote port tree node structure.
+ */
+typedef struct smhba_rp_tree {
+	SMHBA_PORTATTRIBUTES	portattr;
+	SMHBA_SAS_PORT		sasattr;
+	tgt_mapping		*first_entry;
+	int			printed;
+	struct smhba_rp_tree	*parent;
+	struct smhba_rp_tree	*child;
+	struct smhba_rp_tree	*sibling;
+}rp_tree_t;
+
+/*
+ * Report LUN data structure.
+ */
+struct lun {
+	uchar_t	val[8];
+};
+
+typedef struct rep_luns_rsp {
+	uint32_t    length;
+	uint32_t    rsrvd;
+	struct lun  lun[1];
+} rep_luns_rsp_t;
+
+/*
+ * The following flag is used for printing HBA header on-demand.
+ */
+static int g_printHBA = 0;
+
+/*
+ * The following structure is for sorted output of HBA and HBA Port.
+ */
+typedef struct _sas_elem {
+	char	name[256];
+	int	index;
+}sas_elem_t;
+
+/*
+ * The following two functions are for generating hierachy of expander
+ * subcommand.
+ */
+static int
+sas_rp_tree_insert(rp_tree_t **rproot, rp_tree_t *rpnode);
+static int
+sas_rp_tree_print(HBA_HANDLE handle, char *adapterName,
+    HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
+    rp_tree_t *rpnode, inputArg_t *input, int gident,
+    int *printPort);
+static int
+sas_rp_tree_print_desc(HBA_HANDLE handle, HBA_UINT32 portIndex,
+    SMHBA_PORTATTRIBUTES *port, rp_tree_t *desc,
+    inputArg_t *input, int lident, int gident);
+static int
+sas_print_rpnode(inputArg_t *input,
+    rp_tree_t *rpnode, int lident, int gident);
+static void sas_rp_tree_free(rp_tree_t *rproot);
+
+typedef int (*processPortFunc)(HBA_HANDLE handle, char *adapterName,
+    HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
+    SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
+
+static int processHBA(inputArg_t *input,
+    processPortFunc processPort);
+
+static int isPortWWNInArgv(inputArg_t *input, PHBA_WWN pWWN);
+static int isStringInArgv(inputArg_t *input, const char *adapterName);
+static boolean_t compareLUName(char *cmdArg, char *osName);
+static discoveredDevice *LUList = NULL;
+static targetPortList_t *gTargetPortList = NULL;
+
+/* processes for hanlding local HBA info */
+static int handleHBA(SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input,
+    int numberOfPorts, const char *adapterName);
+static int handleHBAPort(HBA_HANDLE handle, char *adapterName,
+    HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
+    SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
+static int processHBAPortPhyInfo(HBA_HANDLE handle, HBA_UINT32 portIndex,
+    SMHBA_PORTATTRIBUTES *port, int pflag);
+static int processHBAPortPhyStat(HBA_HANDLE handle, HBA_UINT32 portIndex,
+    int phyIndex, PSMHBA_SAS_PHY phyattrs, int pflag);
+
+/* process for handling expander info */
+static int handleExpander(HBA_HANDLE handle, char *adapterName,
+    HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
+    SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
+
+/* process for handling target port info */
+static int handleTargetPort(HBA_HANDLE handle, char *adapterName,
+    HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
+    SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
+
+/* process for handling logical unit info */
+static int handleLogicalUnit(HBA_HANDLE handle, char *adapterName,
+    HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
+    SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
+
+/* process for target port SCSI processing */
+static int
+searchTargetPortMappingData(HBA_HANDLE handle, HBA_UINT32 portIndex,
+    SMHBA_PORTATTRIBUTES *port, SMHBA_SAS_PORT *sasattr,
+    struct targetPortConfig *configData);
+
+/* process for target port config processing */
+static int searchTargetPort(HBA_HANDLE handle, HBA_UINT32 portIndex,
+    SMHBA_PORTATTRIBUTES *port, SMHBA_PORTATTRIBUTES *targetattr,
+    SMHBA_SAS_PORT *sasattr, int pflag);
+
+/* process for logical-unit config processing */
+static int
+searchDevice(PSMHBA_SCSIENTRY entryP, HBA_HANDLE handle, HBA_WWN hbaPortWWN,
+    HBA_WWN domainPortWWN, char *portName, int pflag);
+
+/* get domain port out of hba-port phy attr. */
+HBA_STATUS get_domainPort(HBA_HANDLE handle,
+    int portindex, PSMHBA_PORTATTRIBUTES port,
+    HBA_WWN *pdomainPort);
+
+static int
+sas_name_comp(const char *name1, const char *name2);
+static void
+sas_elem_sort(sas_elem_t *array, int nelem);
+
+/*
+ * function for hba subcommand
+ *
+ * Arguments:
+ *	wwnCount - count of the number of WWNs in wwn_argv
+ *	    if wwnCount > 0, then we will only print information for
+ *		the hba ports listed in wwn_argv
+ *	    if wwnCount == 0, then we will print information on all hba ports
+ *	wwn_argv - argument array of hba port WWNs
+ *	options - any options specified by the caller
+ *
+ * returns:
+ *	0	if successful
+ *	>0	otherwise
+ */
+int
+sas_util_list_hba(int hbaCount, char **hba_argv, cmdOptions_t *options)
+{
+	HBA_STATUS		status;
+	int			processHBA_flags = 0;
+	inputArg_t		input;
+	int 			err_cnt = 0;
+
+	/* process each of the options */
+	for (; options->optval; options++) {
+		switch (options->optval) {
+		case 'v':
+			processHBA_flags |= PRINT_VERBOSE;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
+		(void *) fprintf(stderr, "%s %s\n",
+		    gettext("Failed to load SM-HBA libraries."
+		    "Reason:"), getHBAStatus(status));
+		err_cnt++;
+		return (err_cnt);
+	}
+
+	(void *) memset(&input, 0, sizeof (input));
+	/* utilize wwnCount and wwn_argv for hbaCount and hba_argv */
+	input.wwnCount = hbaCount;
+	input.wwn_argv = hba_argv;
+	input.pflag = processHBA_flags;
+
+	/*
+	 * Process and filter for every local hba,
+	 * when the hba is not specificed, print all hba(s).
+	 */
+	err_cnt += processHBA(&input, NULL);
+
+	(void) HBA_FreeLibrary();
+
+	return (err_cnt);
+}
+
+/*
+ * function for hba-port subcommand
+ *
+ * Arguments:
+ *	wwnCount - count of the number of WWNs in wwn_argv
+ *	    if wwnCount > 0, then we will only print information for
+ *		the hba ports listed in wwn_argv
+ *	    if wwnCount == 0, then we will print information on all hba ports
+ *	wwn_argv - argument array of hba port WWNs
+ *	options - any options specified by the caller
+ *
+ * returns:
+ *	0	if successful
+ *	>0	otherwise
+ */
+int
+sas_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
+{
+	HBA_STATUS		status;
+	int			processHBA_flags = 0;
+	inputArg_t		input;
+	int 			err_cnt = 0;
+	char			hbaName[256] = {'\0'};
+
+	/* process each of the options */
+	for (; options->optval; options++) {
+		switch (options->optval) {
+		case 'a':
+			(void *) strlcpy(hbaName,
+			    options->optarg, sizeof (hbaName));
+			break;
+		case 'y':
+			processHBA_flags |= PRINT_PHY;
+			break;
+		case 'l':
+			processHBA_flags |= PRINT_PHY_LINKSTAT;
+			break;
+		case 'v':
+			processHBA_flags |= PRINT_VERBOSE;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
+		(void *) fprintf(stderr, "%s %s\n",
+		    gettext("Failed to load SM-HBA libraries."
+		    "Reason:"), getHBAStatus(status));
+		err_cnt++;
+		return (err_cnt);
+	}
+
+	(void *) memset(&input, 0, sizeof (input));
+	input.wwnCount = wwnCount;
+	input.wwn_argv = wwn_argv;
+	input.hbaName = hbaName;
+	input.pflag = processHBA_flags;
+
+	/*
+	 * Process and filter for every local hba-port,
+	 * when the hba-port is not specificed, print all hba-port(s).
+	 */
+	err_cnt += processHBA(&input, handleHBAPort);
+
+	(void) HBA_FreeLibrary();
+
+	return (err_cnt);
+}
+
+/*
+ * function for expander subcommand
+ *
+ * Arguments:
+ *	wwnCount - the number of Remote Port SAS Address in wwn_argv
+ *	    if wwnCount == 0, then print information on all
+ *		expander devices.
+ *	    if wwnCount > 0, then print information for the exapnders
+ *		given in wwn_argv.
+ *	wwn_argv - array of WWNs
+ *	options - options specified by the caller
+ *
+ * returns:
+ *	0	if successful
+ *	>0	otherwise
+ */
+int
+sas_util_list_expander(int wwnCount, char **wwn_argv, cmdOptions_t *options)
+{
+	HBA_STATUS		status;
+	int			processHBA_flags = 0;
+	char			hbaPort[MAXPATHLEN + 1] = {0};
+	inputArg_t		input;
+	int			err_cnt = 0;
+
+	/* process each of the options */
+	for (; options->optval; options++) {
+		switch (options->optval) {
+		case 'p':
+			(void) strlcpy(hbaPort, options->optarg,
+			    sizeof (hbaPort));
+			break;
+		case 't':
+			processHBA_flags |= PRINT_TARGET_PORT;
+			break;
+		case 'v':
+			processHBA_flags |= PRINT_VERBOSE;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
+		(void *) fprintf(stderr, "%s %s\n",
+		    gettext("Failed to load SM-HBA libraries."
+		    "Reason:"), getHBAStatus(status));
+		err_cnt++;
+		return (err_cnt);
+	}
+
+	(void *) memset(&input, 0, sizeof (input));
+	input.wwnCount = wwnCount;
+	input.wwn_argv = wwn_argv;
+	input.pflag = processHBA_flags;
+	input.hbaName = hbaPort;
+
+	/*
+	 * Process and filter for every hba-port,
+	 * when the hba-port is not specificed, print all hba-port(s).
+	 */
+	err_cnt += processHBA(&input, handleExpander);
+
+	(void) HBA_FreeLibrary();
+
+	return (err_cnt);
+}
+
+/*
+ * function for target-port subcommand
+ *
+ * Arguments:
+ *	wwnCount - the number of Remote Port SAS Address in wwn_argv
+ *	    if wwnCount == 0, then print information on all
+ *		target ports.
+ *	    if wwnCount > 0, then print information for the target ports
+ *		given in wwn_argv.
+ *	wwn_argv - array of WWNs
+ *	options - options specified by the caller
+ *
+ * returns:
+ *	0	if successful
+ *	>0	otherwise
+ */
+int
+sas_util_list_targetport(int tpCount, char **tpArgv, cmdOptions_t *options)
+{
+	HBA_STATUS		status;
+	int			processHBA_flags = 0;
+	int			tp, tpFound;
+	inputArg_t		input;
+	targetPortList_t	*tpListWalk;
+	int			err_cnt = 0;
+	uint64_t		tmpAddr;
+
+	/* process each of the options */
+	for (; options->optval; options++) {
+		switch (options->optval) {
+		case 's':
+			processHBA_flags |= PRINT_TARGET_SCSI;
+			break;
+		case 'v':
+			processHBA_flags |= PRINT_VERBOSE;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
+		(void *) fprintf(stderr, "%s %s\n",
+		    gettext("Failed to load SM-HBA libraries."
+		    "Reason:"), getHBAStatus(status));
+		err_cnt++;
+		return (err_cnt);
+	}
+
+	(void *) memset(&input, 0, sizeof (input));
+	input.wwnCount = tpCount;
+	input.wwn_argv = tpArgv;
+	input.pflag = processHBA_flags;
+
+	/*
+	 * Process and filter for every hba-port,
+	 * when the hba-port is not specificed, print all hba-port(s).
+	 */
+	err_cnt += processHBA(&input, handleTargetPort);
+
+	if (tpCount == 0) {
+		/* list all target port */
+		for (tpListWalk = gTargetPortList; tpListWalk != NULL;
+		    tpListWalk = tpListWalk->next) {
+			err_cnt += printTargetPortInfo(tpListWalk, input.pflag);
+		}
+	} else {
+		/*
+		 * When operands provided, we should set the error code
+		 * only if there are issues related with the operands.
+		 */
+		err_cnt = 0;
+		/*
+		 * list any paths not found first
+		 * this gives the user cleaner output
+		 */
+		for (tp = 0; tp < tpCount; tp++) {
+			errno = 0;
+			tmpAddr = strtoull(tpArgv[tp], NULL, 16);
+			if ((tmpAddr == 0) && (errno != 0)) {
+				err_cnt++;
+				continue;
+			}
+			for (tpListWalk = gTargetPortList, tpFound = B_FALSE;
+			    tpListWalk != NULL;
+			    tpListWalk = tpListWalk->next) {
+				if (wwnConversion(tpListWalk->sasattr.
+				    LocalSASAddress.wwn) == tmpAddr) {
+					tpFound = B_TRUE;
+					break;
+				}
+			}
+			if (tpFound == B_FALSE) {
+				(void *) fprintf(stderr,
+				    "Error: Target Port %s Not Found \n",
+				    tpArgv[tp]);
+				err_cnt++;
+			}
+		}
+		/* list all paths requested in order requested */
+		for (tp = 0; tp < tpCount; tp++) {
+			errno = 0;
+			tmpAddr = strtoull(tpArgv[tp], NULL, 16);
+			if ((tmpAddr == 0) && (errno != 0)) {
+				continue;
+			}
+			for (tpListWalk = gTargetPortList, tpFound = B_FALSE;
+			    tpListWalk != NULL;
+			    tpListWalk = tpListWalk->next) {
+				if (wwnConversion(tpListWalk->sasattr.
+				    LocalSASAddress.wwn) == tmpAddr) {
+					err_cnt += printTargetPortInfo(
+					    tpListWalk,
+					    processHBA_flags);
+				}
+			}
+		}
+	}
+	(void) HBA_FreeLibrary();
+	return (err_cnt);
+}
+/*
+ * This function will enumerate all the hba and hba ports,
+ * call the callback function to proceed with futher process.
+ *
+ * Arguments:
+ *	input - contains all the input parameters.
+ *	processPort - a callback function when handling each port.
+ *
+ *  Return Value:
+ *	    0		sucessfully processed handle
+ *	    >0		error has occured
+ */
+static int
+processHBA(inputArg_t *input, processPortFunc processPort)
+{
+	int			numAdapters = 0;
+	int			matchedHBAs = 0;
+	int			matchedHBAPorts = 0;
+	int			hbaPortExist = 0;
+	HBA_STATUS		status;
+	HBA_HANDLE		handle;
+	HBA_UINT32		numberOfPorts = 0;
+	int			portIndex = 0;
+	HBA_PORTTYPE		porttype;
+	SMHBA_LIBRARYATTRIBUTES libattrs;
+	SMHBA_ADAPTERATTRIBUTES	attrs;
+	SMHBA_PORTATTRIBUTES	port;
+	SMHBA_SAS_PORT		sasattrs;
+	int			i, sum, ret = 0;
+	int			remote_avail = 0;
+	int			local_avail = 0;
+	sas_elem_t		*adpt_array = NULL;
+	sas_elem_t		*port_array = NULL;
+
+	numAdapters = HBA_GetNumberOfAdapters();
+	if (numAdapters == 0) {
+		(void *) fprintf(stderr, "%s\n",
+		    gettext("Error: No Adapters Found."));
+		return (++ret);
+	}
+
+	/*
+	 * To deal with mismatching HBA/HBA Port/Expander Port, we need an
+	 * array of flags for each operands.
+	 */
+	if (input->wwnCount && (processPort != handleTargetPort) &&
+	    (processPort != handleLogicalUnit)) {
+		input->wwn_flag = calloc(input->wwnCount, sizeof (int));
+		if (input->wwn_flag == NULL) {
+			(void *) fprintf(stderr, "%s\n",
+			    gettext("No enough memory on heap"));
+			return (++ret);
+		}
+	}
+
+	adpt_array = calloc(numAdapters, sizeof (sas_elem_t));
+	if (adpt_array == NULL) {
+		(void *) fprintf(stderr, "%s\n",
+		    gettext("No enough memory on heap"));
+		if (input->wwn_flag) {
+			free(input->wwn_flag);
+			input->wwn_flag = NULL;
+		}
+		return (++ret);
+	}
+	for (i = 0; i < numAdapters; i++) {
+		status =
+		    SMHBA_GetVendorLibraryAttributes(i, &libattrs);
+		/*
+		 * If we get SAS incompatible library warning here,
+		 * just skip the following steps.
+		 */
+		if (status != 1) {
+			continue;
+		}
+		status = HBA_GetAdapterName(i, adpt_array[i].name);
+		if (status != HBA_STATUS_OK) {
+			(void *) fprintf(stderr, "%s %d %s %s\n",
+			    gettext("Error: Failed to get the name for"
+			    " HBA index"),
+			    i, gettext("Reason:"),
+			    getHBAStatus(status));
+			ret++;
+			continue;
+		}
+		adpt_array[i].index = i;
+	}
+	/* Sort the HBA Name in place. */
+	sas_elem_sort(adpt_array, numAdapters);
+
+	for (i = 0; i < numAdapters; i++) {
+		int times = 0;
+		if (adpt_array[i].name[0] != '\0') {
+			if ((handle = HBA_OpenAdapter(adpt_array[i].name))
+			    == 0) {
+				(void *) fprintf(stderr, "%s %s.\n",
+				    gettext("Error: Failed to open adapter"),
+				    adpt_array[i].name);
+				ret++;
+				continue;
+			}
+		} else {
+			continue;
+		}
+
+		/*
+		 * We need to support an adapter without hba port.
+		 * So get attributes anyway.
+		 */
+		(void *) memset(&attrs, 0, sizeof (attrs));
+		status = SMHBA_GetAdapterAttributes(handle, &attrs);
+		while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
+		    status == HBA_STATUS_ERROR_BUSY) &&
+		    times++ < HBA_MAX_RETRIES) {
+			(void) sleep(1);
+			status = SMHBA_GetAdapterAttributes(handle,
+			    &attrs);
+		}
+		if (status != HBA_STATUS_OK) {
+			(void *) fprintf(stderr, "%s %s %s %s\n",
+			    gettext("Error: Failed to get attributes"
+			    " for HBA "), adpt_array[i].name,
+			    gettext("Reason:"),
+			    getHBAStatus(status));
+
+			HBA_CloseAdapter(handle);
+			ret++;
+			continue;
+		}
+
+		status = SMHBA_GetNumberOfPorts(handle, &numberOfPorts);
+		if (status != HBA_STATUS_OK) {
+			(void *) fprintf(stderr, "%s %s %s %s\n",
+			    gettext("Error: Failed to get number of ports "
+			    "for HBA"), adpt_array[i].name,
+			    gettext("Reason:"),
+			    getHBAStatus(status));
+			HBA_CloseAdapter(handle);
+			ret++;
+			continue;
+		}
+
+		/*
+		 * Deal with each subcommand for hba filter here,
+		 * processPort is NULL for hba subcommand.
+		 */
+		if (processPort == NULL) {
+			matchedHBAs += handleHBA(&attrs, input,
+			    numberOfPorts, adpt_array[i].name);
+			HBA_CloseAdapter(handle);
+			continue;
+		} else if (processPort == handleHBAPort) {
+			if (input->hbaName[0] != '\0') {
+				if (strcmp(input->hbaName,
+				    adpt_array[i].name) == 0) {
+					matchedHBAs++;
+				} else {
+					continue;
+				}
+			} else {
+				matchedHBAs++;
+			}
+		} else {
+			matchedHBAs++;
+		}
+
+		/*
+		 * In order to have a sorted output for HBA Port, we should
+		 * do the sorting before moving on.
+		 */
+		if (numberOfPorts) {
+			port_array = calloc(numberOfPorts, sizeof (sas_elem_t));
+		}
+		for (portIndex = 0; portIndex < numberOfPorts; portIndex++) {
+			if ((status = SMHBA_GetPortType(handle,
+			    portIndex, &porttype)) != HBA_STATUS_OK) {
+				(void *) fprintf(stderr, "%s %s %s %s\n",
+				    gettext("Failed to get adapter port type "
+				    "for HBA"), adpt_array[i].name,
+				    gettext("Reason:"),
+				    getHBAStatus(status));
+				ret++;
+				continue;
+			}
+			if (porttype != HBA_PORTTYPE_SASDEVICE) {
+				/* skip any non-sas hba port */
+				continue;
+			}
+			(void *) memset(&port, 0, sizeof (port));
+			(void *) memset(&sasattrs, 0, sizeof (sasattrs));
+			port.PortSpecificAttribute.SASPort = &sasattrs;
+			if ((status = SMHBA_GetAdapterPortAttributes(
+			    handle, portIndex, &port)) != HBA_STATUS_OK) {
+				/*
+				 * Not able to get port attributes.
+				 * print out error message and
+				 * move on to the next port
+				 */
+				(void *) fprintf(stderr, "%s %s %s %d %s %s\n",
+				    gettext("Error: Failed to get port "
+				    "attributes for HBA"), adpt_array[i].name,
+				    gettext("port index"), portIndex,
+				    gettext("Reason:"),
+				    getHBAStatus(status));
+				ret++;
+				continue;
+			}
+			(void) strlcpy(port_array[portIndex].name,
+			    port.OSDeviceName,
+			    sizeof (port_array[portIndex].name));
+			port_array[portIndex].index = portIndex;
+		}
+		/* Sort the HBA Port Name here. */
+		if (port_array) {
+			sas_elem_sort(port_array, numberOfPorts);
+		}
+		/*
+		 * Sum up the local hba ports available.
+		 */
+		local_avail += numberOfPorts;
+
+		/*
+		 * Clear g_printHBA flag for expander subcommand.
+		 */
+		g_printHBA = 0;
+
+		/* process each port on the given adapter */
+		for (portIndex = 0;
+		    portIndex < numberOfPorts;
+		    portIndex++) {
+			/*
+			 * We only handle the port which is valid.
+			 */
+			if (port_array[portIndex].name[0] == '\0') {
+				continue;
+			}
+			(void *) memset(&port, 0, sizeof (port));
+			(void *) memset(&sasattrs, 0, sizeof (sasattrs));
+			port.PortSpecificAttribute.SASPort = &sasattrs;
+
+			(void) SMHBA_GetAdapterPortAttributes(handle,
+			    port_array[portIndex].index, &port);
+
+			/*
+			 * We have different things to do for the three
+			 * sub-commands here.
+			 */
+			if (processPort == handleHBAPort) {
+				/*
+				 * For hba-port, we will check whether the
+				 * specified hba port exist first.
+				 * But if no hba port specified, we should
+				 * by pass this check(just let hbaPortExist
+				 * be 1).
+				 */
+				if (input->wwnCount > 0) {
+					if (isStringInArgv(input,
+					    port.OSDeviceName)) {
+						hbaPortExist = 1;
+						if (g_printHBA == 0) {
+							(void *) fprintf(stdout,
+							    "%s %s\n",
+							    "HBA Name:",
+							    adpt_array[i].name);
+							g_printHBA = 1;
+						}
+					}
+				} else {
+					hbaPortExist = 1;
+					if (g_printHBA == 0) {
+						(void *) fprintf(stdout,
+						    "%s %s\n",
+						    "HBA Name:",
+						    adpt_array[i].name);
+						g_printHBA = 1;
+					}
+				}
+			}
+
+			if (processPort == handleExpander) {
+				/*
+				 * For expander device, input->hbaName is
+				 * the hba port name specified on the
+				 * command line(with -p option).
+				 */
+				if (input->hbaName[0] != '\0') {
+					if (strcmp(input->hbaName,
+					    port.OSDeviceName) == 0)
+						hbaPortExist = 1;
+				} else
+					hbaPortExist = 1;
+			}
+
+			if (processPort == handleTargetPort) {
+				/*
+				 * For target port, we don't need to check the
+				 * hba port address, so let it go here.
+				 */
+				hbaPortExist = 1;
+			}
+
+			if (processPort == handleLogicalUnit) {
+				/*
+				 * For lu, we don't need to check the hba
+				 * port address, so let it go here.
+				 */
+				hbaPortExist = 1;
+			}
+
+			if (hbaPortExist) {
+				if (port.PortSpecificAttribute.SASPort->
+				    NumberofDiscoveredPorts) {
+					remote_avail++;
+				}
+				ret += (*processPort)(handle,
+				    adpt_array[i].name,
+				    port_array[portIndex].index, &port,
+				    &attrs, input);
+				/*
+				 * We should reset the hbaPortExist flag
+				 * here for next round of check and count
+				 * for the machedHBAPorts.
+				 */
+				hbaPortExist = 0;
+				matchedHBAPorts++;
+			}
+		}
+		if (port_array) {
+			free(port_array);
+			port_array = NULL;
+		}
+		HBA_CloseAdapter(handle);
+	}
+	if (adpt_array) {
+		free(adpt_array);
+		adpt_array = NULL;
+	}
+
+	/*
+	 * When we are here, we have traversed all the hba and hba ports.
+	 */
+	if (matchedHBAs == 0) {
+		(void *) fprintf(stderr, "%s\n",
+		    gettext("Error: Matching HBA not found."));
+		if (input->wwn_flag) {
+			free(input->wwn_flag);
+			input->wwn_flag = NULL;
+		}
+		return (++ret);
+	} else if (processPort == NULL) {
+		/*
+		 * processPort == NULL signifies hba subcommand.
+		 * If enter here, it means we have at least one matching
+		 * hba, we need to check if there are mismatching ones.
+		 */
+		for (i = 0; i < input->wwnCount; i++) {
+			if (input->wwn_flag[i] == 0) {
+				(void *) fprintf(stderr, "%s %s %s\n",
+				    gettext("Error: HBA"),
+				    input->wwn_argv[i],
+				    gettext("not found."));
+				ret++;
+			}
+		}
+	} else {
+		if (local_avail > 0 && matchedHBAPorts == 0) {
+			(void *) fprintf(stderr, "%s\n",
+			    gettext("Error: Matching HBA Port "
+			    "not found."));
+			if (input->wwn_flag) {
+				free(input->wwn_flag);
+				input->wwn_flag = NULL;
+			}
+			return (++ret);
+		} else if (local_avail == 0) {
+			(void *) fprintf(stderr, "%s\n",
+			    gettext("Error: No HBA Port Configured."));
+			if (input->wwn_flag) {
+				free(input->wwn_flag);
+				input->wwn_flag = NULL;
+			}
+			return (++ret);
+		} else if (processPort == handleHBAPort) {
+			/*
+			 * If enter here, we have at least one HBA port
+			 * matched. For hba-port subcommand, we shall check
+			 * whether there are operands mismatching.
+			 */
+			for (i = 0; i < input->wwnCount; i++) {
+				if (input->wwn_flag[i] == 0) {
+					(void *) fprintf(stderr, "%s %s %s\n",
+					    gettext("Error: HBA Port"),
+					    input->wwn_argv[i],
+					    gettext("not found."));
+					ret++;
+				}
+			}
+		}
+	}
+
+	/*
+	 * For expander subcommand, we need to check if the
+	 * specified sas address(ese) exist (none/partial/all).
+	 */
+	if (processPort == handleExpander) {
+		if (input->wwnCount > 0) {
+			sum = 0;
+			for (i = 0; i < input->wwnCount; i++) {
+				sum += input->wwn_flag[i];
+			}
+			/*
+			 * If sum is zero, it means that for all the given
+			 * operands matching count is zero. So none of the
+			 * specified SAS address exist actually.
+			 */
+			if (sum == 0) {
+				(void *) fprintf(stderr, gettext("Error: "
+				    "Matching SAS Address not found.\n"));
+				free(input->wwn_flag);
+				input->wwn_flag = NULL;
+				return (++ret);
+			}
+
+			/*
+			 * If we get here, it means that some of the specified
+			 * sas address exist, we will know through looping the
+			 * wwn_flag array.
+			 */
+			for (i = 0; i < input->wwnCount; i++) {
+				if (input->wwn_flag[i] == 0) {
+					(void *) fprintf(stderr, "%s %s %s\n",
+					    gettext("Error: SAS Address"),
+					    input->wwn_argv[i],
+					    gettext("not found."));
+					ret++;
+				}
+			}
+		}
+		/* even if no remote port is found it is not an error. */
+	}
+	if (input->wwn_flag) {
+		free(input->wwn_flag);
+		input->wwn_flag = NULL;
+	}
+	return (ret);
+}
+
+/*
+ * This function will handle the phy stuff for hba-port subcommand.
+ *
+ * Arguments:
+ *      handle - handle to hba port.
+ *      portIndex - the index of hba port currently being processed.
+ *      port - pointer to hba port attributes.
+ *      pflag - options user specified.
+ *
+ *  Return Value:
+ *	    0		sucessfully processed handle
+ *	    >0		error has occured
+ */
+static int
+processHBAPortPhyInfo(HBA_HANDLE handle, HBA_UINT32 portIndex,
+    SMHBA_PORTATTRIBUTES *port, int pflag)
+{
+	int 		phyIndex = 0, err_cnt = 0;
+	HBA_UINT32	numphys = 0;
+	HBA_STATUS	status = 0;
+	SMHBA_SAS_PHY	phyattrs;
+
+	if (port == NULL)
+		return (++err_cnt);
+
+	numphys = port->PortSpecificAttribute.SASPort->NumberofPhys;
+	if (numphys == 0)
+		return (0);
+
+	if ((pflag & PRINT_PHY) || (pflag & PRINT_PHY_LINKSTAT))
+		(void *) fprintf(stdout, "%s\n", "    Phy Information:");
+	else
+		return (0);
+
+
+	for (phyIndex = 0; phyIndex < numphys; phyIndex++) {
+		(void *) memset(&phyattrs, 0, sizeof (phyattrs));
+		status = SMHBA_GetSASPhyAttributes(
+		    handle, portIndex, phyIndex, &phyattrs);
+		if (status != HBA_STATUS_OK) {
+			(void *) fprintf(stderr, "%s %d %s %s\n",
+			    gettext("Failed to get SAS Phy attributes"
+			    "phyIndex"), phyIndex,
+			    gettext("Reason:"),
+			    getHBAStatus(status));
+			err_cnt++;
+			continue;
+		}
+		if (pflag & PRINT_PHY)
+			printHBAPortPhyInfo(&phyattrs);
+		if (pflag & PRINT_PHY_LINKSTAT)
+			err_cnt += processHBAPortPhyStat(handle,
+			    portIndex, phyIndex, &phyattrs, pflag);
+	}
+	return (err_cnt);
+}
+
+/*
+ * This function will handle the phy stuff for hba-port subcommand.
+ *
+ * Arguments:
+ *      handle - handle to hba port.
+ *      portIndex - the index of hba port currently being processed.
+ *      port - pointer to hba port attributes.
+ *      pflag - options user specified.
+ *
+ *  Return Value:
+ *	    0		sucessfully processed handle
+ *	    >0		error has occured
+ */
+static int
+processHBAPortPhyStat(HBA_HANDLE handle, HBA_UINT32 portIndex, int phyIndex,
+    PSMHBA_SAS_PHY phyattrs, int pflag)
+{
+	HBA_STATUS		status = 0;
+	SMHBA_PHYSTATISTICS	phystat;
+	SMHBA_SASPHYSTATISTICS	sasphystat;
+
+	if ((pflag & PRINT_PHY) == 0) {
+		(void *) fprintf(stdout, "%s %d\n",
+		    "      Identifier:", phyattrs->PhyIdentifier);
+	}
+
+	(void *) memset(&phystat, 0, sizeof (phystat));
+	(void *) memset(&sasphystat, 0, sizeof (sasphystat));
+	phystat.SASPhyStatistics = &sasphystat;
+	status = SMHBA_GetPhyStatistics(handle, portIndex, phyIndex, &phystat);
+	if (status != HBA_STATUS_OK) {
+		(void *) fprintf(stdout, "%s\n",
+		    "        Link Error Statistics:");
+		(void *) fprintf(stderr, "%s\n",
+		    gettext("            Failed to retrieve Link "
+		    "Error Statistics!"));
+		return (1);
+	}
+	printHBAPortPhyStatistics(phystat.SASPhyStatistics);
+	return (0);
+}
+
+/*
+ * Check whether the pWWN exist in the WWNs list which specified by user.
+ *
+ * Arguments:
+ *	input - contains all the input parameters.
+ *	pWWN - pointer to the hba port sas address.
+ *
+ *  Return Value:
+ *	    1		true, the pWWN exist in the sas address list specified.
+ *	    0		false.
+ */
+static int
+isPortWWNInArgv(inputArg_t *input, PHBA_WWN pWWN)
+{
+	int 		port_wwn_counter = 0;
+	int		portfound = 0;
+	uint64_t	hbaWWN;
+
+	/* list only ports given in wwn_argv */
+	for (port_wwn_counter = 0;
+	    port_wwn_counter < input->wwnCount;
+	    port_wwn_counter++) {
+		hbaWWN = strtoull(input->wwn_argv[port_wwn_counter], NULL,
+		    16);
+		if (hbaWWN == 0 && errno != 0)
+			continue;
+		if (wwnConversion(pWWN->wwn) == hbaWWN) {
+			if (input->wwn_flag) {
+				input->wwn_flag[port_wwn_counter]++;
+			}
+			portfound = 1;
+		}
+	}
+	return (portfound);
+}
+
+/*
+ * Check whether the string value exists in the input list,
+ * which specified by user.
+ *
+ * Arguments:
+ *	input - contains all the input parameters.
+ *	stringName - could be hba adapter name
+ *	                      hba-port name.
+ *
+ *  Return Value:
+ *	    1		true, the HBA exists in the list specified.
+ *	    0		false.
+ */
+static int
+isStringInArgv(inputArg_t *input, const char *stringName)
+{
+	int 		counter = 0;
+	int		found = 0;
+
+	/* list only hba(s) given in wwn_argv */
+	for (counter = 0;
+	    counter < input->wwnCount;
+	    counter++) {
+		if (strcmp(input->wwn_argv[counter],
+		    stringName) == 0) {
+			if (input->wwn_flag)
+				input->wwn_flag[counter]++;
+			found = 1;
+		}
+	}
+	return (found);
+}
+
+/*
+ * Callback function for hba subcommand.
+ *
+ * Arguments:
+ *      attrs - pointer to adapter attributes currently being processed.
+ *	input - contains all the input parameters.
+ *	numberOfPorts - number of ports of this HBA.
+ *
+ *  Return Value:
+ *  	matching number
+ */
+static int handleHBA(SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input,
+    int numberOfPorts, const char *adapterName)
+{
+	int matchingHBA = 1;
+
+	if (input->wwnCount == 0) {
+		printHBAInfo(attrs, input->pflag, numberOfPorts, adapterName);
+	} else {
+		if (isStringInArgv(input, adapterName)) {
+			printHBAInfo(attrs,
+			    input->pflag, numberOfPorts, adapterName);
+		} else {
+			matchingHBA = 0;
+		}
+	}
+
+	return (matchingHBA);
+}
+
+/*
+ * Callback function for hba-port subcommand.
+ *
+ * Arguments:
+ *      handle - handle to hba port.
+ *      portIndex - the index of hba port currently being processed.
+ *      port - pointer to hba port attributes.
+ *      attrs - pointer to adapter attributes currently being processed.
+ *	input - contains all the input parameters.
+ *
+ *  Return Value:
+ *	    0		sucessfully processed handle
+ *	    >0		error has occured
+ */
+/*ARGSUSED*/
+static int handleHBAPort(HBA_HANDLE handle, char *adapterName,
+    HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
+    SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
+{
+	int ret = 0;
+	printHBAPortInfo(port, attrs, input->pflag);
+	ret = processHBAPortPhyInfo(handle, portIndex, port, input->pflag);
+	return (ret);
+}
+
+/*
+ * Callback function for expander subcommand.
+ *
+ * Arguments:
+ *      handle - handle to hba port.
+ *      portIndex - the index of hba port currently being processed.
+ *      port - pointer to hba port attributes.
+ *      attrs - pointer to adapter attributes currently being processed.
+ *	input - contains all the input parameters.
+ *
+ *  Return Value:
+ *	    0		sucessfully processed handle
+ *	    >0		error has occured
+ */
+/*ARGSUSED*/
+static int handleExpander(HBA_HANDLE handle, char *adapterName,
+    HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
+    SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
+{
+	SMHBA_PORTATTRIBUTES	attr;
+	SMHBA_SAS_PORT		sasport;
+	HBA_STATUS		status;
+	int			ret = 0;
+	int			i, numberOfRP;
+	rp_tree_t		*rpnode;
+	rp_tree_t		*rproot = NULL;
+	rp_tree_t		*unsolved_head = NULL;
+	rp_tree_t		*unsolved_tail = NULL;
+	rp_tree_t		*unsolved_sentinel = NULL;
+	int			printPort = 0;
+	int			numberOfEXP = 0;
+	int			unsolved_inserted = 0;
+	int			unsolved_left = 0;
+	int			disco_port_fail = 0;
+	boolean_t		firstPrinted = B_FALSE;
+
+	(void *) memset(&attr, 0, sizeof (attr));
+	(void *) memset(&sasport, 0, sizeof (sasport));
+	attr.PortSpecificAttribute.SASPort = &sasport;
+
+	/*
+	 * Retrive all expander device from this hba port first.
+	 */
+	if ((numberOfRP = port->PortSpecificAttribute.SASPort->
+	    NumberofDiscoveredPorts) == 0) {
+		/* no remote port. just return 0. */
+		return (ret);
+	}
+
+	for (i = 0; i < numberOfRP; i++) {
+		rpnode = calloc(1, sizeof (rp_tree_t));
+		rpnode->portattr.PortSpecificAttribute.SASPort =
+		    &rpnode->sasattr;
+		status = SMHBA_GetDiscoveredPortAttributes(handle,
+		    portIndex, i, &rpnode->portattr);
+		if (status != HBA_STATUS_OK) {
+			disco_port_fail++;
+			free(rpnode);
+			ret++;
+			continue;
+		}
+
+		if (rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) {
+			numberOfEXP++;
+		}
+		/*
+		 * We will try to insert this expander device and target
+		 * ports into the topology tree. If we failed, we can chain
+		 * them together and try again when we have all the
+		 * discovered port information in hands.
+		 */
+		if (rproot == NULL && memcmp(port->
+		    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
+		    rpnode->sasattr.AttachedSASAddress.wwn,
+		    sizeof (HBA_WWN)) == 0) {
+			/*
+			 * The root node of tree should
+			 * be set up first.
+			 */
+			rproot = rpnode;
+		} else {
+			/*
+			 * If we can not set up the root node of
+			 * the tree or we failed to insert
+			 * the disocvered port node, queue it up then.
+			 */
+			if (rproot == NULL ||
+			    sas_rp_tree_insert(&rproot, rpnode) != 0) {
+				if (unsolved_head == NULL) {
+					unsolved_head = rpnode;
+					unsolved_tail = rpnode;
+				} else {
+					rpnode->sibling = unsolved_head;
+					unsolved_head = rpnode;
+				}
+			}
+		}
+	}
+
+	if (disco_port_fail) {
+		(void *) fprintf(stderr, "%s %d %s %s\n",
+		    gettext("Error: Failed to get attributes for"),
+		    disco_port_fail,
+		    gettext("connected ports of HBA port"),
+		    port->OSDeviceName);
+	}
+
+	/* no expander found.  No need further processing. */
+	if (numberOfEXP == 0) {
+		while (unsolved_head) {
+			unsolved_tail =
+			    unsolved_head->sibling;
+			free(unsolved_head);
+			unsolved_head = unsolved_tail;
+		}
+		if (rproot) sas_rp_tree_free(rproot);
+		return (ret);
+	}
+
+	/*
+	 * When we're here, we should already have all information,
+	 * now we try again to insert them into the topology tree.
+	 * unsolved_head is the pointer which point to the head of
+	 * unsolved rpnode linked list.
+	 * unsolved_tail is the pointer which point to the tail of
+	 * unsolved rpnode linked list.
+	 * unsolved_sentinel is for insertion failure detection.
+	 * When we're trying to insert the rpnodes from unsolved
+	 * linked list, it may happen that some of the rpnodes can
+	 * not be inserted no matter how many times we loop through
+	 * this linked list. So we use unsolved_sentinel to identify
+	 * the tail of last round of scanning, and unsolved_inserted
+	 * which is a counter will be used to count how many rpnodes
+	 * have been inserted from last round, if it is zero, which
+	 * means that we can not insert rpnodes into rptree any more,
+	 * and we should stop and deallocate the memory they occupied.
+	 */
+	unsolved_sentinel = unsolved_tail;
+	while (unsolved_head) {
+		rpnode = unsolved_head;
+		unsolved_head = unsolved_head->sibling;
+		if (unsolved_head == NULL)
+			unsolved_tail = NULL;
+		rpnode->sibling = NULL;
+		if (sas_rp_tree_insert(&rproot, rpnode) != 0) {
+			unsolved_tail->sibling = rpnode;
+			unsolved_tail = rpnode;
+			if (rpnode == unsolved_sentinel) {
+				/*
+				 * We just scanned one round for the
+				 * unsolved list. Check to see whether we
+				 * have nodes inserted, if none, we should
+				 * break in case of an indefinite loop.
+				 */
+				if (unsolved_inserted == 0) {
+					/*
+					 * Indicate there is unhandled node.
+					 * Chain free the whole unsolved
+					 * list here.
+					 */
+					unsolved_left++;
+					break;
+				} else {
+					unsolved_inserted = 0;
+					unsolved_sentinel = unsolved_tail;
+				}
+			}
+		} else {
+			/*
+			 * We just inserted one rpnode, increment the
+			 * unsolved_inserted counter. We will utilize this
+			 * counter to detect an indefinite insertion loop.
+			 */
+			unsolved_inserted++;
+		}
+	}
+
+	/* check if there is left out discovered ports. */
+	if (unsolved_left) {
+		ret++;
+		(void *) fprintf(stderr, "%s %s\n",
+		    gettext("Error: Failed to establish expander topology on"),
+		    port->OSDeviceName);
+		(void *) fprintf(stderr, "%s\n",
+		    gettext("       Folowing port(s) are unresolved."));
+		while (unsolved_head) {
+			unsolved_tail =
+			    unsolved_head->sibling;
+			(void *) fprintf(stderr, "%s%016llx ",
+			    firstPrinted ? "" : "\t",
+			    wwnConversion(unsolved_head->sasattr.
+			    LocalSASAddress.wwn));
+			if (firstPrinted == B_FALSE) firstPrinted = B_TRUE;
+			free(unsolved_head);
+			unsolved_head = unsolved_tail;
+		}
+		(void *) fprintf(stderr, "\n");
+		/* still print what we have */
+		ret += sas_rp_tree_print(handle, adapterName, portIndex,
+		    port, rproot, input, 2 * TABLEN, &printPort);
+	} else {
+		ret += sas_rp_tree_print(handle, adapterName, portIndex,
+		    port, rproot, input, 2 * TABLEN, &printPort);
+	}
+
+	if (rproot) sas_rp_tree_free(rproot);
+
+	return (ret);
+}
+
+/*
+ * Callback function for target-port subcommand.
+ *
+ * Arguments:
+ *      handle - handle to hba port.
+ *      portIndex - the index of hba port currently being processed.
+ *      port - pointer to hba port attributes.
+ *      attrs - pointer to adapter attributes currently being processed.
+ *	input - contains all the input parameters.
+ *
+ *  Return Value:
+ *	    0		sucessfully processed handle
+ *	    >0		error has occured
+ */
+/*ARGSUSED*/
+static int handleTargetPort(HBA_HANDLE handle, char *adapterName,
+    HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
+    SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
+{
+	HBA_STATUS		status;
+	SMHBA_PORTATTRIBUTES	targetattr;
+	SMHBA_SAS_PORT		sasattr;
+	int			i;
+	int			ret = 0;
+	int			disco_port_fail = 0;
+
+	targetattr.PortSpecificAttribute.SASPort = &sasattr;
+
+	for (i = 0; i < port->PortSpecificAttribute.SASPort->
+	    NumberofDiscoveredPorts; i++) {
+		status = SMHBA_GetDiscoveredPortAttributes(handle,
+		    portIndex, i, &targetattr);
+		if (status != HBA_STATUS_OK) {
+			disco_port_fail++;
+		} else {
+			/* skip expander device */
+			if (targetattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
+				ret += searchTargetPort(handle, portIndex, port,
+				    &targetattr, &sasattr, input->pflag);
+			}
+		}
+	}
+
+	if (disco_port_fail) {
+		ret++;
+		(void *) fprintf(stderr, "%s %d %s %s\n",
+		    gettext("Error: Failed to get attributes for"),
+		    disco_port_fail,
+		    gettext("connected ports of HBA port"),
+		    port->OSDeviceName);
+	}
+	return (ret);
+}
+
+/*
+ * ****************************************************************************
+ *
+ * compareLUName -
+ * 	compare names directly and also check if disk namees match with
+ *	different slice number or /devices path are speicified and matches.
+ *
+ * cmdArg	- first string to compare
+ * osName	- os name from attributes
+ *
+ * returns 	B_TRUE if the strings match either directly or via devid
+ *		B_FALSE otherwise
+ *
+ * ****************************************************************************
+ */
+static boolean_t
+compareLUName(char *cmdArg, char *osName)
+{
+
+	boolean_t	isSame = B_FALSE;
+	char		dev1[MAXPATHLEN], dev2[MAXPATHLEN];
+	char		*ch1, *ch2;
+
+	if (strcmp(cmdArg, osName) == 0) {
+		isSame = B_TRUE;
+	} else {
+		/* user input didn't match, try to  match the core of args. */
+		(void) strlcpy(dev1, cmdArg, MAXPATHLEN);
+		(void) strlcpy(dev2, osName, MAXPATHLEN);
+		/* is this /devices path */
+		if (((ch1 = strrchr(dev1, ',')) != NULL) &&
+		    ((ch2 = strrchr(dev2, ',')) != NULL)) {
+			*ch1 = *ch2 = '\0';
+			if (strcmp(dev1, dev2) == 0) {
+				isSame = B_TRUE;
+			}
+		/* is this a /dev link */
+		} else if ((strncmp(dev1, "/dev/", 5) == 0) &&
+		    (strncmp(dev2, "/dev/", 5) == 0)) {
+			if ((strstr(dev1, "dsk") != NULL) &&
+			    ((strstr(dev2, "dsk") != NULL))) {
+				/* if it is disk link */
+				if (((ch1 = strrchr(dev1, 's')) != NULL) &&
+				    ((ch2 = strrchr(dev2, 's')) != NULL)) {
+					*ch1 = *ch2 = '\0';
+					if (strcmp(dev1, dev2) == 0) {
+						isSame = B_TRUE;
+					}
+				}
+			} else {
+				/* other dev links */
+				if (strcmp(dev1, dev2) == 0) {
+					isSame = B_TRUE;
+				}
+			}
+		}
+	} /* compare */
+
+	return (isSame);
+}
+
+/*
+ * Process logical-unit(lu) subcommand.
+ *
+ * Arguments:
+ *      luCount - number of OS device name(s) specified by user.
+ *      luArgv - array of OS device name(s) specified by user.
+ *      options - all the options specified by user.
+ *
+ *  Return Value:
+ *	    0		sucessfully processed handle
+ *	    >0		error has occured
+ */
+int
+sas_util_list_logicalunit(int luCount, char **luArgv, cmdOptions_t *options)
+{
+	HBA_STATUS		status;
+	int			processHBA_flags = 0;
+	int			lu;
+	boolean_t		pathFound;
+	boolean_t		verbose;
+	inputArg_t		input;
+	discoveredDevice	*LUListWalk = NULL;
+	int			err_cnt = 0;
+
+	for (; options->optval; options++) {
+		if (options->optval == 'v') {
+			processHBA_flags |= PRINT_VERBOSE;
+		}
+	}
+
+	/* HBA_LoadLibrary() */
+	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
+		(void *) fprintf(stderr, "%s %s\n",
+		    gettext("Failed to load SM-HBA libraries."
+		    "Reason:"), getHBAStatus(status));
+		err_cnt++;
+		return (err_cnt);
+	}
+
+	(void *) memset(&input, 0, sizeof (input));
+	input.pflag = processHBA_flags;
+	input.wwnCount = luCount;
+	input.wwn_argv = luArgv;
+
+	err_cnt += processHBA(&input, handleLogicalUnit);
+	verbose = (input.pflag & PRINT_VERBOSE) ? B_TRUE : B_FALSE;
+
+	if (luCount == 0) {
+		/* list all paths */
+		for (LUListWalk = LUList; LUListWalk != NULL;
+		    LUListWalk = LUListWalk->next) {
+			err_cnt += printOSDeviceNameInfo(LUListWalk, verbose);
+		}
+	} else {
+		/*
+		 * When operands provided, we should set the error code
+		 * only if there are issues related with the operands.
+		 */
+		err_cnt = 0;
+		/*
+		 * list any paths not found first
+		 * this gives the user cleaner output
+		 */
+		for (lu = 0; lu < luCount; lu++) {
+			for (LUListWalk = LUList, pathFound = B_FALSE;
+			    LUListWalk != NULL;
+			    LUListWalk = LUListWalk->next) {
+				if (compareLUName(luArgv[lu],
+				    LUListWalk->OSDeviceName)) {
+					pathFound = B_TRUE;
+					break;
+				}
+			}
+			if (pathFound == B_FALSE) {
+				(void *) fprintf(stderr,
+				    "Error: Logical Unit %s Not Found \n",
+				    luArgv[lu]);
+				err_cnt++;
+			}
+		}
+		/* list all paths requested in order requested */
+		for (lu = 0; lu < luCount; lu++) {
+			for (LUListWalk = LUList; LUListWalk != NULL;
+			    LUListWalk = LUListWalk->next) {
+				if (compareLUName(luArgv[lu],
+				    LUListWalk->OSDeviceName)) {
+					err_cnt += printOSDeviceNameInfo(
+					    LUListWalk,
+					    verbose);
+				}
+			}
+		}
+	}
+	(void) HBA_FreeLibrary();
+	return (err_cnt);
+}
+
+/*
+ * Callback function for logical-unit(lu) subcommand.
+ *
+ * Arguments:
+ *      handle - handle to hba port.
+ *      portIndex - the index of hba port currently being processed.
+ *      port - pointer to hba port attributes.
+ *      attrs - pointer to adapter attributes currently being processed.
+ *	input - contains all the input parameters.
+ *
+ *  Return Value:
+ *	    0		sucessfully processed handle
+ *	    >0		error has occured
+ */
+/*ARGSUSED*/
+static int handleLogicalUnit(HBA_HANDLE handle, char *adapterName,
+    HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
+    SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
+{
+	HBA_STATUS		status;
+	SMHBA_TARGETMAPPING	*map;
+	HBA_WWN			hbaPortWWN, domainPortWWN;
+	char			*portName = NULL;
+	int			numentries;
+	int			count = 0;
+	int			ret = 0;
+
+	hbaPortWWN = port->PortSpecificAttribute.SASPort->LocalSASAddress;
+	portName = port->OSDeviceName;
+
+	status = get_domainPort(handle, portIndex, port, &domainPortWWN);
+	switch (status) {
+		case HBA_STATUS_OK:
+			break;
+		case HBA_STATUS_ERROR_NOT_SUPPORTED:
+			/* don't increase error flag for no phy configuration */
+			return (ret);
+		case HBA_STATUS_ERROR:
+		default:
+			return (++ret);
+	}
+
+	if ((map = calloc(1, sizeof (*map))) == NULL) {
+		(void *) fprintf(stderr, "%s\n",
+		    gettext("No enough memory on heap."));
+		return (++ret);
+	}
+	map->NumberOfEntries = 1;
+
+	/*
+	 * First, we need to get the target mapping data from this hba
+	 * port.
+	 */
+	status = SMHBA_GetTargetMapping(handle,
+	    hbaPortWWN, domainPortWWN, map);
+
+	if (status == HBA_STATUS_ERROR_MORE_DATA) {
+		numentries = map->NumberOfEntries;
+		free(map);
+		map = calloc(1, sizeof (HBA_UINT32) +
+		    (numentries * sizeof (SMHBA_SCSIENTRY)));
+		if (map == NULL) {
+			(void *) fprintf(stderr, "%s\n",
+			    gettext("No enough memory on heap."));
+			return (++ret);
+		}
+		map->NumberOfEntries = numentries;
+		status = SMHBA_GetTargetMapping(handle,
+		    hbaPortWWN, domainPortWWN, map);
+	}
+
+	if (status != HBA_STATUS_OK) {
+		(void *) fprintf(stderr, "%s %016llx %s %s\n",
+		    gettext("Error: Failed to get SCSI mapping data for "
+		    "the HBA port"), wwnConversion(hbaPortWWN.wwn),
+		    gettext("Reason:"),
+		    getHBAStatus(status));
+		free(map);
+		return (++ret);
+	}
+
+	/*
+	 * By iterating each entry of the targetmapping data, we will
+	 * construct a global list of logical unit.
+	 */
+	for (count = 0; count < map->NumberOfEntries; count++) {
+		ret += searchDevice(
+		    &(map->entry[count]), handle, hbaPortWWN, domainPortWWN,
+		    portName, input->pflag);
+	}
+	free(map);
+	return (ret);
+}
+
+/*
+ * Search the matching targetmapping data for given target port and SAM LUN
+ *	and return target mapping data if found.
+ *
+ * Arguments:
+ *      handle - handle to hba port.
+ *      portIndex - hba port index
+ *      port - hba port attributes.
+ *      targetportWWN - target port SAS address.
+ *      domainportWWN - domain port SAS address.
+ *      domainportttr - target port SAS attributes.
+ *      samLUN - samLUN from report LUNs data.
+ *      data - matching target mapping data.
+ *
+ *  Return Value:
+ *	    0		sucessfully processed handle
+ *	    >0		error has occured
+ */
+static int
+searchTargetPortMappingData(HBA_HANDLE handle, HBA_UINT32 portIndex,
+    SMHBA_PORTATTRIBUTES *port, SMHBA_SAS_PORT *sasattr,
+    struct targetPortConfig *configData)
+{
+	int			ret = 0;
+	HBA_STATUS		status;
+	SMHBA_TARGETMAPPING	*map = NULL;
+	HBA_WWN			hbaPortWWN, domainPortWWN;
+	int			numentries, count;
+	targetPortMappingData_t	*TPMapData;
+	struct scsi_inquiry	inq;
+	struct scsi_extended_sense  sense;
+	HBA_UINT32		responseSize, senseSize = 0;
+	uchar_t			rawLUNs[DEFAULT_LUN_LENGTH], *lun_string;
+	HBA_UINT8		scsiStatus;
+	rep_luns_rsp_t		*lun_resp;
+	int			lunNum, numberOfLun, lunCount;
+	uint32_t		lunlength, tmp_lunlength;
+	uint64_t		sasLUN;
+	SMHBA_SCSILUN		smhbaLUN;
+
+	hbaPortWWN = port->PortSpecificAttribute.SASPort->
+	    LocalSASAddress;
+
+	status = get_domainPort(handle, portIndex, port, &domainPortWWN);
+	if (status == HBA_STATUS_OK) {
+		if ((map = calloc(1, sizeof (*map))) == NULL) {
+			(void *) fprintf(stderr, "%s\n",
+			gettext("No enough memory on heap."));
+			return (++ret);
+		}
+		map->NumberOfEntries = 1;
+
+		status = SMHBA_GetTargetMapping(handle, hbaPortWWN,
+		    domainPortWWN, map);
+
+		if (status == HBA_STATUS_ERROR_MORE_DATA) {
+			numentries = map->NumberOfEntries;
+			free(map);
+			map = calloc(1, sizeof (HBA_UINT32) +
+			    (numentries * sizeof (SMHBA_SCSIENTRY)));
+			if (map == NULL) {
+				(void *) fprintf(stderr, "%s\n",
+				    gettext("No enough memory on heap."));
+				return (++ret);
+			}
+			map->NumberOfEntries = numentries;
+			status = SMHBA_GetTargetMapping(handle,
+			    hbaPortWWN, domainPortWWN, map);
+		}
+
+		if (status != HBA_STATUS_OK) {
+			/* continue to build mapping data based SCSI info */
+			ret++;
+			free(map);
+			map = NULL;
+		}
+	}
+
+	/*
+	 * Get report lun data.
+	 */
+	responseSize = DEFAULT_LUN_LENGTH;
+	senseSize = sizeof (struct scsi_extended_sense);
+	(void) memset(&sense, 0, sizeof (sense));
+	status = SMHBA_ScsiReportLUNs(
+	    handle,
+	    hbaPortWWN,
+	    sasattr->LocalSASAddress,
+	    domainPortWWN,
+	    (void *)rawLUNs,
+	    &responseSize,
+	    &scsiStatus,
+	    (void *) &sense, &senseSize);
+
+	/*
+	 * if HBA_STATUS_ERROR_NOT_A_TARGET is return, we can assume this is
+	 * a remote HBA and move on
+	 */
+	if (status != HBA_STATUS_OK) {
+		configData->reportLUNsFailed = B_TRUE;
+		if (map != NULL) {
+			/*
+			 * Let's search mapping data and indicate that Report
+			 * LUNs failed.
+			 */
+			for (count = 0; count < map->NumberOfEntries; count++) {
+				if (memcmp(map->entry[count].PortLun.
+				    PortWWN.wwn, sasattr->LocalSASAddress.wwn,
+				    sizeof (HBA_WWN)) == 0) {
+					/* allocate mapping data for each LUN */
+					TPMapData = calloc(1,
+					    sizeof (targetPortMappingData_t));
+					if (TPMapData == NULL) {
+						(void *) fprintf(stderr, "%s\n",
+						    gettext("No enough "
+						    "memory."));
+						free(map);
+						return (++ret);
+					}
+					TPMapData->mappingExist = B_TRUE;
+					TPMapData->osLUN =
+					    map->entry[count].ScsiId.ScsiOSLun;
+					(void) strlcpy(TPMapData->osDeviceName,
+					    map->entry[count].ScsiId.
+					    OSDeviceName,
+					    sizeof (TPMapData->osDeviceName));
+					TPMapData->inq_vid[0] = '\0';
+					TPMapData->inq_pid[0] = '\0';
+					TPMapData->inq_dtype = DTYPE_UNKNOWN;
+					if (configData->map == NULL) {
+						configData->map = TPMapData;
+					} else {
+						TPMapData->next =
+						    configData->map->next;
+						configData->map = TPMapData;
+					}
+				}
+			}
+		}
+		(void) free(map);
+		return (++ret);
+	}
+	lun_resp = (rep_luns_rsp_t *)((void *)rawLUNs);
+	(void) memcpy(&tmp_lunlength, &(lun_resp->length),
+	    sizeof (tmp_lunlength));
+	lunlength = ntohl(tmp_lunlength);
+	(void) memcpy(&numberOfLun, &lunlength, sizeof (numberOfLun));
+	for (lunCount = 0; lunCount < (numberOfLun / 8); lunCount++) {
+		/* allocate mapping data for each LUN */
+		TPMapData = calloc(1,
+		    sizeof (targetPortMappingData_t));
+		if (TPMapData == NULL) {
+			(void *) fprintf(stderr, "%s\n",
+			    gettext("No enough memory."));
+			free(map);
+			return (++ret);
+		}
+
+		(void) memcpy(&TPMapData->reportLUN, lun_resp->
+		    lun[lunCount].val, sizeof (SMHBA_SCSILUN));
+
+		/*
+		 * now issue standard inquiry to get Vendor
+		 * and product information
+		 */
+		responseSize = sizeof (struct scsi_inquiry);
+		senseSize = sizeof (struct scsi_extended_sense);
+		(void) memset(&inq, 0, sizeof (struct scsi_inquiry));
+		(void) memset(&sense, 0, sizeof (sense));
+		sasLUN = ntohll(wwnConversion(lun_resp->lun[lunCount].val));
+		(void) memcpy(&smhbaLUN, &sasLUN, sizeof (SMHBA_SCSILUN));
+		status = SMHBA_ScsiInquiry(
+		    handle,
+		    hbaPortWWN,
+		    sasattr->LocalSASAddress,
+		    domainPortWWN,
+		    smhbaLUN,
+		    0,
+		    0,
+		    (void *) &inq, &responseSize,
+		    &scsiStatus,
+		    (void *) &sense, &senseSize);
+		if (status != HBA_STATUS_OK) {
+			TPMapData->inq_vid[0] = '\0';
+			TPMapData->inq_pid[0] = '\0';
+			TPMapData->inq_dtype = DTYPE_UNKNOWN;
+			/* indicate that inquiry for this lun is failed */
+			TPMapData->inquiryFailed = B_TRUE;
+		} else {
+			(void *) memcpy(TPMapData->inq_vid, inq.inq_vid,
+			    sizeof (TPMapData->inq_vid));
+			(void *) memcpy(TPMapData->inq_pid, inq.inq_pid,
+			    sizeof (TPMapData->inq_pid));
+			TPMapData->inq_dtype = inq.inq_dtype;
+		}
+
+		if (map != NULL) {
+			for (count = 0; count < map->NumberOfEntries; count++) {
+				if ((memcmp(map->entry[count].PortLun.
+				    PortWWN.wwn, sasattr->LocalSASAddress.wwn,
+				    sizeof (HBA_WWN)) == 0) &&
+				    (memcmp(&(map->entry[count].PortLun.
+				    TargetLun), &smhbaLUN,
+				    sizeof (SMHBA_SCSILUN))
+				    == 0)) {
+					TPMapData->mappingExist = B_TRUE;
+					TPMapData->osLUN =
+					    map->entry[count].ScsiId.ScsiOSLun;
+					(void) strlcpy(TPMapData->osDeviceName,
+					    map->entry[count].ScsiId.
+					    OSDeviceName,
+					    sizeof (TPMapData->osDeviceName));
+					break;
+				}
+			}
+			if (count == map->NumberOfEntries) {
+				TPMapData->osDeviceName[0] = '\0';
+				lun_string = lun_resp->lun[lunCount].val;
+				lunNum = ((lun_string[0] & 0x3F) << 8) |
+				    lun_string[1];
+				TPMapData->osLUN = lunNum;
+			}
+		} else {
+		/* Not able to get any target mapping information */
+			TPMapData->osDeviceName[0] = '\0';
+			lun_string = lun_resp->lun[lunCount].val;
+			lunNum = ((lun_string[0] & 0x3F) << 8) |
+			    lun_string[1];
+			TPMapData->osLUN = lunNum;
+		}
+
+		if (configData->map == NULL) {
+			configData->map = TPMapData;
+		} else {
+			TPMapData->next = configData->map->next;
+			configData->map = TPMapData;
+		}
+	}
+	free(map);
+	return (ret);
+}
+
+/*
+ * Search the discovered LUs and construct the global LU list.
+ *
+ * Arguments:
+ *      handle - handle to hba port.
+ *      portIndex - hba port index
+ *      port - hba port attributes.
+ *      targetattr - target port attributes.
+ *      sasattr - target port SAS attributes.
+ *      pflag - options the user specified.
+ *
+ *  Return Value:
+ *	    0		sucessfully processed handle
+ *	    >0		error has occured
+ */
+static int
+searchTargetPort(HBA_HANDLE handle, HBA_UINT32 portIndex,
+    SMHBA_PORTATTRIBUTES *port, SMHBA_PORTATTRIBUTES *targetattr,
+    SMHBA_SAS_PORT *sasattr, int pflag)
+{
+	int			ret = 0;
+	HBA_WWN			expander;
+	HBA_WWN			domainPortWWN;
+	targetPortList_t 	*discoveredTP, *newTP;
+	targetPortConfig_t	*TPConfig, *newConfig, *prevConfig;
+	boolean_t		foundTP = B_FALSE;
+	boolean_t		foundConfig = B_FALSE;
+	int			status;
+	SMHBA_PORTATTRIBUTES	tgtattr;
+	SMHBA_SAS_PORT		tgtsasport;
+	int			expanderValid = 0;
+
+	status = get_domainPort(handle, portIndex, port, &domainPortWWN);
+	switch (status) {
+		case HBA_STATUS_OK:
+			break;
+		case HBA_STATUS_ERROR_NOT_SUPPORTED:
+			/* don't increase error flag for no phy configuration */
+			return (ret);
+		case HBA_STATUS_ERROR:
+		default:
+			return (++ret);
+	}
+
+	/*
+	 * First, we will iterate the already constructed target port
+	 * list to see whether there is a target port already exist with
+	 * matching target port SAS address.
+	 */
+	for (discoveredTP = gTargetPortList; discoveredTP != NULL;
+	    discoveredTP = discoveredTP->next) {
+		if (memcmp((void *)sasattr->LocalSASAddress.wwn,
+		    (void *)discoveredTP->sasattr.LocalSASAddress.wwn,
+		    sizeof (HBA_WWN)) == 0) {
+			/*
+			 * if the target port exist and
+			 * verbose is not set, just return
+			 */
+			if (((pflag & PRINT_VERBOSE) == 0) &&
+			    ((pflag & PRINT_TARGET_SCSI) == 0)) {
+				return (ret);
+			}
+			foundTP = B_TRUE;
+			break;
+		}
+	}
+
+	if (foundTP == B_TRUE) {
+		/*
+		 * If there is a target port already exist, we should
+		 * add more information on the target port to construct the
+		 * whole topology.
+		 * Here we will check whether the current hba port name
+		 * has already been added.
+		 */
+		/* first get the expander SAS address compare */
+		if (memcmp((void *)port->PortSpecificAttribute.SASPort->
+		    LocalSASAddress.wwn, (void *)sasattr->
+		    AttachedSASAddress.wwn, sizeof (HBA_WWN)) == 0) {
+			/* NO expander */
+			(void) memset((void *)expander.wwn, 0,
+			    sizeof (HBA_WWN));
+			expanderValid = 1;
+		} else {
+			if (wwnConversion(sasattr->AttachedSASAddress.wwn)
+			    != 0) {
+				/* expander exist.  We should verify it.  */
+				(void) memcpy((void *)expander.wwn,
+				    (void *)sasattr->AttachedSASAddress.wwn,
+				    sizeof (HBA_WWN));
+
+				(void *) memset(&tgtattr, 0, sizeof (tgtattr));
+				(void *) memset(&tgtsasport, 0,
+				    sizeof (tgtsasport));
+				tgtattr.PortSpecificAttribute.SASPort
+				    = &tgtsasport;
+				status = SMHBA_GetPortAttributesByWWN(handle,
+				    sasattr->AttachedSASAddress, domainPortWWN,
+				    &tgtattr);
+				if (status == HBA_STATUS_OK && tgtattr.PortType
+				    == HBA_PORTTYPE_SASEXPANDER) {
+					expanderValid = 1;
+				}
+			}
+		}
+
+		for (TPConfig = discoveredTP->configEntry,
+		    foundConfig = B_FALSE; TPConfig != NULL;
+		    TPConfig = TPConfig->next) {
+			if ((strcmp(TPConfig->hbaPortName,
+			    port->OSDeviceName) == 0) &&
+			    (memcmp((void *)expander.wwn, (void *)TPConfig->
+			    expanderSASAddr.wwn,
+			    sizeof (HBA_WWN)) == 0)) {
+				foundConfig = B_TRUE;
+				break;
+			}
+		}
+
+		/*
+		 * If we get here, it means that it is a new hba port/exapnder
+		 * sas address for this discovered target port.
+		 */
+		if (foundConfig == B_FALSE) {
+			newConfig = (targetPortConfig_t *)calloc(1,
+			    sizeof (targetPortConfig_t));
+			if (newConfig == NULL) {
+				(void *) fprintf(stderr,
+				    "%s\n", strerror(errno));
+				return (++ret);
+			}
+
+			(void) strlcpy(newConfig->hbaPortName, port->
+			    OSDeviceName, sizeof (newConfig->hbaPortName));
+			(void) memcpy((void *)newConfig->expanderSASAddr.wwn,
+			    (void *)expander.wwn, sizeof (HBA_WWN));
+			newConfig->expanderValid = expanderValid;
+			if (discoveredTP->configEntry == NULL) {
+				discoveredTP->configEntry = newConfig;
+			} else {
+				TPConfig = discoveredTP->configEntry;
+				prevConfig = TPConfig;
+				while (TPConfig != NULL &&
+				    sas_name_comp(newConfig->hbaPortName,
+				    TPConfig->hbaPortName) > 0) {
+					prevConfig = TPConfig;
+					TPConfig = TPConfig->next;
+				}
+				if (TPConfig == prevConfig) {
+					/* Should be inserted in the head. */
+					newConfig->next = TPConfig;
+					discoveredTP->configEntry = newConfig;
+				} else {
+					newConfig->next = TPConfig;
+					prevConfig->next = newConfig;
+				}
+			}
+			/* if scsi option is not set return */
+			if ((pflag & PRINT_TARGET_SCSI) == 0) {
+				return (0);
+			} else {
+				return (searchTargetPortMappingData(
+				    handle, portIndex, port,
+				    sasattr, newConfig));
+			}
+		}
+	} else {
+		/*
+		 * Here we got a new target port which has not ever exist
+		 * in our global target port list. So add it to the list.
+		 * list.
+		 */
+		newTP = (targetPortList_t *)calloc(1,
+		    sizeof (targetPortList_t));
+
+		if (newTP == NULL) {
+			(void *) fprintf(stderr, "%s\n", strerror(errno));
+			return (++ret);
+		}
+
+		(void) memcpy((void *)&newTP->targetattr, (void *)targetattr,
+		    sizeof (SMHBA_PORTATTRIBUTES));
+		(void) memcpy((void *)&newTP->sasattr, (void *)sasattr,
+		    sizeof (SMHBA_SAS_PORT));
+
+		newConfig = (targetPortConfig_t *)calloc(1,
+		    sizeof (targetPortConfig_t));
+
+		if (newConfig == NULL) {
+			(void *) fprintf(stderr, "%s\n", strerror(errno));
+			free(newTP);
+			return (++ret);
+		}
+
+		(void) strlcpy(newConfig->hbaPortName, port->OSDeviceName,
+		    sizeof (newConfig->hbaPortName));
+		if (memcmp((void *)port->PortSpecificAttribute.SASPort->
+		    LocalSASAddress.wwn, (void *)sasattr->
+		    AttachedSASAddress.wwn, sizeof (HBA_WWN)) == 0) {
+			/* NO expander */
+			(void) memset((void *)newConfig->expanderSASAddr.wwn,
+			    0, sizeof (HBA_WWN));
+		} else {
+			/* expander exist.  We should verify it. */
+			(void) memcpy((void *)newConfig->expanderSASAddr.wwn,
+			    (void *)sasattr->AttachedSASAddress.wwn,
+			    sizeof (HBA_WWN));
+
+			(void *) memset(&tgtattr, 0, sizeof (tgtattr));
+			(void *) memset(&tgtsasport, 0, sizeof (tgtsasport));
+			tgtattr.PortSpecificAttribute.SASPort = &tgtsasport;
+			status = SMHBA_GetPortAttributesByWWN(handle,
+			    sasattr->AttachedSASAddress, domainPortWWN,
+			    &tgtattr);
+			if (status == HBA_STATUS_OK && tgtattr.PortType ==
+			    HBA_PORTTYPE_SASEXPANDER) {
+				expanderValid = 1;
+			}
+			newConfig->expanderValid = expanderValid;
+		}
+
+		newTP->configEntry = newConfig;
+
+		newTP->next = gTargetPortList; /* insert at head */
+		gTargetPortList = newTP; /* set new head */
+
+		/* if scsi option is not set return */
+		if ((pflag & PRINT_TARGET_SCSI) == 0) {
+			return (0);
+		} else {
+			return (searchTargetPortMappingData(
+			    handle, portIndex, port, sasattr, newConfig));
+		}
+	}
+	return (ret);
+}
+
+/*
+ * Search the discovered LUs and construct the global LU list.
+ *
+ * Arguments:
+ *      entryP - one of the target mapping data.
+ *      handle - handle to hba port.
+ *      hbaPortWWN - hba port sas address.
+ *      domainPortWWN - domain port WWN for this sas domain.
+ *      portName - HBA port OS Device Name.
+ *      pflag - options the user specified.
+ *
+ *  Return Value:
+ *	    0		sucessfully processed handle
+ *	    >0		error has occured
+ */
+static int
+searchDevice(PSMHBA_SCSIENTRY entryP,
+    HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN domainPortWWN,
+    char *portName, int pflag)
+{
+	HBA_STATUS		status;
+	int			ret = 0;
+	discoveredDevice 	*discoveredLU, *newDevice;
+	portList		*portElem, *newPort, *prevElem;
+	tgtPortWWNList 		*newTgtWWN, *TgtWWNList;
+	boolean_t		foundDevice = B_FALSE;
+	boolean_t		foundPort = B_FALSE;
+	struct scsi_inquiry	inq;
+	HBA_UINT32		responseSize, senseSize = 0;
+	HBA_UINT8		inq_status;
+	SMHBA_SCSILUN		smhbaLUN;
+	struct scsi_extended_sense sense;
+
+	/* if OSDeviceName is not set, we don't need to search */
+	if (entryP->ScsiId.OSDeviceName[0] == '\0') {
+		return (ret);
+	}
+
+	/*
+	 * First, we will iterate the already constructed discovered LU
+	 * list to see whether there is a LU already exist with the same OS
+	 * device name as current target mapping data entry.
+	 */
+	for (discoveredLU = LUList; discoveredLU != NULL;
+	    discoveredLU = discoveredLU->next) {
+		if (strcmp(entryP->ScsiId.OSDeviceName,
+		    discoveredLU->OSDeviceName) == 0) {
+			/*
+			 * if there is existing OS Device Name and
+			 * verbose is not set, just return
+			 */
+			if ((pflag & PRINT_VERBOSE) == 0) {
+				return (ret);
+			}
+			foundDevice = B_TRUE;
+			break;
+		}
+	}
+
+	if (foundDevice == B_TRUE) {
+		/*
+		 * If there is a discovered LU already exist, we should
+		 * add more information on this LU to construct the whole
+		 * topology.
+		 * Here we will check whether the current hba port has
+		 * already been added.
+		 */
+		for (portElem = discoveredLU->HBAPortList,
+		    foundPort = B_FALSE;  portElem != NULL;
+		    portElem = portElem->next) {
+			if (strcmp(portElem->portName,
+			    portName) == 0) {
+				foundPort = B_TRUE;
+				break;
+			}
+		}
+
+		/*
+		 * If we get here, it means that it is a new hba port name
+		 * for this discovered LU.
+		 */
+		if (foundPort == B_FALSE) {
+			newPort = (portList *)calloc(1, sizeof (portList));
+			if (newPort == NULL) {
+				(void *) fprintf(stderr,
+				    "%s\n", strerror(errno));
+				return (++ret);
+			}
+			(void) strlcpy(newPort->portName, portName,
+			    sizeof (newPort->portName));
+
+			portElem = discoveredLU->HBAPortList;
+			prevElem = portElem;
+			while (portElem != NULL &&
+			    sas_name_comp(newPort->portName, portElem->portName)
+			    > 0) {
+				prevElem = portElem;
+				portElem = portElem->next;
+			}
+			if (portElem == prevElem) {
+				/* Insert in the head of list. */
+				newPort->next = portElem;
+				discoveredLU->HBAPortList = newPort;
+			} else {
+				newPort->next = portElem;
+				prevElem->next = newPort;
+			}
+			/* add Target Port */
+			newPort->tgtPortWWN = (tgtPortWWNList *)calloc(1,
+			    sizeof (tgtPortWWNList));
+			if (newPort->tgtPortWWN == NULL) {
+				(void *) fprintf(stderr,
+				    "%s\n", strerror(errno));
+				return (++ret);
+			}
+			(void *) memcpy((void *)&(newPort->tgtPortWWN->portWWN),
+			    (void *)&(entryP->PortLun.PortWWN),
+			    sizeof (HBA_WWN));
+			/* Set LUN data */
+			newPort->tgtPortWWN->scsiOSLun =
+			    entryP->ScsiId.ScsiOSLun;
+		} else {
+			/*
+			 * Otherwise, we just need to add the target port
+			 * sas address information.
+			 */
+			for (TgtWWNList = portElem->tgtPortWWN;
+			    TgtWWNList != NULL;
+			    TgtWWNList = TgtWWNList->next) {
+				if (memcmp(&TgtWWNList->portWWN,
+				    &entryP->PortLun.PortWWN,
+				    sizeof (HBA_WWN)) == 0)
+					return (0);
+			}
+			/* add it to existing */
+			newTgtWWN = (tgtPortWWNList *)calloc(1,
+			    sizeof (tgtPortWWNList));
+			if (newTgtWWN == NULL) {
+				(void *) fprintf(stderr,
+				    "%s\n", strerror(errno));
+				return (++ret);
+			}
+			/* insert at head */
+			newTgtWWN->next = portElem->tgtPortWWN;
+			portElem->tgtPortWWN = newTgtWWN;
+			(void *) memcpy((void *)&(newTgtWWN->portWWN),
+			    (void *)&(entryP->PortLun.PortWWN),
+			    sizeof (HBA_WWN));
+			/* Set LUN data */
+			newTgtWWN->scsiOSLun =
+			    entryP->ScsiId.ScsiOSLun;
+		}
+	} else {
+		/*
+		 * Here we got a new discovered LU which has not ever exist
+		 * in our global LU list. So add it into our global LU
+		 * list.
+		 */
+		newDevice = (discoveredDevice *)calloc(1,
+		    sizeof (discoveredDevice));
+
+		if (newDevice == NULL) {
+			(void *) fprintf(stderr, "%s\n", strerror(errno));
+			return (++ret);
+		}
+		newDevice->next = LUList; /* insert at head */
+		LUList = newDevice; /* set new head */
+
+		/* copy device name */
+		(void *) strlcpy(newDevice->OSDeviceName,
+		    entryP->ScsiId.OSDeviceName,
+		    sizeof (newDevice->OSDeviceName));
+
+		/* if verbose is not set return */
+		if ((pflag & PRINT_VERBOSE) == 0) {
+			return (0);
+		}
+
+		/* copy WWN data */
+		newDevice->HBAPortList = (portList *)calloc(1,
+		    sizeof (portList));
+		if (newDevice->HBAPortList == NULL) {
+			(void *) fprintf(stderr, "%s\n", strerror(errno));
+			return (++ret);
+		}
+		(void) strlcpy(newDevice->HBAPortList->portName,
+		    portName, sizeof (newDevice->HBAPortList->portName));
+
+		newDevice->HBAPortList->tgtPortWWN =
+		    (tgtPortWWNList *)calloc(1, sizeof (tgtPortWWNList));
+		if (newDevice->HBAPortList->tgtPortWWN == NULL) {
+			(void *) fprintf(stderr, "%s\n", strerror(errno));
+			return (++ret);
+		}
+
+		(void *) memcpy((void *)&(newDevice->HBAPortList->\
+		    tgtPortWWN->portWWN),
+		    (void *)&(entryP->PortLun.PortWWN),
+		    sizeof (HBA_WWN));
+		newDevice->HBAPortList->tgtPortWWN->scsiOSLun =
+		    entryP->ScsiId.ScsiOSLun;
+
+		responseSize = sizeof (struct scsi_inquiry);
+		senseSize = sizeof (struct scsi_extended_sense);
+		(void *) memset(&inq, 0, sizeof (struct scsi_inquiry));
+		(void *) memset(&sense, 0, sizeof (sense));
+		(void *) memcpy(&smhbaLUN, &entryP->PortLun.TargetLun,
+		    sizeof (smhbaLUN));
+
+		/*
+		 * Retrieve the VPD data for the newly found discovered LU.
+		 */
+		status = SMHBA_ScsiInquiry(
+		    handle,
+		    hbaPortWWN,
+		    entryP->PortLun.PortWWN,
+		    domainPortWWN,
+		    smhbaLUN,
+		    0,
+		    0,
+		    (void *) &inq, &responseSize,
+		    &inq_status,
+		    (void *) &sense, &senseSize);
+
+		if (status != HBA_STATUS_OK) {
+			/* init VID/PID/dType as '\0' */
+			newDevice->VID[0] = '\0';
+			newDevice->PID[0] = '\0';
+			newDevice->dType = DTYPE_UNKNOWN;
+			/* initialize inq status */
+			newDevice->inquiryFailed = B_TRUE;
+			ret++;
+		} else {
+			(void *) memcpy(newDevice->VID, inq.inq_vid,
+			    sizeof (newDevice->VID));
+			(void *) memcpy(newDevice->PID, inq.inq_pid,
+			    sizeof (newDevice->PID));
+			newDevice->dType = inq.inq_dtype;
+			/* initialize inq status */
+			newDevice->inquiryFailed = B_FALSE;
+		}
+	}
+	return (ret);
+}
+
+/*
+ * Function we use to insert a newly discovered port.
+ * Return:
+ * 	0 - success
+ * 	>0 - failed
+ */
+static int
+sas_rp_tree_insert(rp_tree_t **rproot,
+    rp_tree_t *rpnode)
+{
+	HBA_UINT8 *wwn1, *wwn2, *wwn3;
+	rp_tree_t *node_ptr;
+	int ret = 0;
+
+	if (rproot == NULL) {
+		(void *) fprintf(stderr, "%s\n",
+		    gettext("Error: NULL rproot"));
+		return (1);
+	}
+
+	if (rpnode == NULL) {
+		(void *) fprintf(stderr, "%s\n",
+		    gettext("Error: NULL rpnode"));
+		return (1);
+	}
+
+	if (*rproot == NULL) {
+		*rproot = rpnode;
+		return (0);
+	}
+
+	wwn1 = (*rproot)->sasattr.LocalSASAddress.wwn;
+	wwn2 = (*rproot)->sasattr.AttachedSASAddress.wwn;
+	wwn3 = rpnode->sasattr.AttachedSASAddress.wwn;
+
+	/*
+	 * If the attched sas address is equal to the local sas address,
+	 * then this should be a child node of current root node.
+	 */
+	if (memcmp(wwn1, wwn3, sizeof (HBA_WWN)) == 0) {
+		(void) sas_rp_tree_insert(&(*rproot)->child, rpnode);
+		rpnode->parent = *rproot;
+	} else if (memcmp(wwn2, wwn3, sizeof (HBA_WWN)) == 0) {
+		/*
+		 * If the attached sas address is equal to the attached sas
+		 * address of current root node, then this should be a
+		 * sibling node.
+		 * Insert the SAS/SATA Device at the head of sibling list.
+		 */
+		if (rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
+			rpnode->sibling = *rproot;
+			*rproot = rpnode;
+		} else {
+			/*
+			 * Insert the SAS Expander at the tail of sibling
+			 * list.
+			 */
+			node_ptr = *rproot;
+			while (node_ptr->sibling != NULL)
+				node_ptr = node_ptr->sibling;
+			node_ptr->sibling = rpnode;
+		}
+		rpnode->parent = (*rproot)->parent;
+	} else {
+		/*
+		 * If enter here, we should first try to insert the discovered
+		 * port node into the child sub-tree, then try to insert to the
+		 * sibling sub-trees. If we failed to insert the discovered
+		 * port node, return 1. The caller will queue this node
+		 * up and retry insertion later.
+		 */
+		if ((*rproot)->child) {
+			ret = sas_rp_tree_insert(&(*rproot)->child, rpnode);
+		}
+		if ((*rproot)->child == NULL || ret != 0) {
+			if ((*rproot)->sibling) {
+				ret = sas_rp_tree_insert(&(*rproot)->sibling,
+				    rpnode);
+			} else
+				ret = 1;
+		}
+		return (ret);
+	}
+	return (0);
+}
+
+/*
+ * Function which will print out the whole disocvered port topology.
+ * Here we use the Preorder Traversal algorithm.
+ * The indentation rules are:
+ * 	1 * TABLEN - for attributes
+ * 	2 * TABLEN - for next tier target port/expander
+ */
+static int
+sas_rp_tree_print(HBA_HANDLE handle, char *adapterName,
+    HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
+    rp_tree_t *rpnode, inputArg_t *input,
+    int gident, int *printPort)
+{
+	int ret = 0, lident;
+
+	if (rpnode == NULL)
+		return (ret);
+	lident = gident;
+
+	/*
+	 * We assume that all the nodes are disocvered ports(sas device or
+	 * expander).
+	 */
+	if (input->wwnCount > 0) {
+		/* Adjust local indentation if a discovered port specified. */
+		lident = 2 * TABLEN;
+		/*
+		 * Check whether current node match one of the specified
+		 * SAS addresses.
+		 */
+		if ((rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) ||
+		    !isPortWWNInArgv(input,
+		    &rpnode->sasattr.LocalSASAddress)) {
+			/*
+			 * Step down to child tree first.
+			 */
+			ret += sas_rp_tree_print(handle, adapterName,
+			    portIndex, port, rpnode->child, input,
+			    gident + 2 * TABLEN, printPort);
+			/*
+			 * Then check the sibling tree.
+			 */
+			ret += sas_rp_tree_print(handle, adapterName,
+			    portIndex, port, rpnode->sibling, input,
+			    gident, printPort);
+			return (ret);
+		}
+	}
+
+	if ((rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) ||
+	    (input->pflag & PRINT_TARGET_PORT)) {
+		/*
+		 * We should print the header(HBA Name + HBA Port Name)
+		 * on-demand. It means that, if we have expander device
+		 * address specified on the command line, we should print
+		 * the header once we find a matching one. Or we will
+		 * print the header from the beginning of the output.
+		 */
+		if (g_printHBA == 0) {
+			(void *) fprintf(stdout, "%s %s\n",
+			    "HBA Name:", adapterName);
+			g_printHBA = 1;
+		}
+
+		if (*printPort == 0) {
+			(void *) fprintf(stdout, "%s%s %s\n",
+			    getIndentSpaces(TABLEN),
+			    "HBA Port Name:", port->OSDeviceName);
+			*printPort = 1;
+		}
+		ret += sas_print_rpnode(input, rpnode, lident, gident);
+	}
+
+	/*
+	 * If operands provided with "-t" option specified, we will print
+	 * the immediate child nodes information under the expander.
+	 */
+	if (input->pflag & PRINT_TARGET_PORT) {
+		/* no operand. ignore the option. */
+		if (input->wwnCount > 0) {
+			if (rpnode->portattr.PortType ==
+			    HBA_PORTTYPE_SASEXPANDER) {
+				ret += sas_rp_tree_print_desc(handle,
+				    portIndex, port, rpnode->child,
+				    input,
+				    lident + 2 * TABLEN,
+				    gident + 2 * TABLEN);
+			}
+		}
+	}
+
+	/*
+	 * Here we use DFS(Depth First Search) algorithm to traverse the
+	 * whole tree.
+	 */
+	ret += sas_rp_tree_print(handle, adapterName,
+	    portIndex, port, rpnode->child, input,
+	    gident + 2 * TABLEN, printPort);
+	ret += sas_rp_tree_print(handle, adapterName,
+	    portIndex, port, rpnode->sibling, input,
+	    gident, printPort);
+	return (ret);
+}
+
+/*
+ * Function which will destroy the whole discovered port tree.
+ * Here we use the Postorder Traversal algorithm.
+ */
+static void sas_rp_tree_free(rp_tree_t *rproot)
+{
+	tgt_mapping *cur, *next;
+
+	if (rproot == NULL)
+		return;
+
+	/*
+	 * Free child tree first.
+	 */
+	if (rproot->child) {
+		sas_rp_tree_free(rproot->child);
+	}
+
+	/*
+	 * Free sibling trees then.
+	 */
+	if (rproot->sibling) {
+		sas_rp_tree_free(rproot->sibling);
+	}
+
+	/*
+	 * Free root node at last.
+	 */
+	cur = rproot->first_entry;
+	while (cur != NULL) {
+		next = cur->next;
+		free(cur);
+		cur = next;
+	}
+	free(rproot);
+}
+
+/*
+ * Function used to print out all the descendant nodes.
+ * handle - handle to HBA.
+ * port - port attributes of current HBA port.
+ * desc - the root node of a subtree which will be processed.
+ * input - input argument.
+ * lident - local indentation for shifting indentation.
+ * gident - global indentation, can also be used to obtain Tier number.
+ */
+/*ARGSUSED*/
+static int
+sas_rp_tree_print_desc(HBA_HANDLE handle, HBA_UINT32 portIndex,
+    SMHBA_PORTATTRIBUTES *port, rp_tree_t *desc,
+    inputArg_t *input, int lident, int gident)
+{
+	int ret = 0;
+	rp_tree_t   *rp_node;
+
+	if (desc == NULL)
+		return (ret);
+	/*
+	 * Walk through the subtree of desc by Pre-Order Traversal Algo.
+	 */
+	for (rp_node = desc; rp_node !=	NULL; rp_node = rp_node->sibling) {
+		ret += sas_print_rpnode(input, rp_node, lident, gident);
+	}
+
+	return (ret);
+}
+
+/*
+ * Function used to print the information of specified SAS address.
+ * handle - handle to a HBA.
+ * port - port attributes of a HBA port.
+ * rpnode - discovered port which will be processed.
+ * lident - local indentation used for shifting indentation.
+ * gident - global indentation used for calculating "Tier" number.
+ */
+static int
+sas_print_rpnode(inputArg_t *input,
+    rp_tree_t *rpnode, int lident, int gident)
+{
+	int ret = 0;
+
+	if (rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) {
+		(void *) fprintf(stdout, "%s%s(Tier %d): %016llx\n",
+		    getIndentSpaces(lident),
+		    "Expander SAS Address",
+		    gident / (2 * TABLEN),
+		    wwnConversion(rpnode->sasattr.LocalSASAddress.wwn));
+	} else {
+		(void *) fprintf(stdout, "%s%s %016llx\n",
+		    getIndentSpaces(lident),
+		    "Target Port SAS Address:",
+		    wwnConversion(rpnode->sasattr.LocalSASAddress.wwn));
+	}
+	if (input->pflag & PRINT_VERBOSE) {
+		if (rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
+			(void *) fprintf(stdout, "%s%s %s\n",
+			    getIndentSpaces(TABLEN + lident),
+			    "Type:",
+			    getStateString(rpnode->portattr.PortType,
+			    porttype_string));
+		} else {
+			(void *) fprintf(stdout, "%s%s %s\n",
+			    getIndentSpaces(TABLEN + lident),
+			    "OS Device Name:",
+			    rpnode->portattr.OSDeviceName);
+			(void *) fprintf(stdout, "%s%s %s\n",
+			    getIndentSpaces(TABLEN + lident),
+			    "State: ",
+			    getStateString(rpnode->portattr.PortState,
+			    portstate_string));
+		}
+	}
+	rpnode->printed = 1;
+	return (ret);
+}
+
+/*
+ * Function used to get the correct domainPortWWN as needed by some of the
+ * SMHBA APIs.
+ * handle - handle to a HBA.
+ * portIndex - index to locate the port.
+ * port - pointer to the structure holding port attributes.
+ * pdomainPort - pointer to the buffer holding domainPortWWN.
+ */
+HBA_STATUS
+get_domainPort(HBA_HANDLE handle,
+    int portIndex, PSMHBA_PORTATTRIBUTES port,
+    HBA_WWN *pdomainPort)
+{
+	HBA_STATUS status;
+	PSMHBA_SAS_PORT sasport;
+	SMHBA_SAS_PHY phyattr;
+
+	sasport = port->PortSpecificAttribute.SASPort;
+	(void *) memset(pdomainPort, 0, sizeof (HBA_WWN));
+	/*
+	 * Since iport can exist without any phys,
+	 * sasinfo hba-port -v has indicated numberOfPhys;
+	 * if there is no phys within the hba, just return OK.
+	 */
+	if (sasport->NumberofPhys > 0) {
+		status = SMHBA_GetSASPhyAttributes(handle, portIndex,
+		    0, &phyattr);
+		if (status != HBA_STATUS_OK)
+			return (status);
+		(void *) memcpy(pdomainPort, &phyattr.domainPortWWN,
+		    sizeof (HBA_WWN));
+	} else {
+		/* return not supported for no phy configured */
+		return (HBA_STATUS_ERROR_NOT_SUPPORTED);
+	}
+	return (HBA_STATUS_OK);
+}
+
+/*
+ * Comparison function for comparing names possibly ending with digits.
+ * Return:
+ * 	<0 - name1 is less than name2.
+ * 	0 - name1 is equal with name2.
+ * 	>0 - name1 is more than name2.
+ */
+static int
+sas_name_comp(const char *name1, const char *name2)
+{
+	int i = 0;
+
+	if (name1 == name2)
+		return (0);
+
+	while ((name1[i] == name2[i]) && (name1[i] != '\0'))
+		i++;
+
+	/* If neither of name1[i] and name2[i] is '\0'. */
+	if (isdigit(name1[i]) && isdigit(name2[i]))
+		return (atoi(&name1[i]) - atoi(&name2[i]));
+
+	/* One of name1[i] and name2[i] is not digit. */
+	return (name1[i] - name2[i]);
+}
+/*
+ * Comparison function for sorting HBA/HBA Port.
+ * arg1 - first argument of type sas_elem_t.
+ * arg2 - second argument of type sas_elem_t.
+ * Return:
+ * 	<0 - arg1 is less than arg2.
+ * 	0 - arg1 is equal with arg2.
+ * 	>0 - arg1 is more than arg2.
+ */
+static int
+sas_elem_compare(const void *arg1, const void *arg2)
+{
+	sas_elem_t *p1, *p2;
+	p1 = (sas_elem_t *)arg1;
+	p2 = (sas_elem_t *)arg2;
+	return (sas_name_comp(p1->name, p2->name));
+}
+
+/*
+ * Sorting function for HBA/HBA Port output.
+ * array - elements array of type sas_elem_t.
+ * nelem - number of elements in array of type sas_elem_t.
+ */
+static void
+sas_elem_sort(sas_elem_t *array, int nelem)
+{
+	qsort((void *)array, nelem, sizeof (sas_elem_t), sas_elem_compare);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sasinfo/sasinfo.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,220 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <errno.h>
+#include <zone.h>
+#include <sasinfo.h>
+
+#define	VERSION_STRING_MAX_LEN	10
+/*
+ * Version number:
+ *  MAJOR - This should only change when there is an incompatible change made
+ *  to the interfaces or the output.
+ *
+ *  MINOR - This should change whenever there is a new command or new feature
+ *  with no incompatible change.
+ */
+#define	VERSION_STRING_MAJOR	    "1"
+#define	VERSION_STRING_MINOR	    "0"
+
+/* globals */
+static char *cmdName;
+
+/* forward declarations */
+static int listHbaFunc(int, char **, cmdOptions_t *, void *);
+static int listHbaPortFunc(int, char **, cmdOptions_t *, void *);
+static int listExpanderFunc(int, char **, cmdOptions_t *, void *);
+static int listTargetPortFunc(int, char **, cmdOptions_t *, void *);
+static int listLogicalUnitFunc(int, char **, cmdOptions_t *, void *);
+static char *getExecBasename(char *);
+
+/*
+ * Add new options here
+ *
+ * Optional option-arguments are not allowed by CLIP
+ */
+optionTbl_t sasinfolongOptions[] = {
+	{"hba", required_argument,	'a', "HBA Name"},
+	{"hba-port", required_argument,	'p', "HBA Port Name"},
+	{"phy", no_argument,		'y', NULL},
+	{"phy-linkstat", no_argument,	'l', NULL},
+	{"scsi-target", no_argument,	's', NULL},
+	{"verbose", no_argument,	'v', NULL},
+	{"target", no_argument,	't', NULL},
+	{NULL, 0, 0}
+};
+
+/*
+ * Add new subcommands here
+ */
+subCommandProps_t sasinfosubcommands[] = {
+	{"hba", listHbaFunc, "v", NULL, NULL,
+		OPERAND_OPTIONAL_MULTIPLE, "HBA Name"},
+	{"hba-port", listHbaPortFunc, "ylva", NULL, NULL,
+		OPERAND_OPTIONAL_MULTIPLE, "HBA Port Name"},
+	{"expander", listExpanderFunc, "ptv", NULL, NULL,
+		OPERAND_OPTIONAL_MULTIPLE, "Expander Device SAS Address"},
+	{"target-port", listTargetPortFunc, "sv", NULL, "sv",
+		OPERAND_OPTIONAL_MULTIPLE, "Target Port SAS Address"},
+	{"logical-unit", listLogicalUnitFunc, "v", NULL, NULL,
+		OPERAND_OPTIONAL_MULTIPLE, "OS Device Name"},
+	{"lu", listLogicalUnitFunc, "v", NULL, NULL,
+		OPERAND_OPTIONAL_MULTIPLE, "OS Device Name"},
+	{NULL, 0, NULL, NULL, NULL, 0, NULL, NULL}
+};
+
+/*
+ * Pass in options/arguments, rest of arguments
+ */
+/*ARGSUSED*/
+static int
+listHbaFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs)
+{
+	return (sas_util_list_hba(objects, argv, options));
+}
+
+/*ARGSUSED*/
+static int
+listHbaPortFunc(int objects, char *argv[], cmdOptions_t *options, void *addArgs)
+{
+	return (sas_util_list_hbaport(objects, argv, options));
+}
+
+/*
+ * Pass in options/arguments, rest of arguments
+ */
+/*ARGSUSED*/
+static int
+listExpanderFunc(int objects, char *argv[], cmdOptions_t *options,
+    void *addArgs)
+{
+	return (sas_util_list_expander(objects, argv, options));
+}
+
+/*ARGSUSED*/
+static int
+listTargetPortFunc(int objects, char *argv[], cmdOptions_t *options,
+    void *addArgs)
+{
+	return (sas_util_list_targetport(objects, argv, options));
+}
+
+/*
+ * Pass in options/arguments, rest of arguments
+ */
+/*ARGSUSED*/
+static int
+listLogicalUnitFunc(int objects, char *argv[], cmdOptions_t *options,
+    void *addArgs)
+{
+	return (sas_util_list_logicalunit(objects, argv, options));
+}
+
+/*
+ * input:
+ *  execFullName - exec name of program (argv[0])
+ *
+ * Returns:
+ *  command name portion of execFullName
+ */
+static char *
+getExecBasename(char *execFullname)
+{
+	char *lastSlash, *execBasename;
+
+	/* guard against '/' at end of command invocation */
+	for (;;) {
+		lastSlash = strrchr(execFullname, '/');
+		if (lastSlash == NULL) {
+			execBasename = execFullname;
+			break;
+		} else {
+			execBasename = lastSlash + 1;
+			if (*execBasename == '\0') {
+				*lastSlash = '\0';
+				continue;
+			}
+			break;
+		}
+	}
+	return (execBasename);
+}
+
+/*
+ * main calls a parser that checks syntax of the input command against
+ * various rules tables.
+ *
+ * The return value from the function is placed in funcRet
+ */
+int
+main(int argc, char *argv[])
+{
+	synTables_t synTables;
+	char versionString[VERSION_STRING_MAX_LEN];
+	int ret;
+	int funcRet;
+	void *subcommandArgs = NULL;
+
+	/* to support locale */
+	(void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
+#define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
+#endif
+	(void) textdomain(TEXT_DOMAIN);
+
+	/* set global command name */
+	cmdName = getExecBasename(argv[0]);
+
+	/* check if is global zone */
+	if (getzoneid() != GLOBAL_ZONEID) {
+		(void *) fprintf(stdout, "%s %s\n",
+		    cmdName, gettext("does not support non-global zone."));
+		return (1);
+	}
+
+	(void *) snprintf(versionString, sizeof (versionString), "%s.%s",
+	    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
+	synTables.versionString = versionString;
+
+	synTables.longOptionTbl = &sasinfolongOptions[0];
+	synTables.subCommandPropsTbl = &sasinfosubcommands[0];
+
+	/* call the CLI parser */
+	ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
+	if (ret == 1) {
+		(void *) fprintf(stdout, "%s %s(1M)\n",
+		    gettext("For more information, please see"), cmdName);
+		return (1);
+	} else if (ret == -1) {
+		(void *) fprintf(stderr, "%s %s\n",
+		    cmdName, strerror(errno));
+		return (1);
+	}
+
+	if (funcRet != 0) {
+		return (1);
+	}
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sasinfo/sasinfo.h	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,138 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SASINFO_H
+#define	_SASINFO_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libintl.h>
+#include <smhbaapi.h>
+#include <sys/types.h>
+#include <sys/scsi/scsi.h>
+#include <inttypes.h>
+#include <cmdparse.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+#include <locale.h>
+
+#ifdef _BIG_ENDIAN
+#define	htonll(x)   (x)
+#define	ntohll(x)   (x)
+#else
+#define	htonll(x)   ((((unsigned long long)htonl(x)) << 32) + htonl(x >> 32))
+#define	ntohll(x)   ((((unsigned long long)ntohl(x)) << 32) + ntohl(x >> 32))
+#endif
+
+/* DEFINES */
+#define	DEFAULT_LUN_COUNT	1024
+#define	LUN_SIZE		8
+#define	LUN_HEADER_SIZE		8
+#define	LUN_LENGTH		LUN_SIZE + LUN_HEADER_SIZE
+#define	DEFAULT_LUN_LENGTH	DEFAULT_LUN_COUNT  * \
+				LUN_SIZE	   + \
+				LUN_HEADER_SIZE
+
+/* flags that are needed to be passed into porcessHBA */
+#define	PRINT_VERBOSE		0x00000001
+#define	PRINT_PHY		0x00000002 /* print phy addresses */
+#define	PRINT_PHY_LINKSTAT	0x00000004 /* print phy link statistics */
+#define	PRINT_TARGET_PORT	0x00000008 /* print target os deivce info */
+#define	PRINT_CHILD		0x00000010 /* print descendant nodes */
+#define	PRINT_TARGET_SCSI	0x00000020 /* print descendant nodes */
+
+#define	HBA_MAX_RETRIES		20
+
+typedef struct _tgtPortWWNList {
+	HBA_WWN portWWN;
+	HBA_UINT32	scsiOSLun;
+	struct _tgtPortWWNList *next;
+} tgtPortWWNList;
+
+typedef struct _portList {
+	char		portName[MAXPATHLEN];
+	tgtPortWWNList	*tgtPortWWN;
+	struct _portList	*next;
+} portList;
+
+/* Discovered LU structure */
+typedef struct _discoveredDevice {
+	boolean_t	inquiryFailed;
+	char 		OSDeviceName[MAXPATHLEN];
+	portList	*HBAPortList;
+	char		VID[8];
+	char		PID[16];
+	uchar_t		dType;
+	struct _discoveredDevice *next;
+} discoveredDevice;
+
+typedef struct targetPortMappingData {
+	boolean_t	mappingExist;
+	boolean_t	inquiryFailed;
+	HBA_UINT32	osLUN;
+	SMHBA_SCSILUN	reportLUN;
+	char		osDeviceName[256];
+	uchar_t		inq_vid[8];
+	uchar_t		inq_pid[16];
+	uchar_t		inq_dtype;
+	struct targetPortMappingData   *next;
+} targetPortMappingData_t;
+
+typedef struct targetPortConfig {
+	char 		hbaPortName[256];
+	HBA_WWN		expanderSASAddr;
+	int 		expanderValid;
+	boolean_t   	reportLUNsFailed;
+	struct 		targetPortMappingData    *map;
+	struct 		targetPortConfig    *next;
+} targetPortConfig_t;
+
+typedef struct targetPortList {
+	SMHBA_PORTATTRIBUTES	targetattr;
+	SMHBA_SAS_PORT		sasattr;
+	struct targetPortConfig *configEntry;
+	struct targetPortList	*next;
+} targetPortList_t;
+
+int sas_util_list_hba(int hbaCount, char **hba_argv, cmdOptions_t *options);
+int sas_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options);
+int sas_util_list_expander(int wwnCount, char **wwn_argv,
+    cmdOptions_t *options);
+int sas_util_list_targetport(int tpCount, char **tpArgv, cmdOptions_t *options);
+int sas_util_list_remoteport(int wwnCount, char **wwn_argv,
+    cmdOptions_t *options);
+int
+sas_util_list_logicalunit(int luCount, char **luArgv, cmdOptions_t *options);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _SASINFO_H */
--- a/usr/src/common/cmdparse/cmdparse.c	Fri Sep 25 18:10:09 2009 -0400
+++ b/usr/src/common/cmdparse/cmdparse.c	Fri Sep 25 16:43:29 2009 -0700
@@ -536,7 +536,16 @@
 		switch (opt) {
 			case '?':
 				subUsage(DETAIL_USAGE, subcommand);
-				exit(0);
+				/*
+				 * getopt can return a '?' when no
+				 * option letters match string. Check for
+				 * the 'real' '?' in optopt.
+				 */
+				if (optopt == '?') {
+					exit(0);
+				} else {
+					exit(1);
+				}
 			default:
 				cmdOptions[i].optval = opt;
 				if (optarg) {
--- a/usr/src/lib/Makefile	Fri Sep 25 18:10:09 2009 -0400
+++ b/usr/src/lib/Makefile	Fri Sep 25 16:43:29 2009 -0700
@@ -147,7 +147,9 @@
 	nametoaddr	\
 	ncad_addr	\
 	hbaapi		\
+	smhba		\
 	sun_fc		\
+	sun_sas		\
 	gss_mechs/mech_krb5	.WAIT	\
 	libkrb5	.WAIT	\
 	krb5	.WAIT	\
@@ -486,6 +488,7 @@
 	smbsrv		\
 	scsi		\
 	hbaapi		\
+	smhba		\
 	libima		\
 	libsun_ima	\
 	mpapi		\
--- a/usr/src/lib/libsecdb/exec_attr.txt	Fri Sep 25 18:10:09 2009 -0400
+++ b/usr/src/lib/libsecdb/exec_attr.txt	Fri Sep 25 16:43:29 2009 -0700
@@ -101,6 +101,7 @@
 File System Management:solaris:cmd:::/usr/sbin/quotaon:uid=0;gid=sys
 File System Management:solaris:cmd:::/usr/sbin/raidctl:privs=sys_config,sys_devices;euid=0
 File System Management:suser:cmd:::/usr/sbin/ramdiskadm:euid=0
+File System Management:solaris:cmd:::/usr/sbin/sasinfo:privs=sys_devices
 File System Management:solaris:cmd:::/usr/sbin/sbdadm:privs=sys_devices
 File System Management:suser:cmd:::/usr/sbin/share:uid=0;gid=root
 File System Management:suser:cmd:::/usr/sbin/sharemgr:uid=0;gid=root
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/Makefile	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,59 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include		../Makefile.lib
+
+
+SUBDIRS=	$(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all :=		TARGET= all
+clean :=	TARGET= clean
+clobber :=	TARGET= clobber
+install :=	TARGET= install
+lint :=		TARGET= lint
+
+# definitions for install_h target
+HDRS=		smhbaapi.h
+HDRDIR=		common
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS) 
+
+# install rule for install_h target
+
+install_h: $(ROOTHDRS)
+
+# These headers and source should be excluded from check target
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/Makefile.com	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,64 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+
+LIBRARY =	libSMHBAAPI.a
+VERS =		.1
+OBJECTS	=	SMHBAAPILIB.o
+CONFIGFILE=	smhba.conf
+ROOTETC=	$(ROOT)/etc
+
+include ../../Makefile.lib
+
+HETCFILES=	$(CONFIGFILE:%=$(ROOTETC)/%)
+HETCFILES:=	FILEMODE= 644
+HETCFILES:=	OWNER= root
+HETCFILES:=	GROUP= sys
+
+LIBS =		$(DYNLIB) $(LINTLIB)
+SRCDIR=		../common
+
+INCS +=		-I$(SRCDIR)
+INCS +=		-I$(SRC)/lib/hbaapi/common
+CFLAGS +=	-DSOLARIS
+CFLAGS +=	-DVERSION='"Version 1"'
+CFLAGS +=	-DUSESYSLOG
+CPPFLAGS +=	$(INCS)
+CPPFLAGS +=	-DPOSIX_THREADS
+
+LDLIBS +=	-lc
+
+$(LINTLIB) := SRCS=	$(SRCDIR)/$(LINTSRC)
+
+$(ROOTETC)/%:	../common/%
+	$(INS.file)
+
+.KEEP_STATE:
+
+all:	$(LIBS) $(HETCFILES)
+
+lint: lintcheck
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/THIRDPARTYLICENSE	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,404 @@
+--------------------------------------------------------------------
+
+*STORAGE NETWORKING INDUSTRY ASSOCIATION
+PUBLIC LICENSE
+Version 1.1 *
+________________________
+
+*1. Definitions.*
+
+    * 1.1 "Commercial Use" means distribution or otherwise making the
+      Covered Code available to a third party.
+    * 1.2 "Contributor" means each entity that creates or contributes to
+      the creation of Modifications.
+    * 1.3 "Contributor Version" means the combination of the Original
+      Code, prior Modifications used by a Contributor, and the
+      Modifications made by that particular Contributor.
+    * 1.4 "Covered Code" means the Original Code or Modifications or the
+      combination of the Original Code and Modifications, in each case
+      including portions thereof.
+    * 1.5 "Electronic Distribution Mechanism" means a mechanism
+      generally accepted in the software development community for the
+      electronic transfer of data.
+    * 1.6 "Executable" means Covered Code in any form other than Source
+      Code.
+    * 1.7 "Initial Developer" means the individual or entity identified
+      as the Initial Developer in the Source Code notice required by
+      Exhibit A.
+    * 1.8 "Larger Work" means a work which combines Covered Code or
+      portions thereof with code not governed by the terms of this License.
+    * 1.9 "License" means this document.
+    * 1.10 "Licensable" means having the right to grant, to the maximum
+      extent possible, whether at the time of the initial grant or
+      subsequently acquired, any and all of the rights conveyed herein.
+    * 1.11 "Modifications" means any addition to or deletion from the
+      substance or structure of either the Original Code or any previous
+      Modifications. When Covered Code is released as a series of files,
+      a Modification is:
+          o A. Any addition to or deletion from the contents of a file
+            containing Original Code or previous Modifications.
+          o B. Any new file that contains any part of the Original Code
+            or previous Modifications.
+
+      1.12 "Original Code" means Source Code of computer software code
+      which is described in the Source Code notice required by Exhibit A
+      as Original Code, and which, at the time of its release under this
+      License is not already Covered Code governed by this License.
+
+    * 1.13 "Patent Claims" means any patent claim(s), now owned or
+      hereafter acquired, including without limitation, method, process,
+      and apparatus claims, in any patent Licensable by grantor.
+    * 1.14 "Source Code" means the preferred form of the Covered Code
+      for making modifications to it, including all modules it contains,
+      plus any associated interface definition files, scripts used to
+      control compilation and installation of an Executable, or source
+      code differential comparisons against either the Original Code or
+      another well known, available Covered Code of the Contributor's
+      choice. The Source Code can be in a compressed or archival form,
+      provided the appropriate decompression or de-archiving software is
+      widely available for no charge.
+    * 1.15 "You" (or "Your") means an individual or a legal entity
+      exercising rights under, and complying with all of the terms of,
+      this License or a future version of this License issued under
+      Section 6.1. For legal entities, "You" includes any entity which
+      controls, is controlled by, or is under common control with You.
+      For purposes of this definition, "control" means (a) the power,
+      direct or indirect, to cause the direction or management of such
+      entity, whether by contract or otherwise, or (b) ownership of more
+      than fifty percent (50%) of the outstanding shares or beneficial
+      ownership of such entity
+
+*2. Source Code License.*
+
+    * 2.1 The Initial Developer Grant. The Initial Developer hereby
+      grants You a world-wide, royalty-free, non-exclusive license,
+      subject to third party intellectual property claims:
+          o (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Initial Developer to use,
+            reproduce, modify, display, perform, sublicense and
+            distribute the Original Code (or portions thereof) with or
+            without Modifications, and/or as part of a Larger Work; and
+          o (b) under Patents Claims infringed by the making, using or
+            selling of Original Code, to make, have made, use, practice,
+            sell, and offer for sale, and/or otherwise dispose of the
+            Original Code (or portions thereof).
+          o (c) the licenses granted in this Section 2.1(a) and (b) are
+            effective on the date Initial Developer first distributes
+            Original Code under the terms of this License.
+          o (d) Notwithstanding Section 2.1(b) above, no patent license
+            is granted: 1) for code that You delete from the Original
+            Code; 2) separate from the Original Code; or 3) for
+            infringements caused by: i) the modification of the Original
+            Code or ii) the combination of the Original Code with other
+            software or devices.
+
+    * 2.2 Contributor Grant. Subject to third party intellectual
+      property claims, each Contributor hereby grants You a world-wide,
+      royalty-free, non-exclusive license
+          o (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Contributor, to use, reproduce,
+            modify, display, perform, sublicense and distribute the
+            Modifications created by such Contributor (or portions
+            thereof) either on an unmodified basis, with other
+            Modifications, as Covered Code and/or as part of a Larger
+            Work; and
+          o (b) under Patent Claims infringed by the making, using, or
+            selling of Modifications made by that Contributor either
+            alone and/or in combination with its Contributor Version (or
+            portions of such combination), to make, use, sell, offer for
+            sale, have made, and/or otherwise dispose of: 1)
+            Modifications made by that Contributor (or portions
+            thereof); and 2) the combination of Modifications made by
+            that Contributor with its Contributor Version (or portions
+            of such combination).
+          o (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+            effective on the date Contributor first makes Commercial Use
+            of the Covered Code.
+          o (d) Notwithstanding Section 2.2(b) above, no patent license
+            is granted: 1) for any code that Contributor has deleted
+            from the Contributor Version; 2) separate from the
+            Contributor Version; 3) for infringements caused by: i)
+            third party modifications of Contributor Version or ii) the
+            combination of Modifications made by that Contributor with
+            other software (except as part of the Contributor Version)
+            or other devices; or 4) under Patent Claims infringed by
+            Covered Code in the absence of Modifications made by that
+            Contributor.
+
+*3. Distribution Obligations.*
+
+    * 3.1 Application of License. The Modifications which You create or
+      to which You contribute are governed by the terms of this License,
+      including without limitation Section 2.2. The Source Code version
+      of Covered Code may be distributed only under the terms of this
+      License or a future version of this License released under Section
+      6.1, and You must include a copy of this License with every copy
+      of the Source Code You distribute. You may not offer or impose any
+      terms on any Source Code version that alters or restricts the
+      applicable version of this License or the recipients' rights
+      hereunder. However, You may include an additional document
+      offering the additional rights described in Section 3.5.
+    * 3.2 Availability of Source Code. Any Modification which You create
+      or to which You contribute must be made available in Source Code
+      form under the terms of this License either on the same media as
+      an Executable version or via an accepted Electronic Distribution
+      Mechanism to anyone to whom you made an Executable version
+      available; and if made available via Electronic Distribution
+      Mechanism, must remain available for at least twelve (12) months
+      after the date it initially became available, or at least six (6)
+      months after a subsequent version of that particular Modification
+      has been made available to such recipients. You are responsible
+      for ensuring that the Source Code version remains available even
+      if the Electronic Distribution Mechanism is maintained by a third
+      party.
+    * 3.3 Description of Modifications. You must cause all Covered Code
+      to which You contribute to contain a file documenting the changes
+      You made to create that Covered Code and the date of any change.
+      You must include a prominent statement that the Modification is
+      derived, directly or indirectly, from Original Code provided by
+      the Initial Developer and including the name of the Initial
+      Developer in (a) the Source Code, and (b) in any notice in an
+      Executable version or related documentation in which You describe
+      the origin or ownership of the Covered Code.
+    * 3.4 Intellectual Property Matters.
+          o (a) Third Party Claims. If Contributor has actual knowledge
+            that a license under a third party's intellectual property
+            rights is required to exercise the rights granted by such
+            Contributor under Sections 2.1 or 2.2, Contributor must
+            include a text file with the Source Code distribution titled
+            "LEGAL" which describes the claim and the party making the
+            claim in sufficient detail that a recipient will know whom
+            to contact. If Contributor obtains such knowledge after the
+            Modification is made available as described in Section 3.2,
+            Contributor shall promptly modify the LEGAL file in all
+            copies Contributor makes available thereafter.
+          o (b) Contributor API's. If Contributor's Modifications
+            include an application programming interface and Contributor
+            has actual knowledge of patent licenses which are reasonably
+            necessary to implement that API, Contributor must also
+            include this information in the LEGAL file.
+          o (c) Representations. Contributor represents that, except as
+            disclosed pursuant to Section 3.4(a) above, Contributor
+            believes that Contributor's Modifications are Contributor's
+            original creation(s) and/or Contributor has sufficient
+            rights to grant the rights conveyed by this License.
+    * 3.5 Required Notices. You must duplicate the notice in *Exhibit A*
+      in each file of the Source Code. If it is not possible to put such
+      notice in a particular Source Code file due to its structure, then
+      You must include such notice in a location (such as a relevant
+      directory) where a user would be most likely to look for such a
+      notice. If You created one or more Modification(s) You may add
+      your name as a Contributor to the notice described in *Exhibit A.
+      *You must also duplicate this License in any documentation for the
+      Source Code where You describe recipients' rights or ownership
+      rights relating to Covered Code. You may choose to offer, and to
+      charge a fee for, warranty, support, indemnity or liability
+      obligations to one or more recipients of Covered Code. However,
+      You may do so only on Your own behalf, and not on behalf of the
+      Initial Developer or any Contributor. You must make it absolutely
+      clear that any such warranty, support, indemnity or liability
+      obligation is offered by You alone, and You hereby agree to
+      indemnify the Initial Developer and every Contributor for any
+      liability (excluding any liability arising from intellectual
+      property claims relating to the Covered Code) incurred by the
+      Initial Developer or such Contributor as a result of warranty,
+      support, indemnity or liability terms You offer.
+    * 3.6 Distribution of Executable Versions. You may distribute
+      Covered Code in Executable form only if the requirements of
+      Section* 3.1-3.5 *have been met for that Covered Code, and if You
+      include a notice stating that the Source Code version of the
+      Covered Code is available under the terms of this License,
+      including a description of how and where You have fulfilled the
+      obligation of Section *3.2.* The notice must be conspicuously
+      included in any notice in an Executable version, related
+      documentation or collateral in which You describe recipients'
+      rights relating to the Covered Code. You may distribute the
+      Executable version of Covered Code or ownership rights under a
+      license of Your choice, which may contain terms different from
+      this License, provided that You are in compliance with the terms
+      of this License and that the license for the Executable version
+      does not attempt to limit or alter the recipient's rights in the
+      Source Code version from the rights set forth in this License. If
+      You distribute the Executable version under a different license
+      You must make it absolutely clear that any terms which differ from
+      this License are offered by You alone, not by the Initial
+      Developer or any Contributor. You hereby agree to indemnify the
+      Initial Developer and every Contributor for any liability
+      (excluding any liability arising from intellectual property claims
+      relating to the Covered Code) incurred by the Initial Developer or
+      such Contributor as a result of any such terms You offer.
+    * 3.7 Larger Works. You may create a Larger Work by combining
+      Covered Code with other code not governed by the terms of this
+      License and distribute the Larger Work as a single product. In
+      such a case, You must make sure the requirements of this License
+      are fulfilled for the Covered Code.
+
+*4. Inability to Comply Due to Statute or Regulation.* If it is
+impossible for You to comply with any of the terms of this License with
+respect to some or all of the Covered Code due to statute, judicial
+order, or regulation then You must: (a) comply with the terms of this
+License to the maximum extent possible; and (b) describe the limitations
+and the code they affect. Such description must be included in the LEGAL
+file described in Section 3.4 and must be included with all
+distributions of the Source Code. Except to the extent prohibited by
+statute or regulation, such description must be sufficiently detailed
+for a recipient of ordinary skill to be able to understand it.
+
+*5. Application of this License.* This License applies to code to which
+the Initial Developer has attached the notice in Exhibit A and to
+related Covered Code.
+
+*6. Versions of the License.*
+
+    * 6.1 New Versions. The Storage Networking Industry Association (the
+      "SNIA") may publish revised and/or new versions of the License
+      from time to time. Each version will be given a distinguishing
+      version number.
+    * 6.2 Effect of New Versions. Once Covered Code has been published
+      under a particular version of the License, You may always continue
+      to use it under the terms of that version. You may also choose to
+      use such Covered Code under the terms of any subsequent version of
+      the License published by the SNIA. No one other than the SNIA has
+      the right to modify the terms applicable to Covered Code created
+      under this License.
+    * 6.3 Derivative Works. If You create or use a modified version of
+      this License (which you may only do in order to apply it to code
+      which is not already Covered Code governed by this License), You
+      must (a) rename Your license so that the phrases "Storage
+      Networking Industry Association," "SNIA," or any confusingly
+      similar phrase do not appear in your license (except to note that
+      your license differs from this License) and (b) otherwise make it
+      clear that Your version of the license contains terms which differ
+      from the SNIA Public License. (Filling in the name of the Initial
+      Developer, Original Code or Contributor in the notice described in
+      Exhibit A shall not of themselves be deemed to be modifications of
+      this License.)
+
+*7. DISCLAIMER OF WARRANTY. COVERED CODE IS PROVIDED UNDER THIS LICENSE
+ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
+IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE
+IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR
+NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY
+RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME
+THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS
+DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO
+USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
+DISCLAIMER.*
+
+*8. TERMINATION.*
+
+    * *8.1 *This License and the rights granted hereunder will terminate
+      automatically if You fail to comply with terms herein and fail to
+      cure such breach within a reasonable time after becoming aware of
+      the breach. All sublicenses to the Covered Code which are properly
+      granted shall survive any termination of this License. Provisions
+      which, by their nature, must remain in effect beyond the
+      termination of this License shall survive.
+    * *8.2* If You initiate litigation by asserting a patent
+      infringement claim (excluding declaratory judgment actions)
+      against Initial Developer or a Contributor (the Initial Developer
+      or Contributor against whom You file such action is referred to as
+      "Participant") alleging that:
+          o *(a)* such Participant's Contributor Version directly or
+            indirectly infringes any patent, then any and all rights
+            granted by such Participant to You under Sections 2.1 and/or
+            2.2 of this License shall, upon 60 days notice from
+            Participant terminate prospectively, unless if within 60
+            days after receipt of notice You either: (i) agree in
+            writing to pay Participant a mutually agreeable reasonable
+            royalty for Your past and future use of Modifications made
+            by such Participant, or (ii) withdraw Your litigation claim
+            with respect to the Contributor Version against such
+            Participant. If within 60 days of notice, a reasonable
+            royalty and payment arrangement are not mutually agreed upon
+            in writing by the parties or the litigation claim is not
+            withdrawn, the rights granted by Participant to You under
+            Sections 2.1 and/or 2.2 automatically terminate at the
+            expiration of the 60 day notice period specified above.
+    * *8.3* If You assert a patent infringement claim against
+      Participant alleging that such Participant's Contributor Version
+      directly or indirectly infringes any patent where such claim is
+      resolved (such as by license or settlement) prior to the
+      initiation of patent infringement litigation, then the reasonable
+      value of the licenses granted by such Participant under Sections
+      2.1 or 2.2 shall be taken into account in determining the amount
+      or value of any payment or license.
+
+       
+
+    * *8.4* In the event of termination under Sections 8.1 or 8.2 above,
+      all end user license agreements (excluding distributors and
+      resellers) which have been validly granted by You or any
+      distributor hereunder prior to termination shall survive termination.
+
+*9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL
+THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE,
+SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY
+DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
+LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION,
+DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR
+MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF
+SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.
+THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR
+PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
+APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT
+ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL
+DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.*
+
+*10. U.S. GOVERNMENT END USERS.* The Covered Code is a "commercial
+item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995),
+consisting of "commercial computer software" and "commercial computer
+software documentation," as such terms are used in 48 C.F.R. 12.212
+(Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1
+through 227.7202-4 (June 1995), all U.S. Government End Users acquire
+Covered Code with only those rights set forth herein.
+
+*11. MISCELLANEOUS *This License represents the complete agreement
+concerning subject matter hereof. If any provision of this License is
+held to be unenforceable, such provision shall be reformed only to the
+extent necessary to make it enforceable. This License shall be governed
+by California law provisions (except to the extent applicable law, if
+any, provides otherwise), excluding its conflict-of-law provisions. The
+application of the United Nations Convention on Contracts for the
+International Sale of Goods is expressly excluded. Any law or regulation
+which provides that the language of a contract shall be construed
+against the drafter shall not apply to this License.
+
+*12. RESPONSIBILITY FOR CLAIMS.* As between Initial Developer and the
+Contributors, each party is responsible for claims and damages arising,
+directly or indirectly, out of its utilization of rights under this
+License and You agree to work with Initial Developer and Contributors to
+distribute such responsibility on an equitable basis. Nothing herein is
+intended or shall be deemed to constitute any admission of liability.
+
+*13. MULTIPLE-LICENSED CODE.* Initial Developer may designate portions
+of the Covered Code as "Multiple-Licensed". "Multiple-Licensed" means
+that the Initial Developer permits you to utilize portions of the
+Covered Code under Your choice of this License or the alternative
+licenses, if any, specified by the Initial Developer in the file
+described in Exhibit A.
+
+*14. ACCEPTANCE.* This License is accepted by You if You retain, use, or
+distribute the Covered Code for any purpose.
+
+*EXHIBIT A —The SNIA Public License.*
+
+The contents of this file are subject to the SNIA Public License Version
+1.1 (the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+    http://mp-mgmt-api.sourceforge.net/SourceLicense-v1.1.html
+
+Software distributed under the License is distributed on an "AS IS"
+basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific language governing rights and limitations under
+the License.
+
+The Original Code is _                    ._
+
+The Initial Developer of the Original Code is _  [COMPLETE THIS]    _.
+
+Contributor(s): ______________________________________.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/THIRDPARTYLICENSE.descrip	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,1 @@
+SM-HBA SOFTWARE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/amd64/Makefile	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,30 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/common/SMHBAAPILIB.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,4988 @@
+/*
+ * ************************************************************************
+ * Description
+ *	HBAAPILIB.c - Implements a sample common (wrapper) HBA API library
+ *
+ * License:
+ *	The contents of this file are subject to the SNIA Public License
+ *	Version 1.0 (the "License"); you may not use this file except in
+ *	compliance with the License. You may obtain a copy of the License at
+ *
+ *	/http://www.snia.org/English/Resources/Code/OpenSource.html
+ *
+ *	Software distributed under the License is distributed on an "AS IS"
+ *	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ *	the License for the specific language governing rights and limitations
+ *	under the License.
+ *
+ * The Original Code is  SNIA HBA API Wrapper Library
+ *
+ * The Initial Developer of the Original Code is:
+ *	Benjamin F. Kuo, Troika Networks, Inc. (benk@troikanetworks.com)
+ *
+ * Contributor(s):
+ *	Tuan Lam, QLogic Corp. (t_lam@qlc.com)
+ *	Dan Willie, Emulex Corp. (Dan.Willie@emulex.com)
+ *	Dixon Hutchinson, Legato Systems, Inc. (dhutchin@legato.com)
+ *	David Dillard, VERITAS Software Corp. (david.dillard@veritas.com)
+ *
+ * ************************************************************************
+ *
+ * Adding on SM-HBA support
+ *
+ * The implementation includes Three different categories functions to support
+ * both HBAAPI and SM-HBA through the same library.
+ *
+ * SM-HBA unique interface:
+ *	1. CHECKLIBRARYANDVERSION(SMHBA) : match SMHBA VSL
+ *	   Or checking specifically if version is SMHBA beforehand.
+ *	2. resolved to ftable.smhbafunctiontable.{interface}
+ * HBAAPIV2 unique functions
+ *	1. CHECKLIBRARYANDVERSION(HBAAPIV2) : validate and match HBAAPI V2 VSL.
+ *	   Or checking specifically if version is HBAAPIV2 beforehand.
+ *	2. resolved to ftable.functiontable.{interface}
+ * Common interface between SM-HBA and HBAAPIV2.
+ *	1. CHECKLIBRARY() : to validate the VSL.
+ *	2. FUNCCOMMON macro to map the appropriate entry point table
+ *	    (union ftable).
+ *	3. If the interface is not supported by HBAAPI(Version 1)
+ *	   the funtiion ptr will be set to NULL.
+ * Common interface between HBAAPI and HBAAPIV2.
+ *	1. Check if version is not SMHBA).
+ *	2. ftable.functiontalbe.(interface)
+ *
+ * ************************************************************************
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#include <string.h>
+/*
+ * Next define forces entry points in the dll to be exported
+ * See hbaapi.h to see what it does.
+ */
+#define	HBAAPI_EXPORTS
+#else
+#include <dlfcn.h>
+#include <strings.h>
+#endif
+#include <stdio.h>
+#include <time.h>
+#include "smhbaapi.h"
+#include "vendorsmhbaapi.h"
+#include <stdlib.h>
+#ifdef USESYSLOG
+#include <syslog.h>
+#endif
+#ifdef SOLARIS
+#include <link.h>
+#include <limits.h>
+static int	*handle;
+static Link_map *map, *mp;
+#endif
+
+/*
+ * LIBRARY_NUM is a shortcut to figure out which library we need to call.
+ *  The top 16 bits of handle are the library index
+ */
+#define	LIBRARY_NUM(handle)	((handle)>>16)
+
+/*
+ * VENDOR_HANDLE turns a global library handle into a vendor specific handle,
+ * with all upper 16 bits set to 0
+ */
+#define	VENDOR_HANDLE(handle)	((handle)&0xFFFF)
+
+#define	HBA_HANDLE_FROM_LOCAL(library, vendor) \
+				(((library)<<16) | ((vendor)&0x0000FFFF))
+
+int _hbaapi_debuglevel = 0;
+#define	DEBUG(L, STR, A1, A2, A3)
+
+#if defined(USESYSLOG) && defined(USELOGFILE)
+FILE *_hbaapi_debug_fd = NULL;
+int _hbaapi_sysloginit = 0;
+#undef DEBUG
+#ifdef WIN32
+#define	DEBUG(L, STR, A1, A2, A3)\
+    if ((L) <= _hbaapi_debuglevel) {\
+	if (_hbaapi_sysloginit == 0) {\
+	    openlog("HBAAPI", LOG_PID|LOG_ODELAY, LOG_USER);\
+	    _hbaapi_sysloginit = 1;\
+	}\
+	syslog(LOG_INFO, (STR), (A1), (A2), (A3));\
+	if (_hbaapi_debug_fd == NULL) {\
+	    char _logFile[MAX_PATH]; \
+	    GetTempPath(MAX_PATH, _logFile); \
+	    strcat(_logFile, "HBAAPI.log"); \
+	    _hbaapi_debug_fd = fopen(_logFile, "a");\
+	}\
+	if (_hbaapi_debug_fd != NULL) {\
+	    fprintf(_hbaapi_debug_fd, #STR "\n", (A1), (A2), (A3));\
+	}\
+	}
+#else /* WIN32 */
+#define	DEBUG(L, STR, A1, A2, A3)\
+	if ((L) <= _hbaapi_debuglevel) {\
+	if (_hbaapi_sysloginit == 0) {\
+	    openlog("HBAAPI", LOG_PID|LOG_ODELAY, LOG_USER);\
+	    _hbaapi_sysloginit = 1;\
+	}\
+	syslog(LOG_INFO, (STR), (A1), (A2), (A3));\
+	if (_hbaapi_debug_fd == NULL) {\
+	    _hbaapi_debug_fd = fopen("/tmp/HBAAPI.log", "a");\
+	}\
+	if (_hbaapi_debug_fd != NULL) {\
+	    fprintf(_hbaapi_debug_fd, #STR  "\n", (A1), (A2), (A3));\
+	}\
+	}
+#endif /* WIN32 */
+
+#else /* Not both USESYSLOG and USELOGFILE */
+#if defined(USESYSLOG)
+int _hbaapi_sysloginit = 0;
+#undef DEBUG
+#define	DEBUG(L, STR, A1, A2, A3) \
+    if ((L) <= _hbaapi_debuglevel) {\
+	if (_hbaapi_sysloginit == 0) {\
+	    openlog("HBAAPI", LOG_PID|LOG_ODELAY, LOG_USER);\
+	    _hbaapi_sysloginit = 1;\
+	}\
+	syslog(LOG_DEBUG, (STR), (A1), (A2), (A3));\
+	}
+#endif /* USESYSLOG */
+#if defined(USELOGFILE)
+FILE *_hbaapi_debug_fd = NULL;
+#undef DEBUG
+#ifdef WIN32
+#define	DEBUG(L, STR, A1, A2, A3) \
+    if ((L) <= _hbaapi_debuglevel) {\
+	if (_hbaapi_debug_fd == NULL) {\
+	    char _logFile[MAX_PATH]; \
+	    GetTempPath(MAX_PATH, _logFile); \
+	    strcat(_logFile, "HBAAPI.log"); \
+	    _hbaapi_debug_fd = fopen(_logFile, "a");\
+	}\
+	}
+#else /* WIN32 */
+#define	DEBUG(L, STR, A1, A2, A3) \
+    if ((L) <= _hbaapi_debuglevel) {\
+	if (_hbaapi_debug_fd == NULL) {\
+	    _hbaapi_debug_fd = fopen("/tmp/HBAAPI.log", "a");\
+	}\
+	if (_hbaapi_debug_fd != NULL) { \
+	    fprintf(_hbaapi_debug_fd, #STR "\n", (A1), (A2), (A3));\
+	}\
+	}
+#endif /* WIN32 */
+#endif /* USELOGFILE */
+#endif /* Not both USELOGFILE and USESYSLOG */
+
+#ifdef POSIX_THREADS
+#include <pthread.h>
+/*
+ * When multiple mutex's are grabed, they must be always be grabbed in
+ * the same order, or deadlock can result.  There are three levels
+ * of mutex's involved in this API.  If LL_mutex is grabbed, always grap
+ * it first.  If AL_mutex is grabbed, it may not be grabbed before
+ * LL_mutex.  If grabbed in a multi grab sequence, the mutex's protecting
+ * the callback lists must always be grabbed last and release before calling
+ * a vendor specific library function that might invoke a callback function
+ * on the same thread.
+ */
+#define	GRAB_MUTEX(M)			grab_mutex(M)
+#define	RELEASE_MUTEX(M)		release_mutex(M)
+#define	RELEASE_MUTEX_RETURN(M, RET)	release_mutex(M); return (RET)
+#elif defined(WIN32)
+#define	GRAB_MUTEX(m)			EnterCriticalSection(m)
+#define	RELEASE_MUTEX(m)		LeaveCriticalSection(m)
+#define	RELEASE_MUTEX_RETURN(m, RET)	LeaveCriticalSection(m); return (RET)
+#else
+#define	GRAB_MUTEX(M)
+#define	RELEASE_MUTEX(M)
+#define	RELEASE_MUTEX_RETURN(M, RET)	return (RET)
+#endif
+
+/*
+ * Vendor library information
+ */
+typedef enum {
+    HBA_LIBRARY_UNKNOWN,
+    HBA_LIBRARY_LOADED,
+    HBA_LIBRARY_NOT_LOADED
+} HBA_LIBRARY_STATUS;
+
+typedef enum {
+    UNKNOWN = 1,
+    SMHBA,
+    HBAAPIV2,
+    HBAAPI
+} LIBRARY_VERSION;
+
+typedef struct hba_library_info {
+    struct hba_library_info
+			*next;
+#ifdef WIN32
+    HINSTANCE		hLibrary;		/* Handle to a loaded DLL */
+#else
+    char		*LibraryName;
+    void*		hLibrary;		/* Handle to a loaded DLL */
+#endif
+    char		*LibraryPath;
+    LIBRARY_VERSION	version;		/* resolve union */
+    HBA_UINT32		numOfAdapters;
+    union {
+	SMHBA_ENTRYPOINTS   smhbafunctionTable;	/* smhba function pointers */
+	HBA_ENTRYPOINTSV2   functionTable;	/* hba api function pointers */
+	} ftable;
+    HBA_LIBRARY_STATUS	status;			/* info on this library */
+    HBA_UINT32		index;
+} HBA_LIBRARY_INFO, *PHBA_LIBRARY_INFO;
+
+#define	ARE_WE_INITED() \
+	if (_hbaapi_librarylist == NULL) { \
+		return (HBA_STATUS_ERROR_NOT_LOADED); \
+	}
+HBA_LIBRARY_INFO *_hbaapi_librarylist = NULL;
+HBA_UINT32 _hbaapi_total_library_count = 0;
+#ifdef POSIX_THREADS
+pthread_mutex_t _hbaapi_LL_mutex = PTHREAD_MUTEX_INITIALIZER;
+#elif defined(WIN32)
+CRITICAL_SECTION _hbaapi_LL_mutex;
+#endif
+
+/*
+ * Macro to use the right function table between smhba and hbaapi.
+ */
+#define	FUNCTABLE(lib_infop) \
+	((lib_infop->version == SMHBA) ? \
+	lib_infop->ftable.smhbafunctionTable : \
+	lib_infop->ftable.functionTable);
+
+/*
+ * Macro to use the right function ptr between smhba and hbaapi function table.
+ * Should be used for an interface common to SM-HBA and HBAAPIV2.
+ */
+#define	FUNCCOMMON(lib_infop, func) \
+	((lib_infop->version == SMHBA) ? \
+	lib_infop->ftable.smhbafunctionTable.func : \
+	lib_infop->ftable.functionTable.func)
+
+/*
+ * Macro to use the hbaapi function ptr.
+ * Should be used for an interface applicable only HBAAPIV2.
+ */
+#define	FUNCHBAAPIV2(lib_infop, func) \
+	lib_infop->ftable.functionTable.func
+
+/*
+ * Macro to use the hbaapi function ptr.
+ * Should be used for an interface applicable only HBAAPIV2.
+ */
+#define	FUNCSMHBA(lib_infop, func) \
+	lib_infop->ftable.smhbafunctionTable.func
+
+/*
+ * Individual adapter (hba) information
+ */
+typedef struct hba_adapter_info {
+    struct hba_adapter_info
+			*next;
+    HBA_STATUS		GNstatus;	/* status from GetAdapterNameFunc */
+    char		*name;
+    HBA_WWN		nodeWWN;
+    HBA_LIBRARY_INFO	*library;
+    HBA_UINT32		index;
+} HBA_ADAPTER_INFO;
+
+HBA_ADAPTER_INFO *_hbaapi_adapterlist = NULL;
+HBA_UINT32 _hbaapi_total_adapter_count = 0;
+#ifdef POSIX_THREADS
+pthread_mutex_t _hbaapi_AL_mutex = PTHREAD_MUTEX_INITIALIZER;
+#elif defined(WIN32)
+CRITICAL_SECTION _hbaapi_AL_mutex;
+#endif
+
+/*
+ * Call back registration
+ */
+typedef struct hba_vendorcallback_elem {
+    struct hba_vendorcallback_elem
+				*next;
+    HBA_CALLBACKHANDLE		vendorcbhandle;
+    HBA_LIBRARY_INFO		*lib_info;
+} HBA_VENDORCALLBACK_ELEM;
+
+/*
+ * Each instance of HBA_ADAPTERCALLBACK_ELEM represents a call to one of
+ * "register" functions that apply to a particular adapter.
+ * HBA_ALLADAPTERSCALLBACK_ELEM is used just for HBA_RegisterForAdapterAddEvents
+ */
+typedef struct hba_adaptercallback_elem {
+    struct hba_adaptercallback_elem
+			*next;
+    HBA_LIBRARY_INFO	*lib_info;
+    void		*userdata;
+    HBA_CALLBACKHANDLE	vendorcbhandle;
+    void		(*callback)();
+} HBA_ADAPTERCALLBACK_ELEM;
+
+typedef struct hba_alladapterscallback_elem {
+    struct hba_alladapterscallback_elem
+				*next;
+    void			*userdata;
+    HBA_VENDORCALLBACK_ELEM	*vendorhandlelist;
+    void			(*callback)();
+} HBA_ALLADAPTERSCALLBACK_ELEM;
+
+HBA_ALLADAPTERSCALLBACK_ELEM *_hbaapi_adapteraddevents_callback_list = NULL;
+HBA_ADAPTERCALLBACK_ELEM *_hbaapi_adapterevents_callback_list = NULL;
+HBA_ADAPTERCALLBACK_ELEM *_hbaapi_adapterportevents_callback_list = NULL;
+HBA_ADAPTERCALLBACK_ELEM *_hbaapi_adapterportstatevents_callback_list = NULL;
+HBA_ADAPTERCALLBACK_ELEM *_hbaapi_targetevents_callback_list = NULL;
+HBA_ADAPTERCALLBACK_ELEM *_hbaapi_linkevents_callback_list = NULL;
+
+HBA_ALLADAPTERSCALLBACK_ELEM *_smhba_adapteraddevents_callback_list = NULL;
+HBA_ADAPTERCALLBACK_ELEM *_smhba_adapterevents_callback_list = NULL;
+HBA_ADAPTERCALLBACK_ELEM *_smhba_adapterportevents_callback_list = NULL;
+HBA_ADAPTERCALLBACK_ELEM *_smhba_adapterportstatevents_callback_list = NULL;
+HBA_ADAPTERCALLBACK_ELEM *_smhba_adapterphystatevents_callback_list = NULL;
+HBA_ADAPTERCALLBACK_ELEM *_smhba_targetevents_callback_list = NULL;
+
+#ifdef POSIX_THREADS
+/* mutex's to protect each list */
+pthread_mutex_t _hbaapi_AAE_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _hbaapi_AE_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _hbaapi_APE_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _hbaapi_APSE_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _hbaapi_TE_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _hbaapi_LE_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _smhba_AAE_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _smhba_AE_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _smhba_APE_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _smhba_APSE_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _smhba_APHYSE_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _smhba_TE_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t _smhba_LE_mutex = PTHREAD_MUTEX_INITIALIZER;
+#elif defined(WIN32)
+CRITICAL_SECTION _hbaapi_AAE_mutex;
+CRITICAL_SECTION _hbaapi_AE_mutex;
+CRITICAL_SECTION _hbaapi_APE_mutex;
+CRITICAL_SECTION _hbaapi_APSE_mutex;
+CRITICAL_SECTION _hbaapi_TE_mutex;
+CRITICAL_SECTION _smhba_AAE_mutex;
+CRITICAL_SECTION _smhba_AE_mutex;
+CRITICAL_SECTION _smhba_APE_mutex;
+CRITICAL_SECTION _smhba_APSE_mutex;
+CRITICAL_SECTION _smhba_APHYSE_mutex;
+CRITICAL_SECTION _smhba_TE_mutex;
+CRITICAL_SECTION _hbaapi_LE_mutex;
+#endif
+
+HBA_ADAPTERCALLBACK_ELEM **cb_lists_array[] = {
+	&_hbaapi_adapterevents_callback_list,
+	&_hbaapi_adapterportevents_callback_list,
+	&_hbaapi_adapterportstatevents_callback_list,
+	&_hbaapi_targetevents_callback_list,
+	&_hbaapi_linkevents_callback_list,
+	&_smhba_adapterevents_callback_list,
+	&_smhba_adapterportevents_callback_list,
+	&_smhba_adapterportstatevents_callback_list,
+	&_smhba_adapterphystatevents_callback_list,
+	&_smhba_targetevents_callback_list,
+	NULL};
+
+/*
+ * Common library internal. Mutex handling
+ */
+#ifdef POSIX_THREADS
+static void
+grab_mutex(pthread_mutex_t *mp) {
+/* LINTED E_FUNC_SET_NOT_USED */
+    int ret;
+    if ((ret = pthread_mutex_lock(mp)) != 0) {
+	perror("pthread_mutex_lock - HBAAPI:");
+	DEBUG(1, "pthread_mutex_lock returned %d", ret, 0, 0);
+	}
+}
+
+static void
+release_mutex(pthread_mutex_t *mp) {
+/* LINTED E_FUNC_SET_NOT_USED */
+    int ret;
+    if ((ret = pthread_mutex_unlock(mp)) != 0) {
+	perror("pthread_mutex_unlock - HBAAPI:");
+	DEBUG(1, "pthread_mutex_unlock returned %d", ret, 0, 0);
+	}
+}
+#endif
+
+/*
+ * Common library internal. Check library and return vendorhandle
+ */
+static HBA_STATUS
+HBA_CheckLibrary(HBA_HANDLE handle,
+    HBA_LIBRARY_INFO **lib_infopp,
+    HBA_HANDLE *vendorhandle) {
+
+    HBA_UINT32		libraryIndex;
+    HBA_LIBRARY_INFO	*lib_infop;
+
+    if (_hbaapi_librarylist == NULL) {
+	return (HBA_STATUS_ERROR);
+	}
+    libraryIndex = LIBRARY_NUM(handle);
+
+    GRAB_MUTEX(&_hbaapi_LL_mutex);
+    for (lib_infop = _hbaapi_librarylist;
+	lib_infop != NULL;
+	lib_infop = lib_infop->next) {
+	if (lib_infop->index == libraryIndex) {
+	    if (lib_infop->status != HBA_LIBRARY_LOADED) {
+		return (HBA_STATUS_ERROR);
+	    }
+	    *lib_infopp = lib_infop;
+	    *vendorhandle = VENDOR_HANDLE(handle);
+	    /* caller will release the mutex */
+	    return (HBA_STATUS_OK);
+	}
+	}
+    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INVALID_HANDLE);
+}
+#define	CHECKLIBRARY() \
+	status = HBA_CheckLibrary(handle, &lib_infop, &vendorHandle);\
+	if (status != HBA_STATUS_OK) { \
+	    return (status); \
+	}
+
+#define	CHECKLIBRARYANDVERSION(ver) \
+	status = HBA_CheckLibrary(handle, &lib_infop, &vendorHandle); \
+	if (status != HBA_STATUS_OK) { \
+	    return (status); \
+	} else { \
+	    if (ver != lib_infop->version) { \
+		RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, \
+		    HBA_STATUS_ERROR_INCOMPATIBLE); \
+	    } \
+	}
+
+/*
+ * freevendorhandlelist is called with _hbaapi_LL_mutex already held
+ */
+static void
+freevendorhandlelist(HBA_VENDORCALLBACK_ELEM *vhlist) {
+    HBA_VENDORCALLBACK_ELEM	*vhlp;
+    HBA_VENDORCALLBACK_ELEM	*vnext;
+    HBARemoveCallbackFunc	registeredfunc;
+
+    for (vhlp = vhlist; vhlp != NULL; vhlp = vnext) {
+	vnext = vhlp->next;
+	registeredfunc =
+	    FUNCCOMMON(vhlp->lib_info, RemoveCallbackHandler);
+	if (registeredfunc == NULL) {
+	    continue;
+	}
+	(registeredfunc)(vhlp->vendorcbhandle);
+	free(vhlp);
+	}
+}
+
+static
+HBA_STATUS
+local_remove_callback(HBA_CALLBACKHANDLE cbhandle) {
+    HBA_ADAPTERCALLBACK_ELEM		***listp;
+    HBA_ADAPTERCALLBACK_ELEM		**lastp;
+    HBA_ALLADAPTERSCALLBACK_ELEM	**lap;
+    HBA_ALLADAPTERSCALLBACK_ELEM	*allcbp;
+    HBA_ADAPTERCALLBACK_ELEM		*cbp;
+    HBARemoveCallbackFunc		registeredfunc;
+    HBA_VENDORCALLBACK_ELEM		*vhlp;
+    HBA_VENDORCALLBACK_ELEM		*vnext;
+    int					found;
+    HBA_STATUS			status = HBA_STATUS_ERROR_INVALID_HANDLE;
+
+
+	/* search through the simple lists first */
+    GRAB_MUTEX(&_hbaapi_AAE_mutex);
+    GRAB_MUTEX(&_hbaapi_AE_mutex);
+    GRAB_MUTEX(&_hbaapi_APE_mutex);
+    GRAB_MUTEX(&_hbaapi_APSE_mutex);
+    GRAB_MUTEX(&_hbaapi_TE_mutex);
+    GRAB_MUTEX(&_hbaapi_LE_mutex);
+    GRAB_MUTEX(&_smhba_AAE_mutex);
+    GRAB_MUTEX(&_smhba_AE_mutex);
+    GRAB_MUTEX(&_smhba_APE_mutex);
+    GRAB_MUTEX(&_smhba_APSE_mutex);
+    GRAB_MUTEX(&_smhba_TE_mutex);
+    for (listp = cb_lists_array, found = 0;
+	    (found == 0 && *listp != NULL); listp++) {
+	lastp = *listp;
+	for (cbp = **listp; cbp != NULL; cbp = cbp->next) {
+	    if (cbhandle != (HBA_CALLBACKHANDLE)cbp) {
+		lastp = &(cbp->next);
+		continue;
+	    }
+	    found = 1;
+	    registeredfunc =
+		FUNCCOMMON(cbp->lib_info, RemoveCallbackHandler);
+	    if (registeredfunc == NULL) {
+		break;
+	    }
+	    (registeredfunc)(cbp->vendorcbhandle);
+	    *lastp = cbp->next;
+	    free(cbp);
+	    break;
+	}
+	}
+    RELEASE_MUTEX(&_hbaapi_LE_mutex);
+    RELEASE_MUTEX(&_hbaapi_TE_mutex);
+    RELEASE_MUTEX(&_hbaapi_APSE_mutex);
+    RELEASE_MUTEX(&_hbaapi_APE_mutex);
+    RELEASE_MUTEX(&_hbaapi_AE_mutex);
+    RELEASE_MUTEX(&_hbaapi_AAE_mutex);
+    RELEASE_MUTEX(&_smhba_AAE_mutex);
+    RELEASE_MUTEX(&_smhba_AE_mutex);
+    RELEASE_MUTEX(&_smhba_APE_mutex);
+    RELEASE_MUTEX(&_smhba_APSE_mutex);
+    RELEASE_MUTEX(&_smhba_TE_mutex);
+
+    if (found != 0) {
+	if (registeredfunc == NULL) {
+	    return (HBA_STATUS_ERROR_NOT_SUPPORTED);
+	}
+	return (HBA_STATUS_OK);
+	}
+
+    GRAB_MUTEX(&_hbaapi_AAE_mutex);
+	/*
+	 * if it wasnt in the simple lists,
+	 * look in the list for adapteraddevents
+	 */
+    lap = &_hbaapi_adapteraddevents_callback_list;
+    for (allcbp = _hbaapi_adapteraddevents_callback_list;
+	    allcbp != NULL;
+	    allcbp = allcbp->next) {
+	if (cbhandle != (HBA_CALLBACKHANDLE)allcbp) {
+	    lap = &allcbp->next;
+	    continue;
+	}
+	for (vhlp = allcbp->vendorhandlelist; vhlp != NULL; vhlp = vnext) {
+	    vnext = vhlp->next;
+	    /* should be HBAAPIV2 VSL to get to here */
+	    registeredfunc =
+		    vhlp->lib_info->ftable.functionTable.RemoveCallbackHandler;
+	    if (registeredfunc == NULL) {
+		continue;
+	    }
+	    (registeredfunc)(vhlp->vendorcbhandle);
+	    free(vhlp);
+	}
+	*lap = allcbp->next;
+	free(allcbp);
+	status = HBA_STATUS_OK;
+	break;
+	}
+    RELEASE_MUTEX(&_hbaapi_AAE_mutex);
+
+	/* now search smhba adapteradd events. */
+    GRAB_MUTEX(&_smhba_AAE_mutex);
+    lap = &_smhba_adapteraddevents_callback_list;
+    for (allcbp = _smhba_adapteraddevents_callback_list;
+	allcbp != NULL;
+	allcbp = allcbp->next) {
+	if (cbhandle != (HBA_CALLBACKHANDLE)allcbp) {
+	    lap = &allcbp->next;
+	    continue;
+	}
+	for (vhlp = allcbp->vendorhandlelist; vhlp != NULL; vhlp = vnext) {
+	    vnext = vhlp->next;
+	    /* should be SMHBA VSL to get to here */
+	    registeredfunc =
+		    vhlp->lib_info->
+			ftable.smhbafunctionTable.RemoveCallbackHandler;
+	    if (registeredfunc == NULL) {
+		continue;
+	    }
+	    (registeredfunc)(vhlp->vendorcbhandle);
+	    free(vhlp);
+	}
+	*lap = allcbp->next;
+	free(allcbp);
+	status = HBA_STATUS_OK;
+	break;
+	}
+    RELEASE_MUTEX(&_smhba_AAE_mutex);
+
+    return (status);
+}
+
+/* LINTED E_STATIC_UE_STATIC_UNUSED */
+static char wwn_str1[17];
+/* LINTED E_STATIC_UE_STATIC_UNUSED */
+static char wwn_str2[17];
+/* LINTED E_STATIC_UE_STATIC_UNUSED */
+static char wwn_str3[17];
+#define	WWN2STR1(wwn) WWN2str(wwn_str1, (wwn))
+#define	WWN2STR2(wwn) WWN2str(wwn_str2, (wwn))
+#define	WWN2STR3(wwn) WWN2str(wwn_str3, (wwn))
+static char *
+/* LINTED E_STATIC_UE_STATIC_UNUSED */
+WWN2str(char *buf, HBA_WWN *wwn) {
+    int j;
+    unsigned char *pc = (unsigned char *)&(wwn->wwn[0]);
+    buf[0] = '\0';
+    for (j = 0; j < 16; j += 2) {
+		(void) sprintf(&buf[j], "%02X", (int)*pc++);
+	}
+    return (buf);
+}
+
+#ifdef WIN32
+BOOL APIENTRY
+DllMain(HANDLE hModule,
+    DWORD  ul_reason_for_call,
+    LPVOID lpReserved)
+{
+	switch (ul_reason_for_call) {
+	case DLL_PROCESS_ATTACH:
+		break;
+	case DLL_PROCESS_DETACH:
+		break;
+	case DLL_THREAD_ATTACH:
+	case DLL_THREAD_DETACH:
+		break;
+	}
+	return (TRUE);
+}
+#endif
+
+/*
+ * Read in the config file and load all the specified vendor specific
+ * libraries and perform the function registration exercise
+ */
+HBA_STATUS
+HBA_LoadLibrary()
+{
+	HBARegisterLibraryFunc RegisterFunc;
+	HBARegisterLibraryV2Func RegisterV2Func;
+	SMHBARegisterLibraryFunc RegisterSMHBAFunc;
+	HBALoadLibraryFunc	LoadLibraryFunc;
+	HBAGetVersionFunc	GetVersionFunc;
+#ifdef	POSIX_THREADS
+	int			ret;
+#endif
+	HBA_STATUS		status;
+	HBA_UINT32		libversion;
+
+	/* Open configuration file from known location */
+#ifdef WIN32
+	LONG		lStatus;
+	HKEY		hkSniaHba, hkVendorLib;
+	FILETIME		ftLastWriteTime;
+	TCHAR		cSubKeyName[256];
+	DWORD		i, dwSize, dwType;
+	BYTE		byFileName[MAX_PATH];
+	HBA_LIBRARY_INFO	*lib_infop;
+
+	if (_hbaapi_librarylist != NULL) {
+		/* this is an app programming error */
+		return (HBA_STATUS_ERROR);
+	}
+
+	lStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\SNIA\\HBA",
+	    0, KEY_READ, &hkSniaHba);
+	if (lStatus != ERROR_SUCCESS) {
+		/* ???Opportunity to send error msg, configuration error */
+		return (HBA_STATUS_ERROR);
+	}
+	/*
+	 * Enumerate all the subkeys. These have the form:
+	 * HKLM\Software\SNIA\HBA\<Vendor id> - note that we don't care
+	 * what the vendor id is
+	 */
+	for (i = 0; ; i++) {
+		dwSize = 255;	/* how big the buffer is */
+		lStatus = RegEnumKeyEx(hkSniaHba, i,
+		    (char *)&cSubKeyName, &dwSize, NULL,
+		    NULL, NULL, &ftLastWriteTime);
+	if (lStatus == ERROR_NO_MORE_ITEMS) {
+		break;	/* we're done */
+	} else if (lStatus == ERROR_MORE_DATA) { /* buffer not big enough */
+		/* do whatever */
+		;
+	}
+	/* Now open the subkey that pertains to this vendor's library */
+	lStatus = RegOpenKeyEx(hkSniaHba, cSubKeyName, 0, KEY_READ,
+	    &hkVendorLib);
+	if (lStatus != ERROR_SUCCESS) {
+		RegCloseKey(hkSniaHba);
+	    /* ???Opportunity to send error msg, installation error */
+		return (HBA_STATUS_ERROR);
+		/*
+		 * you may want to return something
+		 * else or keep trying
+		 */
+	}
+	/*
+	 * The name of the library is contained in a REG_SZ Value
+	 * keyed to "LibraryFile"
+	 */
+	dwSize = MAX_PATH;
+	lStatus = RegQueryValueEx(hkVendorLib, "LibraryFile", NULL, &dwType,
+	    byFileName, &dwSize);
+	if (lStatus != ERROR_SUCCESS) {
+		RegCloseKey(hkVendorLib);
+	    /* ???Opportunity to send error msg, installation error */
+		continue;
+	}
+	lib_infop = (HBA_LIBRARY_INFO *)calloc(1, sizeof (HBA_LIBRARY_INFO));
+	if (lib_infop == NULL) {
+	    /* what is the right thing to do in MS land??? */
+		RegCloseKey(hkVendorLib);
+		/* ???Opportunity to send error msg, installation error */
+		return (HBA_STATUS_ERROR);
+	}
+	lib_infop->status = HBA_LIBRARY_NOT_LOADED;
+	lib_infop->next = _hbaapi_librarylist;
+	lib_infop->index = _hbaapi_total_library_count;
+	_hbaapi_total_library_count++;
+	_hbaapi_librarylist = lib_infop;
+
+	/* Now I can try to load the library */
+	lib_infop->hLibrary = LoadLibrary(byFileName);
+	if (lib_infop->hLibrary == NULL) {
+	    /* printf("unable to load library %s\n", librarypath); */
+	    /* ???Opportunity to send error msg, installation error */
+		goto dud_library;
+	}
+	lib_infop->LibraryPath = strdup(byFileName);
+	DEBUG(1, "HBAAPI loading: %s\n", byFileName, 0, 0);
+
+	RegisterSMHBAFunc = (SMHBARegisterLibraryFunc)
+	    GetProcAddress(lib_infop->hLibrary, "SMHBA_RegisterLibrary");
+	if (RegisterSMHBAFunc != NULL) {
+		status = ((RegisterSMHBAFunc)(SMHBA_ENTRYPOINTS *)
+		    (&lib_infop->ftable.smhbafunctionTable));
+		if (status != HBA_STATUS_OK) {
+			/* library not loaded */
+			/* ???Opportunity to send error msg, library error? */
+			goto dud_library;
+		} else {
+			lib_infop->version = SMHBA;
+		}
+	} else {
+	    /* Call the registration function to get the list of pointers */
+		RegisterV2Func = (HBARegisterLibraryV2Func)GetProcAddress(
+		    lib_infop->hLibrary, "HBA_RegisterLibraryV2");
+		if (RegisterV2Func != NULL) {
+		/*
+		 * Load the function pointers directly into
+		 * the table of functions
+		 */
+		status = ((RegisterV2Func)
+		    (HBA_ENTRYPOINTSV2 *)(&lib_infop->ftable.functionTable));
+		if (status != HBA_STATUS_OK) {
+		    /* library not loaded */
+		    /* ???Opportunity to send error msg, library error? */
+			goto dud_library;
+		} else {
+			lib_infop->version = HBAAPIV2;
+		}
+		} else {
+		/* Maybe the vendor library is only Rev1 */
+		RegisterFunc = (HBARegisterLibraryFunc)
+		    GetProcAddress(lib_infop->hLibrary, "HBA_RegisterLibrary");
+		if (RegisterFunc == NULL) {
+		    /* ???Opportunity to send error msg, library error? */
+			goto dud_library;
+		}
+		/*
+		 * Load the function points directly into
+		 * the Rev 2 table of functions
+		 */
+		status = ((RegisterFunc)(
+		    (HBA_ENTRYPOINTS *)(&lib_infop->ftable.functionTable)));
+		if (status != HBA_STATUS_OK) {
+		    /* library not loaded */
+		    /* ???Opportunity to send error msg, library error? */
+			goto dud_library;
+		} else {
+			lib_infop->version = HBAAPI;
+		}
+		}
+	}
+
+	/* successfully loaded library */
+	/*
+	 * SM-HBA and HBAAPI has a seperate handler for GetVersion but
+	 * they have the same function signature so use the same variable here.
+	 */
+	GetVersionFunc = FUNCCOMMON(lib_infop, GetVersionHandler);
+	if (GetVersionFunc != NULL) {
+		if (lib_infop->version == SMHBA) {
+		/* Check the version of this library before loading */
+		libversion = ((GetVersionFunc)());
+#ifdef NOTDEF /* save for a later time... when it matters */
+		if (libversion < SMHBA_LIBVERSION) {
+			goto dud_library;
+		}
+#endif
+		} else {
+		/* Check the version of this library before loading */
+	    /* Actually... This wrapper is compatible with version 1 */
+		libversion = ((GetVersionFunc)());
+#ifdef NOTDEF /* save for a later time... when it matters */
+		if (libversion < HBA_LIBVERSION) {
+			goto dud_library;
+		}
+#endif
+		}
+	} else {
+	    /* ???Opportunity to send error msg, library error? */
+		goto dud_library;
+	}
+
+	LoadLibraryFunc = FUNCCOMMON(lib_infop, LoadLibraryHandler);
+	if (LoadLibraryFunc == NULL) {
+	    /* Hmmm, dont we need to flag this in a realy big way??? */
+	    /* How about messages to the system event logger ??? */
+	    /* ???Opportunity to send error msg, library error? */
+		goto dud_library;
+	}
+	/* Initialize this library */
+	status = ((LoadLibraryFunc)());
+	if (status != HBA_STATUS_OK) {
+	    /* ???Opportunity to send error msg, library error? */
+		continue;
+	}
+	/* successfully loaded library */
+	lib_infop->status = HBA_LIBRARY_LOADED;
+
+	dud_library: /* its also just the end of the loop */
+	RegCloseKey(hkVendorLib);
+	}
+	RegCloseKey(hkSniaHba);
+
+#else /* Unix as opposed to Win32 */
+	FILE		*hbaconf;
+	char		fullline[512];		/* line read from HBA.conf */
+	char		*libraryname;		/* Read in from file HBA.conf */
+	char		*librarypath;		/* Read in from file HBA.conf */
+	char		hbaConfFilePath[256];
+	char		*charPtr;
+	HBA_LIBRARY_INFO	*lib_infop;
+
+	GRAB_MUTEX(&_hbaapi_LL_mutex);
+	if (_hbaapi_librarylist != NULL) {
+		(void) fprintf(stderr,
+		    "HBA_LoadLibrary: previously unfreed "
+		    "libraries exist, call HBA_FreeLibrary().\n");
+		RELEASE_MUTEX(&_hbaapi_LL_mutex);
+		return (HBA_STATUS_ERROR);
+	}
+
+	(void) strcpy(hbaConfFilePath, "/etc/smhba.conf");
+
+	if ((hbaconf = fopen(hbaConfFilePath, "r")) == NULL) {
+		(void) printf("Cannot open %s\n", hbaConfFilePath);
+		RELEASE_MUTEX(&_hbaapi_LL_mutex);
+		return (HBA_STATUS_ERROR);
+	}
+
+	/* Read in each line and load library */
+	while ((hbaconf != NULL) &&
+	    (fgets(fullline, sizeof (fullline), hbaconf))) {
+		/* Skip the comments... */
+		if ((fullline[0] == '#') || (fullline[0] == '\n')) {
+			continue;
+		}
+
+	/* grab first 'thing' in line (if its there) */
+	if ((libraryname = strtok(fullline, " \t\n")) != NULL) {
+		if (strlen(libraryname) >= 64) {
+			(void) fprintf(stderr,
+			    "Library name(%s) in %s is > 64 characters\n",
+			    libraryname, hbaConfFilePath);
+		}
+	}
+	/* grab second 'thing' in line (if its there) */
+	if ((librarypath = strtok(NULL, " \t\n")) != NULL) {
+		if (strlen(librarypath) >= 256) {
+		(void) fprintf(stderr,
+		    "Library path(%s) in %s is > 256 characters\n",
+		    librarypath, hbaConfFilePath);
+		}
+	}
+
+	/* there should be no more 'things' in the line */
+	if ((charPtr = strtok(NULL, " \n\t")) != NULL) {
+		(void) fprintf(stderr, "Extraneous characters (\"%s\") in %s\n",
+		    charPtr, hbaConfFilePath);
+	}
+
+	/* Continue to the next line if library name or path is invalid */
+	if (libraryname == NULL ||
+	    strlen(libraryname) == 0 ||
+	    librarypath == NULL ||
+	    (strlen(librarypath) == 0)) {
+		continue;
+	}
+
+	/*
+	 * Special case....
+	 * Look for loglevel
+	 */
+	if (strcmp(libraryname, "debuglevel") == 0) {
+		_hbaapi_debuglevel = strtol(librarypath, NULL, 10);
+	    /* error handling does the right thing automagically */
+		continue;
+	}
+
+	lib_infop = (HBA_LIBRARY_INFO *)calloc(1, sizeof (HBA_LIBRARY_INFO));
+	if (lib_infop == NULL) {
+		(void) fprintf(stderr, "HBA_LoadLibrary: out of memeory\n");
+		RELEASE_MUTEX(&_hbaapi_LL_mutex);
+		return (HBA_STATUS_ERROR);
+	}
+	lib_infop->status = HBA_LIBRARY_NOT_LOADED;
+	lib_infop->LibraryName = strdup(libraryname);
+	lib_infop->LibraryPath = strdup(librarypath);
+	lib_infop->numOfAdapters = 0;
+	lib_infop->version = UNKNOWN;
+	lib_infop->index = _hbaapi_total_library_count;
+	_hbaapi_total_library_count++;
+	lib_infop->next = _hbaapi_librarylist;
+	_hbaapi_librarylist = lib_infop;
+
+	/* Load the DLL now */
+	if ((lib_infop->hLibrary = dlopen(librarypath, RTLD_LAZY)) == NULL) {
+	    /* printf("unable to load library %s\n", librarypath); */
+		continue;
+	}
+	/* Call the registration function to get the list of pointers */
+	RegisterSMHBAFunc = (SMHBARegisterLibraryFunc)
+	    dlsym(lib_infop->hLibrary, "SMHBA_RegisterLibrary");
+	if (RegisterSMHBAFunc != NULL) {
+		/*
+		 * Load the function points directly into
+		 * the table of functions
+		 */
+		status = ((RegisterSMHBAFunc)
+		    (&lib_infop->ftable.smhbafunctionTable));
+		if (status != HBA_STATUS_OK) {
+			/* library not loaded */
+			continue;
+		} else {
+			lib_infop->version = SMHBA;
+		}
+	} else {
+		RegisterV2Func = (HBARegisterLibraryV2Func)
+		    dlsym(lib_infop->hLibrary, "HBA_RegisterLibraryV2");
+		if (RegisterV2Func != NULL) {
+		/*
+		 * Load the function points directly into
+		 * the table of functions
+		 */
+		status = ((RegisterV2Func)((HBA_ENTRYPOINTSV2 *)
+		    (&lib_infop->ftable.functionTable)));
+		if (status != HBA_STATUS_OK) {
+		    /* library not loaded */
+			continue;
+		} else {
+			lib_infop->version = HBAAPIV2;
+		}
+		} else {
+		/* Maybe the vendor library is only Rev1 */
+		RegisterFunc = (HBARegisterLibraryFunc)
+		    dlsym(lib_infop->hLibrary, "HBA_RegisterLibrary");
+		if (RegisterFunc == NULL) {
+		    /* This function is required */
+			(void) fprintf(stderr,
+			    "HBA_LoadLibrary: vendor specific RegisterLibrary "
+			    "function not found.  lib: %s\n", librarypath);
+			DEBUG(1, "HBA_LoadLibrary: vendor specific "
+			    "RegisterLibrary function not found.  lib: %s\n",
+			    librarypath, 0, 0);
+			continue;
+		}
+		/*
+		 * Load the function points directly into
+		 * the table of functions
+		 */
+		status = ((RegisterFunc)
+		    ((HBA_ENTRYPOINTS *)(&lib_infop->ftable.functionTable)));
+		if (status != HBA_STATUS_OK) {
+		    /* library not loaded */
+			(void) fprintf(stderr,
+			    "HBA_LoadLibrary: vendor specific RegisterLibrary "
+			    "function encountered an error.  lib: %s\n",
+			    librarypath);
+			DEBUG(1,
+			    "HBA_LoadLibrary: vendor specific RegisterLibrary "
+			    "function encountered an error. lib: %s\n",
+			    librarypath, 0, 0);
+			continue;
+		} else {
+			lib_infop->version = HBAAPI;
+		}
+		}
+	}
+
+	/* successfully loaded library */
+	/*
+	 * SM-HBA and HBAAPI has a seperate handler for GetVersion but
+	 * they have the same function signature so use the same variable here.
+	 */
+	if ((GetVersionFunc = FUNCCOMMON(lib_infop, GetVersionHandler))
+	    == NULL) {
+		continue;
+	}
+	if (lib_infop->version == SMHBA) {
+		libversion = ((GetVersionFunc)());
+		if (libversion < SMHBA_LIBVERSION) {
+			(void) printf("Library version mismatch."
+			    "Got %d expected %d.\n",
+			    libversion, SMHBA_LIBVERSION);
+			continue;
+		}
+	} else {
+		libversion = ((GetVersionFunc)());
+	    /* Check the version of this library before loading */
+	    /* Actually... This wrapper is compatible with version 1 */
+		if (libversion < HBA_LIBVERSION) {
+			(void) printf("Library version mismatch."
+			    "Got %d expected %d.\n",
+			    libversion, HBA_LIBVERSION);
+			continue;
+		}
+	}
+
+	DEBUG(1, "%s libversion = %d", librarypath, libversion, 0);
+	LoadLibraryFunc = FUNCCOMMON(lib_infop, LoadLibraryHandler);
+	if (LoadLibraryFunc == NULL) {
+	    /* this function is required */
+		(void) fprintf(stderr,
+		    "HBA_LoadLibrary: vendor specific LoadLibrary "
+		    "function not found.  lib: %s\n", librarypath);
+		DEBUG(1, "HBA_LoadLibrary: vendor specific LoadLibrary "
+		    "function not found.  lib: %s\n", librarypath, 0, 0);
+		continue;
+	}
+	/* Initialize this library */
+	if ((status = ((LoadLibraryFunc)())) != HBA_STATUS_OK) {
+	    /* maybe this should be a printf so that we CANNOT miss it */
+		(void) fprintf(stderr,
+		    "HBA_LoadLibrary: Encounterd and error loading: %s",
+		    librarypath);
+		DEBUG(1, "Encounterd and error loading: %s", librarypath, 0, 0);
+		DEBUG(1, "  HBA_STATUS: %d", status, 0, 0);
+		continue;
+	}
+	/* successfully loaded library */
+	lib_infop->status = HBA_LIBRARY_LOADED;
+	}
+#endif /* WIN32 or UNIX */
+#ifdef POSIX_THREADS
+	/*
+	 * The _hbaapi_LL_mutex is already grabbed to proctect the caller of
+	 * HBA_FreeLibrary() during loading.
+	 * The mutexes are already initialized
+	 * with PTHREAD_MUTEX_INITIALIZER.  Do we need to init again?
+	 * Keeping the code from HBAAPI source...
+	 */
+	ret = pthread_mutex_init(&_hbaapi_AL_mutex, NULL);
+	if (ret == 0) {
+		ret = pthread_mutex_init(&_hbaapi_AAE_mutex, NULL);
+	}
+	if (ret == 0) {
+		ret = pthread_mutex_init(&_hbaapi_AE_mutex, NULL);
+	}
+	if (ret == 0) {
+		ret = pthread_mutex_init(&_hbaapi_APE_mutex, NULL);
+	}
+	if (ret == 0) {
+		ret = pthread_mutex_init(&_hbaapi_APSE_mutex, NULL);
+	}
+	if (ret == 0) {
+		ret = pthread_mutex_init(&_hbaapi_TE_mutex, NULL);
+	}
+	if (ret == 0) {
+		ret = pthread_mutex_init(&_smhba_AAE_mutex, NULL);
+	}
+	if (ret == 0) {
+		ret = pthread_mutex_init(&_smhba_AE_mutex, NULL);
+	}
+	if (ret == 0) {
+		ret = pthread_mutex_init(&_smhba_APE_mutex, NULL);
+	}
+	if (ret == 0) {
+		ret = pthread_mutex_init(&_smhba_APSE_mutex, NULL);
+	}
+	if (ret == 0) {
+		ret = pthread_mutex_init(&_smhba_TE_mutex, NULL);
+	}
+	if (ret == 0) {
+		ret = pthread_mutex_init(&_hbaapi_LE_mutex, NULL);
+	}
+	if (ret != 0) {
+		perror("pthread_mutex_init - HBA_LoadLibrary");
+		RELEASE_MUTEX(&_hbaapi_LL_mutex);
+		return (HBA_STATUS_ERROR);
+	}
+	RELEASE_MUTEX(&_hbaapi_LL_mutex);
+#elif defined(WIN32)
+	InitializeCriticalSection(&_hbaapi_LL_mutex);
+	InitializeCriticalSection(&_hbaapi_AL_mutex);
+	InitializeCriticalSection(&_hbaapi_AAE_mutex);
+	InitializeCriticalSection(&_hbaapi_AE_mutex);
+	InitializeCriticalSection(&_hbaapi_APE_mutex);
+	InitializeCriticalSection(&_hbaapi_APSE_mutex);
+	InitializeCriticalSection(&_hbaapi_TE_mutex);
+	InitializeCriticalSection(&_hbaapi_LE_mutex);
+	InitializeCriticalSection(&_smhba_AAE_mutex);
+	InitializeCriticalSection(&_smhba_AE_mutex);
+	InitializeCriticalSection(&_smhba_APE_mutex);
+	InitializeCriticalSection(&_smhba_APSE_mutex);
+	InitializeCriticalSection(&_smhba_TE_mutex);
+#endif
+
+	return (HBA_STATUS_OK);
+}
+
+HBA_STATUS
+HBA_FreeLibrary() {
+    HBAFreeLibraryFunc	FreeLibraryFunc;
+/* LINTED E_FUNC_SET_NOT_USED */
+    HBA_STATUS		status;
+    HBA_LIBRARY_INFO	*lib_infop;
+    HBA_LIBRARY_INFO	*lib_next;
+    HBA_ADAPTERCALLBACK_ELEM
+			***listp;
+    HBA_ADAPTER_INFO	*adapt_infop;
+    HBA_ADAPTER_INFO	*adapt_next;
+
+    GRAB_MUTEX(&_hbaapi_LL_mutex);
+    if (_hbaapi_librarylist == NULL) {
+	RELEASE_MUTEX(&_hbaapi_LL_mutex);
+	return (HBA_STATUS_ERROR_NOT_LOADED);
+	}
+
+    GRAB_MUTEX(&_hbaapi_AL_mutex);
+
+    DEBUG(1, "HBA_FreeLibrary()", 0, 0, 0);
+    for (lib_infop = _hbaapi_librarylist; lib_infop != NULL;
+	    lib_infop = lib_next) {
+	lib_next = lib_infop->next;
+	if (lib_infop->status == HBA_LIBRARY_LOADED) {
+	    FreeLibraryFunc = FUNCCOMMON(lib_infop, FreeLibraryHandler);
+	    if (FreeLibraryFunc != NULL) {
+		/* Free this library */
+		status = ((FreeLibraryFunc)());
+		DEBUG(1, "HBA_FreeLibrary() Failed %d", status, 0, 0);
+	    }
+#ifdef WIN32
+	    FreeLibrary(lib_infop->hLibrary);	/* Unload DLL from memory */
+#else
+	    (void) dlclose(lib_infop->hLibrary); /* Unload DLL from memory */
+#endif
+	}
+#ifndef WIN32
+	free(lib_infop->LibraryName);
+#endif
+	free(lib_infop->LibraryPath);
+	free(lib_infop);
+
+	}
+    _hbaapi_librarylist = NULL;
+	/*
+	 * OK, now all functions are disabled except for LoadLibrary,
+	 * Hope no other thread calls it before we have returned
+	 */
+    _hbaapi_total_library_count = 0;
+
+    for (adapt_infop = _hbaapi_adapterlist;
+	    adapt_infop != NULL;
+	    adapt_infop = adapt_next) {
+		adapt_next = adapt_infop->next;
+		free(adapt_infop->name);
+		free(adapt_infop);
+	}
+    _hbaapi_adapterlist = NULL;
+    _hbaapi_total_adapter_count = 0;
+
+	/*
+	 * Free up the callbacks, this is not the most efficient, but it works
+	 */
+	while ((volatile HBA_ADAPTERCALLBACK_ELEM *)
+	    _hbaapi_adapteraddevents_callback_list
+	    != NULL) {
+	(void) local_remove_callback((HBA_CALLBACKHANDLE)
+	    _hbaapi_adapteraddevents_callback_list);
+	}
+	while ((volatile HBA_ADAPTERCALLBACK_ELEM *)
+	    _smhba_adapteraddevents_callback_list
+	    != NULL) {
+	(void) local_remove_callback((HBA_CALLBACKHANDLE)
+	    _smhba_adapteraddevents_callback_list);
+	}
+    for (listp = cb_lists_array; *listp != NULL; listp++) {
+	while ((volatile HBA_ADAPTERCALLBACK_ELEM ***)**listp != NULL) {
+	    (void) local_remove_callback((HBA_CALLBACKHANDLE)**listp);
+	}
+	}
+
+    RELEASE_MUTEX(&_hbaapi_AL_mutex);
+    RELEASE_MUTEX(&_hbaapi_LL_mutex);
+
+#ifdef USESYSLOG
+    closelog();
+#endif
+#ifdef USELOGFILE
+    if (_hbaapi_debug_fd != NULL) {
+	fclose(_hbaapi_debug_fd);
+	}
+    _hbaapi_debug_fd = NULL;
+#endif
+#ifdef POSIX_THREADS
+	/* this will unlock them as well, but who cares */
+	(void) pthread_mutex_destroy(&_hbaapi_LE_mutex);
+	(void) pthread_mutex_destroy(&_hbaapi_TE_mutex);
+	(void) pthread_mutex_destroy(&_hbaapi_APSE_mutex);
+	(void) pthread_mutex_destroy(&_hbaapi_APE_mutex);
+	(void) pthread_mutex_destroy(&_hbaapi_AE_mutex);
+	(void) pthread_mutex_destroy(&_hbaapi_AAE_mutex);
+	(void) pthread_mutex_destroy(&_smhba_TE_mutex);
+	(void) pthread_mutex_destroy(&_smhba_APSE_mutex);
+	(void) pthread_mutex_destroy(&_smhba_APE_mutex);
+	(void) pthread_mutex_destroy(&_smhba_AE_mutex);
+	(void) pthread_mutex_destroy(&_smhba_AAE_mutex);
+	(void) pthread_mutex_destroy(&_hbaapi_AL_mutex);
+	(void) pthread_mutex_destroy(&_hbaapi_LL_mutex);
+#elif defined(WIN32)
+    DeleteCriticalSection(&_hbaapi_LL_mutex);
+    DeleteCriticalSection(&_hbaapi_AL_mutex);
+    DeleteCriticalSection(&_hbaapi_AAE_mutex);
+    DeleteCriticalSection(&_hbaapi_AE_mutex);
+    DeleteCriticalSection(&_hbaapi_APE_mutex);
+    DeleteCriticalSection(&_hbaapi_APSE_mutex);
+    DeleteCriticalSection(&_hbaapi_TE_mutex);
+    DeleteCriticalSection(&_hbaapi_LE_mutex);
+    DeleteCriticalSection(&_smhba_TE_mutex);
+    DeleteCriticalSection(&_smhba_APSE_mutex);
+    DeleteCriticalSection(&_smhba_APE_mutex);
+    DeleteCriticalSection(&_smhba_AE_mutex);
+    DeleteCriticalSection(&_smhba_AAE_mutex);
+#endif
+
+	return (HBA_STATUS_OK);
+}
+
+/*
+ * The API used to use fixed size tables as its primary data structure.
+ * Indexing from 1 to N identified each adapters.  Now the adapters are
+ * on a linked list.  There is a unique "index" foreach each adapter.
+ * Adapters always keep their index, even if they are removed from the
+ * hardware.  The only time the indexing is reset is on HBA_FreeLibrary
+ */
+HBA_UINT32
+HBA_GetNumberOfAdapters()
+{
+	int j = 0;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBAGetNumberOfAdaptersFunc GetNumberOfAdaptersFunc;
+	HBAGetAdapterNameFunc GetAdapterNameFunc;
+	HBA_BOOLEAN		found_name;
+	HBA_ADAPTER_INFO	*adapt_infop;
+	HBA_STATUS		status;
+
+	char adaptername[256];
+	int num_adapters; /* local */
+
+	if (_hbaapi_librarylist == NULL) {
+		return (0);
+	}
+	GRAB_MUTEX(&_hbaapi_LL_mutex); /* pay attention to order */
+	GRAB_MUTEX(&_hbaapi_AL_mutex);
+
+	for (lib_infop = _hbaapi_librarylist;
+	    lib_infop != NULL;
+	    lib_infop = lib_infop->next) {
+
+	if (lib_infop->status != HBA_LIBRARY_LOADED) {
+		continue;
+	}
+
+	GetNumberOfAdaptersFunc =
+	    FUNCCOMMON(lib_infop, GetNumberOfAdaptersHandler);
+	if (GetNumberOfAdaptersFunc == NULL)  {
+		continue;
+	}
+	num_adapters = ((GetNumberOfAdaptersFunc)());
+#ifndef WIN32
+	DEBUG(1, "HBAAPI: num_adapters for %s = %d\n",
+	    lib_infop->LibraryName, num_adapters, 0);
+#else
+	DEBUG(1, "HBAAPI: num_adapters for %s = %d\n",
+	    lib_infop->LibraryPath, num_adapters, 0);
+#endif
+
+	/* Also get the names of all the adapters here and cache */
+	GetAdapterNameFunc = FUNCCOMMON(lib_infop, GetAdapterNameHandler);
+	if (GetAdapterNameFunc == NULL) {
+		continue;
+	}
+
+	for (j = 0; j < num_adapters; j++) {
+		found_name = 0;
+		status = (GetAdapterNameFunc)(j, (char *)&adaptername);
+		if (status == HBA_STATUS_OK) {
+		for (adapt_infop = _hbaapi_adapterlist;
+		    adapt_infop != NULL;
+		    adapt_infop = adapt_infop->next) {
+			/*
+			 * check for duplicates, really,
+			 * this may just be a second
+			 * call to this function
+			 * ??? how do we know when a name becomes stale?
+			 */
+			if (strcmp(adaptername, adapt_infop->name) == 0) {
+				/* already got this one */
+				found_name++;
+			break;
+			}
+		}
+		if (found_name != 0) {
+			continue;
+		}
+		}
+
+		adapt_infop = (HBA_ADAPTER_INFO *)
+		    calloc(1, sizeof (HBA_ADAPTER_INFO));
+		if (adapt_infop == NULL) {
+#ifndef WIN32
+		(void) fprintf(stderr,
+		    "HBA_GetNumberOfAdapters: calloc failed"
+		    " on sizeof:%lu\n",
+		    (unsigned long)(sizeof (HBA_ADAPTER_INFO)));
+#endif
+		RELEASE_MUTEX(&_hbaapi_AL_mutex);
+		RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex,
+		    _hbaapi_total_adapter_count);
+		}
+		if ((adapt_infop->GNstatus = status) == HBA_STATUS_OK) {
+		adapt_infop->name = strdup(adaptername);
+		} else {
+		char dummyname[512];
+		(void) sprintf(dummyname, "NULLADAPTER-%255s-%03d",
+		    lib_infop->LibraryPath, _hbaapi_total_adapter_count);
+		dummyname[511] = '\0';
+		adapt_infop->name = strdup(dummyname);
+		}
+		lib_infop->numOfAdapters++;
+		adapt_infop->library = lib_infop;
+		adapt_infop->next = _hbaapi_adapterlist;
+		adapt_infop->index = _hbaapi_total_adapter_count;
+		_hbaapi_adapterlist = adapt_infop;
+		_hbaapi_total_adapter_count++;
+	}
+	}
+	RELEASE_MUTEX(&_hbaapi_AL_mutex);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, _hbaapi_total_adapter_count);
+}
+
+HBA_STATUS
+HBA_GetAdapterName(
+    HBA_UINT32 adapterindex,
+    char *adaptername)
+{
+	HBA_ADAPTER_INFO	*adapt_infop;
+	HBA_STATUS		ret = HBA_STATUS_ERROR_ILLEGAL_INDEX;
+
+	if (adaptername == NULL) {
+		DEBUG(1, "HBA_GetAdapterName: NULL pointer adatpername",
+		    0, 0, 0);
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	/*
+	 * The adapter index is from old code, but we have
+	 * to support it.  Go down the list looking for
+	 * the adapter
+	 */
+	ARE_WE_INITED();
+	GRAB_MUTEX(&_hbaapi_AL_mutex);
+	*adaptername = '\0';
+	for (adapt_infop = _hbaapi_adapterlist;
+	    adapt_infop != NULL;
+	    adapt_infop = adapt_infop->next) {
+
+	if (adapt_infop->index == adapterindex) {
+		if (adapt_infop->name != NULL &&
+		    adapt_infop->GNstatus == HBA_STATUS_OK) {
+		(void) strcpy(adaptername, adapt_infop->name);
+		} else {
+		*adaptername = '\0';
+		}
+		ret = adapt_infop->GNstatus;
+		break;
+	}
+	}
+	DEBUG(2, "GetAdapterName for index:%d ->%s",
+	    adapterindex, adaptername, 0);
+	RELEASE_MUTEX_RETURN(&_hbaapi_AL_mutex, ret);
+}
+
+HBA_HANDLE
+HBA_OpenAdapter(char *adaptername)
+{
+	HBA_HANDLE		handle;
+	HBAOpenAdapterFunc	OpenAdapterFunc;
+	HBA_ADAPTER_INFO	*adapt_infop;
+	HBA_LIBRARY_INFO	*lib_infop;
+
+	DEBUG(2, "OpenAdapter: %s", adaptername, 0, 0);
+
+	handle = HBA_HANDLE_INVALID;
+	if (_hbaapi_librarylist == NULL) {
+		return (handle);
+	}
+	if (adaptername == NULL) {
+		DEBUG(1, "HBA_OpenAdapter: NULL pointer adatpername",
+		    0, 0, 0);
+		return (handle);
+	}
+	GRAB_MUTEX(&_hbaapi_AL_mutex);
+	for (adapt_infop = _hbaapi_adapterlist;
+	    adapt_infop != NULL;
+	    adapt_infop = adapt_infop->next) {
+	if (strcmp(adaptername, adapt_infop->name) != 0) {
+		continue;
+	}
+	lib_infop = adapt_infop->library;
+	OpenAdapterFunc = FUNCCOMMON(lib_infop, OpenAdapterHandler);
+
+	if (OpenAdapterFunc != NULL) {
+	    /* retrieve the vendor handle */
+		handle = (OpenAdapterFunc)(adaptername);
+		if (handle != 0) {
+		/* or this with the library index to get the common handle */
+		handle = HBA_HANDLE_FROM_LOCAL(lib_infop->index, handle);
+		}
+	}
+	break;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_AL_mutex, handle);
+}
+
+/*
+ * Finding an adapter with matching WWN.
+ */
+HBA_STATUS
+HBA_OpenAdapterByWWN(HBA_HANDLE *phandle, HBA_WWN nodeWWN) {
+    HBA_HANDLE		handle;
+    HBA_LIBRARY_INFO	*lib_infop;
+    HBAGetNumberOfAdaptersFunc
+			GetNumberOfAdaptersFunc;
+    HBAOpenAdapterByWWNFunc
+			OpenAdapterFunc;
+    HBA_STATUS		status;
+
+    DEBUG(2, "OpenAdapterByWWN: %s", WWN2STR1(&nodeWWN), 0, 0);
+    ARE_WE_INITED();
+
+	*phandle = HBA_HANDLE_INVALID;
+
+    GRAB_MUTEX(&_hbaapi_LL_mutex);
+    for (lib_infop = _hbaapi_librarylist;
+	    lib_infop != NULL;
+	    lib_infop = lib_infop->next) {
+
+	status = HBA_STATUS_ERROR_ILLEGAL_WWN;
+
+	if (lib_infop->status != HBA_LIBRARY_LOADED) {
+	    continue;
+	}
+
+	/* only for HBAAPIV2 */
+	if (lib_infop->version != HBAAPIV2) {
+	    continue;
+	}
+
+	GetNumberOfAdaptersFunc =
+		FUNCCOMMON(lib_infop, GetNumberOfAdaptersHandler);
+	if (GetNumberOfAdaptersFunc == NULL)  {
+	    continue;
+	}
+
+	/* look for new hardware */
+	(void) ((GetNumberOfAdaptersFunc)());
+
+	OpenAdapterFunc =
+	    lib_infop->ftable.functionTable.OpenAdapterByWWNHandler;
+	if (OpenAdapterFunc == NULL) {
+	    continue;
+	}
+	/*
+	 * We do not know if the WWN is known by this vendor,
+	 * just try it
+	 */
+	if ((status = (OpenAdapterFunc)(&handle, nodeWWN)) != HBA_STATUS_OK) {
+	    continue;
+	}
+	/* OK, make a vendor non-specific handle */
+	*phandle = HBA_HANDLE_FROM_LOCAL(lib_infop->index, handle);
+	status = HBA_STATUS_OK;
+	break;
+	}
+    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+void
+HBA_RefreshAdapterConfiguration() {
+    DEBUG(2, "HBA_RefreshAdapterConfiguration", 0, 0, 0);
+	(void) HBA_GetNumberOfAdapters();
+}
+
+HBA_UINT32
+HBA_GetVersion() {
+    DEBUG(2, "HBA_GetVersion", 0, 0, 0);
+	return (HBA_LIBVERSION);
+}
+
+/*
+ * This function is VERY OS dependent.  Wing it as best you can.
+ */
+HBA_UINT32
+HBA_GetWrapperLibraryAttributes(
+    HBA_LIBRARYATTRIBUTES *attributes)
+{
+
+	DEBUG(2, "HBA_GetWrapperLibraryAttributes", 0, 0, 0);
+
+	if (attributes == NULL) {
+		DEBUG(1, "HBA_GetWrapperLibraryAttributes:"
+		    "NULL pointer attributes",
+		    0, 0, 0);
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	(void) memset(attributes, 0, sizeof (HBA_LIBRARYATTRIBUTES));
+
+#if defined(SOLARIS)
+	if ((handle = dlopen("libHBAAPI.so", RTLD_NOW)) != NULL) {
+	if (dlinfo(handle, RTLD_DI_LINKMAP, &map) >= 0) {
+		for (mp = map; mp != NULL; mp = mp->l_next) {
+		if (strlen(map->l_name) < 256) {
+			(void) strcpy(attributes->LibPath, map->l_name);
+		}
+		}
+	}
+	}
+#elif defined(WIN32)
+	HMODULE module;
+
+	/* No need to do anything with the module handle */
+	/* It wasn't alloocated so it doesn't need to be freed */
+	module = GetModuleHandle("HBAAPI");
+	if (module != NULL) {
+		if (GetModuleFileName(module, attributes->LibPath,
+		    sizeof (attributes->LibPath)) == 0) {
+			attributes->LibPath[0] = '\0';
+		}
+	}
+#endif
+#if defined(VENDOR)
+	(void) strcpy(attributes->VName, VENDOR);
+#else
+	attributes->VName[0] = '\0';
+#endif
+#if defined(VERSION)
+	(void) strcpy(attributes->VVersion, VERSION);
+#else
+	attributes->VVersion[0] = '\0';
+#endif
+#if defined(BUILD_DATE)
+#if defined(WIN32)
+	int matchCount;
+	matchCount = sscanf(BUILD_DATE, "%u/%u/%u %u:%u:%u",
+	    &attributes->build_date.tm_year,
+	    &attributes->build_date.tm_mon,
+	    &attributes->build_date.tm_mday,
+	    &attributes->build_date.tm_hour,
+	    &attributes->build_date.tm_min,
+	    &attributes->build_date.tm_sec);
+
+	if (matchCount != 6) {
+		memset(&attributes->build_date, 0, sizeof (struct tm));
+	} else {
+		attributes->build_date.tm_year -= 1900;
+		attributes->build_date.tm_isdst = -1;
+	}
+#else
+	if (strptime(BUILD_DATE,
+	    "%Y/%m/%d %T %Z", &(attributes->build_date)) == NULL) {
+		(void) memset(&attributes->build_date, 0, sizeof (struct tm));
+	}
+#endif
+#else
+	(void) memset(&attributes->build_date, 0, sizeof (struct tm));
+#endif
+	return (2);
+}
+
+/*
+ * Callback registation and handling
+ */
+HBA_STATUS
+HBA_RemoveCallback(HBA_CALLBACKHANDLE cbhandle) {
+    HBA_STATUS	status;
+
+    DEBUG(2, "HBA_RemoveCallback", 0, 0, 0);
+    ARE_WE_INITED();
+
+    GRAB_MUTEX(&_hbaapi_LL_mutex);
+    status = local_remove_callback(cbhandle);
+    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+/* Adapter Add Events ************************************************* */
+static void
+/* LINTED E_FUNC_ARG_UNUSED */
+adapteraddevents_callback(void *data, HBA_WWN PortWWN, HBA_UINT32 eventType) {
+    HBA_ALLADAPTERSCALLBACK_ELEM	*cbp;
+
+    DEBUG(3, "AddAdapterEvent, port: %s", WWN2STR1(&PortWWN), 0, 0);
+
+    GRAB_MUTEX(&_hbaapi_AAE_mutex);
+    for (cbp = _hbaapi_adapteraddevents_callback_list;
+	    cbp != NULL;
+	    cbp = cbp->next) {
+	(*cbp->callback)(data, PortWWN, HBA_EVENT_ADAPTER_ADD);
+	}
+    RELEASE_MUTEX(&_hbaapi_AAE_mutex);
+
+}
+
+HBA_STATUS
+HBA_RegisterForAdapterAddEvents(
+    void		(*callback)(
+	void		*data,
+	HBA_WWN		PortWWN,
+	HBA_UINT32	eventType),
+	void		*userData,
+    HBA_CALLBACKHANDLE *callbackHandle) {
+
+    HBA_ALLADAPTERSCALLBACK_ELEM	*cbp;
+    HBA_VENDORCALLBACK_ELEM		*vcbp;
+    HBA_VENDORCALLBACK_ELEM		*vendorhandlelist;
+    HBARegisterForAdapterAddEventsFunc	registeredfunc;
+    HBA_STATUS				status = HBA_STATUS_OK;
+    HBA_STATUS				failure = HBA_STATUS_OK;
+    HBA_LIBRARY_INFO			*lib_infop;
+    int					registered_cnt = 0;
+    int					vendor_cnt = 0;
+    int					not_supported_cnt = 0;
+    int					status_OK_bar_cnt = 0;
+    int					status_OK_cnt = 0;
+
+    DEBUG(2, "HBA_RegisterForAdapterAddEvents", 0, 0, 0);
+    ARE_WE_INITED();
+
+    cbp = (HBA_ALLADAPTERSCALLBACK_ELEM *)
+	calloc(1, sizeof (HBA_ALLADAPTERSCALLBACK_ELEM));
+	*callbackHandle = (HBA_CALLBACKHANDLE) cbp;
+	if (cbp == NULL) {
+#ifndef WIN32
+	(void) fprintf(stderr,
+		"HBA_RegisterForAdapterAddEvents: calloc failed "
+		"for %lu bytes\n",
+		(unsigned long)(sizeof (HBA_ALLADAPTERSCALLBACK_ELEM)));
+#endif
+	return (HBA_STATUS_ERROR);
+	}
+
+    GRAB_MUTEX(&_hbaapi_LL_mutex);
+    GRAB_MUTEX(&_hbaapi_AAE_mutex);
+    cbp->callback = callback;
+    cbp->next = _hbaapi_adapteraddevents_callback_list;
+    _hbaapi_adapteraddevents_callback_list = cbp;
+	/*
+	 * Need to release the mutex now incase the vendor function invokes the
+	 * callback.  We will grap the mutex later to attach the vendor handle
+	 * list to the callback structure
+	 */
+    RELEASE_MUTEX(&_hbaapi_AAE_mutex);
+
+	/*
+	 * now create a list of vendors (vendor libraryies, NOT ADAPTERS)
+	 * that have successfully registerred
+	 */
+	vendorhandlelist = NULL;
+    for (lib_infop = _hbaapi_librarylist;
+	    lib_infop != NULL;
+	    lib_infop = lib_infop->next) {
+
+	/* only for HBAAPI V2 */
+	if ((lib_infop->version != HBAAPIV2)) {
+	    continue;
+	} else {
+	    vendor_cnt++;
+	}
+
+	registeredfunc =
+	    lib_infop->ftable.functionTable.RegisterForAdapterAddEventsHandler;
+	if (registeredfunc == NULL) {
+	    continue;
+	}
+
+	vcbp = (HBA_VENDORCALLBACK_ELEM *)
+	    calloc(1, sizeof (HBA_VENDORCALLBACK_ELEM));
+	if (vcbp == NULL) {
+#ifndef WIN32
+	    (void) fprintf(stderr,
+		    "HBA_RegisterForAdapterAddEvents: "
+		    "calloc failed for %lu bytes\n",
+		    (unsigned long)(sizeof (HBA_VENDORCALLBACK_ELEM)));
+#endif
+	    freevendorhandlelist(vendorhandlelist);
+	    status = HBA_STATUS_ERROR;
+	    break;
+	}
+
+	registered_cnt++;
+	status = (registeredfunc)(adapteraddevents_callback,
+	    userData, &vcbp->vendorcbhandle);
+	if (status == HBA_STATUS_ERROR_NOT_SUPPORTED) {
+	    not_supported_cnt++;
+	    free(vcbp);
+	    continue;
+	} else if (status != HBA_STATUS_OK) {
+	    status_OK_bar_cnt++;
+	    DEBUG(1,
+		    "HBA_RegisterForAdapterAddEvents: Library->%s, Error->%d",
+		    lib_infop->LibraryPath, status, 0);
+#ifndef WIN32
+	    (void) fprintf(stderr,
+		    "HBA_RegisterForAdapterAddEvents: Library->%s, Error->%d",
+		    lib_infop->LibraryPath, status);
+#endif
+	    failure = status;
+	    free(vcbp);
+	    continue;
+	} else {
+	    status_OK_cnt++;
+	}
+	vcbp->lib_info = lib_infop;
+	vcbp->next = vendorhandlelist;
+	vendorhandlelist = vcbp;
+	}
+    if (vendor_cnt == 0) {
+	/* no HBAAPIV2 is deteced.  should be okay? */
+	status = HBA_STATUS_ERROR;
+	} else if (registered_cnt == 0) {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	freevendorhandlelist(vendorhandlelist);
+	(void) local_remove_callback((HBA_CALLBACKHANDLE) cbp);
+	} else if (status_OK_cnt == 0 && not_supported_cnt != 0) {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	} else if (status_OK_cnt == 0) {
+	/*
+	 * At least one vendor library registered this function, but no
+	 * vendor call succeeded
+	 */
+	(void) local_remove_callback((HBA_CALLBACKHANDLE) cbp);
+	status = failure;
+	} else {
+	/* we have had atleast some success, now finish up */
+	GRAB_MUTEX(&_hbaapi_AAE_mutex);
+	/*
+	 * this seems silly, but what if another thread called
+	 * the callback remove
+	 */
+	for (cbp = _hbaapi_adapteraddevents_callback_list;
+	    cbp != NULL; cbp = cbp->next) {
+	    if ((HBA_CALLBACKHANDLE)cbp == *callbackHandle) {
+		/* yup, its still there, hooray */
+		cbp->vendorhandlelist = vendorhandlelist;
+		vendorhandlelist = NULL;
+		break;
+	    }
+	}
+	RELEASE_MUTEX(&_hbaapi_AAE_mutex);
+	if (vendorhandlelist != NULL) {
+		/*
+		 * bummer, somebody removed the callback before we finished
+		 * registration, probably will never happen
+		 */
+	    freevendorhandlelist(vendorhandlelist);
+	    DEBUG(1,
+		    "HBA_RegisterForAdapterAddEvents: HBA_RemoveCallback was "
+		    "called for a handle before registration was finished.",
+		    0, 0, 0);
+	    status = HBA_STATUS_ERROR;
+	} else {
+	    status = HBA_STATUS_OK;
+	}
+	}
+    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+/* Adapter Events (other than add) ************************************** */
+static void
+adapterevents_callback(void *data,
+			HBA_WWN PortWWN,
+			HBA_UINT32 eventType) {
+    HBA_ADAPTERCALLBACK_ELEM	*acbp;
+
+    DEBUG(3, "AdapterEvent, port:%s, eventType:%d", WWN2STR1(&PortWWN),
+	    eventType, 0);
+
+	GRAB_MUTEX(&_hbaapi_AE_mutex);
+	for (acbp = _hbaapi_adapterevents_callback_list;
+	acbp != NULL;
+	acbp = acbp->next) {
+	if (data == (void *)acbp) {
+	    (*acbp->callback)(acbp->userdata, PortWWN, eventType);
+	    break;
+	}
+	}
+    RELEASE_MUTEX(&_hbaapi_AE_mutex);
+}
+HBA_STATUS
+HBA_RegisterForAdapterEvents(
+    void		(*callback) (
+	void		*data,
+	HBA_WWN		PortWWN,
+	HBA_UINT32	eventType),
+    void		*userData,
+    HBA_HANDLE		handle,
+    HBA_CALLBACKHANDLE	*callbackHandle) {
+
+    HBA_ADAPTERCALLBACK_ELEM		*acbp;
+    HBARegisterForAdapterEventsFunc	registeredfunc;
+    HBA_STATUS				status;
+    HBA_LIBRARY_INFO			*lib_infop;
+    HBA_HANDLE				vendorHandle;
+
+    DEBUG(2, "HBA_RegisterForAdapterEvents", 0, 0, 0);
+
+    CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	/* we now have the _hbaapi_LL_mutex */
+
+    registeredfunc =
+	    lib_infop->ftable.functionTable.RegisterForAdapterEventsHandler;
+    if (registeredfunc == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_NOT_SUPPORTED);
+	}
+
+	/*
+	 * that allocated memory is used both as the handle for the
+	 * caller, and as userdata to the vendor call so that on
+	 * callback the specific registration may be recalled
+	 */
+    acbp = (HBA_ADAPTERCALLBACK_ELEM *)
+	calloc(1, sizeof (HBA_ADAPTERCALLBACK_ELEM));
+    if (acbp == NULL) {
+#ifndef WIN32
+	(void) fprintf(stderr,
+		"HBA_RegisterForAdapterEvents: calloc failed for %lu bytes\n",
+		(unsigned long)(sizeof (HBA_ADAPTERCALLBACK_ELEM)));
+#endif
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR);
+	}
+	*callbackHandle = (HBA_CALLBACKHANDLE) acbp;
+    acbp->callback = callback;
+    acbp->userdata = userData;
+    acbp->lib_info = lib_infop;
+
+    status = (registeredfunc)(adapterevents_callback,
+	    (void *)acbp,
+	    vendorHandle,
+	    &acbp->vendorcbhandle);
+    if (status != HBA_STATUS_OK) {
+	free(acbp);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+	}
+
+    GRAB_MUTEX(&_hbaapi_AE_mutex);
+    acbp->next = _hbaapi_adapterevents_callback_list;
+    _hbaapi_adapterevents_callback_list = acbp;
+    RELEASE_MUTEX(&_hbaapi_AE_mutex);
+
+    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_OK);
+}
+
+/* Adapter Port Events ************************************************** */
+static void
+adapterportevents_callback(void *data,
+			    HBA_WWN PortWWN,
+			    HBA_UINT32 eventType,
+			    HBA_UINT32 fabricPortID) {
+    HBA_ADAPTERCALLBACK_ELEM	*acbp;
+
+    DEBUG(3, "AdapterPortEvent, port:%s, eventType:%d fabricPortID:0X%06x",
+	    WWN2STR1(&PortWWN), eventType, fabricPortID);
+
+    GRAB_MUTEX(&_hbaapi_APE_mutex);
+
+    for (acbp = _hbaapi_adapterportevents_callback_list;
+	acbp != NULL;
+	acbp = acbp->next) {
+	if (data == (void *)acbp) {
+	    (*acbp->callback)(acbp->userdata, PortWWN, eventType, fabricPortID);
+	    break;
+	}
+	}
+    RELEASE_MUTEX(&_hbaapi_APE_mutex);
+}
+
+HBA_STATUS
+HBA_RegisterForAdapterPortEvents(
+    void		(*callback) (
+	void		*data,
+	HBA_WWN		PortWWN,
+	HBA_UINT32	eventType,
+	HBA_UINT32	fabricPortID),
+    void		*userData,
+    HBA_HANDLE		handle,
+    HBA_WWN		PortWWN,
+    HBA_CALLBACKHANDLE	*callbackHandle) {
+
+    HBA_ADAPTERCALLBACK_ELEM		*acbp;
+    HBARegisterForAdapterPortEventsFunc	registeredfunc;
+    HBA_STATUS				status;
+    HBA_LIBRARY_INFO			*lib_infop;
+    HBA_HANDLE				vendorHandle;
+
+    DEBUG(2, "HBA_RegisterForAdapterPortEvents for port: %s",
+	    WWN2STR1(&PortWWN), 0, 0);
+
+    CHECKLIBRARYANDVERSION(HBAAPIV2);
+	/* we now have the _hbaapi_LL_mutex */
+
+	registeredfunc =
+	lib_infop->ftable.functionTable.RegisterForAdapterPortEventsHandler;
+    if (registeredfunc == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_NOT_SUPPORTED);
+	}
+
+	/*
+	 * that allocated memory is used both as the handle for the
+	 * caller, and as userdata to the vendor call so that on
+	 * callback the specific registration may be recalled
+	 */
+	acbp = (HBA_ADAPTERCALLBACK_ELEM *)
+	calloc(1, sizeof (HBA_ADAPTERCALLBACK_ELEM));
+    if (acbp == NULL) {
+#ifndef WIN32
+	(void) fprintf(stderr,
+		"HBA_RegisterForAdapterPortEvents: "
+		"calloc failed for %lu bytes\n",
+		(unsigned long)(sizeof (HBA_ADAPTERCALLBACK_ELEM)));
+#endif
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR);
+
+	}
+	*callbackHandle = (HBA_CALLBACKHANDLE) acbp;
+    acbp->callback = callback;
+    acbp->userdata = userData;
+    acbp->lib_info = lib_infop;
+
+    status = (registeredfunc)(adapterportevents_callback,
+	    (void *)acbp,
+	    vendorHandle,
+	    PortWWN,
+	    &acbp->vendorcbhandle);
+    if (status != HBA_STATUS_OK) {
+	free(acbp);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+	}
+
+    GRAB_MUTEX(&_hbaapi_APE_mutex);
+    acbp->next = _hbaapi_adapterportevents_callback_list;
+    _hbaapi_adapterportevents_callback_list = acbp;
+    RELEASE_MUTEX(&_hbaapi_APE_mutex);
+
+    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_OK);
+}
+
+/* Adapter State Events ************************************************ */
+static void
+adapterportstatevents_callback(void *data,
+				HBA_WWN PortWWN,
+				HBA_UINT32 eventType) {
+    HBA_ADAPTERCALLBACK_ELEM	*acbp;
+
+	DEBUG(3, "AdapterPortStatEvent, port:%s, eventType:%d",
+	    WWN2STR1(&PortWWN),
+	    eventType, 0);
+
+    GRAB_MUTEX(&_hbaapi_APSE_mutex);
+    for (acbp = _hbaapi_adapterportstatevents_callback_list;
+	acbp != NULL;
+	acbp = acbp->next) {
+	if (data == (void *)acbp) {
+	    (*acbp->callback)(acbp->userdata, PortWWN, eventType);
+	    return;
+	}
+	}
+    RELEASE_MUTEX(&_hbaapi_APSE_mutex);
+}
+HBA_STATUS
+HBA_RegisterForAdapterPortStatEvents(
+    void		(*callback) (
+	void		*data,
+	HBA_WWN		PortWWN,
+	HBA_UINT32	eventType),
+    void		*userData,
+    HBA_HANDLE		handle,
+    HBA_WWN		PortWWN,
+    HBA_PORTSTATISTICS	stats,
+    HBA_UINT32		statType,
+    HBA_CALLBACKHANDLE	*callbackHandle) {
+
+    HBA_ADAPTERCALLBACK_ELEM	*acbp;
+    HBARegisterForAdapterPortStatEventsFunc
+				registeredfunc;
+    HBA_STATUS			status;
+    HBA_LIBRARY_INFO		*lib_infop;
+    HBA_HANDLE			vendorHandle;
+
+    DEBUG(2, "HBA_RegisterForAdapterPortStatEvents for port: %s",
+	    WWN2STR1(&PortWWN), 0, 0);
+
+    CHECKLIBRARYANDVERSION(HBAAPIV2);
+	/* we now have the _hbaapi_LL_mutex */
+
+    registeredfunc =
+	lib_infop->ftable.functionTable.RegisterForAdapterPortStatEventsHandler;
+    if (registeredfunc == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_NOT_SUPPORTED);
+	}
+
+	/*
+	 * that allocated memory is used both as the handle for the
+	 * caller, and as userdata to the vendor call so that on
+	 * callback the specific registration may be recalled
+	 */
+    acbp = (HBA_ADAPTERCALLBACK_ELEM *)
+	calloc(1, sizeof (HBA_ADAPTERCALLBACK_ELEM));
+    if (acbp == NULL) {
+#ifndef WIN32
+	(void) fprintf(stderr,
+		"HBA_RegisterForAdapterPortStatEvents: "
+		"calloc failed for %lu bytes\n",
+		(unsigned long)(sizeof (HBA_ADAPTERCALLBACK_ELEM)));
+#endif
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR);
+	}
+	*callbackHandle = (HBA_CALLBACKHANDLE) acbp;
+    acbp->callback = callback;
+    acbp->userdata = userData;
+    acbp->lib_info = lib_infop;
+
+    status = (registeredfunc)(adapterportstatevents_callback,
+	    (void *)acbp,
+	    vendorHandle,
+	    PortWWN,
+	    stats,
+	    statType,
+	    &acbp->vendorcbhandle);
+    if (status != HBA_STATUS_OK) {
+	free(acbp);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+	}
+
+    GRAB_MUTEX(&_hbaapi_APSE_mutex);
+    acbp->next = _hbaapi_adapterportstatevents_callback_list;
+    _hbaapi_adapterportstatevents_callback_list = acbp;
+    RELEASE_MUTEX(&_hbaapi_APSE_mutex);
+
+    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_OK);
+}
+
+/* Target Events ******************************************************* */
+static void
+targetevents_callback(void *data,
+    HBA_WWN hbaPortWWN,
+    HBA_WWN discoveredPortWWN,
+    HBA_UINT32 eventType) {
+
+	HBA_ADAPTERCALLBACK_ELEM	*acbp;
+
+    DEBUG(3, "TargetEvent, hbaPort:%s, discoveredPort:%s eventType:%d",
+	    WWN2STR1(&hbaPortWWN), WWN2STR2(&discoveredPortWWN), eventType);
+
+    GRAB_MUTEX(&_hbaapi_TE_mutex);
+    for (acbp = _hbaapi_targetevents_callback_list;
+	acbp != NULL;
+	acbp = acbp->next) {
+	if (data == (void *)acbp) {
+	    (*acbp->callback)(acbp->userdata, hbaPortWWN,
+	    discoveredPortWWN, eventType);
+	    break;
+	}
+	}
+    RELEASE_MUTEX(&_hbaapi_TE_mutex);
+}
+
+HBA_STATUS
+HBA_RegisterForTargetEvents(
+    void		(*callback) (
+	void		*data,
+	HBA_WWN		hbaPortWWN,
+	HBA_WWN		discoveredPortWWN,
+	HBA_UINT32	eventType),
+    void		*userData,
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		discoveredPortWWN,
+    HBA_CALLBACKHANDLE	*callbackHandle,
+    HBA_UINT32		allTargets) {
+
+    HBA_ADAPTERCALLBACK_ELEM
+			*acbp;
+    HBARegisterForTargetEventsFunc
+			registeredfunc;
+    HBA_STATUS		status;
+    HBA_LIBRARY_INFO	*lib_infop;
+    HBA_HANDLE		vendorHandle;
+
+    DEBUG(2, "HBA_RegisterForTargetEvents, hbaPort: %s, discoveredPort: %s",
+	    WWN2STR1(&hbaPortWWN), WWN2STR2(&discoveredPortWWN), 0);
+
+    CHECKLIBRARYANDVERSION(HBAAPIV2);
+	/* we now have the _hbaapi_LL_mutex */
+
+    registeredfunc =
+	    lib_infop->ftable.functionTable.RegisterForTargetEventsHandler;
+    if (registeredfunc == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_NOT_SUPPORTED);
+	}
+
+	/*
+	 * that allocated memory is used both as the handle for the
+	 * caller, and as userdata to the vendor call so that on
+	 * callback the specific registration may be recalled
+	 */
+	acbp = (HBA_ADAPTERCALLBACK_ELEM *)
+	calloc(1, sizeof (HBA_ADAPTERCALLBACK_ELEM));
+    if (acbp == NULL) {
+#ifndef WIN32
+	(void) fprintf(stderr,
+		"HBA_RegisterForTargetEvents: calloc failed for %lu bytes\n",
+		(unsigned long)(sizeof (HBA_ADAPTERCALLBACK_ELEM)));
+#endif
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR);
+	}
+	*callbackHandle = (HBA_CALLBACKHANDLE) acbp;
+    acbp->callback = callback;
+    acbp->userdata = userData;
+    acbp->lib_info = lib_infop;
+
+    status = (registeredfunc)(targetevents_callback,
+	    (void *)acbp,
+	    vendorHandle,
+	    hbaPortWWN,
+	    discoveredPortWWN,
+	    &acbp->vendorcbhandle,
+	    allTargets);
+    if (status != HBA_STATUS_OK) {
+	free(acbp);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+	}
+
+    GRAB_MUTEX(&_hbaapi_TE_mutex);
+    acbp->next = _hbaapi_targetevents_callback_list;
+    _hbaapi_targetevents_callback_list = acbp;
+    RELEASE_MUTEX(&_hbaapi_TE_mutex);
+
+    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_OK);
+}
+
+/* Link Events ********************************************************* */
+static void
+linkevents_callback(void *data,
+    HBA_WWN adapterWWN,
+    HBA_UINT32 eventType,
+    void *pRLIRBuffer,
+    HBA_UINT32 RLIRBufferSize) {
+	HBA_ADAPTERCALLBACK_ELEM	*acbp;
+
+    DEBUG(3, "LinkEvent, hbaWWN:%s, eventType:%d",
+	    WWN2STR1(&adapterWWN), eventType, 0);
+
+    GRAB_MUTEX(&_hbaapi_LE_mutex);
+    for (acbp = _hbaapi_linkevents_callback_list;
+	acbp != NULL;
+	acbp = acbp->next) {
+	if (data == (void *)acbp) {
+	    (*acbp->callback)(acbp->userdata, adapterWWN,
+		eventType, pRLIRBuffer, RLIRBufferSize);
+	    break;
+	}
+	}
+    RELEASE_MUTEX(&_hbaapi_LE_mutex);
+}
+HBA_STATUS
+HBA_RegisterForLinkEvents(
+    void		(*callback) (
+	void		*data,
+	HBA_WWN		adapterWWN,
+	HBA_UINT32	eventType,
+	void		*pRLIRBuffer,
+	HBA_UINT32	RLIRBufferSize),
+    void		*userData,
+    void		*pRLIRBuffer,
+    HBA_UINT32		RLIRBufferSize,
+    HBA_HANDLE		handle,
+    HBA_CALLBACKHANDLE	*callbackHandle) {
+
+    HBA_ADAPTERCALLBACK_ELEM	*acbp;
+    HBARegisterForLinkEventsFunc
+				registeredfunc;
+    HBA_STATUS			status;
+    HBA_LIBRARY_INFO		*lib_infop;
+    HBA_HANDLE			vendorHandle;
+
+    DEBUG(2, "HBA_RegisterForLinkEvents", 0, 0, 0);
+
+    CHECKLIBRARY();
+	/* we now have the _hbaapi_LL_mutex */
+
+    registeredfunc = FUNCCOMMON(lib_infop, RegisterForLinkEventsHandler);
+
+    if (registeredfunc == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_NOT_SUPPORTED);
+	}
+
+	/*
+	 * that allocated memory is used both as the handle for the
+	 * caller, and as userdata to the vendor call so that on
+	 * callback the specific registration may be recalled
+	 */
+    acbp = (HBA_ADAPTERCALLBACK_ELEM *)
+	calloc(1, sizeof (HBA_ADAPTERCALLBACK_ELEM));
+    if (acbp == NULL) {
+#ifndef WIN32
+	(void) fprintf(stderr,
+		"HBA_RegisterForLinkEvents: calloc failed for %lu bytes\n",
+		(unsigned long)(sizeof (HBA_ADAPTERCALLBACK_ELEM)));
+#endif
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR);
+	}
+	*callbackHandle = (HBA_CALLBACKHANDLE) acbp;
+    acbp->callback = callback;
+    acbp->userdata = userData;
+    acbp->lib_info = lib_infop;
+
+    status = (registeredfunc)(linkevents_callback,
+	    (void *)acbp,
+	    pRLIRBuffer,
+	    RLIRBufferSize,
+	    vendorHandle,
+	    &acbp->vendorcbhandle);
+    if (status != HBA_STATUS_OK) {
+	free(acbp);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+	}
+
+    GRAB_MUTEX(&_hbaapi_LE_mutex);
+    acbp->next = _hbaapi_linkevents_callback_list;
+    _hbaapi_linkevents_callback_list = acbp;
+    RELEASE_MUTEX(&_hbaapi_LE_mutex);
+
+    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_OK);
+}
+
+/*
+ * All of the functions below are almost passthru functions to the
+ * vendor specific function
+ */
+
+void
+HBA_CloseAdapter(HBA_HANDLE handle) {
+    HBA_STATUS		status;
+    HBA_LIBRARY_INFO	*lib_infop;
+    HBA_HANDLE		vendorHandle;
+    HBACloseAdapterFunc CloseAdapterFunc;
+
+    DEBUG(2, "HBA_CloseAdapter", 0, 0, 0);
+
+    status = HBA_CheckLibrary(handle, &lib_infop, &vendorHandle);
+    if (status == HBA_STATUS_OK) {
+	CloseAdapterFunc = FUNCCOMMON(lib_infop, CloseAdapterHandler);
+	if (CloseAdapterFunc != NULL) {
+	    ((CloseAdapterFunc)(vendorHandle));
+	}
+	RELEASE_MUTEX(&_hbaapi_LL_mutex);
+	}
+}
+
+HBA_STATUS
+HBA_GetAdapterAttributes(
+    HBA_HANDLE		handle,
+    HBA_ADAPTERATTRIBUTES
+			*hbaattributes)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAGetAdapterAttributesFunc GetAdapterAttributesFunc;
+
+	DEBUG(2, "HBA_GetAdapterAttributes", 0, 0, 0);
+
+	CHECKLIBRARY();
+
+	if (lib_infop->version == SMHBA) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INCOMPATIBLE);
+	}
+
+	GetAdapterAttributesFunc =
+	    lib_infop->ftable.functionTable.GetAdapterAttributesHandler;
+	if (GetAdapterAttributesFunc != NULL) {
+	status = ((GetAdapterAttributesFunc)(vendorHandle, hbaattributes));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_GetAdapterPortAttributes(
+    HBA_HANDLE		handle,
+    HBA_UINT32		portindex,
+    HBA_PORTATTRIBUTES	*portattributes)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAGetAdapterPortAttributesFunc
+	    GetAdapterPortAttributesFunc;
+
+	DEBUG(2, "HBA_GetAdapterPortAttributes", 0, 0, 0);
+
+	CHECKLIBRARY();
+	if (lib_infop->version == SMHBA) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INCOMPATIBLE);
+	}
+
+	GetAdapterPortAttributesFunc =
+	    lib_infop->ftable.functionTable.GetAdapterPortAttributesHandler;
+	if (GetAdapterPortAttributesFunc != NULL) {
+	status = ((GetAdapterPortAttributesFunc)
+	    (vendorHandle, portindex, portattributes));
+	} else {
+		status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_GetPortStatistics(
+    HBA_HANDLE		handle,
+    HBA_UINT32		portindex,
+    HBA_PORTSTATISTICS	*portstatistics)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAGetPortStatisticsFunc
+	    GetPortStatisticsFunc;
+
+	DEBUG(2, "HBA_GetPortStatistics", 0, 0, 0);
+
+	CHECKLIBRARY();
+	if (lib_infop->version == SMHBA) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INCOMPATIBLE);
+	}
+
+	GetPortStatisticsFunc =
+	    lib_infop->ftable.functionTable.GetPortStatisticsHandler;
+	if (GetPortStatisticsFunc != NULL) {
+	status = ((GetPortStatisticsFunc)
+	    (vendorHandle, portindex, portstatistics));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_GetDiscoveredPortAttributes(
+    HBA_HANDLE		handle,
+    HBA_UINT32		portindex,
+    HBA_UINT32		discoveredportindex,
+    HBA_PORTATTRIBUTES	*portattributes)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAGetDiscoveredPortAttributesFunc
+	    GetDiscoveredPortAttributesFunc;
+
+	DEBUG(2, "HBA_GetDiscoveredPortAttributes", 0, 0, 0);
+
+	CHECKLIBRARY();
+	if (lib_infop->version == SMHBA) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INCOMPATIBLE);
+	}
+
+	GetDiscoveredPortAttributesFunc =
+	    lib_infop->ftable.functionTable.GetDiscoveredPortAttributesHandler;
+	if (GetDiscoveredPortAttributesFunc != NULL)  {
+	status = ((GetDiscoveredPortAttributesFunc)
+	    (vendorHandle, portindex, discoveredportindex,
+	    portattributes));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_GetPortAttributesByWWN(
+    HBA_HANDLE		handle,
+    HBA_WWN		PortWWN,
+    HBA_PORTATTRIBUTES	*portattributes)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAGetPortAttributesByWWNFunc
+	    GetPortAttributesByWWNFunc;
+
+	DEBUG(2, "HBA_GetPortAttributesByWWN: %s", WWN2STR1(&PortWWN), 0, 0);
+
+	CHECKLIBRARY();
+	if (lib_infop->version == SMHBA) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INCOMPATIBLE);
+	}
+
+	GetPortAttributesByWWNFunc =
+	    lib_infop->ftable.functionTable.GetPortAttributesByWWNHandler;
+	if (GetPortAttributesByWWNFunc != NULL) {
+	status = ((GetPortAttributesByWWNFunc)
+	    (vendorHandle, PortWWN, portattributes));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SendCTPassThru(
+    HBA_HANDLE		handle,
+    void		*pReqBuffer,
+    HBA_UINT32		ReqBufferSize,
+    void		*pRspBuffer,
+    HBA_UINT32		RspBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASendCTPassThruFunc
+	    SendCTPassThruFunc;
+
+	DEBUG(2, "HBA_SendCTPassThru", 0, 0, 0);
+
+	CHECKLIBRARY();
+	if (lib_infop->version == SMHBA) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INCOMPATIBLE);
+	}
+
+	SendCTPassThruFunc =
+	    lib_infop->ftable.functionTable.SendCTPassThruHandler;
+	if (SendCTPassThruFunc != NULL) {
+	status = (SendCTPassThruFunc)
+	    (vendorHandle,
+	    pReqBuffer, ReqBufferSize,
+	    pRspBuffer, RspBufferSize);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SendCTPassThruV2(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    void		*pReqBuffer,
+    HBA_UINT32		ReqBufferSize,
+    void		*pRspBuffer,
+    HBA_UINT32		*pRspBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASendCTPassThruV2Func
+	    registeredfunc;
+
+	DEBUG(2, "HBA_SendCTPassThruV2m hbaPortWWN: %s",
+	    WWN2STR1(&hbaPortWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+	registeredfunc = FUNCCOMMON(lib_infop, SendCTPassThruV2Handler);
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)
+	    (vendorHandle, hbaPortWWN,
+	    pReqBuffer, ReqBufferSize,
+	    pRspBuffer, pRspBufferSize);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_GetEventBuffer(
+    HBA_HANDLE		handle,
+    PHBA_EVENTINFO	EventBuffer,
+    HBA_UINT32		*EventBufferCount)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAGetEventBufferFunc
+	    GetEventBufferFunc;
+
+	DEBUG(2, "HBA_GetEventBuffer", 0, 0, 0);
+
+	CHECKLIBRARY();
+	if (lib_infop->version == SMHBA) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INCOMPATIBLE);
+	}
+
+	GetEventBufferFunc =
+	    lib_infop->ftable.functionTable.GetEventBufferHandler;
+	if (GetEventBufferFunc != NULL) {
+	status = (GetEventBufferFunc)
+	    (vendorHandle, EventBuffer, EventBufferCount);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SetRNIDMgmtInfo(HBA_HANDLE handle, HBA_MGMTINFO Info) {
+    HBA_STATUS		status;
+    HBA_LIBRARY_INFO	*lib_infop;
+    HBA_HANDLE		vendorHandle;
+    HBASetRNIDMgmtInfoFunc
+			SetRNIDMgmtInfoFunc;
+
+    DEBUG(2, "HBA_SetRNIDMgmtInfo", 0, 0, 0);
+
+    CHECKLIBRARY();
+    SetRNIDMgmtInfoFunc = FUNCCOMMON(lib_infop, SetRNIDMgmtInfoHandler);
+    if (SetRNIDMgmtInfoFunc != NULL) {
+	status = (SetRNIDMgmtInfoFunc)(vendorHandle, Info);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_GetRNIDMgmtInfo(HBA_HANDLE handle, HBA_MGMTINFO *pInfo) {
+    HBA_STATUS		status;
+    HBA_LIBRARY_INFO	*lib_infop;
+    HBA_HANDLE		vendorHandle;
+    HBAGetRNIDMgmtInfoFunc
+	    GetRNIDMgmtInfoFunc;
+
+    DEBUG(2, "HBA_GetRNIDMgmtInfo", 0, 0, 0);
+
+    CHECKLIBRARY();
+    GetRNIDMgmtInfoFunc = FUNCCOMMON(lib_infop, GetRNIDMgmtInfoHandler);
+    if (GetRNIDMgmtInfoFunc != NULL) {
+	status = (GetRNIDMgmtInfoFunc)(vendorHandle, pInfo);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SendRNID(
+    HBA_HANDLE		handle,
+    HBA_WWN		wwn,
+    HBA_WWNTYPE		wwntype,
+    void		*pRspBuffer,
+    HBA_UINT32		*pRspBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASendRNIDFunc	SendRNIDFunc;
+
+	DEBUG(2, "HBA_SendRNID for wwn: %s", WWN2STR1(&wwn), 0, 0);
+
+	CHECKLIBRARY();
+	if (lib_infop->version == SMHBA) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INCOMPATIBLE);
+	}
+
+	SendRNIDFunc = lib_infop->ftable.functionTable.SendRNIDHandler;
+	if (SendRNIDFunc != NULL) {
+	status = ((SendRNIDFunc)(vendorHandle, wwn, wwntype,
+	    pRspBuffer, pRspBufferSize));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SendRNIDV2(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		destWWN,
+    HBA_UINT32		destFCID,
+    HBA_UINT32		NodeIdDataFormat,
+    void		*pRspBuffer,
+    HBA_UINT32		*pRspBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASendRNIDV2Func	registeredfunc;
+
+	DEBUG(2, "HBA_SendRNIDV2, hbaPortWWN: %s", WWN2STR1(&hbaPortWWN), 0, 0);
+
+	CHECKLIBRARY();
+	registeredfunc = FUNCCOMMON(lib_infop, SendRNIDV2Handler);
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)
+	    (vendorHandle, hbaPortWWN, destWWN, destFCID, NodeIdDataFormat,
+	    pRspBuffer, pRspBufferSize);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+void
+HBA_RefreshInformation(HBA_HANDLE handle) {
+    HBA_STATUS		status;
+    HBA_LIBRARY_INFO	*lib_infop;
+    HBA_HANDLE		vendorHandle;
+    HBARefreshInformationFunc
+	    RefreshInformationFunc;
+
+	DEBUG(2, "HBA_RefreshInformation", 0, 0, 0);
+
+	status = HBA_CheckLibrary(handle, &lib_infop, &vendorHandle);
+	if (status == HBA_STATUS_OK) {
+	RefreshInformationFunc =
+	    FUNCCOMMON(lib_infop, RefreshInformationHandler);
+	if (RefreshInformationFunc != NULL) {
+	    ((RefreshInformationFunc)(vendorHandle));
+	}
+	RELEASE_MUTEX(&_hbaapi_LL_mutex);
+	}
+}
+
+void
+HBA_ResetStatistics(HBA_HANDLE handle, HBA_UINT32 portindex) {
+    HBA_STATUS		status;
+    HBA_LIBRARY_INFO	*lib_infop;
+    HBA_HANDLE		vendorHandle;
+    HBAResetStatisticsFunc
+			ResetStatisticsFunc;
+
+    DEBUG(2, "HBA_ResetStatistics", 0, 0, 0);
+
+    status = HBA_CheckLibrary(handle, &lib_infop, &vendorHandle);
+    if (status == HBA_STATUS_OK) {
+	if (lib_infop->version == SMHBA) {
+		RELEASE_MUTEX(&_hbaapi_LL_mutex);
+	}
+
+	ResetStatisticsFunc =
+	    lib_infop->ftable.functionTable.ResetStatisticsHandler;
+	if (ResetStatisticsFunc != NULL) {
+	    ((ResetStatisticsFunc)(vendorHandle, portindex));
+	}
+	RELEASE_MUTEX(&_hbaapi_LL_mutex);
+	}
+}
+
+HBA_STATUS
+HBA_GetFcpTargetMapping(HBA_HANDLE handle, PHBA_FCPTARGETMAPPING mapping) {
+    HBA_STATUS		status;
+    HBA_LIBRARY_INFO	*lib_infop;
+    HBA_HANDLE		vendorHandle;
+    HBAGetFcpTargetMappingFunc GetFcpTargetMappingFunc;
+
+    DEBUG(2, "HBA_GetFcpTargetMapping", 0, 0, 0);
+
+    CHECKLIBRARY();
+    if (lib_infop->version == SMHBA) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INCOMPATIBLE);
+	}
+
+    GetFcpTargetMappingFunc =
+	lib_infop->ftable.functionTable.GetFcpTargetMappingHandler;
+    if (GetFcpTargetMappingFunc != NULL) {
+	status = ((GetFcpTargetMappingFunc)(vendorHandle, mapping));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_GetFcpTargetMappingV2(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_FCPTARGETMAPPINGV2 *pmapping)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAGetFcpTargetMappingV2Func
+	    registeredfunc;
+
+	DEBUG(2, "HBA_GetFcpTargetMapping", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	registeredfunc =
+	    lib_infop->ftable.functionTable.GetFcpTargetMappingV2Handler;
+	if (registeredfunc != NULL) {
+	status = ((registeredfunc)(vendorHandle, hbaPortWWN, pmapping));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_GetFcpPersistentBinding(HBA_HANDLE handle, PHBA_FCPBINDING binding) {
+    HBA_STATUS		status;
+    HBA_LIBRARY_INFO	*lib_infop;
+    HBA_HANDLE		vendorHandle;
+    HBAGetFcpPersistentBindingFunc
+	    GetFcpPersistentBindingFunc;
+
+	DEBUG(2, "HBA_GetFcpPersistentBinding", 0, 0, 0);
+
+	CHECKLIBRARY();
+	if (lib_infop->version == SMHBA) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INCOMPATIBLE);
+	}
+
+	GetFcpPersistentBindingFunc =
+	    lib_infop->ftable.functionTable.GetFcpPersistentBindingHandler;
+	if (GetFcpPersistentBindingFunc != NULL) {
+	status = ((GetFcpPersistentBindingFunc)(vendorHandle, binding));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_ScsiInquiryV2(
+    HBA_HANDLE	handle,
+    HBA_WWN	hbaPortWWN,
+    HBA_WWN	discoveredPortWWN,
+    HBA_UINT64	fcLUN,
+    HBA_UINT8	CDB_Byte1,
+    HBA_UINT8	CDB_Byte2,
+    void	*pRspBuffer,
+    HBA_UINT32	*pRspBufferSize,
+    HBA_UINT8	*pScsiStatus,
+    void	*pSenseBuffer,
+    HBA_UINT32	*pSenseBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAScsiInquiryV2Func ScsiInquiryV2Func;
+
+	DEBUG(2, "HBA_ScsiInquiryV2 to discoveredPortWWN: %s",
+	    WWN2STR1(&discoveredPortWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	ScsiInquiryV2Func =
+	    lib_infop->ftable.functionTable.ScsiInquiryV2Handler;
+	if (ScsiInquiryV2Func != NULL) {
+	status = ((ScsiInquiryV2Func)(
+	    vendorHandle, hbaPortWWN, discoveredPortWWN, fcLUN, CDB_Byte1,
+	    CDB_Byte2, pRspBuffer, pRspBufferSize, pScsiStatus,
+	    pSenseBuffer, pSenseBufferSize));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SendScsiInquiry(
+    HBA_HANDLE	handle,
+    HBA_WWN	PortWWN,
+    HBA_UINT64	fcLUN,
+    HBA_UINT8	EVPD,
+    HBA_UINT32	PageCode,
+    void	*pRspBuffer,
+    HBA_UINT32	RspBufferSize,
+    void	*pSenseBuffer,
+    HBA_UINT32	SenseBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASendScsiInquiryFunc SendScsiInquiryFunc;
+
+	DEBUG(2, "HBA_SendScsiInquiry to PortWWN: %s",
+	    WWN2STR1(&PortWWN), 0, 0);
+
+	CHECKLIBRARY();
+	if (lib_infop->version == SMHBA) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INCOMPATIBLE);
+	}
+
+	SendScsiInquiryFunc =
+	    lib_infop->ftable.functionTable.ScsiInquiryHandler;
+	if (SendScsiInquiryFunc != NULL) {
+	status = ((SendScsiInquiryFunc)(
+	    vendorHandle, PortWWN, fcLUN, EVPD, PageCode, pRspBuffer,
+	    RspBufferSize, pSenseBuffer, SenseBufferSize));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_ScsiReportLUNsV2(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		discoveredPortWWN,
+    void		*pRespBuffer,
+    HBA_UINT32		*pRespBufferSize,
+    HBA_UINT8		*pScsiStatus,
+    void		*pSenseBuffer,
+    HBA_UINT32		*pSenseBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAScsiReportLUNsV2Func ScsiReportLUNsV2Func;
+
+	DEBUG(2, "HBA_ScsiReportLUNsV2 to discoveredPortWWN: %s",
+	    WWN2STR1(&discoveredPortWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	ScsiReportLUNsV2Func =
+	    lib_infop->ftable.functionTable.ScsiReportLUNsV2Handler;
+	if (ScsiReportLUNsV2Func != NULL) {
+	status = ((ScsiReportLUNsV2Func)(
+	    vendorHandle, hbaPortWWN, discoveredPortWWN,
+	    pRespBuffer, pRespBufferSize,
+	    pScsiStatus,
+	    pSenseBuffer, pSenseBufferSize));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SendReportLUNs(
+    HBA_HANDLE handle,
+    HBA_WWN portWWN,
+    void *pRspBuffer,
+    HBA_UINT32 RspBufferSize,
+    void *pSenseBuffer,
+    HBA_UINT32 SenseBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASendReportLUNsFunc SendReportLUNsFunc;
+
+	DEBUG(2, "HBA_SendReportLUNs to PortWWN: %s", WWN2STR1(&portWWN), 0, 0);
+
+	CHECKLIBRARY();
+	if (lib_infop->version == SMHBA) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INCOMPATIBLE);
+	}
+
+	SendReportLUNsFunc = lib_infop->ftable.functionTable.ReportLUNsHandler;
+	if (SendReportLUNsFunc != NULL) {
+	status = ((SendReportLUNsFunc)(
+	    vendorHandle, portWWN, pRspBuffer,
+	    RspBufferSize, pSenseBuffer, SenseBufferSize));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_ScsiReadCapacityV2(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		discoveredPortWWN,
+    HBA_UINT64		fcLUN,
+    void		*pRspBuffer,
+    HBA_UINT32		*pRspBufferSize,
+    HBA_UINT8		*pScsiStatus,
+    void		*pSenseBuffer,
+    HBA_UINT32		*SenseBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAScsiReadCapacityV2Func ScsiReadCapacityV2Func;
+
+	DEBUG(2, "HBA_ScsiReadCapacityV2 to discoveredPortWWN: %s",
+	    WWN2STR1(&discoveredPortWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	ScsiReadCapacityV2Func =
+	    lib_infop->ftable.functionTable.ScsiReadCapacityV2Handler;
+	if (ScsiReadCapacityV2Func != NULL) {
+	status = ((ScsiReadCapacityV2Func)(
+	    vendorHandle, hbaPortWWN, discoveredPortWWN, fcLUN,
+	    pRspBuffer, pRspBufferSize,
+	    pScsiStatus,
+	    pSenseBuffer, SenseBufferSize));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SendReadCapacity(
+    HBA_HANDLE handle,
+    HBA_WWN portWWN,
+    HBA_UINT64 fcLUN,
+    void *pRspBuffer,
+    HBA_UINT32 RspBufferSize,
+    void *pSenseBuffer,
+    HBA_UINT32 SenseBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASendReadCapacityFunc SendReadCapacityFunc;
+
+	DEBUG(2, "HBA_SendReadCapacity to portWWN: %s",
+	    WWN2STR1(&portWWN), 0, 0);
+
+	CHECKLIBRARY();
+	if (lib_infop->version == SMHBA) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_INCOMPATIBLE);
+	}
+
+	SendReadCapacityFunc =
+	    lib_infop->ftable.functionTable.ReadCapacityHandler;
+	if (SendReadCapacityFunc != NULL) {
+	status = ((SendReadCapacityFunc)
+	    (vendorHandle, portWWN, fcLUN, pRspBuffer,
+	    RspBufferSize, pSenseBuffer, SenseBufferSize));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SendRPL(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		agent_wwn,
+    HBA_UINT32		agent_domain,
+    HBA_UINT32		portindex,
+    void		*pRspBuffer,
+    HBA_UINT32		*pRspBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASendRPLFunc registeredfunc;
+
+	DEBUG(2, "HBA_SendRPL to agent_wwn: %s:%d",
+	    WWN2STR1(&agent_wwn), agent_domain, 0);
+
+	CHECKLIBRARY();
+	registeredfunc = FUNCCOMMON(lib_infop, SendRPLHandler);
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)(
+	    vendorHandle, hbaPortWWN, agent_wwn, agent_domain, portindex,
+	    pRspBuffer, pRspBufferSize);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SendRPS(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		agent_wwn,
+    HBA_UINT32		agent_domain,
+    HBA_WWN		object_wwn,
+    HBA_UINT32		object_port_number,
+    void		*pRspBuffer,
+    HBA_UINT32		*pRspBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASendRPSFunc registeredfunc;
+
+	DEBUG(2, "HBA_SendRPS  to agent_wwn: %s:%d",
+	    WWN2STR1(&agent_wwn), agent_domain, 0);
+
+	CHECKLIBRARY();
+	registeredfunc = FUNCCOMMON(lib_infop, SendRPSHandler);
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)(
+	    vendorHandle, hbaPortWWN, agent_wwn, agent_domain,
+	    object_wwn, object_port_number,
+	    pRspBuffer, pRspBufferSize);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SendSRL(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		wwn,
+    HBA_UINT32		domain,
+    void		*pRspBuffer,
+    HBA_UINT32		*pRspBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASendSRLFunc registeredfunc;
+
+	DEBUG(2, "HBA_SendSRL to wwn:%s domain:%d", WWN2STR1(&wwn), domain, 0);
+
+	CHECKLIBRARY();
+	registeredfunc = FUNCCOMMON(lib_infop, SendSRLHandler);
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)(
+	    vendorHandle, hbaPortWWN, wwn, domain,
+	    pRspBuffer, pRspBufferSize);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+HBA_STATUS
+HBA_SendRLS(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		destWWN,
+    void		*pRspBuffer,
+    HBA_UINT32		*pRspBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASendRLSFunc registeredfunc;
+
+	DEBUG(2, "HBA_SendRLS dest_wwn: %s",
+	    WWN2STR1(&destWWN), 0, 0);
+
+	CHECKLIBRARY();
+	registeredfunc = FUNCCOMMON(lib_infop, SendRLSHandler);
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)(
+	    vendorHandle, hbaPortWWN, destWWN,
+	    pRspBuffer, pRspBufferSize);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SendLIRR(
+    HBA_HANDLE		handle,
+    HBA_WWN		sourceWWN,
+    HBA_WWN		destWWN,
+    HBA_UINT8		function,
+    HBA_UINT8		type,
+    void		*pRspBuffer,
+    HBA_UINT32		*pRspBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASendLIRRFunc registeredfunc;
+
+	DEBUG(2, "HBA_SendLIRR destWWN:%s", WWN2STR1(&destWWN), 0, 0);
+
+	CHECKLIBRARY();
+	registeredfunc = FUNCCOMMON(lib_infop, SendLIRRHandler);
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)(
+	    vendorHandle, sourceWWN, destWWN, function, type,
+	    pRspBuffer, pRspBufferSize);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_GetBindingCapability(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_BIND_CAPABILITY *pcapability)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAGetBindingCapabilityFunc
+	    registeredfunc;
+
+	DEBUG(2, "HBA_GetBindingCapability", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	registeredfunc =
+	    lib_infop->ftable.functionTable.GetBindingCapabilityHandler;
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)(vendorHandle, hbaPortWWN, pcapability);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_GetBindingSupport(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_BIND_CAPABILITY *pcapability)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAGetBindingSupportFunc
+	    registeredfunc;
+
+	DEBUG(2, "HBA_GetBindingSupport", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	registeredfunc =
+	    lib_infop->ftable.functionTable.GetBindingSupportHandler;
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)(vendorHandle, hbaPortWWN, pcapability);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SetBindingSupport(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_BIND_CAPABILITY capability)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASetBindingSupportFunc
+	    registeredfunc;
+
+	DEBUG(2, "HBA_SetBindingSupport", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	registeredfunc =
+	    lib_infop->ftable.functionTable.SetBindingSupportHandler;
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)(vendorHandle, hbaPortWWN, capability);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_SetPersistentBindingV2(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    const HBA_FCPBINDING2 *pbinding)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBASetPersistentBindingV2Func
+	    registeredfunc;
+
+	DEBUG(2, "HBA_SetPersistentBindingV2 port: %s",
+	    WWN2STR1(&hbaPortWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	registeredfunc =
+	    lib_infop->ftable.functionTable.SetPersistentBindingV2Handler;
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)(vendorHandle, hbaPortWWN, pbinding);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_GetPersistentBindingV2(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_FCPBINDING2	*pbinding)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAGetPersistentBindingV2Func
+	    registeredfunc;
+
+	DEBUG(2, "HBA_GetPersistentBindingV2 port: %s",
+	    WWN2STR1(&hbaPortWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	registeredfunc =
+	    lib_infop->ftable.functionTable.GetPersistentBindingV2Handler;
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)(vendorHandle, hbaPortWWN, pbinding);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_RemovePersistentBinding(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    const HBA_FCPBINDING2
+			*pbinding)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBARemovePersistentBindingFunc
+	    registeredfunc;
+
+	DEBUG(2, "HBA_RemovePersistentBinding", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	registeredfunc =
+	    lib_infop->ftable.functionTable.RemovePersistentBindingHandler;
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)(vendorHandle, hbaPortWWN, pbinding);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_RemoveAllPersistentBindings(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBARemoveAllPersistentBindingsFunc
+	    registeredfunc;
+
+	DEBUG(2, "HBA_RemoveAllPersistentBindings", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	registeredfunc =
+	    lib_infop->ftable.functionTable.RemoveAllPersistentBindingsHandler;
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)(vendorHandle, hbaPortWWN);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_GetFC4Statistics(
+    HBA_HANDLE		handle,
+    HBA_WWN		portWWN,
+    HBA_UINT8		FC4type,
+    HBA_FC4STATISTICS	*pstatistics)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAGetFC4StatisticsFunc
+	    registeredfunc;
+
+	DEBUG(2, "HBA_GetFC4Statistics port: %s", WWN2STR1(&portWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	registeredfunc =
+	    lib_infop->ftable.functionTable.GetFC4StatisticsHandler;
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)
+	    (vendorHandle, portWWN, FC4type, pstatistics);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+HBA_GetFCPStatistics(
+    HBA_HANDLE		handle,
+    const HBA_SCSIID	*lunit,
+    HBA_FC4STATISTICS	*pstatistics)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	HBAGetFCPStatisticsFunc
+	    registeredfunc;
+
+	DEBUG(2, "HBA_GetFCPStatistics", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	registeredfunc =
+	    lib_infop->ftable.functionTable.GetFCPStatisticsHandler;
+	if (registeredfunc != NULL) {
+	status = (registeredfunc)(vendorHandle, lunit, pstatistics);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_UINT32
+HBA_GetVendorLibraryAttributes(
+    HBA_UINT32 adapter_index,
+    HBA_LIBRARYATTRIBUTES *attributes)
+{
+	HBA_ADAPTER_INFO	*adapt_infop;
+	HBAGetVendorLibraryAttributesFunc
+	    registeredfunc;
+	HBA_UINT32		ret = 0;
+
+	DEBUG(2, "HBA_GetVendorLibraryAttributes adapterindex:%d",
+	    adapter_index, 0, 0);
+	if (_hbaapi_librarylist == NULL) {
+	DEBUG(1, "HBAAPI not loaded yet.", 0, 0, 0);
+	return (0);
+	}
+
+	if (attributes == NULL) {
+		DEBUG(1,
+		    "HBA_GetVendorLibraryAttributes: NULL pointer attributes",
+		    0, 0, 0);
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	(void) memset(attributes, 0, sizeof (HBA_LIBRARYATTRIBUTES));
+
+	GRAB_MUTEX(&_hbaapi_LL_mutex);
+	GRAB_MUTEX(&_hbaapi_AL_mutex);
+	for (adapt_infop = _hbaapi_adapterlist;
+	    adapt_infop != NULL;
+	    adapt_infop = adapt_infop->next) {
+
+	if (adapt_infop->index == adapter_index) {
+
+		if (adapt_infop->library->version == SMHBA) {
+		RELEASE_MUTEX(&_hbaapi_AL_mutex);
+		RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex,
+		    HBA_STATUS_ERROR_INCOMPATIBLE);
+		}
+
+		registeredfunc = adapt_infop->library->
+		    ftable.functionTable.GetVendorLibraryAttributesHandler;
+		if (registeredfunc != NULL) {
+		ret = (registeredfunc)(attributes);
+		} else {
+		/* Version 1 libary? */
+		HBAGetVersionFunc	GetVersionFunc;
+		GetVersionFunc = adapt_infop->library->
+		    ftable.functionTable.GetVersionHandler;
+		if (GetVersionFunc != NULL) {
+			ret = ((GetVersionFunc)());
+		}
+#ifdef NOTDEF
+		else {
+		    /* This should not happen, dont think its going to */
+		}
+#endif
+		}
+		if (attributes->LibPath[0] == '\0') {
+		if (strlen(adapt_infop->library->LibraryPath) < 256) {
+			(void) strcpy(attributes->LibPath,
+			    adapt_infop->library->LibraryPath);
+		}
+		}
+		break;
+	}
+	}
+	RELEASE_MUTEX(&_hbaapi_AL_mutex);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, ret);
+}
+
+
+/*
+ * This function returns SM-HBA version that the warpper library implemented.
+ */
+HBA_UINT32
+SMHBA_GetVersion() {
+    DEBUG(2, "SMHBA_GetVersion", 0, 0, 0);
+    return (SMHBA_LIBVERSION);
+}
+
+/*
+ * This function returns the attributes for the warpper library.
+ */
+HBA_UINT32
+SMHBA_GetWrapperLibraryAttributes(
+    SMHBA_LIBRARYATTRIBUTES *attributes)
+{
+
+	struct timeval tv;
+	struct tm tp;
+
+	DEBUG(2, "SMHBA_GetWrapperLibraryAttributes", 0, 0, 0);
+
+	if (attributes == NULL) {
+		DEBUG(1, "SMHBA_GetWrapperLibraryAttributes: "
+		    "NULL pointer attributes",
+		    0, 0, 0);
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	(void) memset(attributes, 0, sizeof (SMHBA_LIBRARYATTRIBUTES));
+
+#if defined(SOLARIS)
+	if ((handle = dlopen("libSMHBAAPI.so", RTLD_NOW)) != NULL) {
+	if (dlinfo(handle, RTLD_DI_LINKMAP, &map) >= 0) {
+		for (mp = map; mp != NULL; mp = mp->l_next) {
+		if (strlen(map->l_name) < 256) {
+			(void) strcpy(attributes->LibPath, map->l_name);
+		}
+		}
+	}
+	}
+
+#endif
+
+#if defined(VENDOR)
+	(void) strcpy(attributes->VName, VENDOR);
+#else
+	attributes->VName[0] = '\0';
+#endif
+#if	defined(VERSION)
+	(void) strcpy(attributes->VVersion, VERSION);
+#else
+	attributes->VVersion[0] = '\0';
+#endif
+
+	if (gettimeofday(&tv, (void *)0) == 0) {
+	if (localtime_r(&tv.tv_sec, &tp) != NULL) {
+		attributes->build_date.tm_mday = tp.tm_mday;
+		attributes->build_date.tm_mon = tp.tm_mon;
+		attributes->build_date.tm_year = tp.tm_year;
+	} else {
+		(void) memset(&attributes->build_date, 0,
+		    sizeof (attributes->build_date));
+	}
+	(void) memset(&attributes->build_date, 0,
+	    sizeof (attributes->build_date));
+	}
+
+	return (1);
+}
+
+/*
+ * This function returns the attributes for the warpper library.
+ */
+HBA_UINT32
+SMHBA_GetVendorLibraryAttributes(
+    HBA_UINT32 adapter_index,
+    SMHBA_LIBRARYATTRIBUTES *attributes)
+{
+	HBA_ADAPTER_INFO	*adapt_infop;
+	SMHBAGetVendorLibraryAttributesFunc
+	    registeredfunc;
+	HBA_UINT32		ret = 0;
+
+	DEBUG(2, "SMHBA_GetVendorLibraryAttributes adapterindex:%d",
+	    adapter_index, 0, 0);
+	if (_hbaapi_librarylist == NULL) {
+	DEBUG(1, "SMHBAAPI not loaded yet.", 0, 0, 0);
+	return (0);
+	}
+
+	if (attributes == NULL) {
+		DEBUG(1, "SMHBA_GetVendorLibraryAttributes: "
+		    "NULL pointer attributes",
+		    0, 0, 0);
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	(void) memset(attributes, 0, sizeof (SMHBA_LIBRARYATTRIBUTES));
+
+	GRAB_MUTEX(&_hbaapi_LL_mutex);
+	GRAB_MUTEX(&_hbaapi_AL_mutex);
+	for (adapt_infop = _hbaapi_adapterlist;
+	    adapt_infop != NULL;
+	    adapt_infop = adapt_infop->next) {
+
+	if (adapt_infop->index == adapter_index) {
+
+		if (adapt_infop->library->version != SMHBA) {
+		RELEASE_MUTEX(&_hbaapi_AL_mutex);
+		RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex,
+		    HBA_STATUS_ERROR_INCOMPATIBLE);
+		}
+
+		registeredfunc = adapt_infop->library->
+		    ftable.smhbafunctionTable.GetVendorLibraryAttributesHandler;
+		if (registeredfunc != NULL) {
+		ret = (registeredfunc)(attributes);
+#ifdef NOTDEF
+		} else {
+		/* This should not happen since the VSL is already loaded. */
+#endif
+		}
+		if (attributes->LibPath[0] == '\0') {
+		if (strlen(adapt_infop->library->LibraryPath) < 256) {
+			(void) strcpy(attributes->LibPath,
+			    adapt_infop->library->LibraryPath);
+		}
+		}
+		break;
+	}
+	}
+	RELEASE_MUTEX(&_hbaapi_AL_mutex);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, ret);
+}
+
+HBA_STATUS
+SMHBA_GetAdapterAttributes(
+    HBA_HANDLE		handle,
+    SMHBA_ADAPTERATTRIBUTES *hbaattributes)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetAdapterAttributesFunc GetAdapterAttributesFunc;
+
+	DEBUG(2, "SMHBA_GetAdapterAttributes", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetAdapterAttributesFunc =
+	    lib_infop->ftable.smhbafunctionTable.GetAdapterAttributesHandler;
+	if (GetAdapterAttributesFunc != NULL) {
+	status = ((GetAdapterAttributesFunc)(vendorHandle, hbaattributes));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetNumberOfPorts(
+    HBA_HANDLE		handle,
+    HBA_UINT32		*numberofports)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetNumberOfPortsFunc GetNumberOfPortsFunc;
+
+	DEBUG(2, "SMHBA_GetAdapterAttributes", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetNumberOfPortsFunc =
+	    lib_infop->ftable.smhbafunctionTable.GetNumberOfPortsHandler;
+	if (GetNumberOfPortsFunc != NULL) {
+	status = ((GetNumberOfPortsFunc)(vendorHandle, numberofports));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetPortType(
+    HBA_HANDLE		handle,
+    HBA_UINT32		portindex,
+    HBA_PORTTYPE	*porttype)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetPortTypeFunc GetPortTypeFunc;
+
+	DEBUG(2, "SMHBA_GetAdapterAttributes", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetPortTypeFunc =
+	    lib_infop->ftable.smhbafunctionTable.GetPortTypeHandler;
+	if (GetPortTypeFunc != NULL) {
+	status = ((GetPortTypeFunc)(vendorHandle, portindex, porttype));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetAdapterPortAttributes(
+    HBA_HANDLE		handle,
+    HBA_UINT32		portindex,
+    SMHBA_PORTATTRIBUTES	*portattributes)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetAdapterPortAttributesFunc
+	    GetAdapterPortAttributesFunc;
+
+	DEBUG(2, "SMHBA_GetAdapterPortAttributes", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetAdapterPortAttributesFunc =
+	    lib_infop->ftable.smhbafunctionTable.\
+	    GetAdapterPortAttributesHandler;
+	if (GetAdapterPortAttributesFunc != NULL) {
+	status = ((GetAdapterPortAttributesFunc)
+	    (vendorHandle, portindex, portattributes));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetDiscoveredPortAttributes(
+    HBA_HANDLE		handle,
+    HBA_UINT32		portindex,
+    HBA_UINT32		discoveredportindex,
+    SMHBA_PORTATTRIBUTES	*portattributes)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetDiscoveredPortAttributesFunc
+	    GetDiscoveredPortAttributesFunc;
+
+	DEBUG(2, "SMHBA_GetDiscoveredPortAttributes", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetDiscoveredPortAttributesFunc =
+	    lib_infop->ftable.smhbafunctionTable.\
+	    GetDiscoveredPortAttributesHandler;
+	if (GetDiscoveredPortAttributesFunc != NULL)  {
+	status = ((GetDiscoveredPortAttributesFunc)
+	    (vendorHandle, portindex, discoveredportindex,
+	    portattributes));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetPortAttributesByWWN(
+    HBA_HANDLE		handle,
+    HBA_WWN		portWWN,
+    HBA_WWN		domainPortWWN,
+    SMHBA_PORTATTRIBUTES	*portattributes)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetPortAttributesByWWNFunc
+	    GetPortAttributesByWWNFunc;
+
+	DEBUG(2, "SMHBA_GetPortAttributesByWWN: %s", WWN2STR1(&portWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetPortAttributesByWWNFunc =
+	    lib_infop->ftable.smhbafunctionTable.GetPortAttributesByWWNHandler;
+	if (GetPortAttributesByWWNFunc != NULL) {
+	status = ((GetPortAttributesByWWNFunc)
+	    (vendorHandle, portWWN, domainPortWWN, portattributes));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetFCPhyAttributes(
+    HBA_HANDLE		handle,
+    HBA_UINT32		portindex,
+    HBA_UINT32		phyindex,
+    SMHBA_FC_PHY	*phytype)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetFCPhyAttributesFunc GetFCPhyAttributesFunc;
+
+	DEBUG(2, "SMHBA_GetFCPhyAttributesByWWN", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetFCPhyAttributesFunc =
+	    lib_infop->ftable.smhbafunctionTable.GetFCPhyAttributesHandler;
+	if (GetFCPhyAttributesFunc != NULL) {
+	status = ((GetFCPhyAttributesFunc)
+	    (vendorHandle, portindex, phyindex, phytype));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetSASPhyAttributes(
+    HBA_HANDLE		handle,
+    HBA_UINT32		portindex,
+    HBA_UINT32		phyindex,
+    SMHBA_SAS_PHY	*phytype)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetSASPhyAttributesFunc GetSASPhyAttributesFunc;
+
+	DEBUG(2, "SMHBA_GetFCPhyAttributesByWWN", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetSASPhyAttributesFunc =
+	    lib_infop->ftable.smhbafunctionTable.GetSASPhyAttributesHandler;
+	if (GetSASPhyAttributesFunc != NULL) {
+	status = ((GetSASPhyAttributesFunc)
+	    (vendorHandle, portindex, phyindex, phytype));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetProtocolStatistics(
+    HBA_HANDLE		handle,
+    HBA_UINT32		portindex,
+    HBA_UINT32		protocoltype,
+    SMHBA_PROTOCOLSTATISTICS *pProtocolStatistics)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetProtocolStatisticsFunc
+	    GetProtocolStatisticsFunc;
+
+	DEBUG(2, "SMHBA_GetProtocolStatistics port index: %d protocol type: %d",
+	    portindex, protocoltype, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetProtocolStatisticsFunc =
+	    lib_infop->ftable.smhbafunctionTable.GetProtocolStatisticsHandler;
+	if (GetProtocolStatisticsFunc != NULL) {
+	status = (GetProtocolStatisticsFunc)
+	    (vendorHandle, portindex, protocoltype, pProtocolStatistics);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetPhyStatistics(
+    HBA_HANDLE		handle,
+    HBA_UINT32		portindex,
+    HBA_UINT32		phyindex,
+    SMHBA_PHYSTATISTICS *pPhyStatistics)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetPhyStatisticsFunc
+	    GetPhyStatisticsFunc;
+
+	DEBUG(2, "SMHBA_GetPhyStatistics port index: %d phy idex: %d",
+	    portindex, phyindex, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetPhyStatisticsFunc =
+	    lib_infop->ftable.smhbafunctionTable.GetPhyStatisticsHandler;
+	if (GetPhyStatisticsFunc != NULL) {
+	status = (GetPhyStatisticsFunc)
+	    (vendorHandle, portindex, phyindex, pPhyStatistics);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetBindingCapability(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		domainPortWWN,
+    SMHBA_BIND_CAPABILITY *pFlags)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetBindingCapabilityFunc GetBindingCapabilityFunc;
+
+	DEBUG(2, "HBA_GetBindingCapability", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetBindingCapabilityFunc =
+	    lib_infop->ftable.smhbafunctionTable.GetBindingCapabilityHandler;
+	if (GetBindingCapabilityFunc != NULL) {
+	status = (GetBindingCapabilityFunc)(vendorHandle, hbaPortWWN,
+	    domainPortWWN, pFlags);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetBindingSupport(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		domainPortWWN,
+    SMHBA_BIND_CAPABILITY *pFlags)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetBindingSupportFunc
+	    GetBindingSupporFunc;
+
+	DEBUG(2, "SMHBA_GetBindingSupport port: %s",
+	    WWN2STR1(&hbaPortWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetBindingSupporFunc =
+	    lib_infop->ftable.smhbafunctionTable.GetBindingSupportHandler;
+	if (GetBindingSupporFunc != NULL) {
+	status = (GetBindingSupporFunc)(vendorHandle,
+	    hbaPortWWN, domainPortWWN, pFlags);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_SetBindingSupport(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		domainPortWWN,
+    SMHBA_BIND_CAPABILITY flags)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBASetBindingSupportFunc
+	    SetBindingSupporFunc;
+
+	DEBUG(2, "SMHBA_GetBindingSupport port: %s",
+	    WWN2STR1(&hbaPortWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(HBAAPIV2);
+
+	SetBindingSupporFunc =
+	    lib_infop->ftable.smhbafunctionTable.SetBindingSupportHandler;
+	if (SetBindingSupporFunc != NULL) {
+	status = (SetBindingSupporFunc)
+	    (vendorHandle, hbaPortWWN, domainPortWWN, flags);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetTargetMapping(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		domainPortWWN,
+    SMHBA_TARGETMAPPING *pMapping)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetTargetMappingFunc GetTargetMappingFunc;
+
+	DEBUG(2, "SMHBA_GetTargetMapping port WWN: %s",
+	    WWN2STR1(&hbaPortWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetTargetMappingFunc =
+	    lib_infop->ftable.smhbafunctionTable.GetTargetMappingHandler;
+	if (GetTargetMappingFunc != NULL) {
+	status = ((GetTargetMappingFunc)(vendorHandle,
+	    hbaPortWWN, domainPortWWN, pMapping));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetPersistentBinding(
+    HBA_HANDLE handle,
+    HBA_WWN	hbaPortWWN,
+    HBA_WWN	domainPortWWN,
+    SMHBA_BINDING *binding)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetPersistentBindingFunc
+	    GetPersistentBindingFunc;
+
+	DEBUG(2, "SMHBA_GetPersistentBinding port WWN: %s",
+	    WWN2STR1(&hbaPortWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetPersistentBindingFunc =
+	    lib_infop->ftable.smhbafunctionTable.GetPersistentBindingHandler;
+	if (GetPersistentBindingFunc != NULL) {
+	status = ((GetPersistentBindingFunc)(vendorHandle,
+	    hbaPortWWN, domainPortWWN, binding));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_SetPersistentBinding(
+    HBA_HANDLE handle,
+    HBA_WWN	hbaPortWWN,
+    HBA_WWN	domainPortWWN,
+    const SMHBA_BINDING *binding)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBASetPersistentBindingFunc
+	    SetPersistentBindingFunc;
+
+	DEBUG(2, "SMHBA_SetPersistentBinding port WWN: %s",
+	    WWN2STR1(&hbaPortWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	SetPersistentBindingFunc =
+	    lib_infop->ftable.smhbafunctionTable.SetPersistentBindingHandler;
+	if (SetPersistentBindingFunc != NULL) {
+	status = ((SetPersistentBindingFunc)(vendorHandle,
+	    hbaPortWWN, domainPortWWN, binding));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_RemovePersistentBinding(
+    HBA_HANDLE handle,
+    HBA_WWN	hbaPortWWN,
+    HBA_WWN	domainPortWWN,
+    const SMHBA_BINDING *binding)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBARemovePersistentBindingFunc
+	    RemovePersistentBindingFunc;
+
+	DEBUG(2, "SMHBA_RemovePersistentBinding port WWN: %s",
+	    WWN2STR1(&hbaPortWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	RemovePersistentBindingFunc =
+	    lib_infop->ftable.smhbafunctionTable.RemovePersistentBindingHandler;
+	if (RemovePersistentBindingFunc != NULL) {
+	status = ((RemovePersistentBindingFunc)(vendorHandle,
+	    hbaPortWWN, domainPortWWN, binding));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_RemoveAllPersistentBindings(
+    HBA_HANDLE handle,
+    HBA_WWN	hbaPortWWN,
+    HBA_WWN	domainPortWWN)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBARemoveAllPersistentBindingsFunc
+	    RemoveAllPersistentBindingsFunc;
+
+	DEBUG(2, "SMHBA_RemoveAllPersistentBinding port WWN: %s",
+	    WWN2STR1(&hbaPortWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	RemoveAllPersistentBindingsFunc =
+	    lib_infop->ftable.smhbafunctionTable.\
+	    RemoveAllPersistentBindingsHandler;
+	if (RemoveAllPersistentBindingsFunc != NULL) {
+	status = ((RemoveAllPersistentBindingsFunc)(vendorHandle,
+	    hbaPortWWN, domainPortWWN));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_GetLUNStatistics(
+    HBA_HANDLE handle,
+    const HBA_SCSIID *lunit,
+    SMHBA_PROTOCOLSTATISTICS *statistics)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAGetLUNStatisticsFunc GetLUNStatisticsFunc;
+
+	DEBUG(2, "SMHBA_GetLUNStatistics", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	GetLUNStatisticsFunc =
+	    lib_infop->ftable.smhbafunctionTable.GetLUNStatisticsHandler;
+	if (GetLUNStatisticsFunc != NULL) {
+	status = ((GetLUNStatisticsFunc)(vendorHandle, lunit, statistics));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_ScsiInquiry(
+    HBA_HANDLE	handle,
+    HBA_WWN	hbaPortWWN,
+    HBA_WWN	discoveredPortWWN,
+    HBA_WWN	domainPortWWN,
+    SMHBA_SCSILUN	smhbaLUN,
+    HBA_UINT8	CDB_Byte1,
+    HBA_UINT8	CDB_Byte2,
+    void	*pRspBuffer,
+    HBA_UINT32	*pRspBufferSize,
+    HBA_UINT8	*pScsiStatus,
+    void	*pSenseBuffer,
+    HBA_UINT32	*pSenseBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAScsiInquiryFunc ScsiInquiryFunc;
+
+	DEBUG(2, "SMHBA_ScsiInquiry to hba port: %s discoveredPortWWN: %s",
+	    WWN2STR1(&hbaPortWWN), WWN2STR1(&discoveredPortWWN), 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	ScsiInquiryFunc =
+	    lib_infop->ftable.smhbafunctionTable.ScsiInquiryHandler;
+	if (ScsiInquiryFunc != NULL) {
+	status = ((ScsiInquiryFunc)(
+	    vendorHandle, hbaPortWWN, discoveredPortWWN, domainPortWWN,
+	    smhbaLUN, CDB_Byte1, CDB_Byte2, pRspBuffer, pRspBufferSize,
+	    pScsiStatus, pSenseBuffer, pSenseBufferSize));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_ScsiReportLUNs(
+    HBA_HANDLE	handle,
+    HBA_WWN	hbaPortWWN,
+    HBA_WWN	discoveredPortWWN,
+    HBA_WWN	domainPortWWN,
+    void	*pRspBuffer,
+    HBA_UINT32	*pRspBufferSize,
+    HBA_UINT8	*pScsiStatus,
+    void	*pSenseBuffer,
+    HBA_UINT32	*pSenseBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAScsiReportLUNsFunc ScsiReportLUNsFunc;
+
+	DEBUG(2, "SMHBA_ScsiReportLuns to hba port: %s discoveredPortWWN: %s",
+	    WWN2STR1(&hbaPortWWN), WWN2STR1(&discoveredPortWWN), 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	ScsiReportLUNsFunc =
+	    lib_infop->ftable.smhbafunctionTable.ScsiReportLUNsHandler;
+	if (ScsiReportLUNsFunc != NULL) {
+	status = ((ScsiReportLUNsFunc)(
+	    vendorHandle, hbaPortWWN, discoveredPortWWN, domainPortWWN,
+	    pRspBuffer, pRspBufferSize, pScsiStatus, pSenseBuffer,
+	    pSenseBufferSize));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_ScsiReadCapacity(
+    HBA_HANDLE	handle,
+    HBA_WWN	hbaPortWWN,
+    HBA_WWN	discoveredPortWWN,
+    HBA_WWN	domainPortWWN,
+    SMHBA_SCSILUN	smhbaLUN,
+    void	*pRspBuffer,
+    HBA_UINT32	*pRspBufferSize,
+    HBA_UINT8	*pScsiStatus,
+    void	*pSenseBuffer,
+    HBA_UINT32	*pSenseBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBAScsiReadCapacityFunc ScsiReadCapacityFunc;
+
+	DEBUG(2, "SMHBA_ScsiReadCapacity to hba port: %s discoveredPortWWN: %s",
+	    WWN2STR1(&hbaPortWWN), WWN2STR1(&discoveredPortWWN), 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	ScsiReadCapacityFunc =
+	    lib_infop->ftable.smhbafunctionTable.ScsiReadCapacityHandler;
+	if (ScsiReadCapacityFunc != NULL) {
+	status = ((ScsiReadCapacityFunc)(
+	    vendorHandle, hbaPortWWN, discoveredPortWWN, domainPortWWN,
+	    smhbaLUN, pRspBuffer, pRspBufferSize, pScsiStatus, pSenseBuffer,
+	    pSenseBufferSize));
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_SendTEST(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		destWWN,
+    HBA_UINT32		destFCID,
+    void		*pRspBuffer,
+    HBA_UINT32		pRspBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBASendTESTFunc	SendTESTFunc;
+
+	DEBUG(2, "SMHBA_SendTEST, hbaPortWWN: %s destWWN",
+	    WWN2STR1(&hbaPortWWN),
+	    WWN2STR1(&destWWN), 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	SendTESTFunc = lib_infop->ftable.smhbafunctionTable.SendTESTHandler;
+	if (SendTESTFunc != NULL) {
+	status = (SendTESTFunc)
+	    (vendorHandle, hbaPortWWN, destWWN, destFCID,
+	    pRspBuffer, pRspBufferSize);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_SendECHO(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		destWWN,
+    HBA_UINT32		destFCID,
+    void		*pReqBuffer,
+    HBA_UINT32		ReqBufferSize,
+    void		*pRspBuffer,
+    HBA_UINT32		*pRspBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBASendECHOFunc	SendECHOFunc;
+
+	DEBUG(2, "SMHBA_SendECHO, hbaPortWWN: %s destWWN",
+	    WWN2STR1(&hbaPortWWN), WWN2STR1(&destWWN), 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	SendECHOFunc = lib_infop->ftable.smhbafunctionTable.SendECHOHandler;
+	if (SendECHOFunc != NULL) {
+	status = (SendECHOFunc)
+	    (vendorHandle, hbaPortWWN, destWWN, destFCID,
+	    pReqBuffer, ReqBufferSize, pRspBuffer, pRspBufferSize);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+HBA_STATUS
+SMHBA_SendSMPPassThru(
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		destWWN,
+    HBA_WWN		domainPortWWN,
+    void		*pReqBuffer,
+    HBA_UINT32		ReqBufferSize,
+    void		*pRspBuffer,
+    HBA_UINT32		*pRspBufferSize)
+{
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+	SMHBASendSMPPassThruFunc	SendSMPPassThruFunc;
+
+	DEBUG(2, "SMHBA_SendSMPPassThru, hbaPortWWN: %s destWWN: %s",
+	    WWN2STR1(&hbaPortWWN), WWN2STR1(&destWWN), 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	SendSMPPassThruFunc = lib_infop->ftable.\
+	    smhbafunctionTable.SendSMPPassThruHandler;
+
+	if (SendSMPPassThruFunc != NULL) {
+	status = (SendSMPPassThruFunc)
+	    (vendorHandle, hbaPortWWN, destWWN, domainPortWWN,
+	    pReqBuffer, ReqBufferSize, pRspBuffer, pRspBufferSize);
+	} else {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	}
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+/*
+ * Following the similar logic of HBAAPI addaspterevents_callback.
+ *
+ * Unlike other events Adapter Add Event is not limited to a specific
+ * adpater(i.e. no adatper handle is passed for registration) so
+ * the event should be passed to all registrants.  The routine below
+ * is passed to the VSLs as a callback and when Adapter Add event is detected
+ * by VSL it will call smhba_adapteraddevents_callback() which in turn check
+ * if the passed userdata ptr matches with the one stored in the callback list
+ * and calls the stored callback.
+ *
+ * For the situation that multiple clients are registered for Adapter Add event
+ * each registration is passed to VSLs so VSL may call
+ * smhba_adapteraddevents_callback() multiple times or it may call only once
+ * since the callback function is same.  For this implemneation, the userdata
+ * is stored in HBA_ALLADAPTERSCALLBACK_ELEM so it is expected that VSL call
+ * smhba_adapteraddevents_callback() only once and
+ * smhba_adapteraddevents_callback() will call the client callback with proper
+ * userdata.
+ */
+static void
+smhba_adapteraddevents_callback(
+/* LINTED E_FUNC_ARG_UNUSED */
+    void *data,
+    HBA_WWN PortWWN,
+/* LINTED E_FUNC_ARG_UNUSED */
+    HBA_UINT32 eventType)
+{
+	HBA_ALLADAPTERSCALLBACK_ELEM	*cbp;
+
+	DEBUG(3, "AddAdapterEvent, port:%s", WWN2STR1(&PortWWN), 0, 0);
+
+	GRAB_MUTEX(&_smhba_AAE_mutex);
+	for (cbp = _smhba_adapteraddevents_callback_list;
+	    cbp != NULL;
+	    cbp = cbp->next) {
+	(*cbp->callback)(cbp->userdata, PortWWN, HBA_EVENT_ADAPTER_ADD);
+	}
+	RELEASE_MUTEX(&_smhba_AAE_mutex);
+
+}
+
+HBA_STATUS
+SMHBA_RegisterForAdapterAddEvents(
+    void		(*pCallback) (
+	void		*data,
+	HBA_WWN		PortWWN,
+	HBA_UINT32	eventType),
+    void		*pUserData,
+    HBA_CALLBACKHANDLE  *pCallbackHandle) {
+
+    HBA_ALLADAPTERSCALLBACK_ELEM	*cbp;
+    HBA_VENDORCALLBACK_ELEM		*vcbp;
+    HBA_VENDORCALLBACK_ELEM		*vendorhandlelist;
+    SMHBARegisterForAdapterAddEventsFunc	registeredfunc;
+    HBA_STATUS				status = HBA_STATUS_OK;
+    HBA_STATUS				failure = HBA_STATUS_OK;
+    HBA_LIBRARY_INFO			*lib_infop;
+    int					registered_cnt = 0;
+    int					vendor_cnt = 0;
+    int					not_supported_cnt = 0;
+    int					status_OK_bar_cnt = 0;
+    int					status_OK_cnt = 0;
+
+    DEBUG(2, "SMHBA_RegisterForAdapterAddEvents", 0, 0, 0);
+    ARE_WE_INITED();
+
+    cbp = (HBA_ALLADAPTERSCALLBACK_ELEM *)
+	    calloc(1, sizeof (HBA_ALLADAPTERSCALLBACK_ELEM));
+	*pCallbackHandle = (HBA_CALLBACKHANDLE) cbp;
+    if (cbp == NULL) {
+	return (HBA_STATUS_ERROR);
+	}
+
+    GRAB_MUTEX(&_hbaapi_LL_mutex);
+    GRAB_MUTEX(&_smhba_AAE_mutex);
+    cbp->callback = pCallback;
+    cbp->userdata = pUserData;
+    cbp->next = _smhba_adapteraddevents_callback_list;
+    _smhba_adapteraddevents_callback_list = cbp;
+
+	/*
+	 * Need to release the mutex now incase the vendor function invokes the
+	 * callback.  We will grap the mutex later to attach the vendor handle
+	 * list to the callback structure
+	 */
+	RELEASE_MUTEX(&_smhba_AAE_mutex);
+
+
+	/*
+	 * now create a list of vendors (vendor libraryies, NOT ADAPTERS)
+	 * that have successfully registerred
+	 */
+    vendorhandlelist = NULL;
+    for (lib_infop = _hbaapi_librarylist;
+	lib_infop != NULL;
+	lib_infop = lib_infop->next) {
+
+	/* only for HBAAPI V2 */
+	if (lib_infop->version != SMHBA) {
+	    continue;
+	} else {
+	    vendor_cnt++;
+	}
+
+	registeredfunc =
+	    lib_infop->ftable.smhbafunctionTable.\
+	    RegisterForAdapterAddEventsHandler;
+	if (registeredfunc == NULL) {
+	    continue;
+	}
+
+	vcbp = (HBA_VENDORCALLBACK_ELEM *)
+	    calloc(1, sizeof (HBA_VENDORCALLBACK_ELEM));
+	if (vcbp == NULL) {
+	    freevendorhandlelist(vendorhandlelist);
+	    status = HBA_STATUS_ERROR;
+	    break;
+	}
+
+	registered_cnt++;
+	status = (registeredfunc)(smhba_adapteraddevents_callback,
+	    pUserData, &vcbp->vendorcbhandle);
+	if (status == HBA_STATUS_ERROR_NOT_SUPPORTED) {
+	    not_supported_cnt++;
+	    free(vcbp);
+	    continue;
+	} else if (status != HBA_STATUS_OK) {
+	    status_OK_bar_cnt++;
+	    DEBUG(1,
+		    "SMHBA_RegisterForAdapterAddEvents: Library->%s, Error->%d",
+		    lib_infop->LibraryPath, status, 0);
+	    failure = status;
+	    free(vcbp);
+	    continue;
+	} else {
+	    status_OK_cnt++;
+	}
+	vcbp->lib_info = lib_infop;
+	vcbp->next = vendorhandlelist;
+	vendorhandlelist = vcbp;
+	}
+
+    if (vendor_cnt == 0) {
+	/* no SMHBA VSL found.  Should be okay?? */
+	status = HBA_STATUS_ERROR;
+	} else if (registered_cnt == 0) {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	freevendorhandlelist(vendorhandlelist);
+	(void) local_remove_callback((HBA_CALLBACKHANDLE) cbp);
+	} else if (status_OK_cnt == 0 && not_supported_cnt != 0) {
+	status = HBA_STATUS_ERROR_NOT_SUPPORTED;
+	} else if (status_OK_cnt == 0) {
+	/*
+	 * At least one vendor library registered this function, but no
+	 * vendor call succeeded
+	 */
+	(void) local_remove_callback((HBA_CALLBACKHANDLE) cbp);
+	status = failure;
+	} else {
+	/* we have had atleast some success, now finish up */
+	GRAB_MUTEX(&_smhba_AAE_mutex);
+	/*
+	 * this seems silly, but what if another thread called
+	 * the callback remove
+	 */
+	for (cbp = _smhba_adapteraddevents_callback_list;
+	    cbp != NULL; cbp = cbp->next) {
+	    if ((HBA_CALLBACKHANDLE)cbp == *pCallbackHandle) {
+		/* yup, its still there, hooray */
+		cbp->vendorhandlelist = vendorhandlelist;
+		vendorhandlelist = NULL;
+		break;
+	    }
+	}
+	RELEASE_MUTEX(&_smhba_AAE_mutex);
+	if (vendorhandlelist != NULL) {
+		/*
+		 * bummer, somebody removed the callback before we finished
+		 * registration, probably will never happen
+		 */
+	    freevendorhandlelist(vendorhandlelist);
+	    DEBUG(1,
+		    "HBA_RegisterForAdapterAddEvents: HBA_RemoveCallback was "
+		    "called for a handle before registration was finished.",
+		    0, 0, 0);
+	    status = HBA_STATUS_ERROR;
+	} else {
+	    status = HBA_STATUS_OK;
+	}
+	}
+    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+}
+
+/* SMHBA Adapter Events (other than add) ******************************** */
+static void
+smhba_adapterevents_callback(void *data,
+			HBA_WWN PortWWN,
+			HBA_UINT32 eventType)
+{
+	HBA_ADAPTERCALLBACK_ELEM	*acbp;
+
+	DEBUG(3, "AdapterEvent, port:%s, eventType:%d", WWN2STR1(&PortWWN),
+	    eventType, 0);
+
+	GRAB_MUTEX(&_hbaapi_AE_mutex);
+	for (acbp = _smhba_adapterevents_callback_list;
+	    acbp != NULL;
+	    acbp = acbp->next) {
+	if (data == (void *)acbp) {
+		(*acbp->callback)(acbp->userdata, PortWWN, eventType);
+		break;
+	}
+	}
+	RELEASE_MUTEX(&_hbaapi_AE_mutex);
+}
+
+HBA_STATUS
+SMHBA_RegisterForAdapterEvents(
+    void		(*pCallback) (
+	void		*data,
+	HBA_WWN		PortWWN,
+	HBA_UINT32	eventType),
+    void		*pUserData,
+    HBA_HANDLE		handle,
+    HBA_CALLBACKHANDLE	*pCallbackHandle) {
+
+	HBA_ADAPTERCALLBACK_ELEM		*acbp;
+	SMHBARegisterForAdapterEventsFunc	registeredfunc;
+	HBA_STATUS				status;
+	HBA_LIBRARY_INFO			*lib_infop;
+	HBA_HANDLE				vendorHandle;
+
+	DEBUG(2, "SMHBA_RegisterForAdapterEvents", 0, 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+
+	/* we now have the _hbaapi_LL_mutex */
+
+	registeredfunc = lib_infop->ftable.smhbafunctionTable.\
+	    RegisterForAdapterEventsHandler;
+    if (registeredfunc == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_NOT_SUPPORTED);
+	}
+
+	/*
+	 * that allocated memory is used both as the handle for the
+	 * caller, and as userdata to the vendor call so that on
+	 * callback the specific registration may be recalled
+	 */
+	acbp = (HBA_ADAPTERCALLBACK_ELEM *)
+	    calloc(1, sizeof (HBA_ADAPTERCALLBACK_ELEM));
+	if (acbp == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR);
+	}
+	*pCallbackHandle = (HBA_CALLBACKHANDLE) acbp;
+	acbp->callback = pCallback;
+	acbp->userdata = pUserData;
+	acbp->lib_info = lib_infop;
+
+	status = (registeredfunc)(smhba_adapterevents_callback,
+	    (void *)acbp,
+	    vendorHandle,
+	    &acbp->vendorcbhandle);
+    if (status != HBA_STATUS_OK) {
+	free(acbp);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+	}
+
+	GRAB_MUTEX(&_smhba_AE_mutex);
+	acbp->next = _smhba_adapterevents_callback_list;
+	    _hbaapi_adapterevents_callback_list = acbp;
+
+	RELEASE_MUTEX(&_smhba_AE_mutex);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_OK);
+}
+
+/* Adapter Port Events *********************************************** */
+static void
+smhba_adapterportevents_callback(void *data,
+			    HBA_WWN PortWWN,
+			    HBA_UINT32 eventType,
+			    HBA_UINT32 fabricPortID)
+{
+	HBA_ADAPTERCALLBACK_ELEM	*acbp;
+
+	DEBUG(3,
+	    "SMHBA_AdapterPortEvent, port:%s, eventType:%d fabricPortID:0X%06x",
+	    WWN2STR1(&PortWWN), eventType, fabricPortID);
+
+	GRAB_MUTEX(&_smhba_APE_mutex);
+
+	for (acbp = _smhba_adapterportevents_callback_list;
+	    acbp != NULL;
+	    acbp = acbp->next) {
+	if (data == (void *)acbp) {
+		(*acbp->callback)(acbp->userdata, PortWWN,
+		    eventType, fabricPortID);
+		break;
+	}
+	}
+	RELEASE_MUTEX(&_smhba_APE_mutex);
+}
+
+HBA_STATUS
+SMHBA_RegisterForAdapterPortEvents(
+    void		(*pCallback) (
+	void		*pData,
+	HBA_WWN		PortWWN,
+	HBA_UINT32	eventType,
+	HBA_UINT32	fabricPortID),
+    void		*pUserData,
+    HBA_HANDLE		handle,
+    HBA_WWN		portWWN,
+    HBA_UINT32		specificEventType,
+    HBA_CALLBACKHANDLE	*pCallbackHandle) {
+
+	HBA_ADAPTERCALLBACK_ELEM		*acbp;
+	SMHBARegisterForAdapterPortEventsFunc	registeredfunc;
+	HBA_STATUS				status;
+	HBA_LIBRARY_INFO			*lib_infop;
+	HBA_HANDLE				vendorHandle;
+
+	DEBUG(2, "SMHBA_RegisterForAdapterPortEvents for port: %s",
+	    WWN2STR1(&portWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+	/* we now have the _hbaapi_LL_mutex */
+
+	registeredfunc =
+	    lib_infop->ftable.smhbafunctionTable.\
+	    RegisterForAdapterPortEventsHandler;
+	if (registeredfunc == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_NOT_SUPPORTED);
+	}
+
+	/*
+	 * that allocated memory is used both as the handle for the
+	 * caller, and as userdata to the vendor call so that on
+	 * callback the specific registration may be recalled
+	 */
+	acbp = (HBA_ADAPTERCALLBACK_ELEM *)
+	    calloc(1, sizeof (HBA_ADAPTERCALLBACK_ELEM));
+	if (acbp == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR);
+	}
+	*pCallbackHandle = (HBA_CALLBACKHANDLE) acbp;
+	acbp->callback = pCallback;
+	acbp->userdata = pUserData;
+	acbp->lib_info = lib_infop;
+
+	status = (registeredfunc)(smhba_adapterportevents_callback,
+	    (void *)acbp,
+	    vendorHandle,
+	    portWWN,
+	    specificEventType,
+	    &acbp->vendorcbhandle);
+	if (status != HBA_STATUS_OK) {
+	free(acbp);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+	}
+
+	GRAB_MUTEX(&_smhba_APE_mutex);
+	acbp->next = _smhba_adapterportevents_callback_list;
+	_smhba_adapterportevents_callback_list = acbp;
+
+	RELEASE_MUTEX(&_smhba_APE_mutex);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_OK);
+}
+
+/* SMHBA Adapter Port Stat Events ******************************** */
+static void
+smhba_adapterportstatevents_callback(void *data,
+				HBA_WWN portWWN,
+				HBA_UINT32 protocolType,
+				HBA_UINT32 eventType)
+{
+	HBA_ADAPTERCALLBACK_ELEM	*acbp;
+
+	DEBUG(3,
+	    "SMBA_AdapterPortStateEvent, port:%s, eventType:%d",
+	    WWN2STR1(&portWWN), eventType, 0);
+
+	GRAB_MUTEX(&_smhba_APSE_mutex);
+	for (acbp = _smhba_adapterportstatevents_callback_list;
+	    acbp != NULL;
+	    acbp = acbp->next) {
+	if (data == (void *)acbp) {
+		(*acbp->callback)(acbp->userdata, portWWN,
+		    protocolType, eventType);
+		return;
+	}
+	}
+	RELEASE_MUTEX(&_smhba_APSE_mutex);
+}
+
+HBA_STATUS
+SMHBA_RegisterForAdapterPortStatEvents(
+    void		(*pCallback) (
+	void		*pData,
+	HBA_WWN		portWWN,
+	HBA_UINT32	protocolType,
+	HBA_UINT32	eventType),
+    void		*pUserData,
+    HBA_HANDLE		handle,
+    HBA_WWN		portWWN,
+    HBA_UINT32		protocolType,
+    SMHBA_PROTOCOLSTATISTICS	stats,
+    HBA_UINT32		statType,
+    HBA_CALLBACKHANDLE	*pCallbackHandle) {
+
+	HBA_ADAPTERCALLBACK_ELEM	*acbp;
+	SMHBARegisterForAdapterPortStatEventsFunc
+	    registeredfunc;
+	HBA_STATUS			status;
+	HBA_LIBRARY_INFO		*lib_infop;
+	HBA_HANDLE			vendorHandle;
+
+	DEBUG(2, "SMHBA_RegisterForAdapterPortStatEvents for port: %s",
+	    WWN2STR1(&portWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+	/* we now have the _hbaapi_LL_mutex */
+
+	registeredfunc =
+	    lib_infop->ftable.smhbafunctionTable.\
+	    RegisterForAdapterPortStatEventsHandler;
+	if (registeredfunc == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_NOT_SUPPORTED);
+	}
+
+	/*
+	 * that allocated memory is used both as the handle for the
+	 * caller, and as userdata to the vendor call so that on
+	 * callback the specific registration may be recalled
+	 */
+	acbp = (HBA_ADAPTERCALLBACK_ELEM *)
+	    calloc(1, sizeof (HBA_ADAPTERCALLBACK_ELEM));
+	if (acbp == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR);
+	}
+	*pCallbackHandle = (HBA_CALLBACKHANDLE) acbp;
+	acbp->callback = pCallback;
+	acbp->userdata = pUserData;
+	acbp->lib_info = lib_infop;
+
+	status = (registeredfunc)(smhba_adapterportstatevents_callback,
+	    (void *)acbp,
+	    vendorHandle,
+	    portWWN,
+	    protocolType,
+	    stats,
+	    statType,
+	    &acbp->vendorcbhandle);
+	if (status != HBA_STATUS_OK) {
+	free(acbp);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+	}
+
+	GRAB_MUTEX(&_smhba_APSE_mutex);
+	acbp->next = _smhba_adapterportstatevents_callback_list;
+	_smhba_adapterportstatevents_callback_list = acbp;
+
+	RELEASE_MUTEX(&_smhba_APSE_mutex);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_OK);
+}
+
+/* SMHBA Adapter Port Phy Stat Events ************************************ */
+static void
+smhba_adapterphystatevents_callback(void *data,
+				HBA_WWN portWWN,
+				HBA_UINT32 phyIndex,
+				HBA_UINT32 eventType)
+{
+	HBA_ADAPTERCALLBACK_ELEM	*acbp;
+
+	DEBUG(3,
+	    "SMBA_AdapterPortStateEvent, port:%s, eventType:%d",
+	    WWN2STR1(&portWWN), eventType, 0);
+
+	GRAB_MUTEX(&_smhba_APHYSE_mutex);
+	for (acbp = _smhba_adapterphystatevents_callback_list;
+	    acbp != NULL;
+	    acbp = acbp->next) {
+	if (data == (void *)acbp) {
+		(*acbp->callback)(acbp->userdata, portWWN, phyIndex, eventType);
+		return;
+	}
+	}
+	RELEASE_MUTEX(&_smhba_APHYSE_mutex);
+}
+
+HBA_STATUS
+SMHBA_RegisterForAdapterPhyStatEvents(
+    void		(*pCallback) (
+	void		*pData,
+	HBA_WWN		portWWN,
+	HBA_UINT32	phyIndex,
+	HBA_UINT32	eventType),
+    void		*pUserData,
+    HBA_HANDLE		handle,
+    HBA_WWN		portWWN,
+    HBA_UINT32		phyIndex,
+    SMHBA_PHYSTATISTICS	stats,
+    HBA_UINT32		statType,
+    HBA_CALLBACKHANDLE	*pCallbackHandle) {
+
+	HBA_ADAPTERCALLBACK_ELEM	*acbp;
+	SMHBARegisterForAdapterPhyStatEventsFunc
+	    registeredfunc;
+	HBA_STATUS			status;
+	HBA_LIBRARY_INFO		*lib_infop;
+	HBA_HANDLE			vendorHandle;
+
+	DEBUG(2, "SMHBA_RegisterForAdapterPhyStatEvents for port: %s",
+	    WWN2STR1(&portWWN), 0, 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+	/* we now have the _hbaapi_LL_mutex */
+
+	registeredfunc =
+	    lib_infop->ftable.smhbafunctionTable.\
+	    RegisterForAdapterPhyStatEventsHandler;
+	if (registeredfunc == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_NOT_SUPPORTED);
+	}
+
+	/*
+	 * that allocated memory is used both as the handle for the
+	 * caller, and as userdata to the vendor call so that on
+	 * callback the specific registration may be recalled
+	 */
+	acbp = (HBA_ADAPTERCALLBACK_ELEM *)
+	    calloc(1, sizeof (HBA_ADAPTERCALLBACK_ELEM));
+	if (acbp == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR);
+	}
+	*pCallbackHandle = (HBA_CALLBACKHANDLE) acbp;
+	acbp->callback = pCallback;
+	acbp->userdata = pUserData;
+	acbp->lib_info = lib_infop;
+
+	status = (registeredfunc)(smhba_adapterphystatevents_callback,
+	    (void *)acbp,
+	    vendorHandle,
+	    portWWN,
+	    phyIndex,
+	    stats,
+	    statType,
+	    &acbp->vendorcbhandle);
+	if (status != HBA_STATUS_OK) {
+	free(acbp);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+	}
+
+	GRAB_MUTEX(&_smhba_APHYSE_mutex);
+	acbp->next = _smhba_adapterphystatevents_callback_list;
+	_smhba_adapterphystatevents_callback_list = acbp;
+
+	RELEASE_MUTEX(&_smhba_APHYSE_mutex);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_OK);
+}
+
+/* SMHBA Target Events ********************************************* */
+static void
+smhba_targetevents_callback(void *data,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN discoveredPortWWN,
+	HBA_WWN domainPortWWN,
+	HBA_UINT32 eventType)
+{
+	HBA_ADAPTERCALLBACK_ELEM	*acbp;
+
+	DEBUG(3, "TargetEvent, hbaPort:%s, discoveredPort:%s eventType:%d",
+	    WWN2STR1(&hbaPortWWN), WWN2STR2(&discoveredPortWWN), eventType);
+
+	GRAB_MUTEX(&_smhba_TE_mutex);
+	for (acbp = _smhba_targetevents_callback_list;
+	    acbp != NULL;
+	    acbp = acbp->next) {
+	if (data == (void *)acbp) {
+		(*acbp->callback)(acbp->userdata, hbaPortWWN,
+		    discoveredPortWWN, domainPortWWN, eventType);
+		break;
+	}
+	}
+	RELEASE_MUTEX(&_smhba_TE_mutex);
+}
+
+HBA_STATUS
+SMHBA_RegisterForTargetEvents(
+    void		(*pCallback) (
+	void		*pData,
+	HBA_WWN		hbaPortWWN,
+	HBA_WWN		discoveredPortWWN,
+	HBA_WWN		domainPortWWN,
+	HBA_UINT32	eventType),
+    void		*pUserData,
+    HBA_HANDLE		handle,
+    HBA_WWN		hbaPortWWN,
+    HBA_WWN		discoveredPortWWN,
+    HBA_WWN		domainPortWWN,
+    HBA_CALLBACKHANDLE	*pCallbackHandle,
+    HBA_UINT32		allTargets) {
+
+	HBA_ADAPTERCALLBACK_ELEM *acbp;
+	SMHBARegisterForTargetEventsFunc
+	    registeredfunc;
+	HBA_STATUS		status;
+	HBA_LIBRARY_INFO	*lib_infop;
+	HBA_HANDLE		vendorHandle;
+
+	DEBUG(2, "SMHBA_RegisterForTargetEvents, hbaPort:"
+	    "%s, discoveredPort: %s",
+	    WWN2STR1(&hbaPortWWN), WWN2STR2(&discoveredPortWWN), 0);
+
+	CHECKLIBRARYANDVERSION(SMHBA);
+	/* we now have the _hbaapi_LL_mutex */
+
+	registeredfunc = lib_infop->ftable.smhbafunctionTable.\
+	    RegisterForTargetEventsHandler;
+
+	if (registeredfunc == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_NOT_SUPPORTED);
+	}
+
+	/*
+	 * that allocated memory is used both as the handle for the
+	 * caller, and as userdata to the vendor call so that on
+	 * callback the specific registration may be recalled
+	 */
+	acbp = (HBA_ADAPTERCALLBACK_ELEM *)
+	    calloc(1, sizeof (HBA_ADAPTERCALLBACK_ELEM));
+	if (acbp == NULL) {
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR);
+	}
+	*pCallbackHandle = (HBA_CALLBACKHANDLE) acbp;
+	acbp->callback = pCallback;
+	acbp->userdata = pUserData;
+	acbp->lib_info = lib_infop;
+
+	status = (registeredfunc)(smhba_targetevents_callback,
+	    (void *)acbp,
+	    vendorHandle,
+	    hbaPortWWN,
+	    discoveredPortWWN,
+	    domainPortWWN,
+	    &acbp->vendorcbhandle,
+	    allTargets);
+	if (status != HBA_STATUS_OK) {
+	free(acbp);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
+	}
+
+	GRAB_MUTEX(&_smhba_TE_mutex);
+	acbp->next = _smhba_targetevents_callback_list;
+	_smhba_targetevents_callback_list = acbp;
+
+	RELEASE_MUTEX(&_smhba_TE_mutex);
+	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/common/llib-lSMHBAAPI	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,30 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <smhbaapi.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/common/mapfile-vers	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,136 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING:  STOP NOW.  DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+#	usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+
+SUNW_1.1 {
+    global:
+	HBA_GetVersion;
+	HBA_GetWrapperLibraryAttributes;
+	HBA_LoadLibrary;
+	HBA_FreeLibrary;
+	HBA_GetNumberOfAdapters;
+	HBA_GetAdapterName;
+	HBA_OpenAdapter;
+	HBA_CloseAdapter;
+	HBA_GetAdapterAttributes;
+	HBA_GetAdapterPortAttributes;
+	HBA_GetPortStatistics;
+	HBA_GetDiscoveredPortAttributes;
+	HBA_GetPortAttributesByWWN;
+	HBA_SendCTPassThru;
+	HBA_RefreshInformation;
+	HBA_ResetStatistics;
+	HBA_GetFcpTargetMapping;
+	HBA_GetFcpPersistentBinding;
+	HBA_GetEventBuffer;
+	HBA_SetRNIDMgmtInfo;
+	HBA_GetRNIDMgmtInfo;
+	HBA_SendRNID;
+	HBA_SendScsiInquiry;
+	HBA_SendReportLUNs;
+	HBA_SendReadCapacity;
+	HBA_GetVendorLibraryAttributes;
+	HBA_OpenAdapterByWWN;
+	HBA_SendCTPassThruV2;
+	HBA_RefreshAdapterConfiguration;
+	HBA_GetFcpTargetMappingV2;
+	HBA_RemoveCallback;
+	HBA_RegisterForAdapterAddEvents;
+	HBA_RegisterForAdapterEvents;
+	HBA_RegisterForAdapterPortEvents;
+	HBA_RegisterForAdapterPortStatEvents;
+	HBA_RegisterForTargetEvents;
+	HBA_RegisterForLinkEvents;
+	HBA_SendRNIDV2;
+	HBA_SendRLS;
+	HBA_SendRPL;
+	HBA_SendRPS;
+	HBA_SendSRL;
+	HBA_SendLIRR;
+	HBA_ScsiInquiryV2;
+	HBA_ScsiReportLUNsV2;
+	HBA_ScsiReadCapacityV2;
+	HBA_GetBindingCapability;
+	HBA_SetBindingSupport;
+	HBA_GetBindingSupport;
+	HBA_SetPersistentBindingV2;
+	HBA_GetPersistentBindingV2;
+	HBA_RemovePersistentBinding;
+	HBA_RemoveAllPersistentBindings;
+	HBA_GetFC4Statistics;
+	HBA_GetFCPStatistics;
+	SMHBA_GetVersion;
+	SMHBA_GetWrapperLibraryAttributes;
+	SMHBA_GetVendorLibraryAttributes;
+	SMHBA_GetAdapterAttributes;
+	SMHBA_GetNumberOfPorts;
+	SMHBA_GetPortType;
+	SMHBA_GetAdapterPortAttributes;
+	SMHBA_GetDiscoveredPortAttributes;
+	SMHBA_GetPortAttributesByWWN;
+	SMHBA_GetFCPhyAttributes;
+	SMHBA_GetSASPhyAttributes;
+	SMHBA_GetProtocolStatistics;
+	SMHBA_GetPhyStatistics;
+	SMHBA_GetBindingCapability;
+	SMHBA_GetBindingSupport;
+	SMHBA_SetBindingSupport;
+	SMHBA_GetTargetMapping;
+	SMHBA_GetPersistentBinding;
+	SMHBA_SetPersistentBinding;
+	SMHBA_RemovePersistentBinding;
+	SMHBA_RemoveAllPersistentBindings;
+	SMHBA_GetLUNStatistics;
+	SMHBA_ScsiInquiry;
+	SMHBA_ScsiReportLUNs;
+	SMHBA_ScsiReadCapacity;
+	SMHBA_SendTEST;
+	SMHBA_SendECHO;
+	SMHBA_SendSMPPassThru;
+	SMHBA_RegisterForAdapterAddEvents;
+	SMHBA_RegisterForAdapterEvents;
+	SMHBA_RegisterForAdapterPortEvents;
+	SMHBA_RegisterForAdapterPortStatEvents;
+	SMHBA_RegisterForAdapterPortStatEvents;
+	SMHBA_RegisterForTargetEvents;
+
+   local:
+	*;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/common/smhba.conf	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,36 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+# This file contains names and references to SM-HBA libraries
+#
+# Format:
+#
+# <library name>  <library pathname>
+#
+# The library name should be prepended with the domain of
+# the manufacturer or driver author.
+com.sun.sashba		/usr/lib/libsun_sas.so.1
+com.sun.sashba64	/usr/lib/64/libsun_sas.so.1
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/common/smhbaapi.h	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,672 @@
+/*
+ * ****************************************************************************
+ *
+ * Description
+ *	smhbaapi.h - general header file for client
+ *	and library developers
+ *
+ * License:
+ *	The contents of this file are subject to the SNIA Public License
+ *	Version 1.0 (the "License"); you may not use this file except in
+ *	compliance with the License. You may obtain a copy of the License at
+ *
+ *	/http://www.snia.org/English/Resources/Code/OpenSource.html
+ *
+ *	Software distributed under the License is distributed on an "AS IS"
+ *	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ *	the License for the specific language governing rights and limitations
+ *	under the License.
+ *
+ * The Original Code for  SM-HBA API general header file
+ *
+ * The Initial Developer of the Original Code is:
+ *	Benjamin F. Kuo, Troika Networks, Inc. (benk@troikanetworks.com)
+ *
+ * Contributor(s):
+ *	Tuan Lam, QLogic Corp. (t_lam@qlc.com)
+ *	Dan Willie, Emulex Corp. (Dan.Willie@emulex.com)
+ *	Dixon Hutchinson, Legato Systems, Inc. (dhutchin@legato.com)
+ *	David Dillard, VERITAS Software Corp. (david.dillard@veritas.com)
+ *
+ * ****************************************************************************
+ *
+ * Adding on SM-HBA related definitions.
+ *
+ * - Includes the original HBA API header.
+ * - SMHBA_* interfaces and structures are defined.
+ *
+ * ****************************************************************************
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMHBAAPI_H_
+#define	_SMHBAAPI_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <hbaapi.h>
+
+/* Library version string */
+#define	SMHBA_LIBVERSION 1
+
+/*
+ * A SCSI function was requested at a time when issuing the requested command
+ * would cause a SCSI overlapped command condition (see SAM-3)
+ */
+#define	HBA_STATUS_ERROR_TARGET_BUSY	30
+/* SM-HBA 6.2	Status Return Values */
+/* A call was made to HBA_FreeLibrary when no library was loaded */
+#define	HBA_STATUS_ERROR_NOT_LOADED	31
+/* A call was made to HBA_LoadLibrary when a library was already loaded */
+#define	HBA_STATUS_ERROR_ALREADY_LOADED 32
+/*
+ * The Address Identifier specified in a call to HBA_SendRNIDV2
+ * violates access control rules * for that call.
+ */
+#define	HBA_STATUS_ERROR_ILLEGAL_FCID	33
+#define	HBA_STATUS_ERROR_NOT_ASCSIDEVICE    34
+#define	HBA_STATUS_ERROR_INVALID_PROTOCOL_TYPE	35
+#define	HBA_STATUS_ERROR_BAD_EVENT_TYPE	36
+
+
+/* SM-HBA 6.4.1.1 Port Type */
+#define	HBA_PORTTYPE_SASDEVICE   30 /* SAS (SSP or STP) */
+#define	HBA_PORTTYPE_SATADEVICE  31 /* SATA Device, i.e. Direct Attach SATA */
+#define	HBA_PORTTYPE_SASEXPANDER 32 /* SAS Expander */
+
+/* SM-HBA 6.4.1.2 Port State */
+#define	HBA_PORTSTATE_DEGRADED	9 /* Degraded, but Operational mode */
+
+/* SM-HBA 6.11.1.3 Port Speed */
+#define	HBA_PORTSPEED_4GBIT	8  /*  4 GBit / sec */
+
+/* SM-HBA 6.1	Basic Attributes Types */
+typedef struct SMHBA_scsilun {HBA_UINT8 lun[8]; }
+    SMHBA_SCSILUN, *PSMHBA_SCSILUN;
+			/* A byte array representation of a SCSI */
+			/* LUN (see SAM-4). The first byte of the */
+			/* LUN shall be in the first byte of the */
+			/* array, and successive bytes of the SCSI */
+			/* LUN shall be in successive bytes of the */
+			/* array. */
+typedef unsigned long HBA_SCSILUN;
+			/* A 64 bit unsigned integer representation */
+			/* of a SCSI LUN (see SAM-4); */
+			/* may use OS-specific typedef. */
+			/* Byte zero of a SCSI LUN shall be stored */
+			/* in the lowest memory address */
+			/* of the unsigned 64-bit integer value, */
+			/* and successive bytes of the SCSI LUN */
+			/* shall be stored in successively higher memory */
+			/* addresses of the unsigned 64-bit intege value. */
+			/* Note that computers often do not store */
+			/* a byte array in memory in the same order */
+			/* as they store an integer. */
+			/* This standard requires storage as a byte array */
+
+
+/* SM-HBA 6.3.1 Generic Adapter Attribute */
+typedef struct SMHBA_AdapterAttributes {
+	char			Manufacturer[64];
+	char			SerialNumber[64];
+	char			Model[256];
+	char			ModelDescription[256];
+	char			HardwareVersion[256];
+	char			DriverVersion[256];
+	char			OptionROMVersion[256];
+	char			FirmwareVersion[256];
+	HBA_UINT32		VendorSpecificID;
+	char			DriverName[256];
+	char			HBASymbolicName[256];
+	char			RedundantOptionROMVersion[256];
+	char			RedundantFirmwareVersion[256];
+} SMHBA_ADAPTERATTRIBUTES, *PSMHBA_ADAPTERATTRIBUTES;
+
+/* SM-HBA 6.4.6 SMHBA FC Port Attributes */
+typedef struct SMHBA_FC_Port {
+	HBA_WWN			NodeWWN;
+	HBA_WWN			PortWWN;
+	HBA_UINT32		FcId;
+	HBA_COS			PortSupportedClassofService;
+	HBA_FC4TYPES		PortSupportedFc4Types;
+	HBA_FC4TYPES		PortActiveFc4Types;
+	HBA_WWN			FabricName;
+	char			PortSymbolicName[256];
+	HBA_UINT32		NumberofDiscoveredPorts;
+	HBA_UINT8		NumberofPhys;
+}SMHBA_FC_PORT, *PSMHBA_FC_PORT;
+
+/* SM-HBA 6.4.7.1 HBA_SASPortProtocol */
+typedef HBA_UINT32	HBA_SASPORTPROTOCOL;
+#define	HBA_SASPORTPROTOCOL_SSP	    1 /* Serial SCSI Protocol Port */
+#define	HBA_SASPORTPROTOCOL_STP	    2 /* Serial ATA Tunneling Protocol Port */
+#define	HBA_SASPORTPROTOCOL_SMP	    4 /* Serial Management Protocol Port */
+/* SATA Device, Direct Attached or anywhere in the domain. */
+#define	HBA_SASPORTPROTOCOL_SATA    8
+
+/* SM-HBA 6.4.8 SMHBA SAS Port Attributes */
+typedef struct SMHBA_SAS_Port {
+	HBA_SASPORTPROTOCOL	PortProtocol;
+	HBA_WWN			LocalSASAddress;
+	HBA_WWN			AttachedSASAddress;
+	HBA_UINT32		NumberofDiscoveredPorts;
+	HBA_UINT32		NumberofPhys;
+} SMHBA_SAS_PORT, *PSMHBA_SAS_PORT;
+
+/* SM-HBA 6.4.2 Generic Port Attributes */
+typedef union SMHBA_Port {
+	SMHBA_FC_PORT		*FCPort;
+	SMHBA_SAS_PORT		*SASPort;
+} SMHBA_PORT, *PSMHBA_PORT;
+
+typedef struct SMHBA_PortAttributes {
+	HBA_PORTTYPE		PortType;
+	HBA_PORTSTATE		PortState;
+	char			OSDeviceName[256];
+	SMHBA_PORT		PortSpecificAttribute;
+} SMHBA_PORTATTRIBUTES, *PSMHBA_PORTATTRIBUTES;
+
+/* SM-HBA 6.5.1.1 FC Phy Speed */
+typedef HBA_UINT32 HBA_FCPHYSPEED;
+/* Unknown transceiver incapable of reporting */
+#define	HBA_FCSPEED_UNKNOWN		0
+/*
+ * The following are redundantly defined in SM-HBA 6.11.1.3 Port Speed.
+ * #define  HBA_PORTSPEED_1GBIT            1       1 GBit/sec
+ * #define  HBA_PORTSPEED_2GBIT            2          2 GBit/sec
+ * #define  HBA_PORTSPEED_10GBIT           4          10 GBit/sec
+ * #define  HBA_PORTSPEED_4GBIT            8          4 GBit/sec
+ */
+#define	HBA_FCPHYSPEED_8GBIT		16  /* 8 GBit/sec */
+#define	HBA_FCPHYSPEED_16GBIT		32  /* 16 GBit/sec */
+/*
+ * The following conflicts with HBA API
+ * #define  HBA_PORTSPEED_NOT_NEGOTIATED   (1<<15)  Speed not established
+ */
+
+/* SM-HBA 6.6.1.2 SM-HBA FC Phy Type */
+typedef HBA_UINT8 HBA_FCPHYTYPE;
+#define	HBA_FCPHYTYPE_UNKNOWN		    1 /* Unknown Phy type */
+#define	HBA_FCPHYTYPE_OPTICAL		    2 /* Optical Phy */
+#define	HBA_FCPHYTYPE_COPPER		    4 /* Copper Phy */
+
+/* SM-HBA 6.5.2 SM-HBA FC Phy Attributes */
+typedef struct SMHBA_FC_Phy {
+	HBA_FCPHYSPEED	    PhySupportedSpeed;	/* PhySupportedSpeed */
+	HBA_FCPHYSPEED	    PhySpeed;		/* PhySpeed */
+	HBA_FCPHYTYPE	    PhyType;
+	HBA_UINT32	    MaxFrameSize;	/* MaxFrameSize */
+} SMHBA_FC_PHY, *PSMHBA_FC_PHY;
+
+/* SM-HBA 6.5.4 SAS PHY Attribute Data Declaration */
+typedef HBA_UINT32 HBA_SASPHYSPEED;
+
+#define	HBA_SASSTATE_UNKNOWN	0x00 /* Phy is enabled. Speed is unknown */
+#define	HBA_SASSTATE_DISABLED	0x01 /* Phy is disabled. */
+/* Phy is enabled. But failed speed negotiation. */
+#define	HBA_SASSTATE_FAILED	0x02
+/*
+ * Phy is enabled. Detected a SATA device and entered the SATA Spinup hold
+ * state.
+ */
+#define	HBA_SASSTATE_SATASPINUP    0x03
+/* The phy is attached to a Port Selector (see SATA-2.6). */
+#define	HBA_SASSTATE_SATAPORTSEL    0x04
+#define	HBA_SASSPEED_1_5GBIT	    0x08 /*  1.5 GBit/sec */
+#define	HBA_SASSPEED_3GBIT	    0x09 /*  3 GBit/sec */
+#define	HBA_SASSPEED_6GBIT	    0x0a /*  6 GBit/sec */
+
+/* SM-HBA  6.5.5 SAS Phy Attribute */
+typedef struct SMHBA_SAS_Phy {
+	HBA_UINT8	    PhyIdentifier;
+	HBA_SASPHYSPEED	    NegotiatedLinkRate;
+	HBA_SASPHYSPEED	    ProgrammedMinLinkRate;
+	HBA_SASPHYSPEED	    HardwareMinLinkRate;
+	HBA_SASPHYSPEED	    ProgrammedMaxLinkRate;
+	HBA_SASPHYSPEED	    HardwareMaxLinkRate;
+	HBA_WWN		    domainPortWWN;
+} SMHBA_SAS_PHY, *PSMHBA_SAS_PHY;
+
+/* SM-HBA 6.6.1.1 Protocol Statistics Data Declarations */
+/* Statistical counters for FC-4, SSP, STP, SMP protocols */
+typedef struct SMHBA_ProtocolStatistics {
+	HBA_INT64	    SecondsSinceLastReset;
+	HBA_INT64	    InputRequests;
+	HBA_INT64	    OutputRequests;
+	HBA_INT64	    ControlRequests;
+	HBA_INT64	    InputMegabytes;
+	HBA_INT64	    OutputMegabytes;
+} SMHBA_PROTOCOLSTATISTICS, *PSMHBA_PROTOCOLSTATISTICS;
+
+/* SM-HBA 6.6.2.1 Port Statistics Data Declarations */
+typedef struct SMHBA_PortStatistics {
+	HBA_INT64	    SecondsSinceLastReset;
+	HBA_INT64	    TxFrames;
+	HBA_INT64	    TxWords;
+	HBA_INT64	    RxFrames;
+	HBA_INT64	    RxWords;
+}SMHBA_PORTSTATISTICS, *PSMHBA_PORTSTATISTICS;
+
+/* SM-HBA 6.6.2.2 SAS Phy Statistics Data Declaration */
+typedef struct SMHBA_SASPhyStatistics {
+	HBA_INT64	    SecondsSinceLastReset;
+	HBA_INT64	    TxFrames;
+	HBA_INT64	    TxWords;
+	HBA_INT64	    RxFrames;
+	HBA_INT64	    RxWords;
+	HBA_INT64	    InvalidDwordCount;
+	HBA_INT64	    RunningDisparityErrorCount;
+	HBA_INT64	    LossofDwordSyncCount;
+	HBA_INT64	    PhyResetProblemCount;
+} SMHBA_SASPHYSTATISTICS, *PSMHBA_SASPHYSTATISTICS;
+
+/* SM-HBA 6.6.2.4 FC Phy Statistics Data Declaration */
+/* Statistical counters for FC-0, FC-1, and FC-2 */
+typedef struct SMHBA_FCPhyStatistics {
+	HBA_INT64	    SecondsSinceLastReset;
+	HBA_INT64	    TxFrames;
+	HBA_INT64	    TxWords;
+	HBA_INT64	    RxFrames;
+	HBA_INT64	    RxWords;
+	HBA_INT64	    LIPCount;
+	HBA_INT64	    NOSCount;
+	HBA_INT64	    ErrorFrames;
+	HBA_INT64	    DumpedFrames;
+	HBA_INT64	    LinkFailureCount;
+	HBA_INT64	    LossOfSyncCount;
+	HBA_INT64	    LossOfSignalCount;
+	HBA_INT64	    PrimitiveSeqProtocolErrCount;
+	HBA_INT64	    InvalidTxWordCount;
+	HBA_INT64	    InvalidCRCCount;
+}SMHBA_FCPHYSTATISTICS, *PSMHBA_FCPHYSTATISTICS;
+
+/* SM-HBA 6.6.2.1 Phy Statistics Data Declaration */
+typedef union SMHBA_PhyStatistics {
+	SMHBA_SASPHYSTATISTICS	*SASPhyStatistics;
+	SMHBA_FCPHYSTATISTICS	*FCPhyStatistics;
+} SMHBA_PHYSTATISTICS, *PSMHBA_PHYSTATISTICS;
+
+/* SM-HBA 6.7.1.1 SMHBA_BIND_CAPABILITY */
+typedef HBA_UINT32 SMHBA_BIND_CAPABILITY;
+#define	SMHBA_CAN_BIND_TO_WWPN 0x0001
+#define	SMHBA_CAN_BIND_TO_LUID 0x0002
+#define	SMHBA_CAN_BIND_ANY_LUNS 0x0400
+#define	SMHBA_CAN_BIND_AUTOMAP 0x0800
+
+/* SM-HBA 6.7.1.2 SMHBA_BIND_TYPE */
+typedef HBA_UINT32 SMHBA_BIND_TYPE;
+#define	SMHBA_BIND_TO_WWPN 0x0001
+#define	SMHBA_BIND_TO_LUID 0x0002
+
+/* SM-HBA 6.7.1.3 SMHBA_ScsiId */
+typedef struct SMHBA_ScsiId {
+	char	    OSDeviceName[256];
+	HBA_UINT32  ScsiBusNumber;
+	HBA_UINT32  ScsiTargetNumber;
+	HBA_UINT32  ScsiOSLun;
+} SMHBA_SCSIID, *PSMHBA_SCSIID;
+
+/* SM-HBA 6.7.1.4 SMHBA_LUID */
+typedef struct SMHBA_LUID {
+	char	    buffer[256];
+} SMHBA_LUID, *PSMHBA_LUID;
+
+/* SM-HBA 6.7.1.5 SMHBA_PORTLUN */
+typedef struct SMHBA_PORTLUN {
+	HBA_WWN		    PortWWN;
+	HBA_WWN		    domainPortWWN;
+	SMHBA_SCSILUN	    TargetLun;
+} SMHBA_PORTLUN, *PSMHBA_PORTLUN;
+
+/* SM-HBA 6.7.1.6 Composite types */
+typedef struct SMHBA_ScsiEntry {
+	SMHBA_SCSIID ScsiId;
+	SMHBA_PORTLUN PortLun;
+	SMHBA_LUID LUID;
+} SMHBA_SCSIENTRY, *PSMHBA_SCSIENTRY;
+
+typedef struct SMHBA_TargetMapping {
+	HBA_UINT32 NumberOfEntries;
+	SMHBA_SCSIENTRY entry[1]; /* Variable length array */
+} SMHBA_TARGETMAPPING, *PSMHBA_TARGETMAPPING;
+
+typedef struct SMHBA_BindingEntry {
+	SMHBA_BIND_TYPE	type;
+	SMHBA_SCSIID	ScsiId;
+	SMHBA_PORTLUN	PortLun;
+	SMHBA_LUID	LUID;
+	HBA_STATUS	Status;
+} SMHBA_BINDINGENTRY, *PSMHBA_BINDINGENTRY;
+
+typedef struct SMHBA_Binding {
+	HBA_UINT32	    NumberOfEntries;
+	SMHBA_BINDINGENTRY  entry[1]; /* Variable length array */
+} SMHBA_BINDING, *PSMHBA_BINDING;
+
+/* SM-HBA 6.9.5 Library Attribute Data Declarations */
+typedef struct SMHBA_LibraryAttributes {
+	char	    LibPath[256];
+	char	    VName[256];
+	char	    VVersion[256];
+	struct {
+		int	tm_mday;    /* day of the month - [1 - 31] */
+		int	tm_mon;	    /* months since January - [0 - 11] */
+		int	tm_year;    /* years since 1900 */
+	} build_date;
+} SMHBA_LIBRARYATTRIBUTES, *PSMHBA_LIBRARYATTRIBUTES;
+
+/* SM-HBA 6.8.1 Asynchronous Event Data Declarations */
+#define	HBA_EVENT_PORT_BROADCAST_CHANGE 0x205
+#define	HBA_EVENT_PORT_BROADCAST_SES	0x208
+#define	HBA_EVENT_PORT_BROADCAST_D24_0  0x206
+#define	HBA_EVENT_PORT_BROADCAST_D27_4  0x207
+#define	HBA_EVENT_PORT_BROADCAST_D01_4  0x209
+#define	HBA_EVENT_PORT_BROADCAST_D04_7  0x20A
+#define	HBA_EVENT_PORT_BROADCAST_D16_7  0x20B
+#define	HBA_EVENT_PORT_BROADCAST_D29_7  0x20C
+#define	HBA_EVENT_PORT_ALL		0x2FF
+
+/* SM-HBA specific entry points. */
+
+HBA_UINT32 SMHBA_GetVersion();
+
+HBA_UINT32 SMHBA_GetWrapperLibraryAttributes(
+	SMHBA_LIBRARYATTRIBUTES *attributes
+);
+
+HBA_UINT32 SMHBA_GetVendorLibraryAttributes(
+	HBA_UINT32		adapter_index,
+	SMHBA_LIBRARYATTRIBUTES *attributes
+);
+
+HBA_STATUS SMHBA_GetAdapterAttributes(
+	HBA_HANDLE handle,
+	SMHBA_ADAPTERATTRIBUTES *pAdapterAttributes
+);
+
+HBA_STATUS SMHBA_GetNumberOfPorts(
+	HBA_HANDLE handle,
+	HBA_UINT32 *numberofports
+);
+
+HBA_STATUS SMHBA_GetPortType(
+	HBA_HANDLE handle,
+	HBA_UINT32 portindex,
+	HBA_PORTTYPE *porttype
+);
+
+HBA_STATUS SMHBA_GetAdapterPortAttributes(
+	HBA_HANDLE handle,
+	HBA_UINT32 portindex,
+	SMHBA_PORTATTRIBUTES *portattributes
+);
+
+HBA_STATUS SMHBA_GetDiscoveredPortAttributes(
+	HBA_HANDLE handle,
+	HBA_UINT32 portindex,
+	HBA_UINT32 discoveredportindex,
+	SMHBA_PORTATTRIBUTES *porattributes
+);
+
+HBA_STATUS SMHBA_GetPortAttributesByWWN(
+	HBA_HANDLE handle,
+	HBA_WWN portWWN,
+	HBA_WWN domainPortWWN,
+	SMHBA_PORTATTRIBUTES *portattributes
+);
+
+HBA_STATUS SMHBA_GetPortAttributesByWWN(
+	HBA_HANDLE handle,
+	HBA_WWN portWWN,
+	HBA_WWN domainPortWWN,
+	SMHBA_PORTATTRIBUTES *portattributes
+);
+
+HBA_STATUS SMHBA_GetFCPhyAttributes(
+	HBA_HANDLE handle,
+	HBA_UINT32 portindex,
+	HBA_UINT32 phyindex,
+	SMHBA_FC_PHY *phytype
+);
+
+HBA_STATUS SMHBA_GetSASPhyAttributes(
+	HBA_HANDLE handle,
+	HBA_UINT32 portindex,
+	HBA_UINT32 phyindex,
+	SMHBA_SAS_PHY *phytype
+);
+
+HBA_STATUS SMHBA_GetProtocolStatistics(
+	HBA_HANDLE handle,
+	HBA_UINT32 portindex,
+	HBA_UINT32 protocoltype,
+	SMHBA_PROTOCOLSTATISTICS *pProtocolStatistics
+);
+
+HBA_STATUS SMHBA_GetPhyStatistics(
+	HBA_HANDLE handle,
+	HBA_UINT32 portindex,
+	HBA_UINT32 phyindex,
+	SMHBA_PHYSTATISTICS *pPhyStatistics
+);
+
+HBA_STATUS SMHBA_SendTEST(
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN destWWN,
+	HBA_UINT32 destFCID,
+	void *pReqBuffer,
+	HBA_UINT32 ReqBufferSize
+);
+
+HBA_STATUS SMHBA_SendECHO(
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN destWWN,
+	HBA_UINT32 destFCID,
+	void *pReqBuffer,
+	HBA_UINT32 ReqBufferSize,
+	void *pRspBuffer,
+	HBA_UINT32 *pRspBufferSize
+);
+
+HBA_UINT32 SMHBA_SendSMPPassThru(
+	HBA_HANDLE handle,
+	HBA_WWN hbaportWWN,
+	HBA_WWN destportWWN,
+	HBA_WWN domainPortWWN,
+	void *pReqBuffer,
+	HBA_UINT32 ReqBufferSize,
+	void *pRspBuffer,
+	HBA_UINT32 *pRspBufferSize
+);
+
+HBA_STATUS SMHBA_GetBindingCapability(
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN domainPortWWN,
+	SMHBA_BIND_CAPABILITY *pFlags
+);
+
+HBA_STATUS SMHBA_GetBindingSupport(
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN domainPortWWN,
+	SMHBA_BIND_CAPABILITY *pFlags
+);
+
+HBA_STATUS SMHBA_SetBindingSupport(
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN domainPortWWN,
+	SMHBA_BIND_CAPABILITY flags
+);
+
+HBA_STATUS SMHBA_GetTargetMapping(
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN domainPortWWN,
+	SMHBA_TARGETMAPPING *pMapping
+);
+
+HBA_STATUS SMHBA_GetPersistentBinding(
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN domainPortWWN,
+	SMHBA_BINDING *binding
+);
+
+HBA_STATUS SMHBA_SetPersistentBinding(
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN domainPortWWN,
+	const SMHBA_BINDING *binding
+);
+
+HBA_STATUS SMHBA_RemovePersistentBinding(
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN domainPortWWN,
+	const SMHBA_BINDING *binding
+);
+
+HBA_STATUS SMHBA_RemoveAllPersistentBindings(
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN domainPortWWN
+);
+
+HBA_STATUS SMHBA_GetLUNStatistics(
+	HBA_HANDLE handle,
+	const HBA_SCSIID *lunit,
+	SMHBA_PROTOCOLSTATISTICS *statistics
+);
+
+HBA_STATUS SMHBA_ScsiInquiry(
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN discoveredPortWWN,
+	HBA_WWN domainPortWWN,
+	SMHBA_SCSILUN smhbaLUN,
+	HBA_UINT8 CDB_Byte1,
+	HBA_UINT8 CDB_Byte2,
+	void *pRspBuffer,
+	HBA_UINT32 *pRspBufferSize,
+	HBA_UINT8 *pScsiStatus,
+	void *pSenseBuffer,
+	HBA_UINT32 *pSenseBufferSize
+);
+
+HBA_STATUS SMHBA_ScsiReportLUNs(
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN discoveredPortWWN,
+	HBA_WWN domainPortWWN,
+	void *pRspBuffer,
+	HBA_UINT32 *pRspBufferSize,
+	HBA_UINT8 *pScsiStatus,
+	void *pSenseBuffer,
+	HBA_UINT32 *pSenseBufferSize
+);
+
+HBA_STATUS SMHBA_ScsiReadCapacity(
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN discoveredPortWWN,
+	HBA_WWN domainPortWWN,
+	SMHBA_SCSILUN smhbaLUN,
+	void *pRspBuffer,
+	HBA_UINT32 *pRspBufferSize,
+	HBA_UINT8 *pScsiStatus,
+	void *pSenseBuffer,
+	HBA_UINT32 *pSenseBufferSize
+);
+
+HBA_STATUS SMHBA_RegisterForAdapterAddEvents(
+	void (*pCallback) (
+		void *pData,
+		HBA_WWN portWWN,
+		HBA_UINT32 eventType),
+	void *pUserData,
+	HBA_CALLBACKHANDLE *pCallbackHandle
+);
+
+HBA_STATUS SMHBA_RegisterForAdapterEvents(
+	void (*pCallback) (
+		void *pData,
+		HBA_WWN portWWN,
+		HBA_UINT32 eventType),
+	void *pUserData,
+	HBA_HANDLE handle,
+	HBA_CALLBACKHANDLE *pCallbackHandle
+);
+
+HBA_STATUS SMHBA_RegisterForAdapterPortEvents(
+	void (*pCallback) (
+		void *pData,
+		HBA_WWN portWWN,
+		HBA_UINT32 eventType,
+		HBA_UINT32 fabricPortID),
+	void *pUserData,
+	HBA_HANDLE handle,
+	HBA_WWN portWWN,
+	HBA_UINT32 specificEventType,
+	HBA_CALLBACKHANDLE *pCallbackHandle
+);
+
+HBA_STATUS SMHBA_RegisterForAdapterPortStatEvents(
+	void (*pCallback) (
+		void *pData,
+		HBA_WWN portWWN,
+		HBA_UINT32 protocolType,
+		HBA_UINT32 eventType),
+	void *pUserData,
+	HBA_HANDLE handle,
+	HBA_WWN portWWN,
+	HBA_UINT32 protocolType,
+	SMHBA_PROTOCOLSTATISTICS stats,
+	HBA_UINT32 statType,
+	HBA_CALLBACKHANDLE *pCallbackHandle
+);
+
+HBA_STATUS SMHBA_RegisterForAdapterPhyStatEvents(
+	void (*pCallback) (
+		void *pData,
+		HBA_WWN portWWN,
+		HBA_UINT32 phyIndex,
+		HBA_UINT32 eventType),
+	void *pUserData,
+	HBA_HANDLE handle,
+	HBA_WWN portWWN,
+	HBA_UINT32 phyIndex,
+	SMHBA_PHYSTATISTICS stats,
+	HBA_UINT32 statType,
+	HBA_CALLBACKHANDLE *pCallbackHandle
+);
+
+HBA_STATUS SMHBA_RegisterForTargetEvents(
+	void (*pCallback) (
+		void *pData,
+		HBA_WWN hbaPortWWN,
+		HBA_WWN discoveredPortWWN,
+		HBA_WWN domainPortWWN,
+		HBA_UINT32 eventType),
+	void *pUserData,
+	HBA_HANDLE handle,
+	HBA_WWN hbaPortWWN,
+	HBA_WWN discoveredPortWWN,
+	HBA_WWN domainPortWWN,
+	HBA_CALLBACKHANDLE *pCallbackHandle,
+	HBA_UINT32 allTargets
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMHBAAPI_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/common/vendorsmhbaapi.h	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,207 @@
+/*
+ * ****************************************************************************
+ *
+ * Description
+ *	vendorhbaapi.h - incombination with hbaapi.h, defines interface to
+ *		vendor specific API
+ *
+ * License:
+ *	The contents of this file are subject to the SNIA Public License
+ *	Version 1.0 (the "License"); you may not use this file except in
+ *	compliance with the License. You may obtain a copy of the License at
+ *
+ *	/http://www.snia.org/English/Resources/Code/OpenSource.html
+ *
+ *	Software distributed under the License is distributed on an "AS IS"
+ *	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ *	the License for the specific language governing rights and limitations
+ *	under the License.
+ *
+ * The Original Code is  SNIA HBA API general header file
+ *
+ * The Initial Developer of the Original Code is:
+ *	Benjamin F. Kuo, Troika Networks, Inc. (benk@troikanetworks.com)
+ *
+ * Contributor(s):
+ *	Tuan Lam, QLogic Corp. (t_lam@qlc.com)
+ *	Dan Willie, Emulex Corp. (Dan.Willie@emulex.com)
+ *	Dixon Hutchinson, Legato Systems, Inc. (dhutchin@legato.com)
+ *	David Dillard, VERITAS Software Corp. (david.dillard@veritas.com)
+ *
+ * ****************************************************************************
+ *
+ *   Changes:
+ *	12/12/2001 Original revision, code split out of hbaapi.h
+ *	(for other changes... see the CVS logs)
+ * ****************************************************************************
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _VENDORSMHBAAPI_H_
+#define	_VENDORSMHBAAPI_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <vendorhbaapi.h>
+
+/* SM-HBA-2 6.9.2 Function Prototypes */
+typedef HBA_UINT32 (* SMHBAGetVersionFunc)();
+typedef HBA_UINT32 (* SMHBAGetWrapperLibraryAttributesFunc)
+	(HBA_UINT32, SMHBA_LIBRARYATTRIBUTES *);
+typedef HBA_UINT32 (* SMHBAGetVendorLibraryAttributesFunc)
+	(SMHBA_LIBRARYATTRIBUTES *);
+typedef HBA_STATUS (* SMHBAGetAdapterAttributesFunc)
+	(HBA_HANDLE, SMHBA_ADAPTERATTRIBUTES *);
+typedef HBA_STATUS (* SMHBAGetNumberOfPortsFunc)
+	(HBA_HANDLE, HBA_UINT32 *);
+typedef HBA_STATUS (* SMHBAGetPortTypeFunc)
+	(HBA_HANDLE, HBA_UINT32, HBA_PORTTYPE *);
+typedef HBA_STATUS (* SMHBAGetAdapterPortAttributesFunc)
+	(HBA_HANDLE, HBA_UINT32, SMHBA_PORTATTRIBUTES *);
+typedef HBA_STATUS (* SMHBAGetDiscoveredPortAttributesFunc)
+	(HBA_HANDLE, HBA_UINT32, HBA_UINT32, SMHBA_PORTATTRIBUTES *);
+typedef HBA_STATUS (* SMHBAGetPortAttributesByWWNFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, SMHBA_PORTATTRIBUTES *);
+typedef HBA_STATUS (* SMHBAGetFCPhyAttributesFunc)
+	(HBA_HANDLE, HBA_UINT32, HBA_UINT32, SMHBA_FC_PHY *);
+typedef HBA_STATUS (* SMHBAGetSASPhyAttributesFunc)
+	(HBA_HANDLE, HBA_UINT32, HBA_UINT32, SMHBA_SAS_PHY *);
+typedef HBA_STATUS (* SMHBAGetProtocolStatisticsFunc)
+	(HBA_HANDLE, HBA_UINT32, HBA_UINT32, SMHBA_PROTOCOLSTATISTICS *);
+typedef HBA_STATUS (* SMHBAGetPhyStatisticsFunc)
+	(HBA_HANDLE, HBA_UINT32, HBA_UINT32, SMHBA_PHYSTATISTICS *);
+typedef HBA_STATUS (* SMHBASendTESTFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, HBA_UINT32, void *, HBA_UINT32);
+typedef HBA_STATUS (* SMHBASendECHOFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, HBA_UINT32, void *, HBA_UINT32,
+	void *, HBA_UINT32 *);
+typedef HBA_STATUS (* SMHBASendSMPPassThruFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, HBA_WWN, void *, HBA_UINT32, void *,
+	HBA_UINT32 *);
+typedef HBA_STATUS (* SMHBAGetBindingCapabilityFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, SMHBA_BIND_CAPABILITY *);
+typedef HBA_STATUS (* SMHBAGetBindingSupportFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, SMHBA_BIND_CAPABILITY *);
+typedef HBA_STATUS (* SMHBASetBindingSupportFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, SMHBA_BIND_CAPABILITY);
+typedef HBA_STATUS (* SMHBAGetTargetMappingFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, SMHBA_TARGETMAPPING *);
+typedef HBA_STATUS (* SMHBAGetPersistentBindingFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, SMHBA_BINDING *);
+typedef HBA_STATUS (* SMHBASetPersistentBindingFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, const SMHBA_BINDING *);
+typedef HBA_STATUS (* SMHBARemovePersistentBindingFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, const SMHBA_BINDING *);
+typedef HBA_STATUS (* SMHBARemoveAllPersistentBindingsFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN);
+typedef HBA_STATUS (* SMHBAGetLUNStatisticsFunc)
+	(HBA_HANDLE, const HBA_SCSIID *, SMHBA_PROTOCOLSTATISTICS *);
+typedef HBA_STATUS (* SMHBARegisterForAdapterAddEventsFunc)
+	(void (*)(void *, HBA_WWN, HBA_UINT32), void *, HBA_CALLBACKHANDLE *);
+typedef HBA_STATUS (* SMHBARegisterForAdapterEventsFunc)
+	(void (*)(void *, HBA_WWN, HBA_UINT32),
+	void *, HBA_HANDLE, HBA_CALLBACKHANDLE *);
+typedef HBA_STATUS    (* SMHBARegisterForAdapterPortEventsFunc)
+	(void (*)(void *, HBA_WWN, HBA_UINT32, HBA_UINT32),
+	void *, HBA_HANDLE, HBA_WWN, HBA_UINT32, HBA_CALLBACKHANDLE *);
+typedef HBA_STATUS    (* SMHBARegisterForAdapterPortStatEventsFunc)
+	(void (*)(void *, HBA_WWN, HBA_UINT32, HBA_UINT32),
+	void *, HBA_HANDLE, HBA_WWN, HBA_UINT32, SMHBA_PROTOCOLSTATISTICS,
+	HBA_UINT32, HBA_CALLBACKHANDLE *);
+typedef HBA_STATUS    (* SMHBARegisterForAdapterPhyStatEventsFunc)
+	(void (*)(void *, HBA_WWN, HBA_UINT32, HBA_UINT32),
+	void *, HBA_HANDLE, HBA_WWN, HBA_UINT32, SMHBA_PHYSTATISTICS,
+	HBA_UINT32, HBA_CALLBACKHANDLE *);
+typedef HBA_STATUS    (* SMHBARegisterForTargetEventsFunc)
+	(void (*)(void *, HBA_WWN, HBA_WWN, HBA_WWN, HBA_UINT32),
+	void *, HBA_HANDLE, HBA_WWN, HBA_WWN, HBA_WWN,
+	HBA_CALLBACKHANDLE *, HBA_UINT32);
+typedef HBA_STATUS    (* SMHBAScsiInquiryFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, HBA_WWN, SMHBA_SCSILUN, HBA_UINT8,
+	HBA_UINT8, void *, HBA_UINT32 *, HBA_UINT8 *, void *, HBA_UINT32 *);
+typedef HBA_STATUS    (* SMHBAScsiReportLUNsFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, HBA_WWN, void *, HBA_UINT32 *,
+	HBA_UINT8 *, void *, HBA_UINT32 *);
+typedef HBA_STATUS    (* SMHBAScsiReadCapacityFunc)
+	(HBA_HANDLE, HBA_WWN, HBA_WWN, HBA_WWN, SMHBA_SCSILUN, void *,
+	HBA_UINT32 *, HBA_UINT8 *, void *, HBA_UINT32 *);
+
+/* SM-HBA-2 6.9.3 Entry Point Data Declarations */
+typedef struct SMHBA_EntryPoints {
+	SMHBAGetVersionFunc			GetVersionHandler;
+	HBALoadLibraryFunc			LoadLibraryHandler;
+	HBAFreeLibraryFunc			FreeLibraryHandler;
+	HBAGetNumberOfAdaptersFunc		GetNumberOfAdaptersHandler;
+	HBARefreshInformationFunc		RefreshInformationHandler;
+	SMHBAGetVendorLibraryAttributesFunc
+		GetVendorLibraryAttributesHandler;
+	HBAGetAdapterNameFunc			GetAdapterNameHandler;
+	HBAOpenAdapterFunc			OpenAdapterHandler;
+	HBACloseAdapterFunc			CloseAdapterHandler;
+	SMHBAGetAdapterAttributesFunc		GetAdapterAttributesHandler;
+	SMHBAGetNumberOfPortsFunc		GetNumberOfPortsHandler;
+	SMHBAGetPortTypeFunc			GetPortTypeHandler;
+	SMHBAGetAdapterPortAttributesFunc
+		GetAdapterPortAttributesHandler;
+	SMHBAGetDiscoveredPortAttributesFunc
+		GetDiscoveredPortAttributesHandler;
+	SMHBAGetPortAttributesByWWNFunc		GetPortAttributesByWWNHandler;
+	SMHBAGetFCPhyAttributesFunc		GetFCPhyAttributesHandler;
+	SMHBAGetSASPhyAttributesFunc		GetSASPhyAttributesHandler;
+	SMHBAGetProtocolStatisticsFunc		GetProtocolStatisticsHandler;
+	SMHBAGetPhyStatisticsFunc		GetPhyStatisticsHandler;
+	HBASendCTPassThruV2Func			SendCTPassThruV2Handler;
+	HBASetRNIDMgmtInfoFunc			SetRNIDMgmtInfoHandler;
+	HBAGetRNIDMgmtInfoFunc			GetRNIDMgmtInfoHandler;
+	HBASendRNIDV2Func			SendRNIDV2Handler;
+	HBASendRPLFunc				SendRPLHandler;
+	HBASendRPSFunc				SendRPSHandler;
+	HBASendSRLFunc				SendSRLHandler;
+	HBASendLIRRFunc				SendLIRRHandler;
+	HBASendRLSFunc				SendRLSHandler;
+	SMHBASendTESTFunc			SendTESTHandler;
+	SMHBASendECHOFunc			SendECHOHandler;
+	SMHBASendSMPPassThruFunc		SendSMPPassThruHandler;
+	SMHBAGetBindingCapabilityFunc		GetBindingCapabilityHandler;
+	SMHBAGetBindingSupportFunc		GetBindingSupportHandler;
+	SMHBASetBindingSupportFunc		SetBindingSupportHandler;
+	SMHBAGetTargetMappingFunc		GetTargetMappingHandler;
+	SMHBAGetPersistentBindingFunc		GetPersistentBindingHandler;
+	SMHBASetPersistentBindingFunc		SetPersistentBindingHandler;
+	SMHBARemovePersistentBindingFunc	RemovePersistentBindingHandler;
+	SMHBARemoveAllPersistentBindingsFunc
+		RemoveAllPersistentBindingsHandler;
+	SMHBAGetLUNStatisticsFunc		GetLUNStatisticsHandler;
+	SMHBAScsiInquiryFunc			ScsiInquiryHandler;
+	SMHBAScsiReportLUNsFunc			ScsiReportLUNsHandler;
+	SMHBAScsiReadCapacityFunc		ScsiReadCapacityHandler;
+	SMHBARegisterForAdapterAddEventsFunc
+		RegisterForAdapterAddEventsHandler;
+	SMHBARegisterForAdapterEventsFunc	RegisterForAdapterEventsHandler;
+	SMHBARegisterForAdapterPortEventsFunc
+		RegisterForAdapterPortEventsHandler;
+	SMHBARegisterForAdapterPortStatEventsFunc
+		RegisterForAdapterPortStatEventsHandler;
+	SMHBARegisterForAdapterPhyStatEventsFunc
+		RegisterForAdapterPhyStatEventsHandler;
+	SMHBARegisterForTargetEventsFunc	RegisterForTargetEventsHandler;
+	HBARegisterForLinkEventsFunc		RegisterForLinkEventsHandler;
+	HBARemoveCallbackFunc			RemoveCallbackHandler;
+} SMHBA_ENTRYPOINTS, *PSMHBA_ENTRYPOINTS;
+
+typedef HBA_UINT32 (* SMHBARegisterLibraryFunc)(SMHBA_ENTRYPOINTS *);
+
+HBA_STATUS SMHBA_RegisterLibrary(
+	SMHBA_ENTRYPOINTS	*functionTable
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VENDORSMHBAAPI_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/i386/Makefile	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,29 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/sparc/Makefile	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,29 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smhba/sparcv9/Makefile	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,30 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/Makefile	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,54 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include		../Makefile.lib
+
+SUBDIRS=	$(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all :=		TARGET= all
+clean :=	TARGET= clean
+clobber :=	TARGET= clobber
+install :=	TARGET= install
+install_h :=	TARGET= install_h
+lint :=		TARGET= lint
+
+HDRDIR=		common
+
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS) 
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/Makefile.com	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,99 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+LIBRARY =	libsun_sas.a
+VERS =		.1
+
+OBJECTS	=	devtree_hba_disco.o \
+	      	devtree_device_disco.o \
+	      	devtree_phy_disco.o \
+	      	devlink_disco.o \
+	      	event.o \
+	      	verify.o \
+	      	SMHBA_RegisterLibrary.o \
+	      	Sun_sasLoadLibrary.o \
+	      	Sun_sasGetNumberOfAdapters.o \
+	      	Sun_sasGetTargetMapping.o \
+	      	Sun_sasGetAdapterName.o \
+		Sun_sasGetAdapterAttributes.o \
+		Sun_sasGetAdapterPortAttributes.o \
+		Sun_sasGetDiscoveredPortAttributes.o \
+		Sun_sasGetPortAttributesByWWN.o \
+		Sun_sasGetSASPhyAttributes.o \
+		Sun_sasGetPortType.o \
+	      	Sun_sasGetNumberOfPorts.o \
+	      	Sun_sasGetVersion.o \
+	      	Sun_sasGetPhyStatistics.o \
+	      	Sun_sasGetVendorLibraryAttributes.o \
+	      	Sun_sasFreeLibrary.o \
+	      	Sun_sasOpenAdapter.o \
+	      	Sun_sasCloseAdapter.o \
+	      	Sun_sasRefreshInformation.o \
+	      	Sun_sasRefreshAdapterConfiguration.o \
+	      	Sun_sasGetLUNStatistics.o \
+	      	Sun_sasGetProtocolStatistics.o \
+	      	Sun_sasGetPersistentBinding.o \
+	      	Sun_sasSetPersistentBinding.o \
+		Sun_sasSendSMPPassThru.o \
+		Sun_sasScsiInquiry.o \
+		Sun_sasScsiReportLUNs.o \
+		Sun_sasScsiReadCapacity.o \
+		sun_sas.o \
+		log.o 
+
+include ../../Makefile.lib
+
+LIBS =		$(DYNLIB)
+SRCDIR=		../common
+
+INCS +=		-I$(SRCDIR)
+INCS +=		-I$(SRC)/lib/smhba/common
+INCS +=		-I$(SRC)/lib/hbaapi/common
+INCS +=		-I$(SRC)/lib/libdevid
+
+CFLAGS +=	-mt
+CFLAGS +=	-v
+CFLAGS64 +=	-mt
+CFLAGS64 +=	-v
+CPPFLAGS +=	$(INCS) -D_POSIX_PTHREAD_SEMANTICS
+CPPFLAGS +=	-DBUILD_TIME='"Wed Feb 4 12:00:00 2009"'
+
+LDLIBS		+= -ldevinfo
+LDLIBS		+= -lsysevent
+LDLIBS		+= -lnvpair
+LDLIBS		+= -lc
+LDLIBS		+= -lkstat
+LDLIBS		+= -ldevid
+
+$(LINTLIB) := SRCS=	$(SRCDIR)/$(LINTSRC)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/amd64/Makefile	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,34 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+.KEEP_STATE:
+
+all:  $(LIBS)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/SMHBA_RegisterLibrary.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,100 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    <sun_sas.h>
+
+HBA_STATUS
+SMHBA_RegisterLibrary(PSMHBA_ENTRYPOINTS entrypoints)
+{
+	entrypoints->GetVersionHandler = Sun_sasGetVersion;
+	entrypoints->LoadLibraryHandler = Sun_sasLoadLibrary;
+	entrypoints->FreeLibraryHandler = Sun_sasFreeLibrary;
+	entrypoints->GetNumberOfAdaptersHandler = Sun_sasGetNumberOfAdapters;
+	entrypoints->RefreshInformationHandler = Sun_sasRefreshInformation;
+	entrypoints->GetVendorLibraryAttributesHandler =
+	    Sun_sasGetVendorLibraryAttributes;
+	entrypoints->GetAdapterNameHandler = Sun_sasGetAdapterName;
+	entrypoints->OpenAdapterHandler = Sun_sasOpenAdapter;
+	entrypoints->CloseAdapterHandler = Sun_sasCloseAdapter;
+	entrypoints->GetAdapterAttributesHandler = Sun_sasGetAdapterAttributes;
+	entrypoints->GetNumberOfPortsHandler = Sun_sasGetNumberOfPorts;
+	entrypoints->GetPortTypeHandler = Sun_sasGetPortType;
+	entrypoints->GetAdapterPortAttributesHandler =
+	    Sun_sasGetAdapterPortAttributes;
+	entrypoints->GetDiscoveredPortAttributesHandler =
+	    Sun_sasGetDiscoveredPortAttributes;
+	entrypoints->GetPortAttributesByWWNHandler =
+	    Sun_sasGetPortAttributesByWWN;
+	entrypoints->GetFCPhyAttributesHandler = NULL;
+	entrypoints->GetSASPhyAttributesHandler = Sun_sasGetSASPhyAttributes;
+	entrypoints->GetProtocolStatisticsHandler =
+	    Sun_sasGetProtocolStatistics;
+	entrypoints->GetPhyStatisticsHandler = Sun_sasGetPhyStatistics;
+	entrypoints->SendCTPassThruV2Handler = NULL;
+	entrypoints->SetRNIDMgmtInfoHandler = NULL;
+	entrypoints->GetRNIDMgmtInfoHandler = NULL;
+	entrypoints->SendRNIDV2Handler = NULL;
+	entrypoints->SendRPLHandler = NULL;
+	entrypoints->SendRPSHandler = NULL;
+	entrypoints->SendSRLHandler = NULL;
+	entrypoints->SendLIRRHandler = NULL;
+	entrypoints->SendRLSHandler = NULL;
+	entrypoints->SendTESTHandler = NULL;
+	entrypoints->SendECHOHandler = NULL;
+	entrypoints->SendSMPPassThruHandler = Sun_sasSendSMPPassThru;
+	entrypoints->GetBindingCapabilityHandler = NULL;
+		/* Sun_sasGetBindingCapability; */
+	entrypoints->GetBindingSupportHandler = NULL;
+	entrypoints->SetBindingSupportHandler = NULL;
+		/* Sun_sasSetBindingSupport; */
+	entrypoints->GetTargetMappingHandler = Sun_sasGetTargetMapping;
+	entrypoints->SetPersistentBindingHandler = Sun_sasSetPersistentBinding;
+	entrypoints->GetPersistentBindingHandler = Sun_sasGetPersistentBinding;
+	entrypoints->RemovePersistentBindingHandler = NULL;
+		/* Sun_sasRemovePersistentBinding; */
+	entrypoints->RemoveAllPersistentBindingsHandler = NULL;
+		/* Sun_sasRemoveAllPersistentBindings; */
+	entrypoints->GetLUNStatisticsHandler = Sun_sasGetLUNStatistics;
+	entrypoints->ScsiInquiryHandler = Sun_sasScsiInquiry;
+	entrypoints->ScsiReportLUNsHandler = Sun_sasScsiReportLUNs;
+	entrypoints->ScsiReadCapacityHandler = Sun_sasScsiReadCapacity;
+	entrypoints->RegisterForAdapterAddEventsHandler = NULL;
+		/* Sun_sasRegisterForAdapterAddEvents; */
+	entrypoints->RegisterForAdapterEventsHandler = NULL;
+		/* Sun_sasRegisterForAdapterEvents; */
+	entrypoints->RegisterForAdapterPortEventsHandler = NULL;
+		/* Sun_sasRegisterForAdapterPortEvents; */
+	entrypoints->RegisterForAdapterPortStatEventsHandler = NULL;
+		/* Sun_sasRegisterForAdapterPortStatEvents; */
+	entrypoints->RegisterForAdapterPhyStatEventsHandler = NULL;
+		/* Sun_sasRegisterForAdapterPhyStatEvents; */
+	entrypoints->RegisterForTargetEventsHandler = NULL;
+		/* Sun_sasRegisterForTargetEvents; */
+	entrypoints->RegisterForLinkEventsHandler = NULL;
+		/* Sun_sasRegisterForLinkEvents; */
+	entrypoints->RemoveCallbackHandler = NULL; /* Sun_sasRemoveCallback; */
+	return (HBA_STATUS_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasCloseAdapter.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,99 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    <sun_sas.h>
+
+/*
+ * Closes an adapter
+ *
+ * the handle is removed from the open_handles list
+ */
+void
+Sun_sasCloseAdapter(HBA_HANDLE handle)
+{
+	const char			ROUTINE[] = "Sun_sasCloseAdapter";
+	struct open_handle		*open_handle_ptr, *open_handle_prev_ptr;
+	int				found = 0;
+
+	if (global_hba_head == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Attempted to close an invalid handle %08lx. "
+		    "There are no hba handles loaded in the VSL.",
+		    handle);
+		return;
+	}
+
+	/* Removing handle from open_handles; */
+	lock(&open_handles_lock);
+	if (global_hba_head->open_handles == NULL) {
+		/* check to see if there are any open global_hba_head */
+		log(LOG_DEBUG, ROUTINE,
+		    "Attempted to close an invalid handle %08lx. "
+		    "There are no open handles in the VSL.",
+		    handle);
+	} else if (global_hba_head->open_handles->next == NULL) {
+		/* there is only one handle open */
+		if (global_hba_head->open_handles->handle == handle) {
+			free(global_hba_head->open_handles);
+			global_hba_head->open_handles = NULL;
+		} else {
+			log(LOG_DEBUG, ROUTINE,
+			    "Attempted to close an invalid handle %08lx. "
+			    "Unable to find handle to close.", handle);
+		}
+	} else {	/* there is more than one handle open */
+		open_handle_ptr = global_hba_head->open_handles;
+		if (open_handle_ptr->handle == handle) {
+			global_hba_head->open_handles = open_handle_ptr->next;
+			free(open_handle_ptr);
+		} else {
+			for (open_handle_ptr = open_handle_ptr->next,
+			    open_handle_prev_ptr =
+			    global_hba_head->open_handles;
+			    open_handle_ptr != NULL;
+			    open_handle_ptr = open_handle_ptr->next) {
+				if (open_handle_ptr->handle == handle) {
+					open_handle_prev_ptr->next =
+					    open_handle_ptr->next;
+					free(open_handle_ptr);
+					found = 1;
+					break;
+				} else {
+					open_handle_prev_ptr =
+					    open_handle_prev_ptr->next;
+				}
+			}
+			if (found == 0) {
+				log(LOG_DEBUG, ROUTINE,
+				    "Attempted to close an invalid handle "
+				    "%08lx.  Unable to find handle to close.",
+				    handle);
+			}
+		}
+	}
+
+	unlock(&open_handles_lock);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasFreeLibrary.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,131 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#include <sun_sas.h>
+
+/*
+ * Frees the HBA Library.  Must be called after all HBA library functions
+ * to free all resources
+ */
+HBA_STATUS Sun_sasFreeLibrary() {
+	HBA_STATUS 	status;
+
+	lock(&all_hbas_lock);
+
+	status = FreeHBA(global_hba_head);
+
+	/* re-initialize all global variables */
+	global_hba_head = NULL;
+	hba_count = 0;
+	open_handle_index = 1;
+	unlock(&all_hbas_lock);
+	(void) mutex_destroy(&all_hbas_lock);
+
+	/* free sysevent handle. */
+	if (gSysEventHandle != NULL)
+		sysevent_unbind_handle(gSysEventHandle);
+
+	/* Reset our load count so we can be reloaded now */
+	loadCount = 0;
+
+	return (status);
+}
+
+/*
+ * Internal routine to free up hba_ptr's (and all sub-structures)
+ */
+HBA_STATUS FreeHBA(struct sun_sas_hba *hba) {
+	struct sun_sas_hba	*hba_ptr = NULL;
+	struct sun_sas_hba	*last_hba_ptr = NULL;
+	struct sun_sas_port	*hba_port = NULL;
+	struct sun_sas_port	*last_hba_port = NULL;
+	struct sun_sas_port	*tgt_port = NULL;
+	struct sun_sas_port	*last_tgt_port = NULL;
+	struct ScsiEntryList	*scsi_info = NULL;
+	struct ScsiEntryList	*last_scsi_info = NULL;
+	struct phy_info		*phy_ptr = NULL;
+	struct phy_info		*last_phy = NULL;
+	struct open_handle	*open_handle = NULL;
+	struct open_handle	*last_open_handle = NULL;
+
+	last_hba_ptr = NULL;
+	/* walk through global_hba_head list freeing each handle */
+	for (hba_ptr = hba;
+	    hba_ptr != NULL;
+	    hba_ptr = hba_ptr->next) {
+		/* Free the nested structures (port and attached port) */
+		hba_port = hba_ptr->first_port;
+		while (hba_port != NULL) {
+		    /* Free discovered port structure list. */
+		    tgt_port = hba_port->first_attached_port;
+		    while (tgt_port != NULL) {
+			    /* Free target mapping data list first. */
+			    scsi_info = tgt_port->scsiInfo;
+			    while (scsi_info != NULL) {
+				    last_scsi_info = scsi_info;
+				    scsi_info = scsi_info->next;
+				    free(last_scsi_info);
+			    }
+			last_tgt_port = tgt_port;
+			tgt_port = tgt_port->next;
+			free(last_tgt_port->port_attributes.\
+			    PortSpecificAttribute.SASPort);
+			free(last_tgt_port);
+		    }
+
+		    phy_ptr = hba_port->first_phy;
+		    while (phy_ptr != NULL) {
+			last_phy = phy_ptr;
+			phy_ptr = phy_ptr->next;
+			free(last_phy);
+		    }
+
+		    last_hba_port = hba_port;
+		    hba_port = hba_port->next;
+		    free(last_hba_port->port_attributes.\
+			PortSpecificAttribute.SASPort);
+		    free(last_hba_port);
+		}
+
+		open_handle = hba_ptr->open_handles;
+		while (open_handle != NULL) {
+		    last_open_handle = open_handle;
+		    open_handle = open_handle->next;
+		    free(last_open_handle);
+		}
+		/* Free up the top level HBA structure from the last spin */
+		if (last_hba_ptr != NULL) {
+		    free(last_hba_ptr);
+		}
+		last_hba_ptr = hba_ptr;
+	}
+	if (last_hba_ptr != NULL) {
+	    free(last_hba_ptr);
+	}
+
+	return (HBA_STATUS_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetAdapterAttributes.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,62 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    <sun_sas.h>
+/*
+ * Retrieves the attribues for an adapter
+ */
+HBA_STATUS
+Sun_sasGetAdapterAttributes(HBA_HANDLE handle,
+	    PSMHBA_ADAPTERATTRIBUTES attributes) {
+	const char		ROUTINE[] = "Sun_sasGetAdapterAttributes";
+	struct sun_sas_hba 	*hba_ptr;
+	int 			index = 0;
+
+	if (attributes == NULL) {
+	    log(LOG_DEBUG, ROUTINE, "NULL attributes pointer");
+	    return (HBA_STATUS_ERROR_ARG);
+	}
+
+	lock(&all_hbas_lock);
+	index = RetrieveIndex(handle);
+	lock(&open_handles_lock);
+	hba_ptr = RetrieveHandle(index);
+	if (hba_ptr == NULL) {
+	    log(LOG_DEBUG, ROUTINE,
+		"Invalid handle %08lx", handle);
+	    unlock(&open_handles_lock);
+	    unlock(&all_hbas_lock);
+	    return (HBA_STATUS_ERROR_INVALID_HANDLE);
+	}
+
+	(void) memcpy(attributes, &hba_ptr->adapter_attributes,
+	    sizeof (SMHBA_ADAPTERATTRIBUTES));
+
+	unlock(&open_handles_lock);
+	unlock(&all_hbas_lock);
+
+	return (HBA_STATUS_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetAdapterName.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,67 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    "sun_sas.h"
+
+/*
+ * Returns the text string which describes this adapter and which is used to
+ * open the adapter with the library.
+ *
+ * Arguments:
+ *	    index	the index to which adapter to retrive the name
+ *	    name	buffer to which the adapter name will be placed
+ */
+HBA_STATUS Sun_sasGetAdapterName(HBA_UINT32 index, char *name) {
+	const char		ROUTINE[] = "Sun_sasGetAdapterName";
+	struct sun_sas_hba	*hba_ptr;
+
+	if (name == NULL) {
+	    log(LOG_DEBUG, ROUTINE, "NULL adapter name");
+	    return (HBA_STATUS_ERROR_ARG);
+	}
+	lock(&all_hbas_lock);
+	for (hba_ptr = global_hba_head; hba_ptr != NULL;
+		hba_ptr = hba_ptr->next) {
+	    if (hba_ptr->index == index) {
+		    if (hba_ptr->handle_name == NULL) {
+			hba_ptr = NULL;
+			break;
+		    }
+		    /* Flaw in the spec!  How do we know the size of name? */
+		    (void) strlcpy(name, hba_ptr->handle_name,
+			strlen(hba_ptr->handle_name)+1);
+		    break;
+	    }
+	}
+	unlock(&all_hbas_lock);
+	if (hba_ptr == NULL) {
+	    log(LOG_DEBUG, ROUTINE,
+		"Unable to find adapter index %d.", index);
+	    return (HBA_STATUS_ERROR_ILLEGAL_INDEX);
+	}
+
+	return (HBA_STATUS_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetAdapterPortAttributes.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,111 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    <sun_sas.h>
+
+/*
+ * Retrieves the attributes for a specified port of an adapter
+ */
+HBA_STATUS
+Sun_sasGetAdapterPortAttributes(HBA_HANDLE handle,
+	    HBA_UINT32 port, PSMHBA_PORTATTRIBUTES attributes) {
+	const char		ROUTINE[] = "Sun_sasGetAdapterPortAttributes";
+	HBA_STATUS		status;
+	struct sun_sas_hba	*hba_ptr;
+	struct sun_sas_port	*hba_port_ptr;
+	int			index;
+
+	/* Validate the arguments */
+	if ((attributes == NULL) ||
+	    (attributes->PortSpecificAttribute.SASPort == NULL)) {
+	    log(LOG_DEBUG, ROUTINE, "NULL attributes");
+	    return (HBA_STATUS_ERROR_ARG);
+	}
+
+	lock(&all_hbas_lock);
+	index = RetrieveIndex(handle);
+	lock(&open_handles_lock);
+	hba_ptr = RetrieveHandle(index);
+	if (hba_ptr == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx", handle);
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_INVALID_HANDLE);
+	}
+
+	/* Check for stale data */
+	status = verifyAdapter(hba_ptr);
+	if (status != HBA_STATUS_OK) {
+		log(LOG_DEBUG, ROUTINE, "Verify Adapter failed");
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (status);
+	}
+
+	if (hba_ptr->first_port == NULL) {
+	    /* This is probably an internal failure of the library */
+	    if (hba_ptr->device_path) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Internal failure:  Adapter %s contains no port data",
+		    hba_ptr->device_path);
+	    } else {
+		log(LOG_DEBUG, ROUTINE,
+		    "Internal failure:  Adapter at index %d contains no port "
+		    "data", hba_ptr->index);
+	    }
+	    unlock(&open_handles_lock);
+	    unlock(&all_hbas_lock);
+	    return (HBA_STATUS_ERROR);
+	}
+	for (hba_port_ptr = hba_ptr->first_port;
+	    hba_port_ptr != NULL; hba_port_ptr = hba_port_ptr->next) {
+		if (hba_port_ptr->index == port) {
+			break;
+		}
+	}
+	if (hba_port_ptr == NULL || hba_port_ptr->index != port) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Invalid port index %d for handle %08lx.",
+		    port, handle);
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_ILLEGAL_INDEX);
+	}
+
+	attributes->PortType =  hba_port_ptr->port_attributes.PortType;
+	attributes->PortState =  hba_port_ptr->port_attributes.PortState;
+	(void) strlcpy(attributes->OSDeviceName,
+	    hba_port_ptr->port_attributes.OSDeviceName,
+	    sizeof (attributes->OSDeviceName));
+	(void) memcpy(attributes->PortSpecificAttribute.SASPort,
+	    hba_port_ptr->port_attributes.PortSpecificAttribute.SASPort,
+	    sizeof (struct SMHBA_SAS_Port));
+
+	unlock(&open_handles_lock);
+	unlock(&all_hbas_lock);
+
+	return (HBA_STATUS_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetDiscoveredPortAttributes.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,143 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    <sun_sas.h>
+
+/*
+ * Retrieves the attributes for a specified port discovered in the network
+ */
+HBA_STATUS
+Sun_sasGetDiscoveredPortAttributes(HBA_HANDLE handle,
+	    HBA_UINT32 port, HBA_UINT32 discoveredport,
+	    SMHBA_PORTATTRIBUTES *attributes) {
+	const char		ROUTINE[] =
+	    "Sun_sasGetDiscoveredPortAttributes";
+	HBA_STATUS		status;
+	HBA_STATUS		ret = HBA_STATUS_OK;
+	struct sun_sas_hba	*hba_ptr;
+	struct sun_sas_port	*hba_port_ptr, *hba_disco_port;
+	int			index;
+
+	if (attributes == NULL) {
+	    log(LOG_DEBUG, ROUTINE,
+		"NULL attributes argument. Handle %08lx, port %d, "
+		"discovered port %d", handle, port, discoveredport);
+	    return (HBA_STATUS_ERROR_ARG);
+	}
+
+	lock(&all_hbas_lock);
+	index = RetrieveIndex(handle);
+	lock(&open_handles_lock);
+	hba_ptr = RetrieveHandle(index);
+	if (hba_ptr == NULL) {
+	    log(LOG_DEBUG, ROUTINE,
+		"Invalid handle %08lx.", handle);
+	    unlock(&open_handles_lock);
+	    unlock(&all_hbas_lock);
+	    return (HBA_STATUS_ERROR_INVALID_HANDLE);
+	}
+
+	/* Check for stale data */
+	status = verifyAdapter(hba_ptr);
+	if (status != HBA_STATUS_OK) {
+	    log(LOG_DEBUG, ROUTINE, "Verify Adapter failed");
+	    unlock(&open_handles_lock);
+	    unlock(&all_hbas_lock);
+	    return (status);
+	}
+
+
+	if (hba_ptr->first_port == NULL) {
+	    /* This is probably an internal failure of the library */
+	    if (hba_ptr->device_path) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Internal failure:  Adapter %s contains no port data",
+		    hba_ptr->device_path);
+	    } else {
+		log(LOG_DEBUG, ROUTINE,
+		    "Internal failure:  Adapter at index %d contains no port "
+		    "data", hba_ptr->index);
+	    }
+	    unlock(&open_handles_lock);
+	    unlock(&all_hbas_lock);
+	    return (HBA_STATUS_ERROR);
+	}
+
+	for (hba_port_ptr = hba_ptr->first_port;
+	    hba_port_ptr != NULL; hba_port_ptr = hba_port_ptr->next) {
+		if (hba_port_ptr->index == port) {
+			break;
+		}
+	}
+
+	if (hba_port_ptr == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Invalid port index %d for handle %08lx",
+		    port, handle);
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_ILLEGAL_INDEX);
+	}
+
+	/* check to make sure there are devices attached to this port */
+	if (hba_port_ptr->first_attached_port != NULL) {
+		for (hba_disco_port = hba_port_ptr->first_attached_port;
+			hba_disco_port != NULL;
+			hba_disco_port = hba_disco_port->next) {
+		    if (hba_disco_port->index == discoveredport) {
+			break;
+		    }
+		}
+		if (hba_disco_port == NULL) {
+			log(LOG_DEBUG, ROUTINE,
+			    "Invalid discovered port index %d for hba port "
+			    "index %d on handle %08lx.",
+			    discoveredport, port, handle);
+			ret = HBA_STATUS_ERROR_ILLEGAL_INDEX;
+		} else {
+		    attributes->PortType =
+			hba_disco_port->port_attributes.PortType;
+		    attributes->PortState =
+			hba_disco_port->port_attributes.PortState;
+		    (void) strlcpy(attributes->OSDeviceName,
+			hba_disco_port->port_attributes.OSDeviceName,
+			sizeof (attributes->OSDeviceName));
+		    (void) memcpy(attributes->PortSpecificAttribute.SASPort,
+			hba_disco_port->port_attributes.PortSpecificAttribute.
+			SASPort, sizeof (struct SMHBA_SAS_Port));
+		}
+	} else {
+		/* No ports, so we can't possibly return anything */
+		log(LOG_DEBUG, ROUTINE,
+		    "No discovered port on HBA port index %d for handle %08lx",
+		    port, handle);
+		ret = HBA_STATUS_ERROR;
+	}
+	unlock(&open_handles_lock);
+	unlock(&all_hbas_lock);
+
+	return (ret);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetLUNStatistics.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,38 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    "sun_sas.h"
+
+/*
+ * Not Supported
+ */
+/*ARGSUSED*/
+HBA_STATUS Sun_sasGetLUNStatistics(
+	    HBA_HANDLE		handle,
+	    const HBA_SCSIID	*lunit,
+	    SMHBA_PROTOCOLSTATISTICS	*pstatistics) {
+	return (HBA_STATUS_ERROR_NOT_SUPPORTED);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetNumberOfAdapters.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,46 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sun_sas.h>
+
+/*
+ * Returns the number of HBAs supported by the library.  This returns the
+ * current number of HBAs, even if this changes
+ *
+ */
+HBA_UINT32 Sun_sasGetNumberOfAdapters() {
+	    int count;
+	    struct sun_sas_hba	*hba_ptr;
+
+	lock(&all_hbas_lock);
+	/* goes through hba list counting all the hbas found */
+	for (count = 0, hba_ptr = global_hba_head;
+	    hba_ptr != NULL; hba_ptr = hba_ptr->next, count++) {}
+
+	unlock(&all_hbas_lock);
+
+	return (count);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetNumberOfPorts.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,79 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sun_sas.h>
+
+/*
+ * Returns the number of HBAs supported by the library.  This returns the
+ * current number of HBAs, even if this changes
+ *
+ */
+HBA_UINT32 Sun_sasGetNumberOfPorts(
+    HBA_HANDLE handle, HBA_UINT32 *numberofports)
+{
+	const char		    ROUTINE[] = "Sun_sasGetNumberOfPorts";
+	int			    count, index;
+	struct  sun_sas_hba	    *hba_ptr;
+	struct  sun_sas_port	    *hba_port_ptr;
+
+	if (numberofports == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL numberofPorts pointer");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	lock(&all_hbas_lock);
+	index = RetrieveIndex(handle);
+	lock(&open_handles_lock);
+	hba_ptr = RetrieveHandle(index);
+	if (hba_ptr == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx.", handle);
+		/* on error, need to set NumberOfEntries to 0 */
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_INVALID_HANDLE);
+	}
+	/* goes through hba list counting all the hbas found */
+	if (hba_ptr->first_port == NULL) {
+		log(LOG_DEBUG, ROUTINE, "No HBA Port found on handle %08lx.",
+		    handle);
+		/* on error, need to set NumberOfPorts to 0 */
+		*numberofports = 0;
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_OK);
+	}
+
+	for (count = 0, hba_port_ptr = hba_ptr->first_port;
+	    hba_port_ptr != NULL; hba_port_ptr = hba_port_ptr->next, count++) {}
+
+	*numberofports = count;
+
+	unlock(&open_handles_lock);
+	unlock(&all_hbas_lock);
+
+	return (HBA_STATUS_OK);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetPersistentBinding.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,36 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    "sun_sas.h"
+
+/*
+ * Not Supported
+ */
+/*ARGSUSED*/
+HBA_STATUS Sun_sasGetPersistentBinding(HBA_HANDLE hande, HBA_WWN hbPortWWN,
+    HBA_WWN domainPortWWN, SMHBA_BINDING *binding) {
+	return (HBA_STATUS_ERROR_NOT_SUPPORTED);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetPhyStatistics.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,258 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <kstat.h>
+#include <sun_sas.h>
+
+/*
+ * Retrieves the statistics for a specified port.phy on an adapter
+ */
+HBA_STATUS Sun_sasGetPhyStatistics(HBA_HANDLE handle,
+    HBA_UINT32 port, HBA_UINT32 phy, SMHBA_PHYSTATISTICS *pStatistics) {
+	const char	ROUTINE[] = "Sun_sasGetPhyStatistics";
+	HBA_STATUS		status = HBA_STATUS_OK;
+	struct sun_sas_hba	*hba_ptr;
+	struct sun_sas_port	*hba_port_ptr;
+	struct phy_info		*phy_ptr;
+	PSMHBA_SASPHYSTATISTICS	psas;
+	kstat_ctl_t		*kc;
+	kstat_t			*ksp;
+	kstat_named_t		*kname;
+	char			*charptr, path[MAXPATHLEN + 1];
+	char			*driver_name, kstat_name[256];
+	di_node_t		node;
+	int			instance = 0;
+	int			i;
+	uint64_t		iport_wwn;
+
+	/* Validate the arguments */
+	if (pStatistics == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "NULL Phy Statistics buffer of phyIndex: %08lx", phy);
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	psas = pStatistics->SASPhyStatistics;
+	if (psas == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "NULL SAS Phy Statistics buffer of phyIndex: %08lx", phy);
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	lock(&all_hbas_lock);
+
+	if ((hba_ptr = Retrieve_Sun_sasHandle(handle)) == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Invalid HBA handler %08lx of phyIndex: %08lx",
+		    handle, phy);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_INVALID_HANDLE);
+	}
+
+	/* Check for stale data */
+	status = verifyAdapter(hba_ptr);
+	if (status != HBA_STATUS_OK) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Verify Adapter failed for phyIndex: %08lx", phy);
+		unlock(&all_hbas_lock);
+		return (status);
+	}
+
+	for (hba_port_ptr = hba_ptr->first_port;
+	    hba_port_ptr != NULL;
+	    hba_port_ptr = hba_port_ptr->next) {
+		if (hba_port_ptr->index == port) {
+			break;
+		}
+	}
+
+	if (hba_port_ptr == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Invalid port index of phyIndex: %08lx", phy);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_ILLEGAL_INDEX);
+	}
+
+	if (phy >= hba_port_ptr->port_attributes.PortSpecificAttribute.
+	    SASPort->NumberofPhys) {
+		log(LOG_DEBUG, ROUTINE, "Invalid phy index %08lx", phy);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_ILLEGAL_INDEX);
+	}
+
+	/* We need to find out the phy identifier. */
+	for (phy_ptr = hba_port_ptr->first_phy;
+	    phy_ptr != NULL;
+	    phy_ptr = phy_ptr->next) {
+		if (phy == phy_ptr->index)
+			break;
+	}
+
+	if (phy_ptr == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid phy index %08lx", phy);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_ILLEGAL_INDEX);
+	}
+
+	/*
+	 * for statistics that are not supported, its bits should all be
+	 * set to -1
+	 */
+	(void) memset(pStatistics->SASPhyStatistics, 0xff,
+	    sizeof (SMHBA_SASPHYSTATISTICS));
+
+
+	/* First, we need the deivce path to locate the devinfo node. */
+	(void *) strlcpy(path, hba_port_ptr->device_path,
+	    sizeof (path));
+	charptr = strrchr(path, ':');
+	if (charptr) {
+		*charptr = '\0';
+	}
+
+	errno = 0;
+
+	(void *) memset(kstat_name, 0, sizeof (kstat_name));
+	node = di_init(path, DINFOCPYONE);
+	if (node == DI_NODE_NIL) {
+		di_fini(node);
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to take devinfo snapshot on HBA \"%s\" "
+		    "for phyIndex: %08lx due to %s",
+		    path, phy, strerror(errno));
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR);
+	}
+
+	/*
+	 * Then we could fetch the instance number and driver name of this
+	 * device.
+	 */
+	instance = di_instance(node);
+	if (instance == -1) {
+		di_fini(node);
+		log(LOG_DEBUG, ROUTINE,
+		    "An instance number has not been assigned to the "
+		    "device \"%s\" when get phyIndex: %08lx", path, phy);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR);
+	}
+
+	driver_name = di_driver_name(node);
+	if (driver_name == NULL) {
+		di_fini(node);
+		log(LOG_DEBUG, ROUTINE,
+		    "No driver bound to this device \"%s\" "
+		    "when get phyIndex: %08lx",
+		    path, phy);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR);
+	}
+
+	di_fini(node);
+
+	iport_wwn = wwnConversion(hba_port_ptr->port_attributes.\
+	    PortSpecificAttribute.SASPort->LocalSASAddress.wwn);
+
+	/*
+	 * Construct the kstat name here.
+	 */
+	(void) snprintf(kstat_name, sizeof (kstat_name), "%s.%016llx.%u.%u",
+	    driver_name, iport_wwn, instance, phy_ptr->phy.PhyIdentifier);
+
+	/* retrieve all the statistics from kstat. */
+	kc = kstat_open();
+	if (kc == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "kstat_open failed due to \"%s\" of phyIndex: %08lx",
+		    strerror(errno), phy);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR);
+	}
+	ksp = kstat_lookup(kc, NULL, -1, kstat_name);
+	if (ksp == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "No matching kstat name found for \"%s\" "
+		    "of phyIndex: %08lx",
+		    kstat_name, phy);
+		unlock(&all_hbas_lock);
+		(void) kstat_close(kc);
+		return (HBA_STATUS_ERROR);
+	}
+	/* Found the phy we're looking for. */
+	if (kstat_read(kc, ksp, NULL) == -1) {
+		log(LOG_DEBUG, ROUTINE,
+		    "error reading kstat data due to \"%s\" "
+		    "of phyIndex: %08lx",
+		    strerror(errno), phy);
+		unlock(&all_hbas_lock);
+		(void) kstat_close(kc);
+		return (HBA_STATUS_ERROR);
+	}
+
+	kname = (kstat_named_t *)ksp->ks_data;
+	for (i = 0; i < ksp->ks_ndata; i++, kname++) {
+		if (strcmp(kname->name,
+		    "SecondsSinceLastReset") == 0) {
+		    psas->SecondsSinceLastReset = kname->value.ull;
+			continue;
+		}
+		if (strcmp(kname->name, "TxFrames") == 0) {
+			psas->TxFrames = kname->value.ull;
+			continue;
+		}
+		if (strcmp(kname->name, "RxFrames") == 0) {
+			psas->RxFrames = kname->value.ull;
+			continue;
+		}
+		if (strcmp(kname->name, "TxWords") == 0) {
+			psas->TxWords = kname->value.ull;
+			continue;
+		}
+		if (strcmp(kname->name, "RxWords") == 0) {
+			psas->RxWords = kname->value.ull;
+			continue;
+		}
+		if (strcmp(kname->name, "InvalidDwordCount") == 0) {
+			psas->InvalidDwordCount = kname->value.ull;
+			continue;
+		}
+		if (strcmp(kname->name, "RunningDisparityErrorCount") == 0) {
+			psas->RunningDisparityErrorCount = kname->value.ull;
+			continue;
+		}
+		if (strcmp(kname->name, "LossofDwordSyncCount") == 0) {
+			psas->LossofDwordSyncCount = kname->value.ull;
+			continue;
+		}
+		if (strcmp(kname->name, "PhyResetProblemCount") == 0) {
+			psas->PhyResetProblemCount = kname->value.ull;
+		}
+	}
+	unlock(&all_hbas_lock);
+	(void) kstat_close(kc);
+
+	return (HBA_STATUS_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetPortAttributesByWWN.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,189 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    <sun_sas.h>
+
+/*
+ * Retrieves the attributes for a specific discovered port by WWN
+ */
+HBA_STATUS
+Sun_sasGetPortAttributesByWWN(HBA_HANDLE handle, HBA_WWN portWWN,
+    HBA_WWN domainPortWWN, PSMHBA_PORTATTRIBUTES attributes)
+{
+	const char		ROUTINE[] = "Sun_sasGetPortAttributesByWWN";
+	HBA_STATUS		status;
+	struct sun_sas_hba	*hba_ptr;
+	struct sun_sas_port	*hba_port_ptr, *hba_disco_port;
+	int			index, chkDomainPort = 0, domainFound = 0;
+
+	/* Validate the arguments */
+	if (attributes == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL port attributes");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	if (wwnConversion(domainPortWWN.wwn) != 0) {
+		chkDomainPort = 1;
+	}
+
+	lock(&all_hbas_lock);
+	index = RetrieveIndex(handle);
+	lock(&open_handles_lock);
+	hba_ptr = RetrieveHandle(index);
+	if (hba_ptr == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx.", handle);
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_INVALID_HANDLE);
+	}
+
+	/* Check for stale data */
+	status = verifyAdapter(hba_ptr);
+	if (status != HBA_STATUS_OK) {
+		log(LOG_DEBUG, ROUTINE, "Verify adapter failed");
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (status);
+	}
+
+	if (hba_ptr->first_port == NULL) {
+	    /* This is probably an internal failure of the library */
+		if (hba_ptr->device_path) {
+			log(LOG_DEBUG, ROUTINE,
+			    "Internal failure:  Adapter %s contains "
+			    "no port data", hba_ptr->device_path);
+		} else {
+			log(LOG_DEBUG, ROUTINE,
+			    "Internal failure:  Adapter at index %d contains "
+			    "no port data", hba_ptr->index);
+		}
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR);
+	}
+
+	/* Loop over all Adapter ports */
+	for (hba_port_ptr = hba_ptr->first_port;
+	    hba_port_ptr != NULL;
+	    hba_port_ptr = hba_port_ptr->next) {
+		if (chkDomainPort) {
+			if (validateDomainAddress(hba_port_ptr,
+			    domainPortWWN) != HBA_STATUS_OK) {
+				continue;
+			} else
+				domainFound = 1;
+		}
+
+		if (wwnConversion(hba_port_ptr->port_attributes.
+		    PortSpecificAttribute.SASPort->LocalSASAddress.wwn) ==
+		    wwnConversion(portWWN.wwn)) {
+			/*
+			 * We should indicate an error if we enter here
+			 * without domainPortWWN set.
+			 */
+			if (chkDomainPort == 0) {
+				log(LOG_DEBUG, ROUTINE,
+				    "Domain Port WWN should be set when "
+				    "querying HBA port %016llx for "
+				    "handle %08lx",
+				    wwnConversion(portWWN.wwn), handle);
+				unlock(&open_handles_lock);
+				unlock(&all_hbas_lock);
+				return (HBA_STATUS_ERROR_ARG);
+			}
+			attributes->PortType =
+			    hba_port_ptr->port_attributes.PortType;
+			attributes->PortState =
+			    hba_port_ptr->port_attributes.PortState;
+			(void) strlcpy(attributes->OSDeviceName,
+			    hba_port_ptr->port_attributes.OSDeviceName,
+			    sizeof (attributes->OSDeviceName));
+			(void) memcpy(attributes->PortSpecificAttribute.SASPort,
+			    hba_port_ptr->port_attributes.PortSpecificAttribute.
+			    SASPort, sizeof (struct SMHBA_SAS_Port));
+
+			unlock(&open_handles_lock);
+			unlock(&all_hbas_lock);
+			return (HBA_STATUS_OK);
+		}
+
+		/* check to make sure there are devices attached to this port */
+		if (hba_port_ptr->first_attached_port != NULL) {
+
+			/* Loop over all discovered ports */
+			for (hba_disco_port = hba_port_ptr->first_attached_port;
+			    hba_disco_port != NULL;
+			    hba_disco_port = hba_disco_port->next) {
+				if (wwnConversion(hba_disco_port->
+				    port_attributes.PortSpecificAttribute.
+				    SASPort->LocalSASAddress.wwn) ==
+				    wwnConversion(portWWN.wwn)) {
+					attributes->PortType =
+					    hba_disco_port->port_attributes.
+					    PortType;
+					attributes->PortState =
+					    hba_disco_port->port_attributes.
+					    PortState;
+					(void) strlcpy(attributes->OSDeviceName,
+					    hba_disco_port->port_attributes.
+					    OSDeviceName,
+					    sizeof (attributes->OSDeviceName));
+					(void) memcpy(attributes->
+					    PortSpecificAttribute.SASPort,
+					    hba_disco_port->port_attributes.
+					    PortSpecificAttribute.SASPort,
+					    sizeof (struct SMHBA_SAS_Port));
+					unlock(&open_handles_lock);
+					unlock(&all_hbas_lock);
+					return (HBA_STATUS_OK);
+				}
+			}
+		}
+		if (chkDomainPort) {
+			log(LOG_DEBUG, ROUTINE,
+			    "Invalid Port WWN %016llx for handle %08lx",
+			    wwnConversion(portWWN.wwn), handle);
+			unlock(&open_handles_lock);
+			unlock(&all_hbas_lock);
+			return (HBA_STATUS_ERROR_ILLEGAL_WWN);
+		}
+	}
+	if (chkDomainPort && domainFound == 0) {
+		log(LOG_DEBUG, ROUTINE, "No Matching domain port"
+		    " (%16llx) for port (%16llx) for handle %08lx",
+		    wwnConversion(domainPortWWN.wwn),
+		    wwnConversion(portWWN.wwn),
+		    handle);
+	} else {
+		/* We enter here only when chkDomainPort == 0 */
+		log(LOG_DEBUG, ROUTINE,
+		    "Invalid Port WWN %016llx for handle %08lx",
+		    wwnConversion(portWWN.wwn), handle);
+	}
+	unlock(&open_handles_lock);
+	unlock(&all_hbas_lock);
+	return (HBA_STATUS_ERROR_ILLEGAL_WWN);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetPortType.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,98 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sun_sas.h>
+
+/*
+ * Returns the number of HBAs supported by the library.  This returns the
+ * current number of HBAs, even if this changes
+ *
+ */
+HBA_UINT32 Sun_sasGetPortType(HBA_HANDLE handle, HBA_UINT32 port,
+    HBA_PORTTYPE *porttype)
+{
+	const char		    ROUTINE[] = "Sun_sasGetPortType";
+	int			    index;
+	struct  sun_sas_hba	    *hba_ptr;
+	struct  sun_sas_port	    *hba_port_ptr;
+
+	/* Validate the arguments */
+	if (porttype == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL attributes.");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	lock(&all_hbas_lock);
+	index = RetrieveIndex(handle);
+	lock(&open_handles_lock);
+	hba_ptr = RetrieveHandle(index);
+	if (hba_ptr == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx.", handle);
+		/* on error, need to set NumberOfEntries to 0 */
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_INVALID_HANDLE);
+	}
+
+	if (hba_ptr->first_port == NULL) {
+	    /* This is probably an internal failure of the library */
+		if (hba_ptr->device_path) {
+			log(LOG_DEBUG, ROUTINE,
+			    "Internal failure:  Adapter %s contains no port "
+			    "data.", hba_ptr->device_path);
+		} else {
+			log(LOG_DEBUG, ROUTINE,
+			    "Internal failure:  Adapter at index %d contains "
+			    "no port data", hba_ptr->index);
+		}
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR);
+	}
+
+	for (hba_port_ptr = hba_ptr->first_port;
+	    hba_port_ptr != NULL; hba_port_ptr = hba_port_ptr->next) {
+		if (hba_port_ptr->index == port) {
+			break;
+		}
+	}
+
+	if (hba_port_ptr == NULL || hba_port_ptr->index != port) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Invalid port index %d for handle %08lx.",
+		    port, handle);
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_ILLEGAL_INDEX);
+	}
+
+	*porttype = HBA_PORTTYPE_SASDEVICE;
+
+	unlock(&open_handles_lock);
+	unlock(&all_hbas_lock);
+
+	return (HBA_STATUS_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetProtocolStatistics.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,39 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    "sun_sas.h"
+
+/*
+ * Not Supported
+ */
+/*ARGSUSED*/
+HBA_STATUS Sun_sasGetProtocolStatistics(
+	    HBA_HANDLE		handle,
+	    HBA_UINT32		portindex,
+	    HBA_UINT32		protocoltype,
+	    SMHBA_PROTOCOLSTATISTICS	*pstatistics) {
+	return (HBA_STATUS_ERROR_NOT_SUPPORTED);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetSASPhyAttributes.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,99 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    <sun_sas.h>
+
+/*
+ * Retrieves the statistics for a specified port on an adapter
+ */
+HBA_STATUS Sun_sasGetSASPhyAttributes(HBA_HANDLE handle,
+    HBA_UINT32 port, HBA_UINT32 phy, SMHBA_SAS_PHY *pAttributes)
+{
+	const char	ROUTINE[] = "Sun_sasGetSASPhyAttributes";
+	HBA_STATUS		status = HBA_STATUS_OK;
+	struct sun_sas_hba	*hba_ptr;
+	struct sun_sas_port	*hba_port_ptr;
+	struct phy_info		*phy_ptr;
+
+	/* Validate the arguments */
+	if (pAttributes == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL response buffer");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	lock(&all_hbas_lock);
+
+	if ((hba_ptr = Retrieve_Sun_sasHandle(handle)) == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx", handle);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_INVALID_HANDLE);
+	}
+
+	/* Check for stale data */
+	status = verifyAdapter(hba_ptr);
+	if (status != HBA_STATUS_OK) {
+		log(LOG_DEBUG, ROUTINE, "Verify adapter failed");
+		unlock(&all_hbas_lock);
+		return (status);
+	}
+
+	for (hba_port_ptr = hba_ptr->first_port;
+	    hba_port_ptr != NULL;
+	    hba_port_ptr = hba_port_ptr->next) {
+		if (hba_port_ptr->index == port) {
+			break;
+		}
+	}
+
+	if (hba_port_ptr == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid port index");
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_ILLEGAL_INDEX);
+	}
+
+	/* match phy index. */
+	if (phy >= hba_port_ptr->port_attributes.PortSpecificAttribute.
+	    SASPort->NumberofPhys) {
+		log(LOG_DEBUG, ROUTINE, "Invalid phy index %d", phy);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_ILLEGAL_INDEX);
+	} else {
+		for (phy_ptr = hba_port_ptr->first_phy; phy_ptr != NULL;
+		    phy_ptr = phy_ptr->next) {
+			if (phy == phy_ptr->index) {
+				(void) memset(pAttributes, 0,
+				    sizeof (SMHBA_SAS_PHY));
+				(void) memcpy(pAttributes, &phy_ptr->phy,
+				    sizeof (SMHBA_SAS_PHY));
+				unlock(&all_hbas_lock);
+				return (HBA_STATUS_OK);
+			}
+		}
+	}
+
+	unlock(&all_hbas_lock);
+	log(LOG_DEBUG, ROUTINE, "Illegal phy index %d", phy);
+	return (HBA_STATUS_ERROR_ILLEGAL_INDEX);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetTargetMapping.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,179 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    <sun_sas.h>
+
+/*
+ * Retrieves the mapping between targets and OS SCSI information
+ */
+HBA_STATUS
+Sun_sasGetTargetMapping(HBA_HANDLE handle, HBA_WWN hbaPortWWN,
+    HBA_WWN domainPortWWN, SMHBA_TARGETMAPPING *mapping)
+{
+	const char		ROUTINE[] = "Sun_sasGetTargetMapping";
+	int			i, index;
+	int			hbaPortFound = 0;
+	int			domainPortFound = 0;
+	uint_t			total_entries = 0;
+	struct  sun_sas_hba	*hba_ptr;
+	struct  sun_sas_port	*hba_port_ptr, *hba_disco_port;
+	struct	ScsiEntryList	*mapping_ptr;
+
+	if (mapping == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL mapping buffer");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	lock(&all_hbas_lock);
+	index = RetrieveIndex(handle);
+	lock(&open_handles_lock);
+	hba_ptr = RetrieveHandle(index);
+	if (hba_ptr == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx.", handle);
+		/* on error, need to set NumberOfEntries to 0 */
+		mapping->NumberOfEntries = 0;
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_INVALID_HANDLE);
+	}
+
+	/*
+	 * We should indicate an error if no domainPortWWN passed in.
+	 */
+	if (wwnConversion(domainPortWWN.wwn) == 0) {
+		log(LOG_DEBUG, ROUTINE, "domainPortWWN must be provided");
+		mapping->NumberOfEntries = 0;
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	/*
+	 * walk through the list of ports for this hba and count up the number
+	 * of discovered ports on each hba port
+	 */
+	i = 0;
+	for (hba_port_ptr = hba_ptr->first_port; hba_port_ptr != NULL;
+	    hba_port_ptr = hba_port_ptr->next) {
+		if (hbaPortFound == 0) {
+			if (wwnConversion(hba_port_ptr->port_attributes.
+			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn)
+			    != wwnConversion(hbaPortWWN.wwn)) {
+				/*
+				 * Since all the ports under the same HBA have
+				 * the same LocalSASAddress, we should break
+				 * the loop once we find it dosn't match.
+				 */
+				break;
+			} else {
+				hbaPortFound = 1;
+			}
+		}
+
+		/*
+		 * Check whether the domainPortWWN matches.
+		 */
+		if ((validateDomainAddress(hba_port_ptr, domainPortWWN))
+		    != HBA_STATUS_OK) {
+			continue;
+		}
+		domainPortFound = 1;
+
+		for (hba_disco_port = hba_port_ptr->first_attached_port;
+		    hba_disco_port != NULL;
+		    hba_disco_port = hba_disco_port->next) {
+			for (mapping_ptr = hba_disco_port->scsiInfo;
+			    mapping_ptr != NULL;
+			    mapping_ptr = mapping_ptr->next) {
+				/*
+				 * Add the information as much as mapping
+				 * can hold.
+				 */
+				if (wwnConversion(domainPortWWN.wwn) !=
+				    wwnConversion(mapping_ptr->entry.
+				    PortLun.domainPortWWN.wwn)) {
+					continue;
+				}
+
+				if (total_entries < mapping->NumberOfEntries) {
+					(void) memcpy(&mapping->entry[i].ScsiId,
+					    &mapping_ptr->entry.ScsiId,
+					    sizeof (SMHBA_SCSIID));
+					(void) memcpy(&mapping->entry[i].
+					    PortLun, &mapping_ptr->entry.
+					    PortLun, sizeof (SMHBA_PORTLUN));
+					(void) memcpy(&mapping->entry[i].LUID,
+					    &mapping_ptr->entry.LUID,
+					    sizeof (SMHBA_LUID));
+					i++;
+				}
+				total_entries++;
+			}
+		}
+	}
+
+	/*
+	 * check to make sure user has passed in an acceptable PortWWN for
+	 * the given handle
+	 */
+	if (hbaPortFound == 0) {
+		log(LOG_DEBUG, ROUTINE, "Unable to locate requested "
+		    "HBA Port WWN %016llx on handle %08lx",
+		    wwnConversion(hbaPortWWN.wwn), handle);
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_ILLEGAL_WWN);
+	}
+
+	if (domainPortFound == 0) {
+		log(LOG_DEBUG, ROUTINE, "No matching domain "
+		    "port %016llx for port %016llx on handle "
+		    "%08lx", wwnConversion(domainPortWWN.wwn),
+		    wwnConversion(hbaPortWWN.wwn), handle);
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_ILLEGAL_WWN);
+	}
+
+	if (total_entries > mapping->NumberOfEntries) {
+		log(LOG_DEBUG, ROUTINE,
+		    "total entries: %d: mapping->NumberofEntries: %d.",
+		    total_entries, mapping->NumberOfEntries);
+		mapping->NumberOfEntries = total_entries;
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_MORE_DATA);
+	}
+
+	mapping->NumberOfEntries = total_entries;
+
+	/* convert devpath to dev link */
+	convertDevpathToDevlink(mapping);
+
+	unlock(&open_handles_lock);
+	unlock(&all_hbas_lock);
+
+	return (HBA_STATUS_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetVendorLibraryAttributes.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,50 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    <sun_sas.h>
+
+#define	SUN_SMHBA_VENDOR_LIB VSL_NAME
+#define	SUN_SMHBA_VENDOR_LIB_PATH "/usr/lib/libsun_sas.so"
+#define	SUN_SMHBA_VENDOR_LIB_VERSION VSL_STRING_VERSION
+
+HBA_UINT32
+Sun_sasGetVendorLibraryAttributes(SMHBA_LIBRARYATTRIBUTES *attrs) {
+	const char		ROUTINE[] = "Sun_sasGetVendorLibraryAttributes";
+
+	/* Validate the arguments */
+	if (attrs == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL attrs structure");
+		return (SMHBA_LIBRARY_VERSION1);
+	}
+	(void) strlcpy(attrs->LibPath, SUN_SMHBA_VENDOR_LIB_PATH,
+	    sizeof (attrs->LibPath));
+	(void) strlcpy(attrs->VName, SUN_SMHBA_VENDOR_LIB,
+	    sizeof (attrs->VName));
+	(void) strlcpy(attrs->VVersion, SUN_SMHBA_VENDOR_LIB_VERSION,
+	    sizeof (attrs->VVersion));
+
+	return (SMHBA_LIBRARY_VERSION1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetVersion.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,34 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    "sun_sas.h"
+
+/*
+ * Returns the version which the common HBA API library is compatible with.
+ */
+HBA_UINT32 Sun_sasGetVersion() {
+	return (SMHBA_LIBRARY_VERSION1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasLoadLibrary.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,102 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#include <sun_sas.h>
+
+/*
+ * Loads the HBA Library.  Must be called before calling any HBA library
+ * functions
+ *
+ * Return values:
+ *	HBA_STATUS_OK	    library properly loaded
+ *	HBA_STATUS_ERROR    library loaded incorrectly
+ */
+int	loadCount = 0;
+HBA_STATUS Sun_sasLoadLibrary() {
+	const char	ROUTINE[] = "Sun_sasLoadLibrary";
+	di_node_t	root;
+	boolean_t	atLeastOneHBA = B_FALSE;
+	boolean_t	atLeastOneFailure = B_FALSE;
+	hrtime_t	    start = 0;
+	hrtime_t	    end = 0;
+	double		    duration = 0;
+
+	/* Make sure that library has not been already loaded */
+	if (loadCount++ > 0) {
+		log(LOG_DEBUG, ROUTINE, "Library already loaded %d time."
+		    " Ignoring.", loadCount);
+		return (HBA_STATUS_ERROR);
+	}
+	hba_count = 0;
+	open_handle_index = 1;
+	/* Initialize the read-write lock */
+	if (mutex_init(&all_hbas_lock, USYNC_THREAD, NULL)) {
+	    log(LOG_DEBUG, ROUTINE,
+		"Unable to initialize lock in LoadLibrary for reason \"%s\"",
+		strerror(errno));
+	    return (HBA_STATUS_ERROR);
+	}
+	/* grab write lock */
+	lock(&all_hbas_lock);
+
+	start = gethrtime();
+	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
+	    log(LOG_DEBUG, ROUTINE,
+		"Unable to load device tree for reason \"%s\"",
+		strerror(errno));
+	    unlock(&all_hbas_lock);
+	    return (HBA_STATUS_ERROR);
+	}
+	end = gethrtime();
+	duration = end - start;
+	duration /= HR_SECOND;
+	log(LOG_DEBUG, ROUTINE, "Loading device tree init took "
+	    "%.6f seconds", duration);
+
+	/* At load time, we only gather libdevinfo information */
+	if (devtree_get_all_hbas(root) == HBA_STATUS_OK) {
+	    atLeastOneHBA = B_TRUE;
+	} else {
+	    atLeastOneFailure = B_TRUE;
+	}
+
+	di_fini(root);
+
+	unlock(&all_hbas_lock);
+
+	/* Now determine what status code to return */
+	if (atLeastOneHBA) {
+	    /* We've got at least one HBA and possibly some failures */
+	    return (HBA_STATUS_OK);
+	} else if (atLeastOneFailure) {
+	    /* We have no HBAs but have failures */
+	    return (HBA_STATUS_ERROR);
+	} else {
+	    /* We have no HBAs and no failures */
+	    return (HBA_STATUS_OK);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasOpenAdapter.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,59 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    <sun_sas.h>
+
+/*
+ * Opens a named adapter.
+ * By opening an adapter, an upper level application is ensuring that all access
+ * to an HBA_HANDLE between and open and a close is to the same adapter.
+ *
+ * Sun_sasOpenAdapter just creates a new handle and returns the handle.
+ * It does not do a driver open
+ */
+HBA_HANDLE Sun_sasOpenAdapter(char *name) {
+	const char		ROUTINE[] = "Sun_sasOpenAdapter";
+	struct sun_sas_hba 	*hba_ptr;
+
+	if (name == NULL) {
+	    log(LOG_DEBUG, ROUTINE, "NULL adapter name.");
+	    return (HANDLE_ERROR);
+	}
+	lock(&all_hbas_lock);
+	for (hba_ptr = global_hba_head; hba_ptr != NULL;
+		hba_ptr = hba_ptr->next) {
+	    if (strcmp(hba_ptr->handle_name, name) == 0) {
+		    break;
+	    }
+	}
+	unlock(&all_hbas_lock);
+	if (hba_ptr == NULL) {
+	    log(LOG_DEBUG, ROUTINE, "Invalid adapter name \"%s\"", name);
+	    return (HANDLE_ERROR);
+	}
+
+	return (CreateHandle(hba_ptr->index));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasRefreshAdapterConfiguration.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,155 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    <sun_sas.h>
+
+/*
+ * Discover an HBA node with  matching path.
+ * The di_node_t argument should be the root of the device tree.
+ * This routine assumes the locks have been taken
+ */
+static int
+find_matching_hba(di_node_t node, void *arg)
+{
+	int *propData, rval;
+	walkarg_t *wa = (walkarg_t *)arg;
+	char	*devpath, fulldevpath[MAXPATHLEN];
+
+	/* Skip stub(instance -1) nodes */
+	if (IS_STUB_NODE(node)) {
+		return (DI_WALK_CONTINUE);
+	}
+
+	rval = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+	    "sm-hba-supported", &propData);
+	if (rval < 0) {
+		return (DI_WALK_CONTINUE);
+	} else {
+		if ((devpath = di_devfs_path(node)) == NULL) {
+			/* still continue to see if there is matching one. */
+			return (DI_WALK_CONTINUE);
+		}
+		(void) snprintf(fulldevpath, MAXPATHLEN, "%s%s", DEVICES_DIR,
+		    devpath);
+
+		if ((strstr(fulldevpath, wa->devpath)) != NULL) {
+				*wa->flag = B_TRUE;
+			/* Found a node. No need to walk any more. */
+			di_devfs_path_free(devpath);
+			return (DI_WALK_TERMINATE);
+		}
+		di_devfs_path_free(devpath);
+	}
+
+	return (DI_WALK_CONTINUE);
+}
+
+/*
+ * Refreshes information about an HBA
+ *
+ * Note: This routine holds the locks in write mode
+ *       during most of the processing, and as such, will cause
+ *	 all other threads to block on entry into the library
+ *	 until the refresh is complete.  An optimization would be
+ *       to put fine-grain locking in for the open_handle structures.
+ */
+void
+Sun_sasRefreshAdapterConfiguration()
+{
+	const char		    ROUTINE[] =
+	    "Sun_sasRefreshAdapterConfiguration";
+	struct sun_sas_hba	    *hba_ptr;
+	di_node_t		    root;
+	hrtime_t		    start;
+	hrtime_t		    end;
+	double			    duration;
+	walkarg_t		    wa;
+
+	/*
+	 * We're going to be tweaking a lot of global lists, so write
+	 * lock them.
+	 */
+	lock(&all_hbas_lock);
+	lock(&open_handles_lock);
+
+	start = gethrtime();
+	/* Grab device tree */
+	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to load device tree for reason \"%s\"",
+		    strerror(errno));
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return;
+	}
+
+	end = gethrtime();
+	duration = end - start;
+	duration /= HR_SECOND;
+	log(LOG_DEBUG, ROUTINE, "Device tree init took "
+	    "%.6f seconds", duration);
+
+	for (hba_ptr = global_hba_head; hba_ptr != NULL;
+	    hba_ptr = hba_ptr->next) {
+		wa.devpath = hba_ptr->device_path;
+		wa.flag = (boolean_t *)calloc(1, sizeof (boolean_t));
+		*wa.flag = B_FALSE;
+
+		if (di_walk_node(root, DI_WALK_SIBFIRST, &wa,
+		    find_matching_hba) != 0) {
+			log(LOG_DEBUG, ROUTINE, "di_walk_node failed.");
+			unlock(&open_handles_lock);
+			unlock(&all_hbas_lock);
+			S_FREE(wa.flag);
+			di_fini(root);
+			return;
+		}
+
+		if (*wa.flag == B_FALSE) {
+			/*
+			 * Keep the HBA as it is including open handles
+			 * per the SM-HBA standards. Just mark it as invalid.
+			 */
+			log(LOG_DEBUG, ROUTINE, "No matching HBA found. %s",
+			    hba_ptr->device_path);
+			hba_ptr->invalid = B_TRUE;
+		}
+		S_FREE(wa.flag);
+	}
+
+	/*
+	 * Now we marked missing HBA(s). Redisoover hbas to refresh
+	 * or add any new adapter to the hba list.
+	 * Simply call devtree_get_all_hbas().
+	 */
+	if (devtree_get_all_hbas(root) != HBA_STATUS_OK) {
+		log(LOG_DEBUG, ROUTINE, "devtree_get_all_hbas failed.");
+	}
+	di_fini(root);
+
+	unlock(&open_handles_lock);
+	unlock(&all_hbas_lock);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasRefreshInformation.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,159 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    "sun_sas.h"
+
+/*
+ * Discover an HBA node with  mtaching path.
+ * The di_node_t argument should be the root of the device tree.
+ * This routine assumes the locks have been taken
+ */
+static int
+match_smhba_sas_hba(di_node_t node, void *arg)
+{
+	int *propData, rval;
+	walkarg_t *wa = (walkarg_t *)arg;
+	char	*devpath, fulldevpath[MAXPATHLEN];
+
+	/* Skip stub(instance -1) nodes */
+	if (IS_STUB_NODE(node)) {
+		return (DI_WALK_CONTINUE);
+	}
+
+	rval = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+	    "sm-hba-supported", &propData);
+	if (rval < 0) {
+		return (DI_WALK_CONTINUE);
+	} else {
+		if ((devpath = di_devfs_path(node)) == NULL) {
+			/* still continue to see if there is matching one. */
+			return (DI_WALK_CONTINUE);
+		}
+		(void) snprintf(fulldevpath, MAXPATHLEN, "%s%s", DEVICES_DIR,
+		    devpath);
+
+		if ((strstr(fulldevpath, wa->devpath)) != NULL) {
+			/* add the hba to the hba list */
+			if (devtree_get_one_hba(node) ==
+			    HBA_STATUS_OK) {
+				/* succeed to refresh the adapater. */
+				*wa->flag = B_TRUE;
+			}
+			/* Found a node. No need to walk any more. */
+			di_devfs_path_free(devpath);
+			return (DI_WALK_TERMINATE);
+		}
+		di_devfs_path_free(devpath);
+	}
+
+	return (DI_WALK_CONTINUE);
+}
+
+/*
+ * Refreshes information about an HBA
+ *
+ * Note: This routine holds the locks in write mode
+ *       during most of the processing, and as such, will cause
+ *	 all other threads to block on entry into the library
+ *	 until the refresh is complete.  An optimization would be
+ *       to put fine-grain locking in for the open_handle structures.
+ */
+void
+Sun_sasRefreshInformation(HBA_HANDLE handle)
+{
+	const char		    ROUTINE[] = "Sun_sasRefreshInformation";
+	struct sun_sas_hba	    *hba_ptr;
+	struct open_handle	    *oHandle;
+	di_node_t		    root;
+	hrtime_t		    start;
+	hrtime_t		    end;
+	double			    duration;
+	walkarg_t		    wa;
+
+	/* take a lock for hbas and handles during rerfresh. */
+	lock(&all_hbas_lock);
+	lock(&open_handles_lock);
+
+	oHandle = RetrieveOpenHandle(handle);
+	if (oHandle == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx", handle);
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return;
+	}
+
+	/* now we know the associated hba exists in the global list. */
+	start = gethrtime();
+	/* Grab device tree */
+	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to load device tree for reason \"%s\"",
+		    strerror(errno));
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return;
+	}
+
+	end = gethrtime();
+	duration = end - start;
+	duration /= HR_SECOND;
+	log(LOG_DEBUG, ROUTINE, "Device tree init took "
+	    "%.6f seconds", duration);
+
+	hba_ptr = RetrieveHandle(oHandle->adapterIndex);
+	wa.devpath = hba_ptr->device_path;
+	wa.flag = (boolean_t *)calloc(1, sizeof (boolean_t));
+	*wa.flag = B_FALSE;
+
+	/* found the matching hba node and refresh hba ports and targets. */
+	if (di_walk_node(root, DI_WALK_SIBFIRST, &wa,
+	    match_smhba_sas_hba) != 0) {
+		log(LOG_DEBUG, ROUTINE, "di_walk_node failed.");
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		S_FREE(wa.flag);
+		di_fini(root);
+		return;
+	}
+
+	if (*wa.flag != B_TRUE) {
+		/* no matching HBA. */
+		log(LOG_DEBUG, ROUTINE, "No matching HBA found.");
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		S_FREE(wa.flag);
+		di_fini(root);
+		return;
+	}
+
+	S_FREE(wa.flag);
+
+	di_fini(root);
+
+	/* All done, release the locks */
+	unlock(&open_handles_lock);
+	unlock(&all_hbas_lock);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasScsiInquiry.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,273 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sun_sas.h>
+
+/*
+ * Combine uscsi command ans send it out via ioctl
+ */
+static HBA_STATUS
+SendScsiInquiry(const char *devpath, HBA_UINT8 cdb1, HBA_UINT8 cdb2,
+    void *responseBuffer, HBA_UINT32 *responseSize, HBA_UINT8 *scsiStatus,
+    void *senseBuffer, HBA_UINT32 *senseSize)
+{
+	HBA_UINT32		status;
+	struct uscsi_cmd	ucmd_buf;
+	union scsi_cdb		cdb;
+
+	bzero(&cdb, sizeof (cdb));
+	bzero(&ucmd_buf, sizeof (ucmd_buf));
+	bzero(senseBuffer, *senseSize);
+	bzero(responseBuffer, *responseSize);
+
+	cdb.scc_cmd = SCMD_INQUIRY;
+	cdb.g0_addr1 = cdb2;
+	cdb.g0_addr2 = cdb1;
+	cdb.g0_count0 = *responseSize;
+
+	ucmd_buf.uscsi_cdb = (char *)&cdb;
+	ucmd_buf.uscsi_cdblen = CDB_GROUP0;
+	ucmd_buf.uscsi_bufaddr = (caddr_t)responseBuffer;
+	ucmd_buf.uscsi_buflen = *responseSize;
+	ucmd_buf.uscsi_rqbuf = (caddr_t)senseBuffer;
+	ucmd_buf.uscsi_rqlen = *senseSize;
+	ucmd_buf.uscsi_flags = USCSI_READ | USCSI_SILENT | USCSI_RQENABLE;
+
+	status = send_uscsi_cmd(devpath, &ucmd_buf);
+	*scsiStatus = ucmd_buf.uscsi_status;
+	return (status);
+}
+
+
+/*
+ * Send a SCSI inquiry to a remote WWN
+ */
+HBA_STATUS
+Sun_sasScsiInquiry(HBA_HANDLE handle, HBA_WWN portWWN, HBA_WWN targetPortWWN,
+	    HBA_WWN domainPortWWN, SMHBA_SCSILUN smhbaLUN, HBA_UINT8 cdb1,
+	    HBA_UINT8 cdb2, void *responseBuffer, HBA_UINT32 *responseSize,
+	    HBA_UINT8 *scsiStatus, void *senseBuffer, HBA_UINT32 *senseSize)
+{
+	const char		ROUTINE[] = "Sun_sasScsiInquiry";
+	HBA_STATUS		status;
+	int			index = 0;
+	int			domainPortFound = 0;
+	int			hbaPortFound = 0;
+	int			chkDomainPort = 0;
+	struct sun_sas_hba	*hba_ptr = NULL;
+	struct sun_sas_port	*hba_port_ptr, *hba_disco_port;
+	struct ScsiEntryList	*mapping_ptr;
+	hrtime_t		start, end;
+	double			duration;
+	HBA_SCSILUN		hba_lun;
+
+	start = gethrtime();
+	/* Validate the arguments */
+	if (responseBuffer == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL response buffer");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (senseBuffer == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL sense buffer");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (responseSize == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL response size");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (senseSize == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL sense size");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (scsiStatus == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL scsi status");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	lock(&all_hbas_lock);
+	index = RetrieveIndex(handle);
+	lock(&open_handles_lock);
+	if ((hba_ptr = RetrieveHandle(index)) == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx", handle);
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_INVALID_HANDLE);
+	}
+
+	/* Check for stale data */
+	status = verifyAdapter(hba_ptr);
+	if (status != HBA_STATUS_OK) {
+		log(LOG_DEBUG, ROUTINE, "Verify adapter failed");
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (status);
+	}
+
+	/*
+	 * We are not checking to see if our data is stale.
+	 * By verifying this information here, we will take a big performance
+	 * hit.  This check will be done later only if the Inquiry ioctl fails
+	 */
+	if (hba_ptr->device_path == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "HBA handle had NULL device path. \
+		    Unable to send SCSI cmd");
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR);
+	}
+
+	if (wwnConversion(domainPortWWN.wwn))
+		chkDomainPort = 1;
+
+	/* Determine which port to use */
+	for (hba_port_ptr = hba_ptr->first_port;
+	    hba_port_ptr != NULL;
+	    hba_port_ptr = hba_port_ptr->next) {
+
+		if (hbaPortFound == 0) {
+			if (wwnConversion(hba_port_ptr->port_attributes.
+			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn)
+			    != wwnConversion(portWWN.wwn)) {
+				/*
+				 * Since all the ports under the same HBA have
+				 * the same LocalSASAddress, we should break
+				 * the loop once we find it dosn't match.
+				 */
+				break;
+			} else {
+				hbaPortFound = 1;
+			}
+		}
+
+		if (chkDomainPort) {
+			if (hba_port_ptr->first_phy != NULL &&
+			    wwnConversion(hba_port_ptr->first_phy->
+			    phy.domainPortWWN.wwn) ==
+			    wwnConversion(domainPortWWN.wwn)) {
+				domainPortFound = 1;
+			}
+			if (!(domainPortFound)) {
+				continue;
+			}
+		}
+
+		for (hba_disco_port = hba_port_ptr->first_attached_port;
+		    hba_disco_port != NULL;
+		    hba_disco_port = hba_disco_port->next) {
+
+			/*
+			 * If discoveredPort is not given targetPort, just skip
+			 */
+			if (wwnConversion(hba_disco_port->port_attributes.\
+			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn)
+			    != wwnConversion(targetPortWWN.wwn)) {
+				/* Does not match */
+				continue;
+			}
+
+			/*
+			 * If discoveredPort is not a SAS/SATA port, it is not a
+			 * target port
+			 */
+			if ((hba_disco_port->port_attributes.PortType !=
+			    HBA_PORTTYPE_SATADEVICE) &&
+			    (hba_disco_port->port_attributes.PortType !=
+			    HBA_PORTTYPE_SASDEVICE)) {
+				unlock(&open_handles_lock);
+				unlock(&all_hbas_lock);
+				log(LOG_DEBUG, ROUTINE, "Target Port WWN "
+				    "%016llx on handle %08lx is not a Target",
+				    wwnConversion(targetPortWWN.wwn), handle);
+				return (HBA_STATUS_ERROR_NOT_A_TARGET);
+			}
+
+			/*
+			 * Iterating and matching is needed.
+			 */
+			for (mapping_ptr = hba_disco_port->scsiInfo;
+			    mapping_ptr != NULL;
+			    mapping_ptr = mapping_ptr->next) {
+
+				if (memcmp(
+				    &mapping_ptr->entry.PortLun.TargetLun,
+				    &smhbaLUN, sizeof (HBA_SCSILUN))
+				    != 0) {
+					continue;
+				}
+
+				status = SendScsiInquiry(
+				    mapping_ptr->entry.ScsiId.OSDeviceName,
+				    cdb1, cdb2,
+				    responseBuffer, responseSize,
+				    scsiStatus, senseBuffer,
+				    senseSize);
+
+				unlock(&open_handles_lock);
+				unlock(&all_hbas_lock);
+				end = gethrtime();
+				duration = end - start;
+				duration /= HR_SECOND;
+				log(LOG_DEBUG, ROUTINE, "Took total\
+				    of %.4f seconds", duration);
+				return (status);
+			}
+			unlock(&open_handles_lock);
+			unlock(&all_hbas_lock);
+			(void *) memcpy(&hba_lun, &smhbaLUN,
+			    sizeof (HBA_SCSILUN));
+			log(LOG_DEBUG, ROUTINE, "Unable to locate lun"
+			    " %08lx for target %016llx on handle %08lx",
+			    hba_lun, wwnConversion(targetPortWWN.wwn), handle);
+			return (HBA_STATUS_ERROR_INVALID_LUN);
+		}
+		if (chkDomainPort) {
+			unlock(&open_handles_lock);
+			unlock(&all_hbas_lock);
+			log(LOG_DEBUG, ROUTINE, "Unable to locate requested "
+			    "Port WWN %016llx on handle %08lx",
+			    wwnConversion(targetPortWWN.wwn), handle);
+			return (HBA_STATUS_ERROR_ILLEGAL_WWN);
+		}
+	}
+
+	unlock(&open_handles_lock);
+	unlock(&all_hbas_lock);
+	if (hbaPortFound == 0) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to locate requested Port WWN %016llx on "
+		    "handle %08lx", wwnConversion(portWWN.wwn), handle);
+	} else if (chkDomainPort && !domainPortFound) {
+		log(LOG_DEBUG, ROUTINE, "Unable to locate requested"
+		    " domainPortWWN %016llx on handle %08lx",
+		    wwnConversion(domainPortWWN.wwn), handle);
+	} else {
+		log(LOG_DEBUG, ROUTINE, "Unable to locate requested "
+		    "Port WWN %016llx on handle %08lx",
+		    wwnConversion(targetPortWWN.wwn), handle);
+	}
+	return (HBA_STATUS_ERROR_ILLEGAL_WWN);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasScsiReadCapacity.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,261 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sun_sas.h>
+
+/*
+ * Pass request buffer into uscsi command and sent it out via ioctl
+ */
+static HBA_STATUS
+SendScsiReadCapacity(const char *devpath, void *responseBuffer,
+    HBA_UINT32 *responseSize, HBA_UINT8 *scsiStatus,
+    void *senseBuffer, HBA_UINT32 *senseSize)
+{
+	HBA_UINT32		status;
+	struct uscsi_cmd	ucmd_buf;
+	union scsi_cdb		cdb;
+
+	bzero(&cdb, sizeof (cdb));
+	bzero(&ucmd_buf, sizeof (ucmd_buf));
+	bzero(senseBuffer, *senseSize);
+	bzero(responseBuffer, *responseSize);
+
+	cdb.scc_cmd = SCMD_READ_CAPACITY;
+
+	ucmd_buf.uscsi_cdb = (char *)&cdb;
+	ucmd_buf.uscsi_cdblen = CDB_GROUP1;
+	ucmd_buf.uscsi_bufaddr = (caddr_t)responseBuffer;
+	ucmd_buf.uscsi_buflen = *responseSize;
+	ucmd_buf.uscsi_rqbuf = (caddr_t)senseBuffer;
+	ucmd_buf.uscsi_rqlen = *senseSize;
+	ucmd_buf.uscsi_flags = USCSI_READ | USCSI_SILENT | USCSI_RQENABLE;
+	ucmd_buf.uscsi_timeout = 60;
+
+	status = send_uscsi_cmd(devpath, &ucmd_buf);
+	*scsiStatus = ucmd_buf.uscsi_status;
+	return (status);
+}
+
+/*
+ * Send a read capacity to a remote WWN
+ */
+HBA_STATUS
+Sun_sasScsiReadCapacity(HBA_HANDLE handle, HBA_WWN portWWN,
+    HBA_WWN targetPortWWN, HBA_WWN domainPortWWN, SMHBA_SCSILUN smhbaLUN,
+    void *responseBuffer, HBA_UINT32 *responseSize,
+    HBA_UINT8 *scsiStatus, void *senseBuffer, HBA_UINT32 *senseSize)
+{
+	const char		ROUTINE[] = "Sun_sasScsiReadCapacity";
+	HBA_STATUS		status;
+	int			index = 0, domainPortFound = 0;
+	int			hbaPortFound = 0;
+	int			chkDomainPort = 0;
+	struct sun_sas_hba	*hba_ptr = NULL;
+	struct sun_sas_port	*hba_port_ptr, *hba_disco_port;
+	struct ScsiEntryList	*mapping_ptr;
+	hrtime_t		start, end;
+	double			duration;
+	HBA_SCSILUN		hba_lun;
+
+	start = gethrtime();
+	/* Validate the arguments */
+	if (responseBuffer == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL response buffer");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (senseBuffer == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL sense buffer");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (responseSize == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL response size");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (senseSize == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL sense size");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (scsiStatus == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL scsi status");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	lock(&all_hbas_lock);
+	index = RetrieveIndex(handle);
+	lock(&open_handles_lock);
+	if ((hba_ptr = RetrieveHandle(index)) == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx", handle);
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_INVALID_HANDLE);
+	}
+
+	/* Check for stale data */
+	status = verifyAdapter(hba_ptr);
+	if (status != HBA_STATUS_OK) {
+		log(LOG_DEBUG, ROUTINE, "Verify adapter failed");
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (status);
+	}
+
+	if (wwnConversion(domainPortWWN.wwn))
+		chkDomainPort = 1;
+
+	/*
+	 * We are not checking to see if our data is stale.
+	 * By verifying this information here, we will take a big performance
+	 * hit.  This check will be done later only if the FCSM ioctl fails
+	 */
+
+	/* Determine which port to use */
+	for (hba_port_ptr = hba_ptr->first_port;
+	    hba_port_ptr != NULL;
+	    hba_port_ptr = hba_port_ptr->next) {
+
+		if (hbaPortFound == 0) {
+			if (wwnConversion(hba_port_ptr->port_attributes.
+			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn)
+			    != wwnConversion(portWWN.wwn)) {
+				/*
+				 * Since all the ports under the same HBA have
+				 * the same LocalSASAddress, we should break
+				 * the loop once we find it dosn't match.
+				 */
+				break;
+			} else {
+				hbaPortFound = 1;
+			}
+		}
+
+		if (chkDomainPort != 0) {
+			if (hba_port_ptr->first_phy != NULL &&
+			    wwnConversion(hba_port_ptr->first_phy->
+			    phy.domainPortWWN.wwn) ==
+			    wwnConversion(domainPortWWN.wwn)) {
+				domainPortFound = 1;
+			}
+			if (!(domainPortFound)) {
+				continue;
+			}
+		}
+
+		for (hba_disco_port = hba_port_ptr->first_attached_port;
+		    hba_disco_port != NULL;
+		    hba_disco_port = hba_disco_port->next) {
+
+			/*
+			 * If discoveredPort is not given targetPort, just skip
+			 */
+			if (wwnConversion(hba_disco_port->port_attributes.\
+			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn)
+			    != wwnConversion(targetPortWWN.wwn)) {
+				/* Does not match */
+				continue;
+			}
+
+			/*
+			 * If discoveredPort is not a SAS/SATA port, it is not a
+			 * target port
+			 */
+			if ((hba_disco_port->port_attributes.PortType !=
+			    HBA_PORTTYPE_SATADEVICE) &&
+			    (hba_disco_port->port_attributes.PortType !=
+			    HBA_PORTTYPE_SASDEVICE)) {
+				unlock(&open_handles_lock);
+				unlock(&all_hbas_lock);
+				log(LOG_DEBUG, ROUTINE, "Target Port WWN "
+				    "%016llx on handle %08lx is not a Target",
+				    wwnConversion(targetPortWWN.wwn), handle);
+				return (HBA_STATUS_ERROR_NOT_A_TARGET);
+			}
+
+			/*
+			 * Iterating and matching is needed.
+			 */
+			for (mapping_ptr = hba_disco_port->scsiInfo;
+			    mapping_ptr != NULL;
+			    mapping_ptr = mapping_ptr->next) {
+
+				if (memcmp(
+				    &mapping_ptr->entry.PortLun.TargetLun,
+				    &smhbaLUN, sizeof (HBA_SCSILUN))
+				    != 0) {
+					continue;
+				}
+
+				status = SendScsiReadCapacity(
+				    mapping_ptr->entry.ScsiId.\
+				    OSDeviceName,
+				    responseBuffer, responseSize,
+				    scsiStatus, senseBuffer, senseSize);
+
+				unlock(&open_handles_lock);
+				unlock(&all_hbas_lock);
+				end = gethrtime();
+				duration = end - start;
+				duration /= HR_SECOND;
+				log(LOG_DEBUG, ROUTINE, "Took total\
+				    of %.4f seconds", duration);
+				return (status);
+			}
+			unlock(&open_handles_lock);
+			unlock(&all_hbas_lock);
+			(void *) memcpy(&hba_lun, &smhbaLUN,
+			    sizeof (HBA_SCSILUN));
+			log(LOG_DEBUG, ROUTINE, "Unable to locate lun"
+			    " %08lx for target %016llx on handle %08lx",
+			    hba_lun, wwnConversion(targetPortWWN.wwn), handle);
+			return (HBA_STATUS_ERROR_INVALID_LUN);
+		}
+
+		if (chkDomainPort) {
+			unlock(&open_handles_lock);
+			unlock(&all_hbas_lock);
+			log(LOG_DEBUG, ROUTINE, "Unable to locate requested "
+			    "Port WWN %016llx on handle %08lx",
+			    wwnConversion(targetPortWWN.wwn), handle);
+			return (HBA_STATUS_ERROR_ILLEGAL_WWN);
+		}
+	}
+
+	unlock(&open_handles_lock);
+	unlock(&all_hbas_lock);
+	if (hbaPortFound == 0) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to locate requested Port WWN %016llx on "
+		    "handle %08lx", wwnConversion(portWWN.wwn), handle);
+	} else if (chkDomainPort && !domainPortFound) {
+		log(LOG_DEBUG, ROUTINE, "Unable to locate requested"
+		    " domainPortWWN %016llx on handle %08lx",
+		    wwnConversion(domainPortWWN.wwn), handle);
+	} else {
+		log(LOG_DEBUG, ROUTINE, "Unable to locate requested "
+		    "Port WWN %016llx on handle %08lx",
+		    wwnConversion(targetPortWWN.wwn), handle);
+	}
+	return (HBA_STATUS_ERROR_ILLEGAL_WWN);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasScsiReportLUNs.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,233 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sun_sas.h>
+
+/*
+ * Pass scsi request buffer into uscsi command and sent it out via ioctl
+ */
+static HBA_STATUS
+SendScsiReportLUNs(const char *devpath, void *responseBuffer,
+    HBA_UINT32 *responseSize, HBA_UINT8 *scsiStatus,
+    void *senseBuffer, HBA_UINT32 *senseSize)
+{
+	HBA_UINT32		status;
+	struct uscsi_cmd	ucmd_buf;
+	union scsi_cdb		cdb;
+
+	bzero(&cdb, sizeof (cdb));
+	bzero(&ucmd_buf, sizeof (ucmd_buf));
+	bzero(senseBuffer, *senseSize);
+
+	cdb.scc_cmd = SCMD_REPORT_LUNS;
+	FORMG5COUNT(&cdb, *responseSize);
+
+	ucmd_buf.uscsi_cdb = (char *)&cdb;
+	ucmd_buf.uscsi_cdblen = CDB_GROUP5;
+	ucmd_buf.uscsi_bufaddr = (caddr_t)responseBuffer;
+	ucmd_buf.uscsi_buflen = *responseSize;
+	ucmd_buf.uscsi_rqbuf = (caddr_t)senseBuffer;
+	ucmd_buf.uscsi_rqlen = *senseSize;
+	ucmd_buf.uscsi_flags = USCSI_READ | USCSI_SILENT | USCSI_RQENABLE;
+	ucmd_buf.uscsi_timeout = 60;
+
+	status = send_uscsi_cmd(devpath, &ucmd_buf);
+	*scsiStatus = ucmd_buf.uscsi_status;
+	return (status);
+
+}
+
+/*
+ * Send a SCSI report luns command to a remote WWN
+ */
+HBA_STATUS
+Sun_sasScsiReportLUNs(HBA_HANDLE handle, HBA_WWN portWWN, HBA_WWN targetPortWWN,
+    HBA_WWN domainPortWWN, void *responseBuffer, HBA_UINT32 *responseSize,
+    HBA_UINT8 *scsiStatus, void *senseBuffer, HBA_UINT32 *senseSize)
+{
+	const char		ROUTINE[] = "Sun_sasScsiReportLUNs";
+	HBA_STATUS		status;
+	int			index = 0, domainPortFound = 0;
+	int			chkDomainPort = 0;
+	int			hbaPortFound = 0;
+	struct sun_sas_hba	*hba_ptr = NULL;
+	struct sun_sas_port	*hba_port_ptr, *hba_disco_port;
+	struct ScsiEntryList	*mapping_ptr;
+	hrtime_t		start, end;
+	double			duration;
+
+	start = gethrtime();
+
+	/* Validate the arguments */
+	if (responseBuffer == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL response buffer");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (senseBuffer == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL sense buffer");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (responseSize == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL response size");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (senseSize == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL sense size");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (scsiStatus == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL scsi status");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	lock(&all_hbas_lock);
+	index = RetrieveIndex(handle);
+	lock(&open_handles_lock);
+	if ((hba_ptr = RetrieveHandle(index)) == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx", handle);
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_INVALID_HANDLE);
+	}
+
+	/* Check for stale data */
+	status = verifyAdapter(hba_ptr);
+	if (status != HBA_STATUS_OK) {
+		log(LOG_DEBUG, ROUTINE, "Verify adapter failed");
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (status);
+	}
+
+	if (wwnConversion(domainPortWWN.wwn))
+		chkDomainPort = 1;
+	/* Determine which port to use */
+	for (hba_port_ptr = hba_ptr->first_port;
+	    hba_port_ptr != NULL;
+	    hba_port_ptr = hba_port_ptr->next) {
+
+		if (hbaPortFound == 0) {
+			if (wwnConversion(hba_port_ptr->port_attributes.
+			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn)
+			    != wwnConversion(portWWN.wwn)) {
+				/*
+				 * Since all the ports under the same HBA have
+				 * the same LocalSASAddress, we should break
+				 * the loop once we find it dosn't match.
+				 */
+				break;
+			} else {
+				hbaPortFound = 1;
+			}
+		}
+
+		if (chkDomainPort != 0) {
+			if (hba_port_ptr->first_phy != NULL &&
+			    wwnConversion(hba_port_ptr->first_phy->
+			    phy.domainPortWWN.wwn) ==
+			    wwnConversion(domainPortWWN.wwn)) {
+				domainPortFound = 1;
+			}
+			if (!(domainPortFound)) {
+				continue;
+			}
+		}
+
+		for (hba_disco_port = hba_port_ptr->first_attached_port;
+		    hba_disco_port != NULL;
+		    hba_disco_port = hba_disco_port->next) {
+
+			/*
+			 * If discoveredPort is not given targetPort, skip
+			 */
+			if (wwnConversion(hba_disco_port->port_attributes.\
+			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn)
+			    != wwnConversion(targetPortWWN.wwn)) {
+				/* Does not match */
+				continue;
+			}
+
+			/*
+			 * If discoveredPort is not a SAS/SATA port, it is not a
+			 * target port
+			 */
+			if ((hba_disco_port->port_attributes.PortType !=
+			    HBA_PORTTYPE_SATADEVICE) &&
+			    (hba_disco_port->port_attributes.PortType !=
+			    HBA_PORTTYPE_SASDEVICE)) {
+				unlock(&open_handles_lock);
+				unlock(&all_hbas_lock);
+				log(LOG_DEBUG, ROUTINE, "Target Port WWN "
+				    "%016llx on handle %08lx is not a Target",
+				    wwnConversion(targetPortWWN.wwn), handle);
+				return (HBA_STATUS_ERROR_NOT_A_TARGET);
+			}
+
+			if ((mapping_ptr = hba_disco_port->scsiInfo) != NULL) {
+
+				status = SendScsiReportLUNs(
+				    mapping_ptr->entry.ScsiId.OSDeviceName,
+				    responseBuffer, responseSize,
+				    scsiStatus, senseBuffer, senseSize);
+
+				unlock(&open_handles_lock);
+				unlock(&all_hbas_lock);
+				end = gethrtime();
+				duration = end - start;
+				duration /= HR_SECOND;
+				log(LOG_DEBUG, ROUTINE, "Took total\
+				    of %.4f seconds", duration);
+				return (status);
+			}
+		}
+
+		if (chkDomainPort) {
+			unlock(&open_handles_lock);
+			unlock(&all_hbas_lock);
+			log(LOG_DEBUG, ROUTINE, "Unable to located requested "
+			    "Port %016llx on handle %08lx",
+			    wwnConversion(targetPortWWN.wwn), handle);
+			return (HBA_STATUS_ERROR_ILLEGAL_WWN);
+		}
+	}
+
+	unlock(&open_handles_lock);
+	unlock(&all_hbas_lock);
+	if (hbaPortFound == 0) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to locate requested Port WWN %016llx on "
+		    "handle %08lx", wwnConversion(portWWN.wwn), handle);
+	} else if (chkDomainPort && !domainPortFound) {
+		log(LOG_DEBUG, ROUTINE, "Unable to locate requested"
+		    " domainPortWWN %016llx on handle %08lx",
+		    wwnConversion(domainPortWWN.wwn), handle);
+	} else {
+		log(LOG_DEBUG, ROUTINE, "Unable to locate requested "
+		    "Port WWN %016llx on handle %08lx",
+		    wwnConversion(targetPortWWN.wwn), handle);
+	}
+	return (HBA_STATUS_ERROR_ILLEGAL_WWN);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasSendSMPPassThru.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,250 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sun_sas.h>
+#include <sys/scsi/impl/usmp.h>
+
+/*
+ * Pass usmp_cmd into ioctl
+ */
+static HBA_STATUS
+SendSMPPassThru(const char *devpath, void *reqframe, HBA_UINT32 *reqsize,
+    void *rspframe, HBA_UINT32 *rspsize) {
+	const char		ROUTINE[] = "SendSMPPassThru";
+	int			fd;
+	usmp_cmd_t		ucmd_buf;
+	HBA_STATUS		ret;
+
+	bzero(&ucmd_buf, sizeof (ucmd_buf));
+
+	ucmd_buf.usmp_req = (caddr_t)reqframe;
+	ucmd_buf.usmp_rsp = (caddr_t)rspframe;
+	ucmd_buf.usmp_reqsize = (size_t)(*reqsize);
+	ucmd_buf.usmp_rspsize = (size_t)(*rspsize);
+	ucmd_buf.usmp_timeout = SMP_DEFAULT_TIMEOUT;
+
+	/*
+	 * open smp device
+	 */
+
+	if ((fd = open(devpath, O_RDONLY | O_NONBLOCK)) == -1) {
+		log(LOG_DEBUG, ROUTINE,
+		    "open devpath %s failed due to %s",
+		    devpath, strerror(errno));
+		return (HBA_STATUS_ERROR);
+	}
+
+	/*
+	 * send usmp command
+	 */
+	if (ioctl(fd, USMPFUNC, &ucmd_buf) == -1) {
+		if ((errno == ETIME) || (errno == ETIMEDOUT) ||
+		    (errno == EAGAIN)) {
+		    ret = HBA_STATUS_ERROR_TRY_AGAIN;
+		} else if (errno == EBUSY) {
+		    ret = HBA_STATUS_ERROR_BUSY;
+		} else {
+		    ret = HBA_STATUS_ERROR;
+		}
+		log(LOG_DEBUG, ROUTINE, "ioctl:USMPFUNC failed due to %s",
+		    strerror(errno));
+		(void) close(fd);
+		return (ret);
+	}
+
+	(void) close(fd);
+	return (HBA_STATUS_OK);
+}
+
+/*
+ * Send a USMP command to a remote SMP node
+ */
+HBA_STATUS
+Sun_sasSendSMPPassThru(HBA_HANDLE handle, HBA_WWN hbaPortWWN,
+    HBA_WWN destPortWWN, HBA_WWN domainPortWWN, void *pReqBuffer,
+    HBA_UINT32 ReqBufferSize, void *pRspBuffer, HBA_UINT32 *pRspBufferSize)
+{
+	const char		ROUTINE[] = "Sun_sasSendSMPPassThru";
+	HBA_STATUS		status;
+	struct sun_sas_hba	*hba_ptr;
+	int			domainPortFound = 0;
+	int			chkDomainPort = 0;
+	int			hbaPortFound = 0;
+	struct sun_sas_port	*hba_port_ptr, *hba_disco_port;
+	hrtime_t		start, end;
+	double			duration;
+
+	start = gethrtime();
+	/* Validate the arguments */
+	if (pRspBuffer == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL response buffer");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (pReqBuffer == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL sense buffer");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+	if (pRspBufferSize == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL response size");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	lock(&all_hbas_lock);
+	if ((hba_ptr = Retrieve_Sun_sasHandle(handle)) == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx", handle);
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR_INVALID_HANDLE);
+	}
+
+	/* Check for stale data */
+	status = verifyAdapter(hba_ptr);
+	if (status != HBA_STATUS_OK) {
+		log(LOG_DEBUG, ROUTINE, "Verify adapter failed");
+		unlock(&all_hbas_lock);
+		return (status);
+	}
+
+	/*
+	 * We are not checking to see if our data is stale.
+	 * By verifying this information here, we will take a big performance
+	 * hit.  This check will be done later only if the Inquiry ioctl fails
+	 */
+
+	if (hba_ptr->device_path == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "HBA handle had NULL device path.\
+		    Unable to send SCSI cmd");
+		unlock(&all_hbas_lock);
+		return (HBA_STATUS_ERROR);
+	}
+
+	if (wwnConversion(domainPortWWN.wwn))
+		chkDomainPort = 1;
+
+	/* Determine which port to use */
+	for (hba_port_ptr = hba_ptr->first_port;
+	    hba_port_ptr != NULL;
+	    hba_port_ptr = hba_port_ptr->next) {
+
+		if (hbaPortFound == 0) {
+			if (wwnConversion(hba_port_ptr->port_attributes.
+			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn)
+			    != wwnConversion(hbaPortWWN.wwn)) {
+				/*
+				 * Since all the ports under the same HBA have
+				 * the same LocalSASAddress, we should break
+				 * the loop once we find it dosn't match.
+				 */
+				break;
+			} else {
+				hbaPortFound = 1;
+			}
+		}
+
+		if (chkDomainPort != 0) {
+			if (hba_port_ptr->first_phy != NULL &&
+			    wwnConversion(hba_port_ptr->first_phy->
+			    phy.domainPortWWN.wwn) ==
+			    wwnConversion(domainPortWWN.wwn)) {
+				domainPortFound = 1;
+			}
+			if (!(domainPortFound)) {
+				continue;
+			}
+		}
+
+		for (hba_disco_port = hba_port_ptr->first_attached_port;
+		    hba_disco_port != NULL;
+		    hba_disco_port = hba_disco_port->next) {
+
+			/*
+			 * If discoveredPort is not given targetPort, just skip
+			 */
+			if (wwnConversion(hba_disco_port->port_attributes.\
+			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn)
+			    != wwnConversion(destPortWWN.wwn)) {
+				/* Does not match */
+				continue;
+			}
+
+			/*
+			 * If matching targetPort does not support SMP protocal
+			 * return error.
+			 * comment it out for testing only
+			 */
+			if ((hba_disco_port->port_attributes.\
+			    PortSpecificAttribute.SASPort->PortProtocol &
+			    HBA_SASPORTPROTOCOL_SMP) == 0) {
+				log(LOG_DEBUG, ROUTINE, "Input WWN %01611x\
+				    does not support SMP protocol",
+				    wwnConversion(hbaPortWWN.wwn));
+				unlock(&all_hbas_lock);
+				return (HBA_STATUS_ERROR_INVALID_PROTOCOL_TYPE);
+			}
+
+			/*
+			 * SMP target port doesn't have any scsi info.
+			 *   - like /dev/rdsk/cxtxdxsx
+			 * So we use OSDeviceName from port attributes.
+			 *   - like /dev/smp/expd[0-9]
+			 */
+			status = SendSMPPassThru(
+			    hba_disco_port->port_attributes.OSDeviceName,
+			    pReqBuffer, &ReqBufferSize,
+			    pRspBuffer, pRspBufferSize);
+
+			unlock(&all_hbas_lock);
+			end = gethrtime();
+			duration = end - start;
+			duration /= HR_SECOND;
+			log(LOG_DEBUG, ROUTINE, "Took total\
+			    of %.4f seconds", duration);
+			return (status);
+		}
+		if (chkDomainPort) {
+			unlock(&all_hbas_lock);
+			log(LOG_DEBUG, ROUTINE, "Unable to locate"
+			    "requested SMP target port %16llx",
+			    wwnConversion(destPortWWN.wwn));
+			return (HBA_STATUS_ERROR_ILLEGAL_WWN);
+		}
+	}
+	unlock(&all_hbas_lock);
+	if (hbaPortFound == 0) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to locate requested Port WWN %016llx on "
+		    "handle %08lx", wwnConversion(hbaPortWWN.wwn), handle);
+	} else if (chkDomainPort && !domainPortFound) {
+		log(LOG_DEBUG, ROUTINE, "Unable to locate requested"
+		    " domainPortWWN %016llx on handle %08lx",
+		    wwnConversion(domainPortWWN.wwn), handle);
+	} else {
+		log(LOG_DEBUG, ROUTINE, "Unable to locate"
+		    "requested SMP target port %16llx",
+		    wwnConversion(destPortWWN.wwn));
+	}
+	return (HBA_STATUS_ERROR_ILLEGAL_WWN);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/Sun_sasSetPersistentBinding.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,36 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include    "sun_sas.h"
+
+/*
+ * Not Supported
+ */
+/*ARGSUSED*/
+HBA_STATUS Sun_sasSetPersistentBinding(HBA_HANDLE handel, HBA_WWN hbaPortWWN,
+    HBA_WWN domainPortWWN, const SMHBA_BINDING *binding) {
+	return (HBA_STATUS_ERROR_NOT_SUPPORTED);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/devlink_disco.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,251 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sun_sas.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <libdevinfo.h>
+
+/*
+ * structure for di_devlink_walk
+ */
+typedef struct walk_devlink {
+	char *path;
+	size_t len;
+	char **linkpp;
+} walk_devlink_t;
+
+/*
+ * callback funtion for di_devlink_walk
+ * Find matching /dev link for the given path argument.
+ * devlink element and callback function argument.
+ * The input path is expected to not have "/devices".
+ */
+static int
+get_devlink(di_devlink_t devlink, void *arg)
+{
+	const char ROUTINE[] = "get_devlink";
+	walk_devlink_t *warg = (walk_devlink_t *)arg;
+
+	/*
+	 * When path is specified, it doesn't have minor
+	 * name. Therefore, the ../.. prefixes needs to be stripped.
+	 */
+	if (warg->path) {
+		char *content = (char *)di_devlink_content(devlink);
+		char *start = strstr(content, "/devices");
+
+		if (start == NULL ||
+		    strncmp(start, warg->path, warg->len) != 0 ||
+		    /* make it sure the device path has minor name */
+		    start[warg->len] != ':') {
+			return (DI_WALK_CONTINUE);
+		}
+	}
+
+	*(warg->linkpp) = strdup(di_devlink_path(devlink));
+	log(LOG_DEBUG, ROUTINE, "Walk terminate");
+	return (DI_WALK_TERMINATE);
+}
+
+/*
+ * Convert /devices paths to /dev sym-link paths.
+ * The mapping buffer OSDeviceName paths will be
+ * converted to short names.
+ * mappings The target mappings data to convert to short names
+ *
+ * If no link is found, the long path is left as is.
+ * Note: The NumberOfEntries field MUST not be greater than the size
+ * of the array passed in.
+ */
+void
+convertDevpathToDevlink(PSMHBA_TARGETMAPPING mappings)
+{
+	const char ROUTINE[] = "convertDevpathToLink";
+	di_devlink_handle_t hdl;
+	walk_devlink_t	    warg;
+	int		    j;
+	char		    *minor_path, *devlinkp;
+
+	if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
+		log(LOG_DEBUG, ROUTINE, "di_devlink failed: errno:%d",
+		    strerror(errno));
+		return;
+	}
+
+	for (j = 0; j < mappings->NumberOfEntries; j++) {
+		if (strchr(mappings->entry[j].ScsiId.OSDeviceName, ':')) {
+			/* search link for minor node */
+			minor_path = mappings->entry[j].ScsiId.OSDeviceName;
+			if (strstr(minor_path, "/devices") != NULL) {
+				minor_path = mappings->entry[j].ScsiId.
+				    OSDeviceName + strlen("/devices");
+			}
+			warg.path = NULL;
+		} else {
+			minor_path = NULL;
+			if (strstr(mappings->entry[j].ScsiId.OSDeviceName,
+			    "/devices") != NULL) {
+				warg.len = strlen(mappings->entry[j].ScsiId.
+				    OSDeviceName) - strlen("/devices");
+				warg.path = mappings->entry[j].
+				    ScsiId.OSDeviceName + strlen("/devices");
+			} else {
+				warg.len = strlen(mappings->entry[j].ScsiId.
+				    OSDeviceName);
+				warg.path = mappings->entry[j].ScsiId.
+				    OSDeviceName;
+			}
+		}
+
+		devlinkp = NULL;
+		warg.linkpp = &devlinkp;
+		(void) di_devlink_walk(hdl, NULL, minor_path, DI_PRIMARY_LINK,
+		    (void *)&warg, get_devlink);
+
+		if (devlinkp != NULL) {
+			(void) snprintf(mappings->entry[j].ScsiId.OSDeviceName,
+			    sizeof (mappings->entry[j].ScsiId.OSDeviceName),
+			    "%s", devlinkp);
+			free(devlinkp);
+		}
+
+	}
+
+	(void) di_devlink_fini(&hdl);
+}
+
+/*
+ * Finds controller path for a give device path.
+ *
+ * Return value: /dev link for dir and minor name.
+ */
+static HBA_STATUS
+lookupLink(char *path, char *link, const char *dir, const char *mname)
+{
+	const char ROUTINE[] = "lookupLink";
+	DIR    *dp;
+	char    buf[MAXPATHLEN];
+	char    node[MAXPATHLEN];
+	char	*charptr;
+	struct dirent *newdirp, *dirp;
+	ssize_t	count;
+	int	dirplen;
+	char	*subpath;
+	char	tmpPath[MAXPATHLEN];
+
+	if ((dp = opendir(dir)) == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		"Unable to open %s to find controller number.", dir);
+		return (HBA_STATUS_ERROR);
+	}
+
+	if (link == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Invalid argument for storing the link.");
+		return (HBA_STATUS_ERROR);
+	}
+
+	/*
+	 * dirplen is large enough to fit the largest path-
+	 * struct dirent includes one byte (the terminator)
+	 * so we don't add 1 to the calculation here.
+	 */
+	dirplen = pathconf(dir, _PC_NAME_MAX);
+	dirplen = ((dirplen <= 0) ? MAXNAMELEN : dirplen) +
+	    sizeof (struct dirent);
+	dirp = (struct dirent *)malloc(dirplen);
+	if (dirp == NULL) {
+		OUT_OF_MEMORY(ROUTINE);
+		return (HBA_STATUS_ERROR);
+	}
+
+	while ((readdir_r(dp, dirp, &newdirp)) == 0 && newdirp != NULL) {
+		if (strcmp(dirp->d_name, ".") == 0 ||
+		    strcmp(dirp->d_name, "..") == 0) {
+			continue;
+		}
+		/*
+		 * set to another pointer since dirp->d_name length is 1
+		 * that will store only the first char 'c' from the name.
+		 */
+		charptr = dirp->d_name;
+		(void) snprintf(node, strlen(charptr) + strlen(dir) + 2,
+		    "%s/%s", dir, charptr);
+		if (count = readlink(node, buf, sizeof (buf))) {
+			subpath = NULL;
+			subpath = strstr(buf, path);
+			buf[count] = '\0';
+			if (subpath != NULL) {
+				(void) strlcpy(tmpPath, path, MAXPATHLEN);
+				(void) strlcat(tmpPath, mname, MAXPATHLEN);
+				/*
+				 * if device path has substring of path
+				 * and exactally matching with :scsi suffix
+				 */
+				if (strcmp(subpath, tmpPath) == 0) {
+					(void) strlcpy(link, node, MAXPATHLEN);
+					(void) closedir(dp);
+					S_FREE(dirp);
+					return (HBA_STATUS_OK);
+				}
+			}
+		}
+	}
+
+	(void) closedir(dp);
+	S_FREE(dirp);
+	return (HBA_STATUS_ERROR);
+}
+
+/*
+ * Finds controller path for a give device path.
+ *
+ * Return vale:i smp devlink.
+ */
+HBA_STATUS
+lookupControllerLink(char *path, char *link)
+{
+	const char dir[] = "/dev/cfg";
+	const char mname[] = ":scsi";
+	return (lookupLink(path, link, dir, mname));
+}
+
+/*
+ * Finds smp devlink  for a give smp path.
+ *
+ * Return vale: smp devlink.
+ */
+HBA_STATUS
+lookupSMPLink(char *path, char *link)
+{
+	const char dir[] = "/dev/smp";
+	const char mname[] = ":smp";
+	return (lookupLink(path, link, dir, mname));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/devtree_device_disco.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,1075 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include	<sun_sas.h>
+#include	<sys/types.h>
+#include	<netinet/in.h>
+#include	<inttypes.h>
+#include	<ctype.h>
+#include	<sys/scsi/scsi_address.h>
+#include	<libdevid.h>
+
+/*
+ * Get the preferred minor node for the given path.
+ * ":n" for tapes, ":c,raw" for disks,
+ * and ":0" for enclosures.
+ */
+static void
+get_minor(char *devpath, char *minor)
+{
+	const char	ROUTINE[] = "get_minor";
+	char	fullpath[MAXPATHLEN];
+	int	fd;
+
+	if ((strstr(devpath, "/st@")) || (strstr(devpath, "/tape@"))) {
+		(void) strcpy(minor, ":n");
+	} else if (strstr(devpath, "/smp@")) {
+		(void) strcpy(minor, ":smp");
+	} else if ((strstr(devpath, "/ssd@")) || (strstr(devpath, "/sd@")) ||
+	    (strstr(devpath, "/disk@"))) {
+		(void) strcpy(minor, ":c,raw");
+	} else if ((strstr(devpath, "/ses@")) || (strstr(devpath,
+	    "/enclosure@"))) {
+		(void) snprintf(fullpath, MAXPATHLEN, "%s%s%s", DEVICES_DIR,
+		    devpath, ":0");
+		/* reset errno to 0 */
+		errno = 0;
+		if ((fd = open(fullpath, O_RDONLY)) == -1) {
+			/*
+			 * :0 minor doesn't exist. assume bound to sgen driver
+			 * and :ses minor exist.
+			 */
+			if (errno == ENOENT) {
+				(void) strcpy(minor, ":ses");
+			}
+		} else {
+			(void) strcpy(minor, ":0");
+			(void) close(fd);
+		}
+	} else {
+		log(LOG_DEBUG, ROUTINE, "Unrecognized target (%s)",
+		    devpath);
+		minor[0] = '\0';
+	}
+
+}
+
+/*
+ * Get the LUID through libdevid.
+ *
+ * devpath: /devices path for the devices.
+ * luidi: devid string.
+ */
+static void
+get_luid(char *devpath, char *luid)
+{
+	const char	ROUTINE[] = "get_luid";
+	int 		fd;
+	ddi_devid_t 	devid = NULL;
+	char 		*devidstr;
+
+	/* reset errno. */
+	errno = 0;
+	if ((fd = open(devpath,  O_RDONLY|O_NDELAY)) >= 0) {
+		if (devid_get(fd, &devid) == 0) {
+			if ((devidstr = devid_to_guid(devid)) != NULL) {
+				(void) strlcpy(luid, devidstr, 256);
+				devid_free_guid(devidstr);
+			} else {
+				log(LOG_DEBUG, ROUTINE,
+				    "failed to get devid guid on (%s) : %s",
+				    devpath, strerror(errno));
+			}
+			devid_free(devid);
+		} else {
+			log(LOG_DEBUG, ROUTINE,
+			    "failed to get devid on (%s)", devpath);
+		}
+		(void) close(fd);
+	} else {
+		log(LOG_DEBUG, ROUTINE, "open failed on (%s) error: %s",
+		    devpath, strerror(errno));
+	}
+}
+
+/*
+ * Free the attached port allocation.
+ */
+static void
+free_attached_port(struct sun_sas_port *port_ptr)
+{
+	struct sun_sas_port 	*tgt_port, *last_tgt_port;
+	struct ScsiEntryList	*scsi_info = NULL, *last_scsi_info = NULL;
+
+	tgt_port = port_ptr->first_attached_port;
+	while (tgt_port != NULL) {
+		/* Free target mapping data list first. */
+		scsi_info = tgt_port->scsiInfo;
+		while (scsi_info != NULL) {
+			last_scsi_info = scsi_info;
+			scsi_info = scsi_info->next;
+			free(last_scsi_info);
+		}
+		last_tgt_port = tgt_port;
+		tgt_port = tgt_port->next;
+		free(last_tgt_port->port_attributes.\
+		    PortSpecificAttribute.SASPort);
+		free(last_tgt_port);
+	}
+
+	port_ptr->first_attached_port = NULL;
+	port_ptr->port_attributes.PortSpecificAttribute.\
+	    SASPort->NumberofDiscoveredPorts = 0;
+}
+
+/*
+ * Fill domainPortWWN.
+ * should be called after completing discovered port discovery.
+ */
+void
+fillDomainPortWWN(struct sun_sas_port *port_ptr)
+{
+	const char    ROUTINE[] = "fillDomainPortWWN";
+	struct sun_sas_port *disco_port_ptr;
+	struct phy_info *phy_ptr;
+	uint64_t    domainPort = 0;
+	struct ScsiEntryList	    *mapping_ptr;
+
+	for (disco_port_ptr = port_ptr->first_attached_port;
+	    disco_port_ptr != NULL; disco_port_ptr = disco_port_ptr->next) {
+		if (disco_port_ptr->port_attributes.PortType ==
+		    HBA_PORTTYPE_SASEXPANDER &&
+		    wwnConversion(disco_port_ptr->port_attributes.
+		    PortSpecificAttribute.SASPort->
+		    AttachedSASAddress.wwn) ==
+		    wwnConversion(port_ptr->port_attributes.
+		    PortSpecificAttribute.SASPort->
+		    LocalSASAddress.wwn)) {
+			(void) memcpy(&domainPort,
+			    disco_port_ptr->port_attributes.
+			    PortSpecificAttribute.
+			    SASPort->LocalSASAddress.wwn, 8);
+			break;
+		}
+	}
+
+	if (domainPort == 0) {
+		if (port_ptr->first_attached_port) {
+			/*
+			 * there is no expander device attached on an HBA port
+			 * domainPortWWN should not stay to 0 since multiple
+			 * hba ports can have the same LocalSASAddres within
+			 * the same HBA.
+			 * Set the SAS address of direct attached target.
+			 */
+			if (wwnConversion(port_ptr->port_attributes.
+			    PortSpecificAttribute.SASPort->
+			    LocalSASAddress.wwn) ==
+			    wwnConversion(port_ptr->first_attached_port->
+			    port_attributes.PortSpecificAttribute.
+			    SASPort->AttachedSASAddress.wwn)) {
+				(void) memcpy(&domainPort,
+				    port_ptr->first_attached_port->
+				    port_attributes.PortSpecificAttribute.
+				    SASPort->LocalSASAddress.wwn, 8);
+			} else {
+				/*
+				 * SAS address is not upstream connected.
+				 * domainPortWWN stays as 0.
+				 */
+				log(LOG_DEBUG, ROUTINE,
+				    "DomainPortWWN is not set. "
+				    "Device(s) are visible on the HBA port "
+				    "but there is no expander or directly "
+				    "attached port with matching upsteam "
+				    "attached SAS address for "
+				    "HBA port (Local SAS Address: %016llx).",
+				    wwnConversion(port_ptr->port_attributes.
+				    PortSpecificAttribute.
+				    SASPort->LocalSASAddress.wwn));
+				return;
+			}
+		} else {
+			/*
+			 * There existss an iport without properly configured
+			 * child smp ndoes or  child node or pathinfo.
+			 * domainPortWWN stays as 0.
+			 */
+			log(LOG_DEBUG, ROUTINE,
+			    "DomainPortWWN is not set.  No properly "
+			    "configured smp or directly attached port "
+			    "found on HBA port(Local SAS Address: %016llx).",
+			    wwnConversion(port_ptr->port_attributes.
+			    PortSpecificAttribute.
+			    SASPort->LocalSASAddress.wwn));
+			return;
+		}
+	}
+
+	/* fill up phy info */
+	for (phy_ptr = port_ptr->first_phy; phy_ptr != NULL;
+	    phy_ptr = phy_ptr->next) {
+		(void) memcpy(phy_ptr->phy.domainPortWWN.wwn, &domainPort, 8);
+	}
+
+	/* fill up target mapping */
+	for (disco_port_ptr = port_ptr->first_attached_port;
+	    disco_port_ptr != NULL; disco_port_ptr = disco_port_ptr->next) {
+		for (mapping_ptr = disco_port_ptr->scsiInfo;
+		    mapping_ptr != NULL;
+		    mapping_ptr = mapping_ptr->next) {
+			(void) memcpy(mapping_ptr->entry.PortLun.
+			    domainPortWWN.wwn, &domainPort, 8);
+		}
+	}
+}
+
+/*
+ * Finds attached device(target) from devinfo node.
+ */
+static HBA_STATUS
+get_attached_devices_info(di_node_t node, struct sun_sas_port *port_ptr)
+{
+	const char		    ROUTINE[] = "get_attached_devices_info";
+	char			    *propStringData = NULL;
+	int			    *propIntData = NULL;
+	int64_t			    *propInt64Data = NULL;
+	uchar_t			    *propByteData = NULL;
+	scsi_lun_t		    samLun;
+	char			    *unit_address;
+	char			    *charptr;
+	char			    *devpath, link[MAXNAMELEN];
+	char			    fullpath[MAXPATHLEN+1];
+	char			    minorname[MAXNAMELEN+1];
+	struct ScsiEntryList	    *mapping_ptr;
+	HBA_WWN			    SASAddress, AttachedSASAddress;
+	struct sun_sas_port	    *disco_port_ptr;
+	uint_t			    state = 0;
+	int			    portfound, rval, size, count, i;
+	int			    port_state = HBA_PORTSTATE_ONLINE;
+	uint64_t		    tmpAddr;
+
+	if (port_ptr == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL port_ptr argument");
+		return (HBA_STATUS_ERROR);
+	}
+
+	if ((devpath = di_devfs_path(node)) == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Device in device tree has no path. Skipping.");
+		return (HBA_STATUS_ERROR);
+	}
+
+	if ((di_instance(node) == -1) || di_retired(node)) {
+		log(LOG_DEBUG, ROUTINE,
+		    "dev node (%s) returned instance of -1 or is retired. "
+		    " Skipping.", devpath);
+		di_devfs_path_free(devpath);
+		return (HBA_STATUS_OK);
+	}
+	state = di_state(node);
+	/* when node is not attached and online, set the state to offline. */
+	if (((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) ||
+	    ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE)) {
+		log(LOG_DEBUG, ROUTINE,
+		    "dev node (%s) is either OFFLINE or DETACHED",
+		    devpath);
+		port_state = HBA_PORTSTATE_OFFLINE;
+	}
+
+	/* add the "/devices" in the begining at the end */
+	(void) snprintf(fullpath, sizeof (fullpath), "%s%s",
+	    DEVICES_DIR, devpath);
+
+	(void) memset(&SASAddress, 0, sizeof (SASAddress));
+	if ((unit_address = di_bus_addr(node)) != NULL) {
+		if ((charptr = strchr(unit_address, ',')) != NULL) {
+			*charptr = '\0';
+		}
+		for (charptr = unit_address; *charptr != '\0'; charptr++) {
+			if (isxdigit(*charptr)) {
+				break;
+			}
+		}
+		if (*charptr != '\0') {
+			tmpAddr = htonll(strtoll(charptr, NULL, 16));
+			(void) memcpy(&SASAddress.wwn[0], &tmpAddr, 8);
+		} else {
+			log(LOG_DEBUG, ROUTINE,
+			    "No proper target port info on unit address of %s",
+			    fullpath);
+			di_devfs_path_free(devpath);
+			return (HBA_STATUS_ERROR);
+		}
+	} else {
+		log(LOG_DEBUG, ROUTINE,
+		    "Fail to get unit address of %s.",
+		    fullpath);
+		di_devfs_path_free(devpath);
+		return (HBA_STATUS_ERROR);
+	}
+
+	(void) memset(&AttachedSASAddress, 0, sizeof (AttachedSASAddress));
+	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "attached-port",
+	    &propStringData) != -1) {
+		for (charptr = propStringData; *charptr != '\0'; charptr++) {
+			if (isxdigit(*charptr)) {
+				break;
+			}
+		}
+		if (*charptr != '\0') {
+			tmpAddr = htonll(strtoll(charptr, NULL, 16));
+			(void) memcpy(AttachedSASAddress.wwn, &tmpAddr, 8);
+			/* check the attached address of hba port. */
+			if (memcmp(port_ptr->port_attributes.
+			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
+			    &tmpAddr, 8) == 0) {
+				/*
+				 * When attached-port is set from iport
+				 * attached-port prop, we do the cross check
+				 * with device's own SAS address.
+				 *
+				 * If not set, we store device's own SAS
+				 * address to iport attached SAS address.
+				 */
+				if (wwnConversion(port_ptr->port_attributes.
+				    PortSpecificAttribute.SASPort->
+				    AttachedSASAddress.wwn)) {
+					/* verify the Attaached SAS Addr. */
+					if (memcmp(port_ptr->port_attributes.
+					    PortSpecificAttribute.SASPort->
+					    AttachedSASAddress.wwn,
+					    SASAddress.wwn, 8) != 0) {
+				/* indentation move begin. */
+				log(LOG_DEBUG, ROUTINE,
+				    "iport attached-port(%016llx) do not"
+				    " match with level 1 Local"
+				    " SAS address(%016llx).",
+				    wwnConversion(port_ptr->port_attributes.
+				    PortSpecificAttribute.
+				    SASPort->AttachedSASAddress.wwn),
+				    wwnConversion(SASAddress.wwn));
+				di_devfs_path_free(devpath);
+				free_attached_port(port_ptr);
+				return (HBA_STATUS_ERROR);
+				/* indentation move ends. */
+					}
+				} else {
+					(void) memcpy(port_ptr->port_attributes.
+					    PortSpecificAttribute.
+					    SASPort->AttachedSASAddress.wwn,
+					    &SASAddress.wwn[0], 8);
+				}
+			}
+		} else {
+			log(LOG_DEBUG, ROUTINE,
+			    "No proper attached SAS address value on device %s",
+			    fullpath);
+			di_devfs_path_free(devpath);
+			free_attached_port(port_ptr);
+			return (HBA_STATUS_ERROR);
+		}
+	} else {
+		log(LOG_DEBUG, ROUTINE,
+		    "Property AttachedSASAddress not found for device \"%s\"",
+		    fullpath);
+		di_devfs_path_free(devpath);
+		free_attached_port(port_ptr);
+		return (HBA_STATUS_ERROR);
+	}
+
+	/*
+	 * walk the disco list to make sure that there isn't a matching
+	 * port and node wwn or a matching device path
+	 */
+	portfound = 0;
+	for (disco_port_ptr = port_ptr->first_attached_port;
+	    disco_port_ptr != NULL;
+	    disco_port_ptr = disco_port_ptr->next) {
+		if ((disco_port_ptr->port_attributes.PortState !=
+		    HBA_PORTSTATE_ERROR) && (memcmp(disco_port_ptr->
+		    port_attributes.PortSpecificAttribute.
+		    SASPort->LocalSASAddress.wwn, SASAddress.wwn, 8) == 0)) {
+			/*
+			 * found matching disco_port
+			 * look for matching device path
+			 */
+			portfound = 1;
+			for (mapping_ptr = disco_port_ptr->scsiInfo;
+			    mapping_ptr != NULL;
+			    mapping_ptr = mapping_ptr->next) {
+				if (strstr(mapping_ptr-> entry.ScsiId.
+				    OSDeviceName, devpath) != 0) {
+					log(LOG_DEBUG, ROUTINE,
+					    "Found an already discovered "
+					    "device %s.", fullpath);
+					di_devfs_path_free(devpath);
+					return (HBA_STATUS_OK);
+				}
+			}
+			if (portfound == 1) {
+				break;
+			}
+		}
+	}
+
+	if (portfound == 0) {
+		/*
+		 * there are no matching SAS address.
+		 * this must be a new device
+		 */
+		if ((disco_port_ptr = (struct sun_sas_port *)calloc(1,
+		    sizeof (struct sun_sas_port))) == NULL)  {
+			OUT_OF_MEMORY(ROUTINE);
+			di_devfs_path_free(devpath);
+			free_attached_port(port_ptr);
+			return (HBA_STATUS_ERROR);
+		}
+
+		if ((disco_port_ptr->port_attributes.PortSpecificAttribute.\
+		    SASPort = (struct SMHBA_SAS_Port *)calloc(1,
+		    sizeof (struct SMHBA_SAS_Port))) == NULL) {
+			OUT_OF_MEMORY("add_hba_port_info");
+			di_devfs_path_free(devpath);
+			free_attached_port(port_ptr);
+			return (HBA_STATUS_ERROR);
+		}
+
+		(void) memcpy(disco_port_ptr->port_attributes.
+		    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
+		    SASAddress.wwn, 8);
+		(void) memcpy(disco_port_ptr->port_attributes.
+		    PortSpecificAttribute.SASPort->AttachedSASAddress.wwn,
+		    AttachedSASAddress.wwn, 8);
+
+		/* Default to unknown until we figure out otherwise */
+		rval = di_prop_lookup_strings(DDI_DEV_T_ANY, node,
+		    "variant", &propStringData);
+		if (rval < 0) {
+			/* check if it is SMP target */
+			charptr = di_driver_name(node);
+			if (charptr != NULL && (strncmp(charptr, "smp",
+			    strlen(charptr)) == 0)) {
+				disco_port_ptr->port_attributes.PortType =
+				    HBA_PORTTYPE_SASEXPANDER;
+				disco_port_ptr->port_attributes.
+				    PortSpecificAttribute.
+				    SASPort->PortProtocol =
+				    HBA_SASPORTPROTOCOL_SMP;
+				if (lookupSMPLink(devpath, (char *)link) ==
+				    HBA_STATUS_OK) {
+		/* indentation changed here. */
+		(void) strlcpy(disco_port_ptr->port_attributes.
+		    OSDeviceName, link,
+		    sizeof (disco_port_ptr->port_attributes.OSDeviceName));
+		/* indentation change ends here. */
+				} else {
+		/* indentation changed here. */
+		get_minor(devpath, minorname);
+		(void) snprintf(fullpath, sizeof (fullpath), "%s%s%s",
+		    DEVICES_DIR, devpath, minorname);
+		(void) strlcpy(disco_port_ptr->port_attributes.
+		    OSDeviceName, fullpath,
+		    sizeof (disco_port_ptr->port_attributes.OSDeviceName));
+		/* indentation change ends here. */
+				}
+			} else {
+				disco_port_ptr->port_attributes.PortType =
+				    HBA_PORTTYPE_SASDEVICE;
+				disco_port_ptr->port_attributes.\
+				    PortSpecificAttribute.\
+				    SASPort->PortProtocol =
+				    HBA_SASPORTPROTOCOL_SSP;
+			}
+		} else {
+			if ((strcmp(propStringData, "sata") == 0) ||
+			    (strcmp(propStringData, "atapi") == 0)) {
+				disco_port_ptr->port_attributes.PortType =
+				    HBA_PORTTYPE_SATADEVICE;
+				disco_port_ptr->port_attributes.\
+				    PortSpecificAttribute.SASPort->PortProtocol
+				    = HBA_SASPORTPROTOCOL_SATA;
+			} else {
+				log(LOG_DEBUG, ROUTINE,
+				    "Unexpected variant prop value %s found on",
+				    " device %s", propStringData, fullpath);
+				/*
+				 * Port type will be 0
+				 * which is not valid type.
+				 */
+			}
+		}
+
+		/* SMP device was handled already */
+		if (disco_port_ptr->port_attributes.OSDeviceName[0] == '\0') {
+		/* indentation change due to ctysle check on sizeof. */
+		size = sizeof (disco_port_ptr->port_attributes.OSDeviceName);
+			(void) strlcpy(disco_port_ptr->port_attributes.
+			    OSDeviceName, fullpath, size);
+		}
+
+		/* add new discovered port into the list */
+
+		if (port_ptr->first_attached_port == NULL) {
+			port_ptr->first_attached_port = disco_port_ptr;
+			disco_port_ptr->index = 0;
+			port_ptr->port_attributes.PortSpecificAttribute.\
+			    SASPort->NumberofDiscoveredPorts = 1;
+		} else {
+			disco_port_ptr->next = port_ptr->first_attached_port;
+			port_ptr->first_attached_port = disco_port_ptr;
+			disco_port_ptr->index = port_ptr->port_attributes.\
+			    PortSpecificAttribute.\
+			    SASPort->NumberofDiscoveredPorts;
+			port_ptr->port_attributes.PortSpecificAttribute.\
+			    SASPort->NumberofDiscoveredPorts++;
+		}
+		disco_port_ptr->port_attributes.PortState = port_state;
+	}
+
+	if (disco_port_ptr->port_attributes.PortType ==
+	    HBA_PORTTYPE_SASEXPANDER) {
+	    /* No mapping data for expander device.  return ok here. */
+		di_devfs_path_free(devpath);
+		return (HBA_STATUS_OK);
+	}
+
+	if ((mapping_ptr = (struct ScsiEntryList *)calloc
+		    (1, sizeof (struct ScsiEntryList))) == NULL) {
+		OUT_OF_MEMORY(ROUTINE);
+		di_devfs_path_free(devpath);
+		free_attached_port(port_ptr);
+		return (HBA_STATUS_ERROR);
+	}
+
+	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "lun",
+	    &propIntData) != -1) {
+		mapping_ptr->entry.ScsiId.ScsiOSLun = *propIntData;
+	} else {
+		if ((charptr = strchr(unit_address, ',')) != NULL) {
+			charptr++;
+			mapping_ptr->entry.ScsiId.ScsiOSLun =
+			    strtoull(charptr, NULL, 10);
+		} else {
+			log(LOG_DEBUG, ROUTINE,
+			    "Failed to get LUN from the unit address of device "
+			    " %s.", fullpath);
+			di_devfs_path_free(devpath);
+			free_attached_port(port_ptr);
+			return (HBA_STATUS_ERROR);
+		}
+	}
+
+	/* get TargetLun(SAM-LUN). */
+	if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, "lun64",
+	    &propInt64Data) != -1) {
+		samLun = scsi_lun64_to_lun(*propInt64Data);
+		(void) memcpy(&mapping_ptr->entry.PortLun.TargetLun,
+		    &samLun, 8);
+	} else {
+		log(LOG_DEBUG, "get_attached_devices_info",
+		    "No lun64 prop found on device %s.", fullpath);
+		di_devfs_path_free(devpath);
+		free_attached_port(port_ptr);
+		return (HBA_STATUS_ERROR);
+	}
+
+	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+	    "target", &propIntData) != -1) {
+		mapping_ptr->entry.ScsiId.ScsiTargetNumber = *propIntData;
+	} else {
+		mapping_ptr->entry.ScsiId.ScsiTargetNumber = di_instance(node);
+	}
+
+	/* get ScsiBusNumber */
+	mapping_ptr->entry.ScsiId.ScsiBusNumber = port_ptr->cntlNumber;
+
+	(void) memcpy(mapping_ptr->entry.PortLun.PortWWN.wwn,
+	    SASAddress.wwn, 8);
+
+	/* Store the devices path for now.  We'll convert to /dev later */
+	get_minor(devpath, minorname);
+	(void) snprintf(mapping_ptr->entry.ScsiId.OSDeviceName,
+	    sizeof (mapping_ptr->entry.ScsiId.OSDeviceName),
+	    "%s%s%s", DEVICES_DIR, devpath, minorname);
+
+	count = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, "inquiry-page-83",
+	    (uchar_t **)&propByteData);
+	if (count < 0) {
+		get_luid(mapping_ptr->entry.ScsiId.OSDeviceName,
+		    mapping_ptr->entry.LUID.buffer);
+	} else {
+		for (i = 0, charptr = mapping_ptr->entry.LUID.buffer; i < count;
+		    i++, charptr += 2) {
+			(void) sprintf(charptr, "%02x", propByteData[i]);
+		}
+		*charptr = '\0';
+	}
+
+	if (disco_port_ptr->scsiInfo == NULL) {
+		disco_port_ptr->scsiInfo = mapping_ptr;
+	} else {
+		mapping_ptr->next = disco_port_ptr->scsiInfo;
+		disco_port_ptr->scsiInfo = mapping_ptr;
+	}
+
+	di_devfs_path_free(devpath);
+
+	return (HBA_STATUS_OK);
+}
+
+/*
+ * Finds attached device(target) from pathinfo node.
+ */
+static HBA_STATUS
+get_attached_paths_info(di_path_t path, struct sun_sas_port *port_ptr)
+{
+	char			    ROUTINE[] = "get_attached_paths_info";
+	char			    *propStringData = NULL;
+	int			    *propIntData = NULL;
+	int64_t			    *propInt64Data = NULL;
+	scsi_lun_t		    samLun;
+	char			    *unit_address;
+	char			    *charptr;
+	char			    *clientdevpath = NULL;
+	char			    *pathdevpath = NULL;
+	char			    fullpath[MAXPATHLEN+1];
+	char			    minorname[MAXNAMELEN+1];
+	struct ScsiEntryList	    *mapping_ptr;
+	HBA_WWN			    SASAddress, AttachedSASAddress;
+	struct sun_sas_port	    *disco_port_ptr;
+	di_path_state_t		    state = 0;
+	di_node_t		    clientnode;
+	int			    portfound, size;
+	int			    port_state = HBA_PORTSTATE_ONLINE;
+	uint64_t		    tmpAddr;
+
+	if (port_ptr == NULL) {
+		log(LOG_DEBUG, ROUTINE, "NULL port_ptr argument");
+		return (HBA_STATUS_ERROR);
+	}
+
+	/* if not null, free before return. */
+	pathdevpath = di_path_devfs_path(path);
+
+	state = di_path_state(path);
+	/* when node is not attached and online, set the state to offline. */
+	if ((state == DI_PATH_STATE_OFFLINE) ||
+	    (state == DI_PATH_STATE_FAULT)) {
+		log(LOG_DEBUG, ROUTINE,
+		    "path node (%s) is either OFFLINE or FAULT state",
+		    pathdevpath ?  pathdevpath : "(missing device path)");
+		port_state = HBA_PORTSTATE_OFFLINE;
+	}
+
+	if (clientnode = di_path_client_node(path)) {
+		if (di_retired(clientnode)) {
+			log(LOG_DEBUG, ROUTINE,
+			    "client node of path (%s) is retired. Skipping.",
+			    pathdevpath ?  pathdevpath :
+			    "(missing device path)");
+			if (pathdevpath) di_devfs_path_free(pathdevpath);
+			return (HBA_STATUS_OK);
+		}
+		if ((clientdevpath = di_devfs_path(clientnode)) == NULL) {
+			log(LOG_DEBUG, ROUTINE,
+			    "Client device of path (%s) has no path. Skipping.",
+			    pathdevpath ?  pathdevpath :
+			    "(missing device path)");
+			if (pathdevpath) di_devfs_path_free(pathdevpath);
+			return (HBA_STATUS_ERROR);
+		}
+	} else {
+		log(LOG_DEBUG, ROUTINE,
+		    "Failed to get client device from a path (%s).",
+		    pathdevpath ?  pathdevpath :
+		    "(missing device path)");
+		if (pathdevpath) di_devfs_path_free(pathdevpath);
+		return (HBA_STATUS_ERROR);
+	}
+
+	/* add the "/devices" in the begining and the :devctl at the end */
+	(void) snprintf(fullpath, sizeof (fullpath), "%s%s", DEVICES_DIR,
+	    clientdevpath);
+
+	(void) memset(&SASAddress, 0, sizeof (SASAddress));
+	if ((unit_address = di_path_bus_addr(path)) != NULL) {
+		if ((charptr = strchr(unit_address, ',')) != NULL) {
+			*charptr = '\0';
+		}
+		for (charptr = unit_address; *charptr != '\0'; charptr++) {
+			if (isxdigit(*charptr)) {
+				break;
+			}
+		}
+		if (charptr != '\0') {
+			tmpAddr = htonll(strtoll(charptr, NULL, 16));
+			(void) memcpy(&SASAddress.wwn[0], &tmpAddr, 8);
+		} else {
+			log(LOG_DEBUG, ROUTINE,
+			    "No proper target port info on unit address of "
+			    "path (%s).", pathdevpath ?  pathdevpath :
+			    "(missing device path)");
+			if (pathdevpath) di_devfs_path_free(pathdevpath);
+			di_devfs_path_free(clientdevpath);
+			return (HBA_STATUS_ERROR);
+		}
+	} else {
+		log(LOG_DEBUG, ROUTINE, "Fail to get unit address of path(%s).",
+		    "path (%s).", pathdevpath ?  pathdevpath :
+		    "(missing device path)");
+		if (pathdevpath) di_devfs_path_free(pathdevpath);
+		di_devfs_path_free(clientdevpath);
+		return (HBA_STATUS_ERROR);
+	}
+
+	(void) memset(&AttachedSASAddress, 0, sizeof (AttachedSASAddress));
+	if (di_path_prop_lookup_strings(path, "attached-port",
+	    &propStringData) != -1) {
+		for (charptr = propStringData; *charptr != '\0'; charptr++) {
+			if (isxdigit(*charptr)) {
+				break;
+			}
+		}
+		if (*charptr != '\0') {
+			tmpAddr = htonll(strtoll(charptr, NULL, 16));
+			(void) memcpy(AttachedSASAddress.wwn, &tmpAddr, 8);
+			/*  check the attached address of hba port. */
+			if (memcmp(port_ptr->port_attributes.
+			    PortSpecificAttribute.SASPort->
+			    LocalSASAddress.wwn, &tmpAddr, 8) == 0) {
+				if (wwnConversion(port_ptr->port_attributes.
+				    PortSpecificAttribute.SASPort->
+				    AttachedSASAddress.wwn)) {
+					/* verify the attaached SAS Addr. */
+					if (memcmp(port_ptr->port_attributes.
+					    PortSpecificAttribute.SASPort->
+					    AttachedSASAddress.wwn,
+					    SASAddress.wwn, 8) != 0) {
+				/* indentation move begin. */
+				log(LOG_DEBUG, ROUTINE,
+				    "iport attached-port(%016llx) do not"
+				    " match with level 1 Local"
+				    " SAS address(%016llx).",
+				    wwnConversion(port_ptr->port_attributes.
+				    PortSpecificAttribute.
+				    SASPort->AttachedSASAddress.wwn),
+				    wwnConversion(SASAddress.wwn));
+				if (pathdevpath)
+					di_devfs_path_free(pathdevpath);
+				di_devfs_path_free(clientdevpath);
+				free_attached_port(port_ptr);
+				return (HBA_STATUS_ERROR);
+				/* indentation move ends. */
+					}
+				} else {
+					/* store the Attaached SAS Addr. */
+					(void) memcpy(port_ptr->port_attributes.
+					    PortSpecificAttribute.
+					    SASPort->AttachedSASAddress.wwn,
+					    &SASAddress.wwn[0], 8);
+				}
+			}
+		} else {
+			log(LOG_DEBUG, ROUTINE,
+			    "No proper attached SAS address value of path (%s)",
+			    pathdevpath ?  pathdevpath :
+			    "(missing device path)");
+			if (pathdevpath) di_devfs_path_free(pathdevpath);
+			di_devfs_path_free(clientdevpath);
+			free_attached_port(port_ptr);
+			return (HBA_STATUS_ERROR);
+		}
+	} else {
+		log(LOG_DEBUG, ROUTINE,
+		    "Property attached-port not found for path (%s)",
+		    pathdevpath ?  pathdevpath :
+		    "(missing device path)");
+		if (pathdevpath) di_devfs_path_free(pathdevpath);
+		di_devfs_path_free(clientdevpath);
+		free_attached_port(port_ptr);
+		return (HBA_STATUS_ERROR);
+	}
+
+	/*
+	 * walk the disco list to make sure that there isn't a matching
+	 * port and node wwn or a matching device path
+	 */
+	portfound = 0;
+	for (disco_port_ptr = port_ptr->first_attached_port;
+	    disco_port_ptr != NULL;
+	    disco_port_ptr = disco_port_ptr->next) {
+		if ((disco_port_ptr->port_attributes.PortState !=
+		    HBA_PORTSTATE_ERROR) &&
+		    (memcmp(disco_port_ptr->port_attributes.
+		    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
+		    SASAddress.wwn, 8) == 0)) {
+			/*
+			 * found matching disco_port
+			 * look for matching device path
+			 */
+			portfound = 1;
+			for (mapping_ptr = disco_port_ptr->scsiInfo;
+			    mapping_ptr != NULL;
+			    mapping_ptr = mapping_ptr->next) {
+				if (strstr(mapping_ptr-> entry.ScsiId.
+				    OSDeviceName, clientdevpath) != 0) {
+					log(LOG_DEBUG, ROUTINE,
+					    "Found an already discovered "
+					    "device %s.", clientdevpath);
+					if (pathdevpath)
+						di_devfs_path_free(pathdevpath);
+					di_devfs_path_free(clientdevpath);
+					return (HBA_STATUS_OK);
+				}
+			}
+			if (portfound == 1) {
+				break;
+			}
+		}
+	}
+
+	if (portfound == 0) {
+		/*
+		 * there are no matching SAS address.
+		 * this must be a new device
+		 */
+		if ((disco_port_ptr = (struct sun_sas_port *)calloc(1,
+				    sizeof (struct sun_sas_port))) == NULL)  {
+			OUT_OF_MEMORY(ROUTINE);
+			if (pathdevpath) di_devfs_path_free(pathdevpath);
+			di_devfs_path_free(clientdevpath);
+			free_attached_port(port_ptr);
+			return (HBA_STATUS_ERROR);
+		}
+
+		if ((disco_port_ptr->port_attributes.PortSpecificAttribute.\
+		    SASPort = (struct SMHBA_SAS_Port *)calloc(1,
+		    sizeof (struct SMHBA_SAS_Port))) == NULL) {
+			OUT_OF_MEMORY("add_hba_port_info");
+			if (pathdevpath) di_devfs_path_free(pathdevpath);
+			di_devfs_path_free(clientdevpath);
+			free_attached_port(port_ptr);
+			return (HBA_STATUS_ERROR);
+		}
+
+		(void) memcpy(disco_port_ptr->port_attributes.
+		    PortSpecificAttribute.
+		    SASPort->LocalSASAddress.wwn, SASAddress.wwn, 8);
+		(void) memcpy(disco_port_ptr->port_attributes.
+		    PortSpecificAttribute.
+		    SASPort->AttachedSASAddress.wwn, AttachedSASAddress.wwn, 8);
+
+		/* Default to unknown until we figure out otherwise */
+		if (di_path_prop_lookup_strings(path, "variant",
+		    &propStringData) != -1) {
+			if ((strcmp(propStringData, "sata") == 0) ||
+			    (strcmp(propStringData, "atapi") == 0)) {
+				disco_port_ptr->port_attributes.PortType =
+				    HBA_PORTTYPE_SATADEVICE;
+				disco_port_ptr->port_attributes.\
+				    PortSpecificAttribute.SASPort->PortProtocol
+				    = HBA_SASPORTPROTOCOL_SATA;
+			} else {
+				log(LOG_DEBUG, ROUTINE,
+				    "Unexpected variant prop value %s found on",
+				    " path (%s)", propStringData,
+				    pathdevpath ?  pathdevpath :
+				    "(missing device path)");
+				/*
+				 * Port type will be 0
+				 * which is not valid type.
+				 */
+			}
+		} else {
+			disco_port_ptr->port_attributes.PortType =
+			    HBA_PORTTYPE_SASDEVICE;
+			disco_port_ptr->port_attributes.PortSpecificAttribute.\
+			    SASPort->PortProtocol = HBA_SASPORTPROTOCOL_SSP;
+		}
+
+		if (disco_port_ptr->port_attributes.OSDeviceName[0] == '\0') {
+		/* indentation change due to ctysle check on sizeof. */
+		size = sizeof (disco_port_ptr->port_attributes.OSDeviceName);
+			if (pathdevpath != NULL) {
+				(void) strlcpy(disco_port_ptr->port_attributes.
+				    OSDeviceName, pathdevpath, size);
+			}
+		}
+
+		/* add new discovered port into the list */
+		if (port_ptr->first_attached_port == NULL) {
+			port_ptr->first_attached_port = disco_port_ptr;
+			disco_port_ptr->index = 0;
+			port_ptr->port_attributes.PortSpecificAttribute.\
+			    SASPort->NumberofDiscoveredPorts = 1;
+		} else {
+			disco_port_ptr->next = port_ptr->first_attached_port;
+			port_ptr->first_attached_port = disco_port_ptr;
+			disco_port_ptr->index = port_ptr->port_attributes.\
+			    PortSpecificAttribute.\
+			    SASPort->NumberofDiscoveredPorts;
+			port_ptr->port_attributes.PortSpecificAttribute.\
+			    SASPort->NumberofDiscoveredPorts++;
+		}
+		disco_port_ptr->port_attributes.PortState = port_state;
+	}
+
+	if ((mapping_ptr = (struct ScsiEntryList *)calloc
+		    (1, sizeof (struct ScsiEntryList))) == NULL) {
+		OUT_OF_MEMORY(ROUTINE);
+		if (pathdevpath) di_devfs_path_free(pathdevpath);
+		di_devfs_path_free(clientdevpath);
+		free_attached_port(port_ptr);
+		return (HBA_STATUS_ERROR);
+	}
+
+	if (di_path_prop_lookup_ints(path, "lun", &propIntData) != -1) {
+		mapping_ptr->entry.ScsiId.ScsiOSLun = *propIntData;
+	} else {
+		if ((charptr = strchr(unit_address, ',')) != NULL) {
+			charptr++;
+			mapping_ptr->entry.ScsiId.ScsiOSLun =
+			    strtoull(charptr, NULL, 10);
+		} else {
+			log(LOG_DEBUG, ROUTINE,
+			    "Failed to get LUN from unit address of path(%s).",
+			    pathdevpath ?  pathdevpath :
+			    "(missing device path)");
+			if (pathdevpath) di_devfs_path_free(pathdevpath);
+			di_devfs_path_free(clientdevpath);
+			free_attached_port(port_ptr);
+			return (HBA_STATUS_ERROR);
+		}
+	}
+
+	/* Get TargetLun(SAM LUN). */
+	if (di_path_prop_lookup_int64s(path, "lun64", &propInt64Data) != -1) {
+		samLun = scsi_lun64_to_lun(*propInt64Data);
+		(void) memcpy(&mapping_ptr->entry.PortLun.TargetLun,
+		    &samLun, 8);
+	} else {
+		log(LOG_DEBUG, ROUTINE, "No lun64 prop found on path (%s)",
+		    pathdevpath ?  pathdevpath :
+		    "(missing device path)");
+		if (pathdevpath) di_devfs_path_free(pathdevpath);
+		di_devfs_path_free(clientdevpath);
+		free_attached_port(port_ptr);
+		return (HBA_STATUS_ERROR);
+	}
+
+	if (di_path_prop_lookup_ints(path, "target", &propIntData) != -1) {
+		mapping_ptr->entry.ScsiId.ScsiTargetNumber = *propIntData;
+	} else {
+		mapping_ptr->entry.ScsiId.ScsiTargetNumber =
+		    di_path_instance(path);
+	}
+
+	/* get ScsiBusNumber */
+	mapping_ptr->entry.ScsiId.ScsiBusNumber = port_ptr->cntlNumber;
+
+	(void) memcpy(mapping_ptr->entry.PortLun.PortWWN.wwn,
+	    SASAddress.wwn, 8);
+
+	/* Store the devices path for now.  We'll convert to /dev later */
+	get_minor(clientdevpath, minorname);
+	(void) snprintf(mapping_ptr->entry.ScsiId.OSDeviceName,
+	    sizeof (mapping_ptr->entry.ScsiId.OSDeviceName),
+	    "%s%s%s", DEVICES_DIR, clientdevpath, minorname);
+
+	/* get luid. */
+	if (di_prop_lookup_strings(DDI_DEV_T_ANY, clientnode,
+	    "client-guid", &propStringData) != -1) {
+		(void) strlcpy(mapping_ptr->entry.LUID.buffer, propStringData,
+		    sizeof (mapping_ptr->entry.LUID.buffer));
+	} else {
+		log(LOG_DEBUG, ROUTINE, "No client-guid prop found on path(%s)",
+		    pathdevpath ?  pathdevpath :
+		    "(missing device path)");
+		if (pathdevpath) di_devfs_path_free(pathdevpath);
+		di_devfs_path_free(clientdevpath);
+		free_attached_port(port_ptr);
+		return (HBA_STATUS_ERROR);
+	}
+
+	if (disco_port_ptr->scsiInfo == NULL) {
+		disco_port_ptr->scsiInfo = mapping_ptr;
+	} else {
+		mapping_ptr->next = disco_port_ptr->scsiInfo;
+		disco_port_ptr->scsiInfo = mapping_ptr;
+	}
+
+	if (pathdevpath) di_devfs_path_free(pathdevpath);
+	di_devfs_path_free(clientdevpath);
+
+	return (HBA_STATUS_OK);
+}
+
+/*
+ * walks the devinfo tree retrieving all hba information
+ */
+extern HBA_STATUS
+devtree_attached_devices(di_node_t node, struct sun_sas_port *port_ptr)
+{
+	const char		ROUTINE[] = "devtree_attached_devices";
+	di_node_t		nodechild = DI_NODE_NIL;
+	di_path_t		path = DI_PATH_NIL;
+
+	/* child should be device */
+	if ((nodechild = di_child_node(node)) == DI_NODE_NIL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "No devinfo child on the HBA port node.");
+	}
+
+	if ((path = di_path_phci_next_path(node, path)) ==
+	    DI_PATH_NIL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "No pathinfo node on the HBA port node.");
+	}
+
+	if ((nodechild == DI_NODE_NIL) && (path == DI_PATH_NIL)) {
+		return (HBA_STATUS_OK);
+	}
+
+	while (nodechild != DI_NODE_NIL) {
+		if (get_attached_devices_info(nodechild, port_ptr)
+		    != HBA_STATUS_OK) {
+			break;
+		}
+		nodechild = di_sibling_node(nodechild);
+	}
+
+
+	while (path != DI_PATH_NIL) {
+		if (get_attached_paths_info(path, port_ptr)
+		    != HBA_STATUS_OK) {
+			break;
+		}
+		path = di_path_phci_next_path(node, path);
+	}
+
+	return (HBA_STATUS_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/devtree_hba_disco.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,634 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#include	<sun_sas.h>
+#include	<sys/modctl.h>
+#include	<sys/types.h>
+#include	<netinet/in.h>
+#include	<inttypes.h>
+#include	<ctype.h>
+
+/* free hba port info for the given hba */
+static void
+free_hba_port(struct sun_sas_hba *hba_ptr)
+{
+	struct sun_sas_port	*hba_port = NULL;
+	struct sun_sas_port	*last_hba_port = NULL;
+	struct sun_sas_port	*tgt_port = NULL;
+	struct sun_sas_port	*last_tgt_port = NULL;
+	struct ScsiEntryList	*scsi_info = NULL;
+	struct ScsiEntryList	*last_scsi_info = NULL;
+	struct phy_info		*phy_ptr = NULL;
+	struct phy_info		*last_phy = NULL;
+
+	/* Free the nested structures (port and attached port) */
+	hba_port = hba_ptr->first_port;
+	while (hba_port != NULL) {
+		/* Free discovered port structure list. */
+		tgt_port = hba_port->first_attached_port;
+		while (tgt_port != NULL) {
+			/* Free target mapping data list first. */
+			scsi_info = tgt_port->scsiInfo;
+			while (scsi_info != NULL) {
+				last_scsi_info = scsi_info;
+				scsi_info = scsi_info->next;
+				free(last_scsi_info);
+			}
+			last_tgt_port = tgt_port;
+			tgt_port = tgt_port->next;
+			free(last_tgt_port->port_attributes.\
+			    PortSpecificAttribute.SASPort);
+			free(last_tgt_port);
+		}
+		hba_port->first_attached_port = NULL;
+
+		phy_ptr = hba_port->first_phy;
+		while (phy_ptr != NULL) {
+			last_phy = phy_ptr;
+			phy_ptr = phy_ptr->next;
+			free(last_phy);
+		}
+		hba_port->first_phy = NULL;
+
+		last_hba_port = hba_port;
+		hba_port = hba_port->next;
+		free(last_hba_port->port_attributes.\
+		    PortSpecificAttribute.SASPort);
+		free(last_hba_port);
+	}
+
+	hba_ptr->first_port = NULL;
+}
+
+/*
+ * Internal routine for adding an HBA port
+ */
+static HBA_STATUS
+add_hba_port_info(di_node_t portNode, struct sun_sas_hba *hba_ptr, int protocol)
+{
+	const char		    ROUTINE[] = "add_hba_port_info";
+	struct sun_sas_port	    *port_ptr;
+	char			    *portDevpath;
+	int			    *propIntData;
+	char			    *propStringData;
+	uint64_t		    tmpAddr;
+	char			    *charptr, cntlLink[MAXPATHLEN] = {'\0'};
+	int			    rval;
+	uint_t			    state = HBA_PORTSTATE_UNKNOWN;
+
+	if (hba_ptr == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Sun_sas handle ptr set to NULL.");
+		return (HBA_STATUS_ERROR_ARG);
+	}
+
+	if ((port_ptr = (struct sun_sas_port *)calloc(1,
+	    sizeof (struct sun_sas_port))) == NULL) {
+		OUT_OF_MEMORY(ROUTINE);
+		return (HBA_STATUS_ERROR);
+	}
+
+	if ((port_ptr->port_attributes.PortSpecificAttribute.SASPort =
+	    (struct SMHBA_SAS_Port *)calloc(1, sizeof (struct SMHBA_SAS_Port)))
+	    == NULL) {
+		OUT_OF_MEMORY(ROUTINE);
+		return (HBA_STATUS_ERROR);
+	}
+
+	if ((portDevpath = di_devfs_path(portNode)) == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to get device path from HBA Port Node.");
+		S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
+		S_FREE(port_ptr);
+		return (HBA_STATUS_ERROR);
+	}
+
+	state = di_state(portNode);
+	if (((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) ||
+	    ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE)) {
+		log(LOG_DEBUG, ROUTINE,
+		    "HBA port node %s is either OFFLINE or DETACHED",
+		    portDevpath);
+		port_ptr->port_attributes.PortState = HBA_PORTSTATE_OFFLINE;
+	} else {
+		port_ptr->port_attributes.PortState = HBA_PORTSTATE_ONLINE;
+	}
+
+	port_ptr->port_attributes.PortType = HBA_PORTTYPE_SASDEVICE;
+
+	(void) strlcpy(port_ptr->device_path, portDevpath, MAXPATHLEN + 1);
+
+	if (lookupControllerLink(portDevpath, (char *)cntlLink) ==
+	    HBA_STATUS_OK) {
+		(void) strlcpy(port_ptr->port_attributes.OSDeviceName, cntlLink,
+		    sizeof (port_ptr->port_attributes.OSDeviceName));
+		if ((charptr = strrchr(cntlLink, '/')) != NULL) {
+			charptr++;
+		}
+		if (charptr[0] ==  'c') {
+			port_ptr->cntlNumber = atoi(++charptr);
+		} else {
+			port_ptr->cntlNumber = -1;
+		}
+	} else {
+		(void) snprintf(port_ptr->port_attributes.OSDeviceName,
+		    sizeof (port_ptr->port_attributes.OSDeviceName),
+		    "%s%s%s", DEVICES_DIR, portDevpath, SCSI_SUFFIX);
+	}
+
+	di_devfs_path_free(portDevpath);
+
+	port_ptr->port_attributes.PortSpecificAttribute.
+	    SASPort->PortProtocol = protocol;
+
+	rval = di_prop_lookup_strings(DDI_DEV_T_ANY, portNode,
+	    "initiator-port", &propStringData);
+	if (rval < 0) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to get initiator-port from HBA port node %s.",
+		    port_ptr->port_attributes.OSDeviceName);
+		S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
+		S_FREE(port_ptr);
+		return (HBA_STATUS_ERROR);
+	} else {
+		for (charptr = propStringData; *charptr != '\0'; charptr++) {
+			if (isxdigit(*charptr)) {
+				break;
+			}
+		}
+		if (*charptr != '\0') {
+			tmpAddr = htonll(strtoll(charptr, NULL, 16));
+			(void) memcpy(port_ptr->port_attributes.
+			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
+			    &tmpAddr, 8);
+		} else {
+			log(LOG_DEBUG, ROUTINE,
+			    "No proper intiator-port prop value on HBA port %s",
+			    port_ptr->port_attributes.OSDeviceName);
+		}
+	}
+
+	rval = di_prop_lookup_strings(DDI_DEV_T_ANY, portNode,
+	    "attached-port", &propStringData);
+	if (rval < 0) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to get attached-port from HBA port node %s.",
+		    port_ptr->port_attributes.OSDeviceName);
+		S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
+		S_FREE(port_ptr);
+		return (HBA_STATUS_ERROR);
+	} else {
+		for (charptr = propStringData; *charptr != '\0'; charptr++) {
+			if (isxdigit(*charptr)) {
+				break;
+			}
+		}
+		if (*charptr != '\0') {
+			tmpAddr = htonll(strtoll(charptr, NULL, 16));
+			(void) memcpy(port_ptr->port_attributes.
+			    PortSpecificAttribute.SASPort->
+			    AttachedSASAddress.wwn, &tmpAddr, 8);
+		} else {
+			/* continue even if the attached port is NULL. */
+			log(LOG_DEBUG, ROUTINE,
+			    "No proper attached-port prop value: "
+			    "HBA port Local SAS Address(%016llx)",
+			    wwnConversion(port_ptr->port_attributes.
+			    PortSpecificAttribute.
+			    SASPort->LocalSASAddress.wwn));
+		}
+	}
+
+	rval = di_prop_lookup_ints(DDI_DEV_T_ANY, portNode,
+	    "num-phys", &propIntData);
+	if (rval < 0) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to get NumberofPhys from HBA port %s.",
+		    port_ptr->port_attributes.OSDeviceName);
+		S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
+		S_FREE(port_ptr);
+		return (HBA_STATUS_ERROR);
+	} else {
+		port_ptr->port_attributes.PortSpecificAttribute.\
+		    SASPort->NumberofPhys = *propIntData;
+	}
+
+	if (port_ptr->port_attributes.PortSpecificAttribute.\
+	    SASPort->NumberofPhys > 0) {
+		if (get_phy_info(portNode, port_ptr) != HBA_STATUS_OK) {
+			log(LOG_DEBUG, ROUTINE,
+			    "Failed to get phy info on HBA port %s.",
+			    port_ptr->port_attributes.OSDeviceName);
+			S_FREE(port_ptr->port_attributes.
+			    PortSpecificAttribute.SASPort);
+			S_FREE(port_ptr);
+		}
+	}
+
+	/* devtree_attached_devices(portSubtreenode, port_ptr); */
+	if (devtree_attached_devices(portNode, port_ptr) != HBA_STATUS_OK) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Failed to get attached device info HBA port %s.",
+		    port_ptr->port_attributes.OSDeviceName);
+		S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
+		S_FREE(port_ptr);
+	}
+
+	fillDomainPortWWN(port_ptr);
+
+	/* add new port onto hba handle list */
+	if (hba_ptr->first_port == NULL) {
+		port_ptr->index = 0;
+		hba_ptr->first_port = port_ptr;
+	} else {
+		port_ptr->index = hba_ptr->first_port->index + 1;
+		port_ptr->next = hba_ptr->first_port;
+		hba_ptr->first_port = port_ptr;
+	}
+
+	return (HBA_STATUS_OK);
+}
+
+HBA_STATUS
+refresh_hba(di_node_t hbaNode, struct sun_sas_hba *hba_ptr)
+{
+	const char	ROUTINE[] = "refresh_hba";
+	di_node_t	portNode;
+	int		protocol = 0;
+	int		*propIntData;
+
+	/*
+	 * clean up existing hba port, discovered target, phy info.
+	 * leave open handles intact.
+	 */
+	free_hba_port(hba_ptr);
+
+	if ((portNode = di_child_node(hbaNode)) == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "HBA node doesn't have iport child.");
+		return (HBA_STATUS_ERROR);
+	}
+
+	if ((di_prop_lookup_ints(DDI_DEV_T_ANY, hbaNode,
+	    "supported-protocol", &propIntData)) == -1) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to get supported-protocol from HBA node.");
+	} else {
+		protocol = *propIntData;
+	}
+
+	while (portNode != DI_NODE_NIL) {
+		if (add_hba_port_info(portNode, hba_ptr, protocol)
+		    == HBA_STATUS_ERROR) {
+			S_FREE(hba_ptr->first_port);
+			S_FREE(hba_ptr);
+			return (HBA_STATUS_ERROR);
+		}
+		portNode = di_sibling_node(portNode);
+	}
+
+	return (HBA_STATUS_OK);
+}
+
+/*
+ * Discover information for one HBA in the device tree.
+ * The di_node_t argument should be a node with smhba-supported prop set
+ * to true.
+ * Without iport support, the devinfo node will represent one port hba.
+ * This routine assumes the locks have been taken.
+ */
+HBA_STATUS
+devtree_get_one_hba(di_node_t hbaNode)
+{
+	const char		ROUTINE[] = "devtree_get_one_hba";
+	char			*propdata = NULL;
+	int			*propIntData = NULL;
+	struct sun_sas_hba	*new_hba, *hba_ptr;
+	char			*hbaDevpath, *hba_driver;
+	int			protocol = 0;
+	di_node_t		portNode;
+	int			hba_instance = -1;
+
+	hba_instance = di_instance(hbaNode);
+	if (hba_instance == -1) {
+		log(LOG_DEBUG, ROUTINE,
+		    "portNode has instance of -1");
+		return (DI_WALK_CONTINUE);
+	}
+
+	if ((hbaDevpath = di_devfs_path(hbaNode)) == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Unable to get "
+		    "device path from hbaNode");
+		return (HBA_STATUS_ERROR);
+	}
+
+	/* check to see if this is a repeat HBA */
+	if (global_hba_head) {
+		for (hba_ptr = global_hba_head;
+		    hba_ptr != NULL;
+		    hba_ptr = hba_ptr->next) {
+			if ((strncmp(hba_ptr->device_path, hbaDevpath,
+			    strlen(hbaDevpath))) == 0) {
+				if (refresh_hba(hbaNode, hba_ptr) !=
+				    HBA_STATUS_OK) {
+					log(LOG_DEBUG, ROUTINE, "Refresh failed"
+					    " on hbaNode %s", hbaDevpath);
+				}
+				di_devfs_path_free(hbaDevpath);
+				return (HBA_STATUS_OK);
+			}
+		}
+	}
+
+	/* this is a new hba */
+	if ((new_hba = (struct sun_sas_hba *)calloc(1,
+	    sizeof (struct sun_sas_hba))) == NULL) {
+		OUT_OF_MEMORY(ROUTINE);
+		di_devfs_path_free(hbaDevpath);
+		return (HBA_STATUS_ERROR);
+	}
+
+	(void) strlcpy(new_hba->device_path, hbaDevpath,
+	    sizeof (new_hba->device_path));
+	di_devfs_path_free(hbaDevpath);
+
+	(void) snprintf(new_hba->adapter_attributes.HBASymbolicName,
+	    sizeof (new_hba->adapter_attributes.HBASymbolicName),
+	    "%s%s", DEVICES_DIR, new_hba->device_path);
+
+	/* Manufacturer */
+	if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
+	    "Manufacturer", (char **)&propdata)) == -1) {
+		(void) strlcpy(new_hba->adapter_attributes.Manufacturer,
+		    SUN_MICROSYSTEMS,
+		    sizeof (new_hba->adapter_attributes.Manufacturer));
+	} else {
+		(void) strlcpy(new_hba->adapter_attributes.Manufacturer,
+		    propdata,
+		    sizeof (new_hba->adapter_attributes.Manufacturer));
+	}
+
+	/* SerialNumber */
+	if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
+	    "SerialNumber", (char **)&propdata)) == -1) {
+		new_hba->adapter_attributes.SerialNumber[0] = '\0';
+	} else {
+		(void) strlcpy(new_hba->adapter_attributes.SerialNumber,
+		    propdata,
+		    sizeof (new_hba->adapter_attributes.SerialNumber));
+	}
+
+	/* Model */
+	if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
+	    "ModelName", (char **)&propdata)) == -1) {
+		new_hba->adapter_attributes.Model[0] = '\0';
+	} else {
+		(void) strlcpy(new_hba->adapter_attributes.Model,
+		    propdata,
+		    sizeof (new_hba->adapter_attributes.Model));
+	}
+
+	/* FirmwareVersion */
+	if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
+	    "firmware-version", (char **)&propdata)) == -1) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Property \"%s\" not found for device \"%s\"",
+		    "firmware-version", new_hba->device_path);
+	} else {
+		(void) strlcpy(new_hba->adapter_attributes.FirmwareVersion,
+		    propdata,
+		    sizeof (new_hba->adapter_attributes.FirmwareVersion));
+	}
+
+	/* HardwareVersion */
+	if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
+	    "hardware-version", (char **)&propdata)) == -1) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Property \"%s\" not found for device \"%s\"",
+		    "hardware-version", new_hba->device_path);
+	} else {
+		(void) strlcpy(new_hba->adapter_attributes.HardwareVersion,
+		    propdata,
+		    sizeof (new_hba->adapter_attributes.HardwareVersion));
+	}
+
+	/* DriverVersion */
+	if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
+	    "driver-version", (char **)&propdata)) == -1) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Property \"%s\" not found for device \"%s\"",
+		    "driver-version", new_hba->device_path);
+	} else {
+		(void) strlcpy(new_hba->adapter_attributes.DriverVersion,
+		    propdata,
+		    sizeof (new_hba->adapter_attributes.DriverVersion));
+	}
+
+	if ((di_prop_lookup_ints(DDI_DEV_T_ANY, hbaNode,
+	    "supported-protocol", &propIntData)) == -1) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to get supported-protocol from HBA node.");
+	} else {
+		protocol = *propIntData;
+	}
+
+	/* We don't use these */
+	new_hba->adapter_attributes.OptionROMVersion[0] = '\0';
+	new_hba->adapter_attributes.RedundantOptionROMVersion[0] = '\0';
+	new_hba->adapter_attributes.RedundantFirmwareVersion[0] = '\0';
+	new_hba->adapter_attributes.VendorSpecificID = 0;
+
+	if ((hba_driver = di_driver_name(hbaNode)) != NULL) {
+		(void) strlcpy(new_hba->adapter_attributes.DriverName,
+		    hba_driver,
+		    sizeof (new_hba->adapter_attributes.DriverName));
+	} else {
+		log(LOG_DEBUG, ROUTINE,
+		    "HBA driver name not found for device \"%s\"",
+		    new_hba->device_path);
+	}
+
+	/*
+	 * Name the adapter: like SUNW-pmcs-1
+	 * Using di_instance number as the suffix for the name for persistent
+	 * among rebooting.
+	 */
+	(void) snprintf(new_hba->handle_name, HANDLE_NAME_LENGTH, "%s-%s-%d",
+	    "SUNW", new_hba->adapter_attributes.DriverName, hba_instance);
+
+	if ((portNode = di_child_node(hbaNode)) == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "HBA driver doesn't have iport child. \"%s\"",
+		    new_hba->device_path);
+		/* continue on with an hba without any port. */
+		new_hba->index = hba_count++;
+
+		/*
+		 * add newly created handle into global_hba_head list
+		 */
+		if (global_hba_head != NULL) {
+			/*
+			 * Make sure to move the open_handles list to back to
+			 * the head if it's there (for refresh scenario)
+			 */
+			if (global_hba_head->open_handles) {
+				new_hba->open_handles =
+				    global_hba_head->open_handles;
+				global_hba_head->open_handles = NULL;
+			}
+			/* Now bump the new one to the head of the list */
+			new_hba->next = global_hba_head;
+			global_hba_head = new_hba;
+		} else {
+			global_hba_head = new_hba;
+		}
+		return (HBA_STATUS_OK);
+	}
+
+	while (portNode != DI_NODE_NIL) {
+		if (add_hba_port_info(portNode, new_hba, protocol)
+		    == HBA_STATUS_ERROR) {
+			S_FREE(new_hba->first_port);
+			S_FREE(new_hba);
+			return (HBA_STATUS_ERROR);
+		}
+		portNode = di_sibling_node(portNode);
+	}
+
+	new_hba->index = hba_count++;
+
+	/*
+	 * add newly created handle into global_hba_head list
+	 */
+	if (global_hba_head != NULL) {
+		/*
+		 * Make sure to move the open_handles list to back to the
+		 * head if it's there (for refresh scenario)
+		 */
+		if (global_hba_head->open_handles) {
+			new_hba->open_handles = global_hba_head->open_handles;
+			global_hba_head->open_handles = NULL;
+		}
+		/* Now bump the new one to the head of the list */
+		new_hba->next = global_hba_head;
+		global_hba_head = new_hba;
+	} else {
+		global_hba_head = new_hba;
+	}
+
+	return (HBA_STATUS_OK);
+}
+
+/*
+ * Discover information for all HBAs found on the system.
+ * The di_node_t argument should be the root of the device tree.
+ * This routine assumes the locks have been taken
+ */
+static int
+lookup_smhba_sas_hba(di_node_t node, void *arg)
+{
+	const char	ROUTINE[] = "lookup_smhba_sas_hba";
+	int 		*propData, rval;
+	walkarg_t 	*wa = (walkarg_t *)arg;
+
+	/* Skip stub(instance -1) nodes */
+	if (IS_STUB_NODE(node)) {
+		log(LOG_DEBUG, ROUTINE, "Walk continue");
+		return (DI_WALK_CONTINUE);
+	}
+
+	rval = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+	    "sm-hba-supported", &propData);
+	if (rval >= 0) {
+		if (*propData) {
+			/* add the hba to the hba list */
+			if (devtree_get_one_hba(node) != HBA_STATUS_OK) {
+				*(wa->flag) = B_TRUE;
+			}
+			/* Found a node. No need to walk the child. */
+			log(LOG_DEBUG, ROUTINE, "Walk prunechild");
+			return (DI_WALK_PRUNECHILD);
+		}
+	}
+
+	return (DI_WALK_CONTINUE);
+}
+
+/*
+ * Discover information for all HBAs found on the system.
+ * The di_node_t argument should be the root of the device tree.
+ * This routine assumes the locks have been taken
+ */
+HBA_STATUS
+devtree_get_all_hbas(di_node_t root)
+{
+	const char	ROUTINE[] = "devtree_get_all_hbas";
+	int		rv, ret = HBA_STATUS_ERROR;
+	walkarg_t	wa;
+
+	wa.devpath = NULL;
+	if ((wa.flag = (boolean_t *)calloc(1,
+	    sizeof (boolean_t))) == NULL) {
+		OUT_OF_MEMORY(ROUTINE);
+		return (HBA_STATUS_ERROR);
+	}
+	*wa.flag = B_FALSE;
+	rv = di_walk_node(root, DI_WALK_SIBFIRST, &wa, lookup_smhba_sas_hba);
+
+	if (rv == 0) {
+		/*
+		 * Now determine what status code to return, taking
+		 * partial failure scenarios into consideration.
+		 *
+		 * If we have at least one working HBA, then we return an
+		 * OK status.  If we have no good HBAs, but at least one
+		 * failed HBA, we return an ERROR status.  If we have
+		 * no HBAs and no failures, we return OK.
+		 */
+		if (global_hba_head) {
+			/*
+			 * We've got at least one HBA and possibly some
+			 * failures.
+			 */
+			ret = HBA_STATUS_OK;
+		} else if (*(wa.flag)) {
+			/* We have no HBAs but have failures */
+			ret = HBA_STATUS_ERROR;
+		} else {
+			/* We have no HBAs and no failures */
+			ret = HBA_STATUS_OK;
+		}
+	}
+
+
+	S_FREE(wa.flag);
+
+	if (ret == HBA_STATUS_OK)
+		(void) registerSysevent();
+
+	return (ret);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/devtree_phy_disco.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,202 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sun_sas.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libdevinfo.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+/*
+ * structure for di_devlink_walk
+ */
+typedef struct walk_devlink {
+	char *path;
+	size_t len;
+	char **linkpp;
+} walk_devlink_t;
+
+/*
+ * Free the phy allocation.
+ */
+static void
+free_phy_info(struct sun_sas_port *port_ptr)
+{
+	struct phy_info *phy_ptr, *last_phy;
+
+	phy_ptr = port_ptr->first_phy;
+	while (phy_ptr != NULL) {
+		last_phy = phy_ptr;
+		phy_ptr = phy_ptr->next;
+		free(last_phy);
+	}
+
+	port_ptr->first_phy = NULL;
+
+}
+
+/*
+ * callback funtion for di_devlink_walk
+ * Find matching /dev link for the given path argument.
+ * devlink element and callback function argument.
+ * The input path is expected to not have "/devices".
+ */
+extern HBA_STATUS
+get_phy_info(di_node_t node, struct sun_sas_port *port_ptr)
+{
+	const char ROUTINE[] = "get_phy_info";
+	char *portDevpath = NULL;
+	uchar_t	*propByteData = NULL;
+	struct phy_info *phy_ptr;
+	uint_t nvcount;
+	int rval, count, i;
+	nvlist_t *nvl, **phyInfoVal;
+	uint8_t phyId;
+	int8_t negoRate, prgmMinRate, prgmMaxRate, hwMinRate, hwMaxRate;
+
+	/*
+	 * When path is specified, it doesn't have minor
+	 * name. Therefore, the ../.. prefixes needs to be stripped.
+	 */
+	if ((portDevpath = di_devfs_path(node)) == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		"Unable to get device path from portNode.");
+	}
+
+	count = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, "phy-info",
+	    (uchar_t **)&propByteData);
+	if (count < 0) {
+		if (portDevpath) {
+			log(LOG_DEBUG, ROUTINE,
+			    "Property phy-info not found on port %s%s",
+			    DEVICES_DIR, portDevpath);
+			di_devfs_path_free(portDevpath);
+		} else {
+			log(LOG_DEBUG, ROUTINE, "Property phy-info not found.");
+		}
+		return (HBA_STATUS_ERROR);
+	} else {
+		rval = nvlist_unpack((char *)propByteData, count, &nvl, 0);
+		if (rval != 0) {
+			if (portDevpath) {
+				log(LOG_DEBUG, ROUTINE,
+				    "nvlist_unpack failed on port %s%s",
+				    DEVICES_DIR, portDevpath);
+				di_devfs_path_free(portDevpath);
+			} else {
+				log(LOG_DEBUG, ROUTINE,
+				    "nvlist_unpack failed.");
+			}
+			return (HBA_STATUS_ERROR);
+		} else {
+			rval = nvlist_lookup_nvlist_array(nvl, "phy-info-nvl",
+			    &phyInfoVal, &nvcount);
+			if (rval != 0) {
+				if (portDevpath) {
+					log(LOG_DEBUG, ROUTINE,
+					    "nvlist array phy-info-nvl not\
+					    found on port %s%s", DEVICES_DIR,
+					    portDevpath);
+					di_devfs_path_free(portDevpath);
+				} else {
+					log(LOG_DEBUG, ROUTINE,
+					    "nvlist array phy-info-nvl not\
+					    found");
+				}
+				nvlist_free(nvl);
+				return (HBA_STATUS_ERROR);
+			} else {
+		/* indentation moved */
+		for (i = 0; i < nvcount; i++) {
+			if (nvlist_lookup_uint8(phyInfoVal[i],
+			    "PhyIdentifier", &phyId) != 0) {
+				/* Indicate a failure : no better way to set */
+				phyId = 0xff;
+			}
+			if (nvlist_lookup_int8(phyInfoVal[i],
+			    "NegotiatedLinkRate", &negoRate) != 0) {
+				negoRate = HBA_SASSTATE_UNKNOWN;
+			}
+			if (nvlist_lookup_int8(phyInfoVal[i],
+			    "ProgrammedMinLinkRate", &prgmMinRate) != 0) {
+				prgmMinRate = HBA_SASSTATE_UNKNOWN;
+			}
+			if (nvlist_lookup_int8(phyInfoVal[i],
+			    "ProgrammedMaxLinkRate", &prgmMaxRate) != 0) {
+				prgmMaxRate = HBA_SASSTATE_UNKNOWN;
+			}
+			if (nvlist_lookup_int8(phyInfoVal[i],
+			    "HardwareMinLinkRate", &hwMinRate) != 0) {
+				hwMinRate = HBA_SASSTATE_UNKNOWN;
+			}
+			if (nvlist_lookup_int8(phyInfoVal[i],
+			    "HardwareMaxLinkRate", &hwMaxRate) != 0) {
+				hwMaxRate = HBA_SASSTATE_UNKNOWN;
+			}
+
+			if ((phy_ptr = (struct phy_info *)calloc(1,
+			    sizeof (struct phy_info))) == NULL)  {
+				OUT_OF_MEMORY(ROUTINE);
+				if (portDevpath)
+					di_devfs_path_free(portDevpath);
+				free_phy_info(port_ptr);
+				nvlist_free(nvl);
+				return (HBA_STATUS_ERROR);
+			}
+			phy_ptr->phy.PhyIdentifier = phyId;
+			phy_ptr->phy.NegotiatedLinkRate = negoRate;
+			phy_ptr->phy.ProgrammedMinLinkRate = prgmMinRate;
+			phy_ptr->phy.ProgrammedMaxLinkRate = prgmMaxRate;
+			phy_ptr->phy.HardwareMinLinkRate = hwMinRate;
+			phy_ptr->phy.HardwareMaxLinkRate = hwMaxRate;
+			/*
+			 * we will fill domain port later.
+			 */
+			(void) memset(phy_ptr->phy.domainPortWWN.wwn, 0, 8);
+			phy_ptr->index = i;
+			if (port_ptr->first_phy == NULL) {
+				port_ptr->first_phy = phy_ptr;
+			} else {
+				phy_ptr->next = port_ptr->first_phy;
+				port_ptr->first_phy = phy_ptr;
+			}
+
+		}
+		nvlist_free(nvl);
+		/* end of indentation move */
+			}
+		}
+	}
+
+	if (portDevpath) {
+		di_devfs_path_free(portDevpath);
+	}
+
+	return (HBA_STATUS_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/event.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,268 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include	<sun_sas.h>
+#include	<libsysevent.h>
+#include	<sys/types.h>
+#include	<netinet/in.h>
+#include	<inttypes.h>
+#include	<ctype.h>
+
+
+/* Remove these 5 when the header containing the event names aver available. */
+/*
+ * Event definitions
+ */
+/* Event Class */
+#define	EC_HBA		    "EC_hba"
+#define	EC_DR		    "EC_dr"
+/* Event Sub-Class */
+#define	ESC_SAS_HBA_PORT_BROADCAST  "ESC_sas_hba_port_broadcast"
+#define	ESC_SAS_PHY_EVENT	"ESC_sas_phy_event"
+#define	ESC_DR_TARGET_STATE_CHANGE  "ESC_dr_target_state_change"
+
+/* Broadcast Event Types */
+#define	SAS_PORT_BROADCAST_CHANGE   "port_broadcast_change"
+#define	SAS_PORT_BROADCAST_SES	    "port_broadcast_ses"
+#define	SAS_PORT_BROADCAST_D24_0    "port_broadcast_d24_0"
+#define	SAS_PORT_BROADCAST_D27_4    "port_broadcast_d27_4"
+#define	SAS_PORT_BROADCAST_D01_4    "port_broadcast_d01_4"
+#define	SAS_PORT_BROADCAST_D04_7    "port_broadcast_d04_7"
+#define	SAS_PORT_BROADCAST_D16_7    "port_broadcast_d16_7"
+#define	SAS_PORT_BROADCAST_D29_7    "port_broadcast_d29_7"
+
+/* Phy Event Types */
+#define	SAS_PHY_ONLINE		"port_online"
+#define	SAS_PHY_OFFLINE		"port_offline"
+#define	SAS_PHY_REMOVE		"port_remove"
+
+/* Event payload */
+#define	SAS_DRV_INST		"driver_instance"
+#define	SAS_PORT_ADDR		"port_address"
+#define	SAS_DEVFS_PATH		"devfs_path"
+#define	SAS_EVENT_TYPE		"event_type"
+
+#define	HBA_PORT_MATCH		1
+#define	TARGET_PORT_MATCH	2
+#define	PHY_MATCH		3
+
+#define	REMOVED		1
+#define	ONLINE		2
+#define	OFFLINE		3
+
+sysevent_handle_t *gSysEventHandle = NULL;
+
+/* Calls the client callback function, if one is registered */
+static HBA_STATUS
+updateMatchingPhy(HBA_WWN portAddr, uint8_t phyId, int update, uint8_t linkRate)
+{
+	const char  ROUTINE[] = "updateMatchingPhy";
+	struct sun_sas_hba	*hba_ptr;
+	struct sun_sas_port	*hba_port_ptr;
+	struct phy_info		*phy_ptr;
+
+	log(LOG_DEBUG, ROUTINE, "- phy matching");
+	/* grab write lock */
+	lock(&all_hbas_lock);
+	/* loop through HBAs */
+	for (hba_ptr = global_hba_head; hba_ptr != NULL;
+	    hba_ptr = hba_ptr->next) {
+		/* loop through HBA ports */
+		for (hba_port_ptr = hba_ptr->first_port;
+		    hba_port_ptr != NULL;
+		    hba_port_ptr = hba_port_ptr->next) {
+			if (wwnConversion(hba_port_ptr->
+			    port_attributes.PortSpecificAttribute.
+			    SASPort->LocalSASAddress.wwn) ==
+			    wwnConversion(portAddr.wwn)) {
+				/* loop through phys */
+				for (phy_ptr = hba_port_ptr->first_phy;
+				    phy_ptr != NULL; phy_ptr =
+				    phy_ptr->next) {
+					if (phy_ptr->phy.PhyIdentifier ==
+					    phyId) {
+						if (update == REMOVED) {
+							phy_ptr->invalid =
+							    B_TRUE;
+						} else if (update == OFFLINE) {
+							phy_ptr->phy.
+							    NegotiatedLinkRate
+							    = 0;
+						} else { /* online */
+							phy_ptr->phy.
+							    NegotiatedLinkRate
+							    = linkRate;
+						}
+						unlock(&all_hbas_lock);
+						return (HBA_STATUS_OK);
+					}
+				} /* for phys */
+			} /* wwn mismatch. continue */
+		} /* for HBA ports */
+	} /* for HBAs */
+
+	unlock(&all_hbas_lock);
+	return (HBA_STATUS_ERROR);
+}
+
+/* Event handler called by system */
+static void
+syseventHandler(sysevent_t *ev)
+{
+
+	const char	ROUTINE[] = "syseventHandler";
+	nvlist_t 	*attrList = NULL;
+	char		*eventStr, *portAddrStr, *charptr;
+	int		update;
+	uint64_t 	addr;
+	uint8_t		phyId, linkRate;
+	HBA_WWN		portAddr;
+
+	/* Is the event one of ours? */
+	if (strncmp(EC_HBA, sysevent_get_class_name(ev), strlen(EC_HBA)) == 0) {
+		/* handle phy events */
+		if (strncmp(ESC_SAS_PHY_EVENT, sysevent_get_subclass_name(ev),
+		    strlen(ESC_SAS_PHY_EVENT)) == 0) {
+			if (sysevent_get_attr_list(ev, &attrList) != 0) {
+				log(LOG_DEBUG, ROUTINE,
+				    "Failed to get event attributes on %s/%s",
+				    EC_HBA, ESC_SAS_PHY_EVENT);
+				return;
+			} else {
+				if (nvlist_lookup_string(attrList,
+				    "event_type", &eventStr) != 0) {
+					log(LOG_DEBUG, ROUTINE,
+					    "Event type not found");
+					return;
+				} else {
+					if (strncmp(eventStr, "phy_online",
+					    sizeof (eventStr)) == 0) {
+						update = ONLINE;
+						if (nvlist_lookup_uint8(
+						    attrList, "link_rate",
+						    &linkRate) != 0) {
+							log(LOG_DEBUG, ROUTINE,
+							    "Link Rate not \
+							    found");
+							return;
+						}
+					} else if (strncmp(eventStr,
+					    "phy_offline",
+					    sizeof (eventStr)) == 0) {
+						update = OFFLINE;
+					} else if (strncmp(eventStr,
+					    "phy_remove",
+					    sizeof (eventStr)) == 0) {
+						update = REMOVED;
+					} else {
+						log(LOG_DEBUG, ROUTINE,
+						    "Invalid event type");
+						return;
+					}
+				}
+				if (nvlist_lookup_string(attrList,
+				    "port_address", &portAddrStr) != 0) {
+					log(LOG_DEBUG, ROUTINE,
+					    "Port SAS address not found");
+					return;
+				} else {
+					for (charptr = portAddrStr;
+					    charptr != NULL; charptr++) {
+						if (isxdigit(*charptr)) {
+							break;
+						}
+					}
+					addr = htonll(strtoll(charptr,
+					    NULL, 16));
+					(void) memcpy(portAddr.wwn, &addr, 8);
+				}
+				if (nvlist_lookup_uint8(attrList,
+				    "PhyIdentifier", &phyId) != 0) {
+					log(LOG_DEBUG, ROUTINE,
+					    "Port SAS address not found");
+					return;
+				}
+			}
+			if (updateMatchingPhy(portAddr, phyId, update,
+			    linkRate) != HBA_STATUS_OK) {
+				log(LOG_DEBUG, ROUTINE,
+				    "updating phy for the events failed.");
+			}
+		}
+	} else if (strncmp(EC_DR,  sysevent_get_class_name(ev), 2) == 0) {
+		/* handle DR events */
+		log(LOG_DEBUG, ROUTINE,
+		    "handle EC_dr events.");
+	} else {
+		log(LOG_DEBUG, ROUTINE,
+		    "Found Unregistered event. - exit");
+		return;
+	}
+
+	log(LOG_DEBUG, ROUTINE, "- exit");
+}
+
+/* Registers events to the sysevent framework */
+HBA_STATUS
+registerSysevent() {
+
+	const char ROUTINE[] = "registerSysevent";
+	const char *hba_subclass_list[] = {
+		ESC_SAS_PHY_EVENT
+	};
+	const char *dr_subclass_list[] = {
+		ESC_DR_TARGET_STATE_CHANGE
+	};
+
+	gSysEventHandle = sysevent_bind_handle(syseventHandler);
+	if (gSysEventHandle == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "- sysevent_bind_handle() failed");
+		log(LOG_DEBUG, ROUTINE, "- error exit");
+		return (HBA_STATUS_ERROR);
+	}
+
+	if (sysevent_subscribe_event(gSysEventHandle, EC_HBA,
+	    hba_subclass_list, 1) != 0) {
+		log(LOG_DEBUG, ROUTINE,
+		    "- sysevent_subscribe_event() failed for EC_HBA subclass");
+		log(LOG_DEBUG, ROUTINE, "- error exit");
+		sysevent_unbind_handle(gSysEventHandle);
+		return (HBA_STATUS_ERROR);
+	}
+
+	if (sysevent_subscribe_event(gSysEventHandle, EC_DR,
+	    dr_subclass_list, 1) != 0) {
+		log(LOG_DEBUG, ROUTINE,
+		    "- sysevent_subscribe_event() failed for DR subclass");
+		log(LOG_DEBUG, ROUTINE, "- error exit");
+		sysevent_unbind_handle(gSysEventHandle);
+		return (HBA_STATUS_ERROR);
+	}
+
+	log(LOG_DEBUG, ROUTINE, "- exit");
+
+	return (HBA_STATUS_ERROR);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/log.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,68 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/varargs.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sun_sas.h>
+
+#define	MAX_LOG_LEN 2048
+
+void
+log(
+	int level,
+	const char *routine,
+	char *msg,
+	...
+)
+{
+	char header[MAX_LOG_LEN+1];
+	char message[MAX_LOG_LEN+1];
+	int oldErrno = 0;
+	va_list ap;
+
+	oldErrno = errno;
+
+	(void) memset(&header,  0, MAX_LOG_LEN+1);
+	(void) memset(&message, 0, MAX_LOG_LEN+1);
+
+	va_start(ap, msg);
+	(void) snprintf(header, MAX_LOG_LEN, "%s: %s: %s",
+	    "SM-HBA Sun SAS VSL", routine, msg);
+
+	/* LINTED E_SEC_PRINTF_VAR_FMT */
+	(void) vsnprintf(message, MAX_LOG_LEN, header, ap);
+
+	/* LINTED E_SEC_PRINTF_VAR_FMT */
+	syslog(level, message);
+
+	va_end(ap);
+
+	errno = oldErrno;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/mapfile-vers	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,77 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING:  STOP NOW.  DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+#	usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+
+SUNWprivate {
+    global:
+	SMHBA_RegisterLibrary;
+	Sun_sasGetNumberOfAdapters;
+	Sun_sasLoadLibrary;
+	Sun_sasFreeLibrary;
+	Sun_sasRefreshInformation;
+	Sun_sasRefreshAdapterConfiguration;
+	Sun_sasCloseAdapter;
+	Sun_sasFreeLibrary;
+	Sun_sasGetAdapterAttributes;
+	Sun_sasGetAdapterName;
+	Sun_sasGetAdapterPortAttributes;
+	Sun_sasGetDiscoveredPortAttributes;
+	Sun_sasGetLUNStatistics;
+	Sun_sasGetNumberOfAdapters;
+	Sun_sasGetNumberOfPorts;
+	Sun_sasSetPersistentBinding;
+	Sun_sasGetPersistentBinding;
+	Sun_sasGetPhyStatistics;
+	Sun_sasGetPortAttributesByWWN;
+	Sun_sasGetPortType;
+	Sun_sasGetProtocolStatistics;
+	Sun_sasGetSASPhyAttributes;
+	Sun_sasGetTargetMapping;
+	Sun_sasGetVendorLibraryAttributes;
+	Sun_sasGetVersion;
+	Sun_sasScsiReadCapacity;
+	Sun_sasScsiReportLUNs;
+	Sun_sasScsiInquiry;
+	Sun_sasLoadLibrary;
+	Sun_sasSendSMPPassThru;
+	Sun_sasOpenAdapter;
+	FreeHBA;
+    local:
+	*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/sun_sas.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,431 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#include <sys/byteorder.h>
+#include <sun_sas.h>
+
+/*
+ * creates a handle each time Sun_sas_OpenAdapter() is called.
+ *
+ * a open_handle_struct was created to keep track of which handles are currently
+ * open.  This prevents a user from using an old handle that corresponds to
+ * an hba that has already been closed.
+ */
+HBA_HANDLE
+CreateHandle(int adapterIndex)
+{
+	const char		ROUTINE[] = "CreateHandle";
+	struct open_handle	*new_open_handle;
+	HBA_UINT32		new_handle_index;
+	HBA_UINT8		max_handle_wrap = 0;
+
+	if (global_hba_head == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "an error as occurred.  global_hba_head is "
+		    "NULL.  Library may not be loaded yet.");
+		return (HANDLE_ERROR);
+	}
+
+	while (RetrieveIndex(open_handle_index) != -1)  {
+		open_handle_index = open_handle_index + 1;
+		if (open_handle_index == 0) {
+			/*
+			 * If open_handle_index wraps back to zero again,
+			 * that means all handles are currently in use.
+			 * Spec only allows for 16 bits of handles
+			 */
+			if (max_handle_wrap == 1) {
+				log(LOG_DEBUG, ROUTINE,
+				    "Max number of handles reached.");
+				return (HANDLE_ERROR);
+			}
+			open_handle_index = 1;
+			max_handle_wrap = 1;
+		}
+	}
+
+	new_handle_index = open_handle_index;
+	if ((new_open_handle = (struct open_handle *)calloc(1,
+	    sizeof (struct open_handle))) == NULL) {
+		OUT_OF_MEMORY(ROUTINE);
+		return (HANDLE_ERROR);
+	}
+	(void) memset(new_open_handle, 0, sizeof (struct open_handle));
+	new_open_handle->adapterIndex = adapterIndex;
+	new_open_handle->handle = new_handle_index;
+
+	lock(&open_handles_lock);
+
+	/* add new open handle struct to the open_handles list */
+	if (global_hba_head->open_handles == NULL) {
+		global_hba_head->open_handles = new_open_handle;
+	} else {
+		new_open_handle->next = global_hba_head->open_handles;
+		global_hba_head->open_handles = new_open_handle;
+	}
+
+	unlock(&open_handles_lock);
+	open_handle_index = open_handle_index + 1;
+	if (open_handle_index == 0) {
+		open_handle_index = 1;
+	}
+
+	return (new_handle_index);
+}
+
+/*
+ * given a handle, returns the adapterIndex number.
+ *
+ * This functions checkes to see if the given handle corresponds to an open
+ * HBA.  If it does, the adapterIndex is returned.
+ */
+int
+RetrieveIndex(HBA_HANDLE handle)
+{
+
+	struct open_handle	*open_handle_ptr;
+
+	lock(&open_handles_lock);
+
+	open_handle_ptr = RetrieveOpenHandle(handle);
+
+	unlock(&open_handles_lock);
+	if (open_handle_ptr == NULL) {
+		return (-1);
+	}
+
+	return (open_handle_ptr->adapterIndex);
+}
+/*
+ * Given a handle, returns the open_handle structure
+ * The routine assumes that the open_handles_lock has already
+ * been taken.
+ */
+struct open_handle *
+RetrieveOpenHandle(HBA_HANDLE handle)
+{
+
+	const char		ROUTINE[] = "RetrieveOpenHandle";
+	struct open_handle	*open_handle_ptr = NULL;
+
+	if (global_hba_head == NULL) {
+		log(LOG_DEBUG, ROUTINE, "No adpater is found.");
+		return (NULL);
+	}
+
+	for (open_handle_ptr = global_hba_head->open_handles;
+	    open_handle_ptr != NULL;
+	    open_handle_ptr = open_handle_ptr->next) {
+		if (open_handle_ptr->handle == handle) {
+			break;
+		}
+	}
+
+	return (open_handle_ptr);
+}
+
+/*
+ * Given an adapterIndex, this functions returns a pointer to the handle
+ * structure.  This handle structure holds the hba's information
+ * Caller must take all_hbas_lock first.
+ */
+struct sun_sas_hba *
+RetrieveHandle(int index)
+{
+	struct sun_sas_hba 	*hba_ptr = NULL;
+
+	for (hba_ptr = global_hba_head; hba_ptr != NULL;
+	    hba_ptr = hba_ptr->next) {
+		if (hba_ptr->index == index)
+			break;
+	}
+
+	return (hba_ptr);
+}
+
+/*
+ * Given an adapterIndex, this functions returns a pointer to the handle
+ * structure and extracts it from the global list.
+ *
+ * all_hbas_lock must be taken already.
+ */
+struct sun_sas_hba *
+ExtractHandle(int index)
+{
+	struct sun_sas_hba 	*last = NULL;
+	struct sun_sas_hba 	*hba_ptr = NULL;
+
+	for (hba_ptr = global_hba_head;
+	    hba_ptr != NULL;
+	    last = hba_ptr, hba_ptr = hba_ptr->next) {
+		if (hba_ptr->index == index) {
+			if (last) {
+				last->next = hba_ptr->next;
+			} else {
+				/* Hmm, must be the head of the list. */
+				global_hba_head = hba_ptr->next;
+			}
+			hba_ptr->next = NULL; /* Zap it to be safe */
+			break;
+		}
+	}
+
+	return (hba_ptr);
+}
+
+
+/*
+ * Given an handle, this functions returns a pointer to the handle structure
+ * for that hba
+ *
+ * Caller must take all_hbas_lock first.
+ */
+struct sun_sas_hba *
+Retrieve_Sun_sasHandle(HBA_HANDLE handle)
+{
+	const char		    ROUTINE[] = "Retrieve_Sun_sasHandle";
+	struct	sun_sas_hba	    *handle_struct = NULL;
+	int			    index;
+
+	/* Retrieve fp device path from handle */
+	index = RetrieveIndex(handle);
+	if (index == -1) {
+		log(LOG_DEBUG, ROUTINE,
+		    "handle could not be found.");
+		return (handle_struct);
+	}
+	lock(&open_handles_lock);
+	handle_struct = RetrieveHandle(index);
+	if (handle_struct == NULL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "could not find index in the handle list.");
+		unlock(&open_handles_lock);
+		return (handle_struct);
+	}
+	unlock(&open_handles_lock);
+
+	return (handle_struct);
+}
+
+/*
+ * Take a mutex lock.  The routine will try, and if it fails,
+ * it will loop for a while and retry.  If it fails many times,
+ * it will start writing to the log file.
+ */
+void
+lock(mutex_t *mp)
+{
+	int status;
+	int loop = 0;
+	const char ROUTINE[] = "lock";
+
+	do {
+		loop++;
+		status = mutex_trylock(mp);
+		switch (status) {
+			case 0:
+				break;
+			case EFAULT:
+				log(LOG_DEBUG, ROUTINE,
+				    "Lock failed: fault 0x%x", mp);
+				break;
+			case EINVAL:
+				log(LOG_DEBUG, ROUTINE,
+				    "Lock failed: invalid 0x%x", mp);
+				break;
+			case EBUSY:
+				if (loop > DEADLOCK_WARNING) {
+					log(LOG_DEBUG, ROUTINE,
+					    "Lock busy, possible deadlock:0x%x",
+					    mp);
+				}
+				break;
+			case EOWNERDEAD:
+				log(LOG_DEBUG, ROUTINE,
+				    "Lock failed: owner dead 0x%x",
+				    mp);
+				break;
+			case ELOCKUNMAPPED:
+				log(LOG_DEBUG, ROUTINE,
+				    "Lock failed: unmapped 0x%x",
+				    mp);
+				break;
+			case ENOTRECOVERABLE:
+				log(LOG_DEBUG, ROUTINE,
+				    "Lock failed: not recoverable 0x%x", mp);
+			default:
+				if (loop > DEADLOCK_WARNING) {
+					log(LOG_DEBUG, ROUTINE,
+					    "Lock failed: %s 0x%x",
+					    strerror(status), mp);
+					break;
+				}
+		}
+
+		if (status) {
+			(void) sleep(LOCK_SLEEP);
+		}
+
+	} while (status);
+}
+
+/*
+ * Unlock a mutex lock.
+ */
+void
+unlock(mutex_t *mp)
+{
+	(void) mutex_unlock(mp);
+}
+
+
+/*
+ * Get the Port WWN of the first adapter port.  This routine
+ * is used by the old V1 interfaces so that they can call
+ * the new V2 interfaces and exhibit the same behavior.
+ * In the event of error the WWN will be zero.
+ *
+ * This function will transition to PAA state but it will not
+ * verfiy whether data is stale or not
+ */
+HBA_WWN
+getFirstAdapterPortWWN(HBA_HANDLE handle)
+{
+	const char	ROUTINE[] = "getFirstAdapterPortWWN";
+	HBA_WWN			pwwn = {0, 0, 0, 0, 0, 0, 0, 0};
+	struct sun_sas_hba	*hba_ptr = NULL;
+	int			index = 0;
+	HBA_STATUS		status;
+
+	lock(&all_hbas_lock);
+	index = RetrieveIndex(handle);
+	lock(&open_handles_lock);
+	hba_ptr = RetrieveHandle(index);
+	if (hba_ptr == NULL) {
+		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx", handle);
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (pwwn); /* zero WWN */
+	}
+
+	/* Check for stale data */
+	status = verifyAdapter(hba_ptr);
+	if (status != HBA_STATUS_OK) {
+		log(LOG_DEBUG, ROUTINE, "Verify adapter failed");
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (pwwn);
+	}
+
+	if (hba_ptr->first_port == NULL) {
+		/* This is probably an internal failure of the library */
+		if (hba_ptr->device_path) {
+			log(LOG_DEBUG, ROUTINE,
+			    "Internal failure:  Adapter %s contains no "
+			    "port data", hba_ptr->device_path);
+		} else {
+			log(LOG_DEBUG, ROUTINE,
+			    "Internal failure:  Adapter at index %d contains "
+			    " no support data", hba_ptr->index);
+		}
+		unlock(&open_handles_lock);
+		unlock(&all_hbas_lock);
+		return (pwwn); /* zero WWN */
+	}
+	/* Set the WWN now and return it */
+	pwwn = hba_ptr->first_port->port_attributes.PortSpecificAttribute.\
+	    SASPort->LocalSASAddress;
+	unlock(&open_handles_lock);
+	unlock(&all_hbas_lock);
+
+	return (pwwn);
+}
+
+u_longlong_t
+wwnConversion(uchar_t *wwn)
+{
+	u_longlong_t tmp;
+	(void) memcpy(&tmp, wwn, sizeof (u_longlong_t));
+	tmp = ntohll(tmp);
+	return (tmp);
+}
+
+/*
+ * Using ioctl to send uscsi command out
+ */
+HBA_STATUS
+send_uscsi_cmd(const char *devpath, struct uscsi_cmd *ucmd)
+{
+	const char	ROUTINE[] = "send_uscsi_cmd";
+	int		fd;
+	HBA_STATUS	ret;
+
+	/* set default timeout to 200 */
+	ucmd->uscsi_timeout = 200;
+
+	/* reset errno. */
+	errno = 0;
+	if ((fd = open(devpath, O_RDONLY | O_NDELAY)) == -1) {
+		log(LOG_DEBUG, ROUTINE,
+		    "open devpath %s failed: %s", devpath, strerror(errno));
+		return (HBA_STATUS_ERROR);
+	}
+
+	if (ioctl(fd, USCSICMD, ucmd) == -1) {
+		if (errno == EBUSY) {
+			ret = HBA_STATUS_ERROR_BUSY;
+		} else if (errno == EAGAIN) {
+			ret = HBA_STATUS_ERROR_TRY_AGAIN;
+		} else {
+			ret = HBA_STATUS_ERROR;
+		}
+		log(LOG_DEBUG, ROUTINE,
+		    "ioctl send uscsi to devpath: %s failed: %s",
+		    devpath, strerror(errno));
+		(void) close(fd);
+		return (ret);
+	}
+
+	(void) close(fd);
+
+	return (HBA_STATUS_OK);
+}
+
+/*
+ * Check whether the given Domain Address is valid.
+ */
+HBA_STATUS
+validateDomainAddress(struct sun_sas_port *hba_port_ptr, HBA_WWN DomainAddr)
+{
+	if (hba_port_ptr->first_phy != NULL &&
+	    wwnConversion(hba_port_ptr->first_phy->
+	    phy.domainPortWWN.wwn) ==
+	    wwnConversion(DomainAddr.wwn)) {
+		return (HBA_STATUS_OK);
+	}
+	return (HBA_STATUS_ERROR);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/sun_sas.h	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,294 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#ifndef	_SUN_SAS_H
+#define	_SUN_SAS_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <smhbaapi.h>
+#include <vendorsmhbaapi.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <limits.h>
+#include <syslog.h>
+#include <thread.h>
+#include <synch.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <libdevinfo.h>
+#include <sys/time.h>
+#include <sys/scsi/generic/commands.h>
+#include <sys/scsi/impl/commands.h>
+#include <sys/scsi/impl/sense.h>
+#include <sys/scsi/generic/inquiry.h>
+#include <sys/scsi/impl/uscsi.h>
+#include <sys/varargs.h>
+#include <sys/varargs.h>
+#include <libsysevent.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#define	VSL_NUMERIC_VERSION	1
+#define	VSL_STRING_VERSION	"Version 1"
+#define	VSL_NAME		"Sun T11 SM-HBA Vendor Library for SAS HBAs"
+#define	SMHBA_LIBRARY_VERSION1	VSL_NUMERIC_VERSION
+
+/* The /dev links we expose */
+#define	DEV_DISK_DIR		"/dev/rdsk"
+#define	DEV_TAPE_DIR		"/dev/rmt"
+#define	DEV_ES_DIR		"/dev/es"
+#define	DEV_CFG_DIR		"/dev/cfg"
+#define	DEVICES_DIR		"/devices"
+#define	DEVCTL_SUFFIX		":devctl"
+#define	SCSI_SUFFIX		":scsi"
+
+/* To be consistent, when out of memory call this macro routine */
+#define	OUT_OF_MEMORY(routine)  \
+    log(LOG_DEBUG, routine, "Out of memory.")
+
+#define	S_FREE(x)   (((x) != NULL) ? (free(x), (x) = NULL) : (void *)0)
+
+#define	IS_STUB_NODE(s) (di_instance(s) == -1 && \
+	di_nodeid(s) == (DI_PROM_NODEID))
+
+/* manf+model+10(char length of UINTMAX)+6(for 2 -'s, NULL & extra 3bytes */
+#define	HANDLE_NAME_LENGTH  (64 + 256 + 10 + 6)
+#define	HANDLE_ERROR	0 /* This is an error condition */
+
+/* Some timing values */
+#define	LOCK_SLEEP	    1
+#define	BUSY_SLEEP	    10000 /* 1/100 second */
+#define	BUSY_RETRY_TIMER    5000000000 /* Retry for 5 seconds */
+#define	STATE_RETRY_TIMER   10000000000 /* Retry for 10 seconds */
+#define	HR_SECOND	    1000000000
+/* How many times to silently retry, before starting to print warnings */
+#define	DEADLOCK_WARNING    10
+
+#define	MAX_LUN		4096
+#define	REP_LUNS_RSP_SIZE   sizeof (rep_luns_rsp_t)+  \
+				(sizeof (lun_list_element_t)*(MAX_LUN - 1))
+
+/* misc */
+#define	SUN_MICROSYSTEMS	"Sun Microsystems, Inc."
+
+mutex_t		all_hbas_lock;
+mutex_t		open_handles_lock;
+mutex_t		log_file_lock;
+HBA_UINT32	hba_count;
+HBA_UINT16	open_handle_index;
+
+
+/* Internal structures that aren't exposed to clients */
+struct open_handle {
+	int			adapterIndex;
+	HBA_UINT32		handle;
+	struct open_handle	*next;
+};
+
+struct sun_sas_hba {
+	HBA_UINT32		index;  /* Can be sparse */
+	struct open_handle	*open_handles;
+	int			fd;	    /* when open, the FD */
+	/* The libdevinfo HBA path (lacking /devices) */
+	char			device_path[MAXPATHLEN];
+	char			handle_name[HANDLE_NAME_LENGTH];
+	SMHBA_ADAPTERATTRIBUTES	adapter_attributes;
+
+	/* State tracking */
+	boolean_t		invalid;
+	struct sun_sas_hba	*next;
+	struct sun_sas_port	*first_port;
+};
+
+struct sun_sas_hba *global_hba_head;
+
+struct ScsiEntryList {
+	SMHBA_SCSIENTRY		entry;
+	struct ScsiEntryList	*next;
+};
+
+struct phy_info {
+	HBA_UINT32		index;
+	boolean_t		invalid;
+	SMHBA_SAS_PHY		phy;
+	struct phy_info		*next;
+};
+
+struct sun_sas_port {
+	HBA_UINT32		index;
+	boolean_t		invalid;
+
+	/* The libdevinfo HBA path (lacking /devices) */
+	char			device_path[MAXPATHLEN];
+	SMHBA_PORTATTRIBUTES	port_attributes;
+	struct ScsiEntryList	*scsiInfo;
+	int			cntlNumber;
+
+	/* The following are used to track the device map */
+	int			num_devices;
+	struct sun_sas_port	*first_attached_port; /* Only for HBA port */
+	struct phy_info		*first_phy;	/* Only for HBA port */
+	struct sun_sas_port	*next;
+};
+
+typedef struct walkarg {
+	char *devpath;
+	boolean_t *flag;
+} walkarg_t;
+
+extern int	loadCount;
+
+extern sysevent_handle_t *gSysEventHandle;
+
+/* External routines */
+extern HBA_STATUS SMHBA_RegisterLibrary(PSMHBA_ENTRYPOINTS);
+extern HBA_UINT32 Sun_sasGetVendorLibraryAttributes(SMHBA_LIBRARYATTRIBUTES *);
+extern HBA_STATUS Sun_sasGetAdapterAttributes(HBA_HANDLE,
+    SMHBA_ADAPTERATTRIBUTES *);
+extern HBA_UINT32 Sun_sasGetNumberOfAdapters();
+extern HBA_STATUS Sun_sasGetAdapterName(HBA_UINT32, char *);
+extern HBA_STATUS Sun_sasGetPortType(HBA_HANDLE, HBA_UINT32, HBA_PORTTYPE *);
+extern HBA_STATUS Sun_sasGetAdapterPortAttributes(HBA_HANDLE, HBA_UINT32,
+    SMHBA_PORTATTRIBUTES *);
+extern HBA_STATUS Sun_sasGetPortAttributesByWWN(HBA_HANDLE, HBA_WWN, HBA_WWN,
+    SMHBA_PORTATTRIBUTES *);
+extern HBA_STATUS Sun_sasGetFCPhyAttributes(HBA_HANDLE, HBA_UINT32, HBA_UINT32,
+    SMHBA_FC_PHY *);
+extern HBA_STATUS Sun_sasGetSASPhyAttributes(HBA_HANDLE, HBA_UINT32,
+    HBA_UINT32, SMHBA_SAS_PHY *);
+extern HBA_STATUS Sun_sasGetProtocolStatistics(HBA_HANDLE, HBA_UINT32,
+    HBA_UINT32, SMHBA_PROTOCOLSTATISTICS *);
+extern HBA_STATUS Sun_sasGetPhyStatistics(HBA_HANDLE, HBA_UINT32,
+    HBA_UINT32, SMHBA_PHYSTATISTICS *);
+extern HBA_STATUS Sun_sasSendSMPPassThru(HBA_HANDLE, HBA_WWN,  HBA_WWN, HBA_WWN,
+    void *, HBA_UINT32, void *, HBA_UINT32 *);
+extern HBA_STATUS Sun_sasGetBindingCapability(HBA_HANDLE, HBA_WWN, HBA_WWN,
+    SMHBA_BIND_CAPABILITY *);
+extern HBA_STATUS Sun_sasGetBindingSupport(HBA_HANDLE, HBA_WWN, HBA_WWN,
+    SMHBA_BIND_CAPABILITY *);
+extern HBA_STATUS Sun_sasSetBindingSupport(HBA_HANDLE, HBA_WWN, HBA_WWN,
+    SMHBA_BIND_CAPABILITY);
+extern HBA_STATUS Sun_sasGetTargetMapping(HBA_HANDLE, HBA_WWN, HBA_WWN,
+    SMHBA_TARGETMAPPING *);
+extern HBA_STATUS Sun_sasGetPersistentBinding(HBA_HANDLE, HBA_WWN, HBA_WWN,
+    SMHBA_BINDING *);
+extern HBA_STATUS Sun_sasSetPersistentBinding(HBA_HANDLE, HBA_WWN, HBA_WWN,
+    const SMHBA_BINDING *);
+extern HBA_STATUS Sun_sasRemovePersistentBinding(HBA_HANDLE, HBA_WWN, HBA_WWN,
+    const SMHBA_BINDING *);
+extern HBA_STATUS Sun_sasRemoveAllPersistentBindings(HBA_HANDLE, HBA_WWN,
+    HBA_WWN);
+extern HBA_STATUS Sun_sasGetLUNStatistics(HBA_HANDLE, const HBA_SCSIID *,
+    SMHBA_PROTOCOLSTATISTICS *);
+extern HBA_STATUS Sun_sasRegisterForAdapterAddEvents(void (*)(void *, HBA_WWN,
+    HBA_UINT32), void *, HBA_CALLBACKHANDLE *);
+extern HBA_STATUS Sun_sasRegisterForAdapterEvents(void (*)(void *, HBA_WWN,
+    HBA_UINT32), void *, HBA_HANDLE, HBA_CALLBACKHANDLE *);
+extern HBA_STATUS Sun_sasRegisterForAdapterPortEvents(void (*)(void *, HBA_WWN,
+    HBA_UINT32, HBA_UINT32), void *, HBA_HANDLE, HBA_WWN, HBA_UINT32,
+    HBA_CALLBACKHANDLE *);
+extern HBA_STATUS Sun_sasRegisterForAdapterPortStatEvents(void (*)(void *,
+    HBA_WWN, HBA_UINT32, HBA_UINT32), void *, HBA_HANDLE, HBA_WWN, HBA_UINT32,
+    SMHBA_PROTOCOLSTATISTICS, HBA_UINT32, HBA_CALLBACKHANDLE *);
+extern HBA_STATUS    Sun_sasRegisterForAdapterPhyStatEvents(void (*)(void *,
+    HBA_WWN, HBA_UINT32, HBA_UINT32), void *, HBA_HANDLE, HBA_WWN, HBA_UINT32,
+    SMHBA_PHYSTATISTICS, HBA_UINT32, HBA_CALLBACKHANDLE *);
+extern HBA_STATUS Sun_sasRegisterForTargetEvents(void (*)(void *, HBA_WWN,
+    HBA_WWN, HBA_WWN, HBA_UINT32), void *, HBA_HANDLE, HBA_WWN, HBA_WWN,
+    HBA_WWN, HBA_CALLBACKHANDLE *, HBA_UINT32);
+extern HBA_STATUS Sun_sasRegisterForLinkEvents(void (*)(void *, HBA_WWN,
+    HBA_UINT32, void *, HBA_UINT32), void *, void *, HBA_UINT32, HBA_HANDLE,
+    HBA_CALLBACKHANDLE *);
+extern HBA_STATUS Sun_sasScsiInquiry(HBA_HANDLE, HBA_WWN, HBA_WWN, HBA_WWN,
+    SMHBA_SCSILUN, HBA_UINT8, HBA_UINT8, void *, HBA_UINT32 *, HBA_UINT8 *,
+    void *, HBA_UINT32 *);
+extern HBA_STATUS Sun_sasScsiReportLUNs(HBA_HANDLE, HBA_WWN, HBA_WWN,
+    HBA_WWN, void *, HBA_UINT32 *, HBA_UINT8 *, void *, HBA_UINT32 *);
+extern HBA_STATUS Sun_sasScsiReadCapacity(HBA_HANDLE, HBA_WWN, HBA_WWN, HBA_WWN,
+    SMHBA_SCSILUN, void *, HBA_UINT32 *, HBA_UINT8 *, void *, HBA_UINT32 *);
+extern HBA_UINT32 Sun_sasGetVersion();
+extern HBA_STATUS Sun_sasLoadLibrary();
+extern HBA_STATUS Sun_sasFreeLibrary();
+extern HBA_UINT32 Sun_sasGetNumberOfAdapters();
+extern HBA_UINT32 Sun_sasGetNumberOfPorts(HBA_HANDLE, HBA_UINT32 *);
+extern HBA_STATUS Sun_sasGetAdapterName(HBA_UINT32, char *);
+extern HBA_HANDLE Sun_sasOpenAdapter(char *);
+extern void Sun_sasCloseAdapter(HBA_HANDLE);
+extern HBA_STATUS Sun_sasGetDiscoveredPortAttributes(HBA_HANDLE, HBA_UINT32,
+    HBA_UINT32, SMHBA_PORTATTRIBUTES *);
+extern HBA_STATUS Sun_sasGetPortAttributesByWWN(HBA_HANDLE, HBA_WWN, HBA_WWN,
+    SMHBA_PORTATTRIBUTES *);
+extern void Sun_sasRefreshInformation(HBA_HANDLE);
+extern void Sun_sasRefreshAdapterConfiguration(void);
+extern HBA_STATUS Sun_sasRemoveCallback(HBA_CALLBACKHANDLE);
+
+
+/* Internal routines */
+extern void log(int, const char *, char *, ...);
+extern u_longlong_t wwnConversion(uchar_t *wwn);
+extern HBA_STATUS devtree_attached_devices(di_node_t, struct sun_sas_port *);
+extern HBA_HANDLE CreateHandle(int);
+extern int RetrieveIndex(HBA_HANDLE);
+extern struct open_handle *RetrieveOpenHandle(HBA_HANDLE);
+extern struct sun_sas_hba *RetrieveHandle(int);
+extern struct sun_sas_hba *ExtractHandle(int);
+extern struct sun_sas_hba *Retrieve_Sun_sasHandle(HBA_HANDLE);
+extern void lock(mutex_t *mp);
+extern void unlock(mutex_t *mp);
+extern void reportSense(struct scsi_extended_sense *, const char *);
+extern HBA_STATUS verifyAdapter(struct sun_sas_hba *hba_ptr);
+extern HBA_STATUS devtree_get_all_hbas(di_node_t root);
+extern HBA_STATUS devtree_get_one_hba(di_node_t node);
+extern HBA_STATUS FreeHBA(struct sun_sas_hba *hba);
+extern HBA_WWN getFirstAdapterPortWWN(HBA_HANDLE handle);
+extern HBA_STATUS getPortStateCounter(char *fpPath, HBA_UINT32 *stateCount);
+extern HBA_STATUS lookupControllerLink(char *path, char *link);
+extern HBA_STATUS lookupSMPLink(char *path, char *link);
+extern void convertDevpathToDevlink(PSMHBA_TARGETMAPPING mappings);
+extern void fillDomainPortWWN(struct sun_sas_port *);
+extern HBA_STATUS get_phy_info(di_node_t, struct sun_sas_port *);
+extern HBA_STATUS send_uscsi_cmd(const char *devpath, struct uscsi_cmd *ucmd);
+extern HBA_STATUS registerSysevent();
+extern HBA_STATUS validateDomainAddress(struct sun_sas_port *, HBA_WWN);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _SUN_SAS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/common/verify.c	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,79 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sun_sas.h>
+#include <signal.h>
+
+/*
+ * Verify that a given adapter is present on the system.
+ * No checks will be performed on the targets, and it is assumed
+ * that an adapter can't change the number of ports it has.
+ */
+HBA_STATUS
+verifyAdapter(struct sun_sas_hba *hba_ptr) {
+	const char	    ROUTINE[] = "verifyAdapter";
+	char		    *charptr, path[MAXPATHLEN+1];
+	di_node_t	    node;
+	uint_t		    state;
+
+	/*
+	 * valid test for a removed HBA.
+	 */
+	if (hba_ptr == NULL) {
+	    log(LOG_DEBUG, ROUTINE, "Null hba_ptr argument");
+	    return (HBA_STATUS_ERROR);
+	}
+	(void) strlcpy(path, hba_ptr->device_path, sizeof (path));
+
+	charptr = strrchr(path, ':');
+	if (charptr) {
+	    *charptr = '\0';
+	}
+
+	errno = 0;
+
+	node = di_init(path, DINFOCPYALL);
+	if (node == DI_NODE_NIL) {
+		log(LOG_DEBUG, ROUTINE,
+		    "Unable to take devinfo snapshot on HBA \"%s\" due to %s",
+		    path, strerror(errno));
+		return (HBA_STATUS_ERROR);
+	} else {
+		state = di_state(node);
+		if (((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) ||
+		    ((state & DI_BUS_DOWN) == DI_BUS_DOWN) ||
+		    ((state & DI_BUS_QUIESCED) == DI_BUS_QUIESCED)) {
+			di_fini(node);
+			log(LOG_DEBUG, ROUTINE,
+			    "devinfo node is not online state: %d", state);
+			return (HBA_STATUS_ERROR);
+		}
+	}
+
+	di_fini(node);
+
+	return (HBA_STATUS_OK);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/i386/Makefile	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,29 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/sparc/Makefile	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,33 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.com
+
+.KEEP_STATE:
+
+all:  $(LIBS)
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/sun_sas/sparcv9/Makefile	Fri Sep 25 16:43:29 2009 -0700
@@ -0,0 +1,34 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+.KEEP_STATE:
+
+all:  $(LIBS)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- a/usr/src/pkgdefs/SUNWsmhba/prototype_com	Fri Sep 25 18:10:09 2009 -0400
+++ b/usr/src/pkgdefs/SUNWsmhba/prototype_com	Fri Sep 25 16:43:29 2009 -0700
@@ -34,6 +34,18 @@
 
 #
 #
-i copyright
 i pkginfo
 i depend
+i copyright
+d none usr 0755 root sys
+d none usr/lib 0755 root bin
+f none usr/lib/libSMHBAAPI.so.1 0755 root bin
+s none usr/lib/libSMHBAAPI.so=libSMHBAAPI.so.1
+f none usr/lib/llib-lSMHBAAPI 0644 root bin
+f none usr/lib/llib-lSMHBAAPI.ln 0644 root bin
+f none usr/lib/libsun_sas.so.1 0755 root bin
+s none usr/lib/libsun_sas.so=libsun_sas.so.1
+d none usr/sbin 0755 root bin
+f none usr/sbin/sasinfo 0555 root bin
+d none usr/include 0755 root bin
+f none usr/include/smhbaapi.h 0644 root bin
--- a/usr/src/pkgdefs/SUNWsmhba/prototype_i386	Fri Sep 25 18:10:09 2009 -0400
+++ b/usr/src/pkgdefs/SUNWsmhba/prototype_i386	Fri Sep 25 16:43:29 2009 -0700
@@ -36,3 +36,17 @@
 # Include ISA independent files (prototype_com)
 #
 !include prototype_com
+#
+#
+# List files which are i386 specific here
+#
+# source locations relative to the prototype file
+#
+#
+# SUNWsmhba
+d none usr/lib/amd64 0755 root bin
+f none usr/lib/amd64/libSMHBAAPI.so.1 0755 root bin
+s none usr/lib/amd64/libSMHBAAPI.so=libSMHBAAPI.so.1
+f none usr/lib/amd64/llib-lSMHBAAPI.ln 644 root bin
+f none usr/lib/amd64/libsun_sas.so.1 0755 root bin
+s none usr/lib/amd64/libsun_sas.so=libsun_sas.so.1
--- a/usr/src/pkgdefs/SUNWsmhba/prototype_sparc	Fri Sep 25 18:10:09 2009 -0400
+++ b/usr/src/pkgdefs/SUNWsmhba/prototype_sparc	Fri Sep 25 16:43:29 2009 -0700
@@ -36,3 +36,17 @@
 # Include ISA independent files (prototype_com)
 #
 !include prototype_com
+#
+#
+# List files which are i386 specific here
+#
+# source locations relative to the prototype file
+#
+#
+# SUNWsmhba
+d none usr/lib/sparcv9 0755 root bin
+f none usr/lib/sparcv9/libSMHBAAPI.so.1 0755 root bin
+s none usr/lib/sparcv9/libSMHBAAPI.so=libSMHBAAPI.so.1
+f none usr/lib/sparcv9/llib-lSMHBAAPI.ln 0644 root bin
+f none usr/lib/sparcv9/libsun_sas.so.1 0755 root bin
+s none usr/lib/sparcv9/libsun_sas.so=libsun_sas.so.1
--- a/usr/src/pkgdefs/SUNWsmhbar/pkginfo.tmpl	Fri Sep 25 18:10:09 2009 -0400
+++ b/usr/src/pkgdefs/SUNWsmhbar/pkginfo.tmpl	Fri Sep 25 16:43:29 2009 -0700
@@ -39,5 +39,5 @@
 HOTLINE="Please contact your local service provider"
 EMAIL=""
 SUNW_PKG_ALLZONES="true"
-SUNW_PKG_HOLLOW="false"
+SUNW_PKG_HOLLOW="true"
 SUNW_PKG_THISZONE="false"
--- a/usr/src/pkgdefs/SUNWsmhbar/prototype_com	Fri Sep 25 18:10:09 2009 -0400
+++ b/usr/src/pkgdefs/SUNWsmhbar/prototype_com	Fri Sep 25 16:43:29 2009 -0700
@@ -38,3 +38,5 @@
 i pkginfo
 i depend
 i i.preserve
+d none etc 0755 root sys
+e preserve etc/smhba.conf 0644 root sys