summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHyon Kim <Hyon.Kim@Sun.COM>2009-09-25 16:43:29 -0700
committerHyon Kim <Hyon.Kim@Sun.COM>2009-09-25 16:43:29 -0700
commit9e86db79b7d1bbc5f2f04e99954cbd5eae0e22bb (patch)
tree474da51b64b142f6788f9d4d3798ae0a4a3fa49a
parentebf418d7ab5c89ce3e7fb31d6a454171f5f7f518 (diff)
downloadillumos-joyent-9e86db79b7d1bbc5f2f04e99954cbd5eae0e22bb.tar.gz
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.
-rw-r--r--usr/src/cmd/Makefile2
-rw-r--r--usr/src/cmd/sasinfo/Makefile83
-rw-r--r--usr/src/cmd/sasinfo/printAttrs.c582
-rw-r--r--usr/src/cmd/sasinfo/printAttrs.h72
-rw-r--r--usr/src/cmd/sasinfo/sasinfo-list.c2799
-rw-r--r--usr/src/cmd/sasinfo/sasinfo.c220
-rw-r--r--usr/src/cmd/sasinfo/sasinfo.h138
-rw-r--r--usr/src/common/cmdparse/cmdparse.c11
-rw-r--r--usr/src/lib/Makefile3
-rw-r--r--usr/src/lib/libsecdb/exec_attr.txt1
-rw-r--r--usr/src/lib/smhba/Makefile59
-rw-r--r--usr/src/lib/smhba/Makefile.com64
-rw-r--r--usr/src/lib/smhba/THIRDPARTYLICENSE404
-rw-r--r--usr/src/lib/smhba/THIRDPARTYLICENSE.descrip1
-rw-r--r--usr/src/lib/smhba/amd64/Makefile30
-rw-r--r--usr/src/lib/smhba/common/SMHBAAPILIB.c4988
-rw-r--r--usr/src/lib/smhba/common/llib-lSMHBAAPI30
-rw-r--r--usr/src/lib/smhba/common/mapfile-vers136
-rw-r--r--usr/src/lib/smhba/common/smhba.conf36
-rw-r--r--usr/src/lib/smhba/common/smhbaapi.h672
-rw-r--r--usr/src/lib/smhba/common/vendorsmhbaapi.h207
-rw-r--r--usr/src/lib/smhba/i386/Makefile29
-rw-r--r--usr/src/lib/smhba/sparc/Makefile29
-rw-r--r--usr/src/lib/smhba/sparcv9/Makefile30
-rw-r--r--usr/src/lib/sun_sas/Makefile54
-rw-r--r--usr/src/lib/sun_sas/Makefile.com99
-rw-r--r--usr/src/lib/sun_sas/amd64/Makefile34
-rw-r--r--usr/src/lib/sun_sas/common/SMHBA_RegisterLibrary.c100
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasCloseAdapter.c99
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasFreeLibrary.c131
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetAdapterAttributes.c62
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetAdapterName.c67
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetAdapterPortAttributes.c111
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetDiscoveredPortAttributes.c143
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetLUNStatistics.c38
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetNumberOfAdapters.c46
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetNumberOfPorts.c79
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetPersistentBinding.c36
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetPhyStatistics.c258
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetPortAttributesByWWN.c189
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetPortType.c98
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetProtocolStatistics.c39
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetSASPhyAttributes.c99
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetTargetMapping.c179
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetVendorLibraryAttributes.c50
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasGetVersion.c34
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasLoadLibrary.c102
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasOpenAdapter.c59
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasRefreshAdapterConfiguration.c155
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasRefreshInformation.c159
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasScsiInquiry.c273
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasScsiReadCapacity.c261
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasScsiReportLUNs.c233
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasSendSMPPassThru.c250
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasSetPersistentBinding.c36
-rw-r--r--usr/src/lib/sun_sas/common/devlink_disco.c251
-rw-r--r--usr/src/lib/sun_sas/common/devtree_device_disco.c1075
-rw-r--r--usr/src/lib/sun_sas/common/devtree_hba_disco.c634
-rw-r--r--usr/src/lib/sun_sas/common/devtree_phy_disco.c202
-rw-r--r--usr/src/lib/sun_sas/common/event.c268
-rw-r--r--usr/src/lib/sun_sas/common/log.c68
-rw-r--r--usr/src/lib/sun_sas/common/mapfile-vers77
-rw-r--r--usr/src/lib/sun_sas/common/sun_sas.c431
-rw-r--r--usr/src/lib/sun_sas/common/sun_sas.h294
-rw-r--r--usr/src/lib/sun_sas/common/verify.c79
-rw-r--r--usr/src/lib/sun_sas/i386/Makefile29
-rw-r--r--usr/src/lib/sun_sas/sparc/Makefile33
-rw-r--r--usr/src/lib/sun_sas/sparcv9/Makefile34
-rw-r--r--usr/src/pkgdefs/SUNWsmhba/prototype_com14
-rw-r--r--usr/src/pkgdefs/SUNWsmhba/prototype_i38614
-rw-r--r--usr/src/pkgdefs/SUNWsmhba/prototype_sparc14
-rw-r--r--usr/src/pkgdefs/SUNWsmhbar/pkginfo.tmpl2
-rw-r--r--usr/src/pkgdefs/SUNWsmhbar/prototype_com2
73 files changed, 17717 insertions, 3 deletions
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile
index 7a1485f89d..3ddc3f1d43 100644
--- a/usr/src/cmd/Makefile
+++ b/usr/src/cmd/Makefile
@@ -353,6 +353,7 @@ COMMON_SUBDIRS= \
runat \
sa \
saf \
+ sasinfo \
savecore \
sbdadm \
script \
@@ -686,6 +687,7 @@ MSGSUBDIRS= \
rmformat \
rmmount \
rmvolmgr \
+ sasinfo \
sbdadm \
scadm \
script \
diff --git a/usr/src/cmd/sasinfo/Makefile b/usr/src/cmd/sasinfo/Makefile
new file mode 100644
index 0000000000..2f35783729
--- /dev/null
+++ b/usr/src/cmd/sasinfo/Makefile
@@ -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
diff --git a/usr/src/cmd/sasinfo/printAttrs.c b/usr/src/cmd/sasinfo/printAttrs.c
new file mode 100644
index 0000000000..ae66526d59
--- /dev/null
+++ b/usr/src/cmd/sasinfo/printAttrs.c
@@ -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);
+}
diff --git a/usr/src/cmd/sasinfo/printAttrs.h b/usr/src/cmd/sasinfo/printAttrs.h
new file mode 100644
index 0000000000..40d66e6689
--- /dev/null
+++ b/usr/src/cmd/sasinfo/printAttrs.h
@@ -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 */
diff --git a/usr/src/cmd/sasinfo/sasinfo-list.c b/usr/src/cmd/sasinfo/sasinfo-list.c
new file mode 100644
index 0000000000..57b39b8247
--- /dev/null
+++ b/usr/src/cmd/sasinfo/sasinfo-list.c
@@ -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);
+}
diff --git a/usr/src/cmd/sasinfo/sasinfo.c b/usr/src/cmd/sasinfo/sasinfo.c
new file mode 100644
index 0000000000..5e032543fd
--- /dev/null
+++ b/usr/src/cmd/sasinfo/sasinfo.c
@@ -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);
+}
diff --git a/usr/src/cmd/sasinfo/sasinfo.h b/usr/src/cmd/sasinfo/sasinfo.h
new file mode 100644
index 0000000000..af803584aa
--- /dev/null
+++ b/usr/src/cmd/sasinfo/sasinfo.h
@@ -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 */
diff --git a/usr/src/common/cmdparse/cmdparse.c b/usr/src/common/cmdparse/cmdparse.c
index a773311033..7a9e575d71 100644
--- a/usr/src/common/cmdparse/cmdparse.c
+++ b/usr/src/common/cmdparse/cmdparse.c
@@ -536,7 +536,16 @@ cmdParse(int argc, char *argv[], synTables_t synTable, void *callArgs,
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) {
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 7f523ccaa8..557b39a8fe 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -147,7 +147,9 @@ SUBDIRS += \
nametoaddr \
ncad_addr \
hbaapi \
+ smhba \
sun_fc \
+ sun_sas \
gss_mechs/mech_krb5 .WAIT \
libkrb5 .WAIT \
krb5 .WAIT \
@@ -486,6 +488,7 @@ HDRSUBDIRS= \
smbsrv \
scsi \
hbaapi \
+ smhba \
libima \
libsun_ima \
mpapi \
diff --git a/usr/src/lib/libsecdb/exec_attr.txt b/usr/src/lib/libsecdb/exec_attr.txt
index 272ab0191d..d0cd0b360b 100644
--- a/usr/src/lib/libsecdb/exec_attr.txt
+++ b/usr/src/lib/libsecdb/exec_attr.txt
@@ -101,6 +101,7 @@ File System Management:solaris:cmd:::/usr/sbin/quotaoff:uid=0;gid=sys
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
diff --git a/usr/src/lib/smhba/Makefile b/usr/src/lib/smhba/Makefile
new file mode 100644
index 0000000000..d17215194c
--- /dev/null
+++ b/usr/src/lib/smhba/Makefile
@@ -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
diff --git a/usr/src/lib/smhba/Makefile.com b/usr/src/lib/smhba/Makefile.com
new file mode 100644
index 0000000000..e13057c82b
--- /dev/null
+++ b/usr/src/lib/smhba/Makefile.com
@@ -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
diff --git a/usr/src/lib/smhba/THIRDPARTYLICENSE b/usr/src/lib/smhba/THIRDPARTYLICENSE
new file mode 100644
index 0000000000..464ee756eb
--- /dev/null
+++ b/usr/src/lib/smhba/THIRDPARTYLICENSE
@@ -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): ______________________________________.
+
diff --git a/usr/src/lib/smhba/THIRDPARTYLICENSE.descrip b/usr/src/lib/smhba/THIRDPARTYLICENSE.descrip
new file mode 100644
index 0000000000..ab95413837
--- /dev/null
+++ b/usr/src/lib/smhba/THIRDPARTYLICENSE.descrip
@@ -0,0 +1 @@
+SM-HBA SOFTWARE
diff --git a/usr/src/lib/smhba/amd64/Makefile b/usr/src/lib/smhba/amd64/Makefile
new file mode 100644
index 0000000000..dfeeb9953a
--- /dev/null
+++ b/usr/src/lib/smhba/amd64/Makefile
@@ -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)
diff --git a/usr/src/lib/smhba/common/SMHBAAPILIB.c b/usr/src/lib/smhba/common/SMHBAAPILIB.c
new file mode 100644
index 0000000000..ae2fd4b0d8
--- /dev/null
+++ b/usr/src/lib/smhba/common/SMHBAAPILIB.c
@@ -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);
+}
diff --git a/usr/src/lib/smhba/common/llib-lSMHBAAPI b/usr/src/lib/smhba/common/llib-lSMHBAAPI
new file mode 100644
index 0000000000..18e4b625cb
--- /dev/null
+++ b/usr/src/lib/smhba/common/llib-lSMHBAAPI
@@ -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>
diff --git a/usr/src/lib/smhba/common/mapfile-vers b/usr/src/lib/smhba/common/mapfile-vers
new file mode 100644
index 0000000000..c1c823a847
--- /dev/null
+++ b/usr/src/lib/smhba/common/mapfile-vers
@@ -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:
+ *;
+};
+
diff --git a/usr/src/lib/smhba/common/smhba.conf b/usr/src/lib/smhba/common/smhba.conf
new file mode 100644
index 0000000000..c93436e087
--- /dev/null
+++ b/usr/src/lib/smhba/common/smhba.conf
@@ -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
+
diff --git a/usr/src/lib/smhba/common/smhbaapi.h b/usr/src/lib/smhba/common/smhbaapi.h
new file mode 100644
index 0000000000..958b34f342
--- /dev/null
+++ b/usr/src/lib/smhba/common/smhbaapi.h
@@ -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_ */
diff --git a/usr/src/lib/smhba/common/vendorsmhbaapi.h b/usr/src/lib/smhba/common/vendorsmhbaapi.h
new file mode 100644
index 0000000000..42982bc909
--- /dev/null
+++ b/usr/src/lib/smhba/common/vendorsmhbaapi.h
@@ -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_ */
diff --git a/usr/src/lib/smhba/i386/Makefile b/usr/src/lib/smhba/i386/Makefile
new file mode 100644
index 0000000000..075f16dfdc
--- /dev/null
+++ b/usr/src/lib/smhba/i386/Makefile
@@ -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)
diff --git a/usr/src/lib/smhba/sparc/Makefile b/usr/src/lib/smhba/sparc/Makefile
new file mode 100644
index 0000000000..075f16dfdc
--- /dev/null
+++ b/usr/src/lib/smhba/sparc/Makefile
@@ -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)
diff --git a/usr/src/lib/smhba/sparcv9/Makefile b/usr/src/lib/smhba/sparcv9/Makefile
new file mode 100644
index 0000000000..dfeeb9953a
--- /dev/null
+++ b/usr/src/lib/smhba/sparcv9/Makefile
@@ -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)
diff --git a/usr/src/lib/sun_sas/Makefile b/usr/src/lib/sun_sas/Makefile
new file mode 100644
index 0000000000..073fe728d5
--- /dev/null
+++ b/usr/src/lib/sun_sas/Makefile
@@ -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
diff --git a/usr/src/lib/sun_sas/Makefile.com b/usr/src/lib/sun_sas/Makefile.com
new file mode 100644
index 0000000000..d3ddf2f450
--- /dev/null
+++ b/usr/src/lib/sun_sas/Makefile.com
@@ -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
diff --git a/usr/src/lib/sun_sas/amd64/Makefile b/usr/src/lib/sun_sas/amd64/Makefile
new file mode 100644
index 0000000000..5180f1b702
--- /dev/null
+++ b/usr/src/lib/sun_sas/amd64/Makefile
@@ -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)
diff --git a/usr/src/lib/sun_sas/common/SMHBA_RegisterLibrary.c b/usr/src/lib/sun_sas/common/SMHBA_RegisterLibrary.c
new file mode 100644
index 0000000000..eb71a418f7
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/SMHBA_RegisterLibrary.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasCloseAdapter.c b/usr/src/lib/sun_sas/common/Sun_sasCloseAdapter.c
new file mode 100644
index 0000000000..d6dc259be6
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasCloseAdapter.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasFreeLibrary.c b/usr/src/lib/sun_sas/common/Sun_sasFreeLibrary.c
new file mode 100644
index 0000000000..caffe52de1
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasFreeLibrary.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetAdapterAttributes.c b/usr/src/lib/sun_sas/common/Sun_sasGetAdapterAttributes.c
new file mode 100644
index 0000000000..d5e5e55ec1
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetAdapterAttributes.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetAdapterName.c b/usr/src/lib/sun_sas/common/Sun_sasGetAdapterName.c
new file mode 100644
index 0000000000..bf945aedb9
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetAdapterName.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetAdapterPortAttributes.c b/usr/src/lib/sun_sas/common/Sun_sasGetAdapterPortAttributes.c
new file mode 100644
index 0000000000..cd60698a72
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetAdapterPortAttributes.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetDiscoveredPortAttributes.c b/usr/src/lib/sun_sas/common/Sun_sasGetDiscoveredPortAttributes.c
new file mode 100644
index 0000000000..10de1cbcff
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetDiscoveredPortAttributes.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetLUNStatistics.c b/usr/src/lib/sun_sas/common/Sun_sasGetLUNStatistics.c
new file mode 100644
index 0000000000..7c6cda031a
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetLUNStatistics.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetNumberOfAdapters.c b/usr/src/lib/sun_sas/common/Sun_sasGetNumberOfAdapters.c
new file mode 100644
index 0000000000..71bf0fc315
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetNumberOfAdapters.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetNumberOfPorts.c b/usr/src/lib/sun_sas/common/Sun_sasGetNumberOfPorts.c
new file mode 100644
index 0000000000..ff35c7c21a
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetNumberOfPorts.c
@@ -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);
+
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetPersistentBinding.c b/usr/src/lib/sun_sas/common/Sun_sasGetPersistentBinding.c
new file mode 100644
index 0000000000..7fedb970e2
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetPersistentBinding.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetPhyStatistics.c b/usr/src/lib/sun_sas/common/Sun_sasGetPhyStatistics.c
new file mode 100644
index 0000000000..10f73604cf
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetPhyStatistics.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetPortAttributesByWWN.c b/usr/src/lib/sun_sas/common/Sun_sasGetPortAttributesByWWN.c
new file mode 100644
index 0000000000..5c4723791a
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetPortAttributesByWWN.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetPortType.c b/usr/src/lib/sun_sas/common/Sun_sasGetPortType.c
new file mode 100644
index 0000000000..3c422e4777
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetPortType.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetProtocolStatistics.c b/usr/src/lib/sun_sas/common/Sun_sasGetProtocolStatistics.c
new file mode 100644
index 0000000000..e53df6b6a5
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetProtocolStatistics.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetSASPhyAttributes.c b/usr/src/lib/sun_sas/common/Sun_sasGetSASPhyAttributes.c
new file mode 100644
index 0000000000..b4aceb9f50
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetSASPhyAttributes.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetTargetMapping.c b/usr/src/lib/sun_sas/common/Sun_sasGetTargetMapping.c
new file mode 100644
index 0000000000..7d83e386bf
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetTargetMapping.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetVendorLibraryAttributes.c b/usr/src/lib/sun_sas/common/Sun_sasGetVendorLibraryAttributes.c
new file mode 100644
index 0000000000..0257e3525b
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetVendorLibraryAttributes.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasGetVersion.c b/usr/src/lib/sun_sas/common/Sun_sasGetVersion.c
new file mode 100644
index 0000000000..0e7ac6c824
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasGetVersion.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasLoadLibrary.c b/usr/src/lib/sun_sas/common/Sun_sasLoadLibrary.c
new file mode 100644
index 0000000000..b5df2a4cc8
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasLoadLibrary.c
@@ -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);
+ }
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasOpenAdapter.c b/usr/src/lib/sun_sas/common/Sun_sasOpenAdapter.c
new file mode 100644
index 0000000000..4556b4f86e
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasOpenAdapter.c
@@ -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));
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasRefreshAdapterConfiguration.c b/usr/src/lib/sun_sas/common/Sun_sasRefreshAdapterConfiguration.c
new file mode 100644
index 0000000000..591342ad39
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasRefreshAdapterConfiguration.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasRefreshInformation.c b/usr/src/lib/sun_sas/common/Sun_sasRefreshInformation.c
new file mode 100644
index 0000000000..fc26c9aa08
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasRefreshInformation.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasScsiInquiry.c b/usr/src/lib/sun_sas/common/Sun_sasScsiInquiry.c
new file mode 100644
index 0000000000..144a85d89d
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasScsiInquiry.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasScsiReadCapacity.c b/usr/src/lib/sun_sas/common/Sun_sasScsiReadCapacity.c
new file mode 100644
index 0000000000..7295fe0aaa
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasScsiReadCapacity.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasScsiReportLUNs.c b/usr/src/lib/sun_sas/common/Sun_sasScsiReportLUNs.c
new file mode 100644
index 0000000000..62b428d4d4
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasScsiReportLUNs.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasSendSMPPassThru.c b/usr/src/lib/sun_sas/common/Sun_sasSendSMPPassThru.c
new file mode 100644
index 0000000000..914f47de06
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasSendSMPPassThru.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/Sun_sasSetPersistentBinding.c b/usr/src/lib/sun_sas/common/Sun_sasSetPersistentBinding.c
new file mode 100644
index 0000000000..c879b12ecc
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/Sun_sasSetPersistentBinding.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/devlink_disco.c b/usr/src/lib/sun_sas/common/devlink_disco.c
new file mode 100644
index 0000000000..9b616e2293
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/devlink_disco.c
@@ -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));
+}
diff --git a/usr/src/lib/sun_sas/common/devtree_device_disco.c b/usr/src/lib/sun_sas/common/devtree_device_disco.c
new file mode 100644
index 0000000000..cb788e6605
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/devtree_device_disco.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/devtree_hba_disco.c b/usr/src/lib/sun_sas/common/devtree_hba_disco.c
new file mode 100644
index 0000000000..bd3ff0898c
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/devtree_hba_disco.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/devtree_phy_disco.c b/usr/src/lib/sun_sas/common/devtree_phy_disco.c
new file mode 100644
index 0000000000..53351912f7
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/devtree_phy_disco.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/event.c b/usr/src/lib/sun_sas/common/event.c
new file mode 100644
index 0000000000..a4030d5d1b
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/event.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/log.c b/usr/src/lib/sun_sas/common/log.c
new file mode 100644
index 0000000000..d556ecc8d7
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/log.c
@@ -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;
+}
diff --git a/usr/src/lib/sun_sas/common/mapfile-vers b/usr/src/lib/sun_sas/common/mapfile-vers
new file mode 100644
index 0000000000..d0085ce9e1
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/mapfile-vers
@@ -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:
+ *;
+};
diff --git a/usr/src/lib/sun_sas/common/sun_sas.c b/usr/src/lib/sun_sas/common/sun_sas.c
new file mode 100644
index 0000000000..152a25a723
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/sun_sas.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/common/sun_sas.h b/usr/src/lib/sun_sas/common/sun_sas.h
new file mode 100644
index 0000000000..d6872e5628
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/sun_sas.h
@@ -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 */
diff --git a/usr/src/lib/sun_sas/common/verify.c b/usr/src/lib/sun_sas/common/verify.c
new file mode 100644
index 0000000000..c87aee5672
--- /dev/null
+++ b/usr/src/lib/sun_sas/common/verify.c
@@ -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);
+}
diff --git a/usr/src/lib/sun_sas/i386/Makefile b/usr/src/lib/sun_sas/i386/Makefile
new file mode 100644
index 0000000000..47878e05bc
--- /dev/null
+++ b/usr/src/lib/sun_sas/i386/Makefile
@@ -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)
diff --git a/usr/src/lib/sun_sas/sparc/Makefile b/usr/src/lib/sun_sas/sparc/Makefile
new file mode 100644
index 0000000000..7cdca9a2c6
--- /dev/null
+++ b/usr/src/lib/sun_sas/sparc/Makefile
@@ -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)
diff --git a/usr/src/lib/sun_sas/sparcv9/Makefile b/usr/src/lib/sun_sas/sparcv9/Makefile
new file mode 100644
index 0000000000..5180f1b702
--- /dev/null
+++ b/usr/src/lib/sun_sas/sparcv9/Makefile
@@ -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)
diff --git a/usr/src/pkgdefs/SUNWsmhba/prototype_com b/usr/src/pkgdefs/SUNWsmhba/prototype_com
index c9b99b144d..550c08725f 100644
--- a/usr/src/pkgdefs/SUNWsmhba/prototype_com
+++ b/usr/src/pkgdefs/SUNWsmhba/prototype_com
@@ -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
diff --git a/usr/src/pkgdefs/SUNWsmhba/prototype_i386 b/usr/src/pkgdefs/SUNWsmhba/prototype_i386
index 11675a0e66..d90538f75d 100644
--- a/usr/src/pkgdefs/SUNWsmhba/prototype_i386
+++ b/usr/src/pkgdefs/SUNWsmhba/prototype_i386
@@ -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
diff --git a/usr/src/pkgdefs/SUNWsmhba/prototype_sparc b/usr/src/pkgdefs/SUNWsmhba/prototype_sparc
index 11675a0e66..21c2dd7e68 100644
--- a/usr/src/pkgdefs/SUNWsmhba/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWsmhba/prototype_sparc
@@ -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
diff --git a/usr/src/pkgdefs/SUNWsmhbar/pkginfo.tmpl b/usr/src/pkgdefs/SUNWsmhbar/pkginfo.tmpl
index 5c8258f718..eb69932827 100644
--- a/usr/src/pkgdefs/SUNWsmhbar/pkginfo.tmpl
+++ b/usr/src/pkgdefs/SUNWsmhbar/pkginfo.tmpl
@@ -39,5 +39,5 @@ CLASSES="none preserve"
HOTLINE="Please contact your local service provider"
EMAIL=""
SUNW_PKG_ALLZONES="true"
-SUNW_PKG_HOLLOW="false"
+SUNW_PKG_HOLLOW="true"
SUNW_PKG_THISZONE="false"
diff --git a/usr/src/pkgdefs/SUNWsmhbar/prototype_com b/usr/src/pkgdefs/SUNWsmhbar/prototype_com
index ba927f2988..c81b97a3cd 100644
--- a/usr/src/pkgdefs/SUNWsmhbar/prototype_com
+++ b/usr/src/pkgdefs/SUNWsmhbar/prototype_com
@@ -38,3 +38,5 @@ i copyright
i pkginfo
i depend
i i.preserve
+d none etc 0755 root sys
+e preserve etc/smhba.conf 0644 root sys