diff options
author | Hyon Kim <Hyon.Kim@Sun.COM> | 2009-09-25 16:43:29 -0700 |
---|---|---|
committer | Hyon Kim <Hyon.Kim@Sun.COM> | 2009-09-25 16:43:29 -0700 |
commit | 9e86db79b7d1bbc5f2f04e99954cbd5eae0e22bb (patch) | |
tree | 474da51b64b142f6788f9d4d3798ae0a4a3fa49a | |
parent | ebf418d7ab5c89ce3e7fb31d6a454171f5f7f518 (diff) | |
download | illumos-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.
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 |