OpenSolaris_b135/lib/hbaapi/common/HBAAPILIB-sun.c

/*************************************************************************
 * Description
 *	HBAAPILIB-sun.c - Implements the Sun Extention for Target mode
 *		FCHBA discovery
 *
 * 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.
 *
 *************************************************************************
 */
/*
 * 	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 <dlfcn.h>
#include "hbaapi.h"
#include "hbaapi-sun.h"
#include "vendorhbaapi.h"
#include <stdlib.h>
#ifdef USESYSLOG
#include <syslog.h>
#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))

extern int _hbaapi_debuglevel;
#define DEBUG(L, STR, A1, A2, A3)

#if defined(USESYSLOG) && defined(USELOGFILE)
extern FILE *_hbaapi_debug_fd;
extern int _hbaapi_sysloginit;
#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_INFO, (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

/*
 * HBA_LIBRARY_STATUS and HBA_LIBRARY_INFO are redefined here.
 * Avoid any change in the common code.
 */
typedef enum {
    HBA_LIBRARY_UNKNOWN,
    HBA_LIBRARY_LOADED,
    HBA_LIBRARY_NOT_LOADED
} HBA_LIBRARY_STATUS;

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;
    HBA_ENTRYPOINTSV2	functionTable;		/* Function pointers */
    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); \
	}

extern HBA_LIBRARY_INFO *_hbaapi_librarylist;
extern HBA_UINT32 _hbaapi_total_library_count;
#ifdef POSIX_THREADS
extern pthread_mutex_t _hbaapi_LL_mutex;
#elif defined(WIN32)
extern CRITICAL_SECTION _hbaapi_LL_mutex;
#endif

/*
 * Function type def fop Sun extentions.
 */
typedef HBA_UINT32	(* Sun_HBAGetNumberOfTgtAdaptersFunc)();
typedef HBA_STATUS	(* Sun_HBAGetTgtAdapterNameFunc)(HBA_UINT32, char *);
typedef HBA_HANDLE	(* Sun_HBAOpenTgtAdapterFunc)(char *);
typedef HBA_STATUS	(* Sun_HBAOpenTgtAdapterByWWNFunc)
			    (HBA_HANDLE *, HBA_WWN);
typedef	HBA_STATUS	(* Sun_HBANPIVGetAdapterAttributesFunc)
			    (HBA_HANDLE, HBA_ADAPTERATTRIBUTES *);
typedef	HBA_STATUS	(* Sun_HBAGetNPIVPortInfoFunc)
			    (HBA_HANDLE, HBA_UINT32, HBA_UINT32, HBA_NPIVATTRIBUTES *);
typedef HBA_STATUS	(* Sun_HBADeleteNPIVPortFunc)
			    (HBA_HANDLE, HBA_UINT32, HBA_WWN);
typedef HBA_STATUS	(* Sun_HBACreateNPIVPortFunc)
			    (HBA_HANDLE, HBA_UINT32, HBA_WWN, HBA_WWN, HBA_UINT32 *);
typedef	HBA_STATUS	(* Sun_HBAAdapterReturnWWNFunc)
			    (HBA_HANDLE, HBA_UINT32, HBA_WWN *, HBA_WWN *);
typedef	HBA_STATUS	(* Sun_HBAAdapterCreateWWNFunc)
			    (HBA_HANDLE, HBA_UINT32, HBA_WWN *, HBA_WWN *, HBA_WWN *,
			    HBA_INT32);
typedef	HBA_STATUS	(* Sun_HBAGetPortNPIVAttributesFunc)
			    (HBA_HANDLE, HBA_UINT32, HBA_PORTNPIVATTRIBUTES *);
typedef	HBA_STATUS	(* Sun_HBARegisterForAdapterDeviceEventsFunc)
			    (void (*)(void *, HBA_WWN, HBA_UINT32, HBA_UINT32),
			    void *, HBA_HANDLE, HBA_WWN, HBA_CALLBACKHANDLE *);
typedef	HBA_STATUS	(* Sun_HBADoForceLipFunc)(HBA_HANDLE, int *);

/*
 * Individual adapter (hba) information
 * Same as hbaadapter with different structure name.
 */
typedef struct hba_tgtadapter_info {
    struct hba_tgtadapter_info
			*next;
    HBA_STATUS		GNstatus; /* status from GetTgtAdapterNameFunc */
    char		*name;
    HBA_WWN		nodeWWN;
    HBA_LIBRARY_INFO	*library;
    HBA_UINT32		index;
} HBA_TGTADAPTER_INFO;

/*
 * Make the list as an array with max size 16
 */
HBA_TGTADAPTER_INFO *_hbaapi_tgtadapterlist;
HBA_UINT32 _hbaapi_total_tgtadapter_count = 0;
#ifdef POSIX_THREADS
pthread_mutex_t _hbaapi_tgtAL_mutex = PTHREAD_MUTEX_INITIALIZER;
#elif defined(WIN32)
CRITICAL_SECTION _hbaapi_tgtAL_mutex;
#endif

/*
 * Common library internal. Mutex handling
 */
#ifdef POSIX_THREADS
static void
grab_mutex(pthread_mutex_t *mp) {
    int ret;
    if((ret = pthread_mutex_lock(mp)) != 0) {
	perror("pthread_mutex_lock - HBAAPI:");
	DEBUG(0, "pthread_mutex_lock returned %d", ret, 0, 0);
    }
}

static void
release_mutex(pthread_mutex_t *mp) {
    int ret;
    if((ret = pthread_mutex_unlock(mp)) != 0) {
	perror("pthread_mutex_unlock - HBAAPI:");
	DEBUG(0, "pthread_mutex_unlock returned %d", ret, 0, 0);
    }
}
#endif

/*
 * 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
Sun_HBA_GetNumberOfTgtAdapters()
{
    int j=0;
    HBA_LIBRARY_INFO	*lib_infop;
    Sun_HBAGetNumberOfTgtAdaptersFunc
			GetNumberOfTgtAdaptersFunc = NULL;
    Sun_HBAGetTgtAdapterNameFunc
			GetTgtAdapterNameFunc = NULL;
    HBA_BOOLEAN		found_name;
    HBA_TGTADAPTER_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_tgtAL_mutex);

    for (lib_infop = _hbaapi_librarylist;
	 lib_infop != NULL;
	 lib_infop = lib_infop->next) {

	if (lib_infop->status != HBA_LIBRARY_LOADED) {
	    continue;
	}

	if (lib_infop->hLibrary != NULL) {
            GetNumberOfTgtAdaptersFunc = (Sun_HBAGetNumberOfTgtAdaptersFunc)
		dlsym(lib_infop->hLibrary, "Sun_fcGetNumberOfTgtAdapters");
            GetTgtAdapterNameFunc = (Sun_HBAGetTgtAdapterNameFunc)
		dlsym(lib_infop->hLibrary, "Sun_fcGetTgtAdapterName");
	    if (GetNumberOfTgtAdaptersFunc == NULL ||
		GetTgtAdapterNameFunc == NULL)	{
		GetNumberOfTgtAdaptersFunc = GetTgtAdapterNameFunc = NULL;
                continue;
            }
	} else {
	    continue;
	}

	num_adapters = ((GetNumberOfTgtAdaptersFunc)());
#ifndef WIN32
	DEBUG(1, "HBAAPI: number of target mode adapters for %s = %d\n",
	      lib_infop->LibraryName, num_adapters, 0);
#else
	DEBUG(1, "HBAAPI: number of target mode_adapters for %s = %d\n",
	      lib_infop->LibraryPath, num_adapters, 0);
#endif

	for (j = 0; j < num_adapters; j++) {
	    found_name = 0;
	    status = (GetTgtAdapterNameFunc)(j, (char *)&adaptername);
	    if(status == HBA_STATUS_OK) {
		for(adapt_infop = _hbaapi_tgtadapterlist;
		    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_TGTADAPTER_INFO *)
		calloc(1, sizeof(HBA_TGTADAPTER_INFO));
	    if(adapt_infop == NULL) {
#ifndef WIN32
		fprintf(stderr,
			"HBA_GetNumberOfAdapters: calloc failed on sizeof:%d\n",
			sizeof(HBA_TGTADAPTER_INFO));
#endif
		RELEASE_MUTEX(&_hbaapi_tgtAL_mutex);
		RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex,
				     _hbaapi_total_tgtadapter_count);
	    }
	    if((adapt_infop->GNstatus = status) == HBA_STATUS_OK) {
		adapt_infop->name = strdup(adaptername);
	    } else {
		char dummyname[512];
		sprintf(dummyname, "NULLADAPTER-%s-%03d",
			lib_infop->LibraryPath, _hbaapi_total_tgtadapter_count);
		dummyname[255] = '\0';
		adapt_infop->name = strdup(dummyname);
	    }
	    adapt_infop->library = lib_infop;
	    adapt_infop->next = _hbaapi_tgtadapterlist;
	    adapt_infop->index = _hbaapi_total_tgtadapter_count;
	    _hbaapi_tgtadapterlist = adapt_infop;
	    _hbaapi_total_tgtadapter_count++;
	}
	GetNumberOfTgtAdaptersFunc = GetTgtAdapterNameFunc = NULL;
    }
    RELEASE_MUTEX(&_hbaapi_tgtAL_mutex);
    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, _hbaapi_total_tgtadapter_count);
}

HBA_STATUS
Sun_HBA_GetTgtAdapterName(
    HBA_UINT32 adapterindex,
    char *adaptername)
{
    HBA_TGTADAPTER_INFO	*adapt_infop;
    HBA_STATUS		ret = HBA_STATUS_ERROR_ILLEGAL_INDEX;

    if (adaptername == NULL) {
	    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_tgtAL_mutex);
    *adaptername = '\0';
    for(adapt_infop = _hbaapi_tgtadapterlist;
	adapt_infop != NULL;
	adapt_infop = adapt_infop->next) {

	if(adapt_infop->index == adapterindex) {
	    if(adapt_infop->name != NULL &&
	       adapt_infop->GNstatus == HBA_STATUS_OK) {
		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
Sun_HBA_OpenTgtAdapter(char* adaptername)
{
    HBA_HANDLE		handle;
    Sun_HBAOpenTgtAdapterFunc	OpenTgtAdapterFunc;
    HBA_TGTADAPTER_INFO	*adapt_infop;
    HBA_LIBRARY_INFO	*lib_infop;

    DEBUG(2, "OpenAdapter: %s", adaptername, 0, 0);

    if(_hbaapi_librarylist == NULL) {
	return(HBA_HANDLE_INVALID);
    }
    if (adaptername == NULL) {
	return(HBA_STATUS_ERROR_ARG);
    }
    handle = HBA_HANDLE_INVALID;
    GRAB_MUTEX(&_hbaapi_AL_mutex);
    for(adapt_infop = _hbaapi_tgtadapterlist;
	adapt_infop != NULL;
	adapt_infop = adapt_infop->next) {
	if (strcmp(adaptername, adapt_infop->name) != 0) {
	    continue;
	}
	lib_infop = adapt_infop->library;
        OpenTgtAdapterFunc = (Sun_HBAOpenTgtAdapterFunc)
		dlsym(lib_infop->hLibrary, "Sun_fcOpenTgtAdapter");
	if (OpenTgtAdapterFunc != NULL) {
	    /* retrieve the vendor handle */
	    handle = (OpenTgtAdapterFunc)(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);
}

/*
 * This function ignores the list of known adapters and instead tries
 * each vendors open function to see if one of them
 * can open an adapter when referenced with a particular WWN
 */
HBA_STATUS
Sun_HBA_OpenTgtAdapterByWWN(HBA_HANDLE *phandle, HBA_WWN nodeWWN)
{
    HBA_HANDLE		handle;
    HBA_LIBRARY_INFO	*lib_infop;
    Sun_HBAGetNumberOfTgtAdaptersFunc
			GetNumberOfTgtAdaptersFunc;
    Sun_HBAOpenTgtAdapterByWWNFunc
			OpenTgtAdapterByWWNFunc;
    HBA_STATUS		status;

    DEBUG(2, "OpenAdapterByWWN: %s", WWN2STR1(&nodeWWN), 0, 0);

    if (phandle == NULL) {
	    return(HBA_STATUS_ERROR_ARG);
    }

    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;
	}

        GetNumberOfTgtAdaptersFunc = (Sun_HBAGetNumberOfTgtAdaptersFunc)
		dlsym(lib_infop->hLibrary, "Sun_fcGetNumberOfTgtAdapters");
        OpenTgtAdapterByWWNFunc = (Sun_HBAOpenTgtAdapterByWWNFunc)
		dlsym(lib_infop->hLibrary, "Sun_fcOpenTgtAdapterByWWN");
	if (GetNumberOfTgtAdaptersFunc == NULL ||
		OpenTgtAdapterByWWNFunc == NULL) {
		GetNumberOfTgtAdaptersFunc = OpenTgtAdapterByWWNFunc = NULL;
                continue;
        }

	(void) ((GetNumberOfTgtAdaptersFunc)());

	if((status = (OpenTgtAdapterByWWNFunc)(&handle, nodeWWN))
	    != HBA_STATUS_OK) {
	    GetNumberOfTgtAdaptersFunc = OpenTgtAdapterByWWNFunc = NULL;
	    continue;
	}
	/* OK, make a vendor non-specific handle */
	*phandle = HBA_HANDLE_FROM_LOCAL(lib_infop->index, handle);
	status = HBA_STATUS_OK;
	break;

	GetNumberOfTgtAdaptersFunc = OpenTgtAdapterByWWNFunc = NULL;
    }
    RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
}

static HBA_STATUS
HBA_NPIV_CheckLibrary(HBA_HANDLE handle,
			HBA_LIBRARY_INFO **lib_infopp,
			HBA_HANDLE *vendorhandle) {
	HBA_UINT32		libraryIndex;
	HBA_LIBRARY_INFO	*lib_infop;

	if (vendorhandle == NULL) {
		return(HBA_STATUS_ERROR_ARG);
	}
	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	NPIVCHECKLIBRARY() \
	status = HBA_NPIV_CheckLibrary(handle, &lib_infop, &vendorHandle); \
	if(status != HBA_STATUS_OK) { \
		return(status); \
	}

HBA_STATUS
Sun_HBA_NPIVGetAdapterAttributes (
    HBA_HANDLE		handle,
    HBA_ADAPTERATTRIBUTES
			*hbaattributes)
{
	HBA_STATUS		status;
	HBA_LIBRARY_INFO	*lib_infop;
	HBA_HANDLE		vendorHandle;
	Sun_HBANPIVGetAdapterAttributesFunc	NPIVGetAdapterAttributesFunc;

	DEBUG(2, "HBA_NPIVGetAdapterAttributes", 0, 0, 0);

	NPIVCHECKLIBRARY();
	NPIVGetAdapterAttributesFunc = (Sun_HBANPIVGetAdapterAttributesFunc)
	    dlsym(lib_infop->hLibrary, "Sun_fcNPIVGetAdapterAttributes");
	if (NPIVGetAdapterAttributesFunc != NULL) {
		status = ((NPIVGetAdapterAttributesFunc)(vendorHandle,
			hbaattributes));
	} else {
		status = HBA_STATUS_ERROR_NOT_SUPPORTED;
	}
	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
}

HBA_STATUS
Sun_HBA_GetNPIVPortInfo (
    HBA_HANDLE		handle,
    HBA_UINT32		portindex,
    HBA_UINT32		vportindex,
    HBA_NPIVATTRIBUTES	*attributes)
{
	HBA_STATUS		status;
	HBA_LIBRARY_INFO	*lib_infop;
	HBA_HANDLE		vendorHandle;
	Sun_HBAGetNPIVPortInfoFunc	GetNPIVPortInfoFunc;

	NPIVCHECKLIBRARY();
	GetNPIVPortInfoFunc = (Sun_HBAGetNPIVPortInfoFunc)
		dlsym(lib_infop->hLibrary, "Sun_fcGetNPIVPortInfo");
	if (GetNPIVPortInfoFunc != NULL) {
		status = ((GetNPIVPortInfoFunc)(vendorHandle, portindex,
			vportindex, attributes));
	} else {
		status = HBA_STATUS_ERROR_NOT_SUPPORTED;
	}
	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
}

HBA_STATUS
Sun_HBA_DeleteNPIVPort (
    HBA_HANDLE		handle,
    HBA_UINT32		portindex,
    HBA_WWN		vportWWN)
{
	HBA_STATUS		status;
	HBA_LIBRARY_INFO	*lib_infop;
	HBA_HANDLE		vendorHandle;
	Sun_HBADeleteNPIVPortFunc	DeleteNPIVPortFunc;

	NPIVCHECKLIBRARY();
	DeleteNPIVPortFunc = (Sun_HBADeleteNPIVPortFunc)
		dlsym(lib_infop->hLibrary, "Sun_fcDeleteNPIVPort");
	if (DeleteNPIVPortFunc != NULL) {
		status = ((DeleteNPIVPortFunc)(vendorHandle,
		    portindex, vportWWN));
	} else {
		status = HBA_STATUS_ERROR_NOT_SUPPORTED;
	}
	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
}

HBA_STATUS
Sun_HBA_CreateNPIVPort (
    HBA_HANDLE		handle,
    HBA_UINT32		portindex,
    HBA_WWN		vnodeWWN,
    HBA_WWN		vportWWN,
    HBA_UINT32		*vportindex)
{
	HBA_STATUS		status;
	HBA_LIBRARY_INFO	*lib_infop;
	HBA_HANDLE		vendorHandle;
	Sun_HBACreateNPIVPortFunc	CreateNPIVPortFunc;

	NPIVCHECKLIBRARY();
	CreateNPIVPortFunc = (Sun_HBACreateNPIVPortFunc)
		dlsym(lib_infop->hLibrary, "Sun_fcCreateNPIVPort");
	if (CreateNPIVPortFunc != NULL) {
		status = ((CreateNPIVPortFunc)(vendorHandle,
		    portindex, vnodeWWN, vportWWN, vportindex));
	} else {
		status = HBA_STATUS_ERROR_NOT_SUPPORTED;
	}
	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
}

HBA_STATUS
Sun_HBA_GetPortNPIVAttributes (
    HBA_HANDLE		handle,
    HBA_UINT32		portindex,
    HBA_PORTNPIVATTRIBUTES	*portnpivattributes)
{
	HBA_STATUS		status;
	HBA_LIBRARY_INFO	*lib_infop;
	HBA_HANDLE		vendorHandle;
	Sun_HBAGetPortNPIVAttributesFunc	GetPortNPIVAttributesFunc;

	NPIVCHECKLIBRARY();
	GetPortNPIVAttributesFunc = (Sun_HBAGetPortNPIVAttributesFunc)
		dlsym(lib_infop->hLibrary, "Sun_fcGetPortNPIVAttributes");
	if (GetPortNPIVAttributesFunc != NULL) {
		status = ((GetPortNPIVAttributesFunc)(
		    vendorHandle, portindex, portnpivattributes));
	} else {
		status = HBA_STATUS_ERROR_NOT_SUPPORTED;
	}
	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
}

HBA_STATUS
Sun_HBA_AdapterCreateWWN (
    HBA_HANDLE		handle,
    HBA_UINT32		portindex,
    HBA_WWN		*nwwn,
    HBA_WWN		*pwwn,
    HBA_WWN		*OUI,
    HBA_INT32		method)
{
	HBA_STATUS		status;
	HBA_LIBRARY_INFO	*lib_infop;
	HBA_HANDLE		vendorHandle;
	Sun_HBAAdapterCreateWWNFunc	AdapterCreateWWNFunc;

	NPIVCHECKLIBRARY();
	AdapterCreateWWNFunc = (Sun_HBAAdapterCreateWWNFunc)
		dlsym(lib_infop->hLibrary, "Sun_fcAdapterCreateWWN");
	if (AdapterCreateWWNFunc != NULL) {
		status = ((AdapterCreateWWNFunc)(vendorHandle,
		    portindex, nwwn, pwwn, OUI, method));
	} else {
		status = HBA_STATUS_ERROR_NOT_SUPPORTED;
	}
	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
}

HBA_STATUS
Sun_HBA_AdapterReturnWWN (
    HBA_HANDLE		handle,
    HBA_UINT32		portindex,
    HBA_WWN		*nwwn,
    HBA_WWN		*pwwn)
{
	HBA_STATUS		status;
	HBA_LIBRARY_INFO	*lib_infop;
	HBA_HANDLE		vendorHandle;
	Sun_HBAAdapterReturnWWNFunc	AdapterReturnWWNFunc;

	NPIVCHECKLIBRARY();
	AdapterReturnWWNFunc = (Sun_HBAAdapterReturnWWNFunc)
		dlsym(lib_infop->hLibrary, "Sun_fcAdapterReturnWWN");
	if (AdapterReturnWWNFunc != NULL) {
		status = ((AdapterReturnWWNFunc)(vendorHandle,
		    portindex, nwwn, pwwn));
	} else {
		status = HBA_STATUS_ERROR_NOT_SUPPORTED;
	}
	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
}

typedef struct hba_npivadaptercallback_elem {
    struct hba_npivadaptercallback_elem
			*next;
    HBA_LIBRARY_INFO	*lib_info;
    void		*userdata;
    HBA_CALLBACKHANDLE	vendorcbhandle;
    void		(*callback)();
} HBA_NPIVADAPTERCALLBACK_ELEM;
extern HBA_NPIVADAPTERCALLBACK_ELEM *_hbaapi_adapterdeviceevents_callback_list;

/* Adapter Device Events ********************************************************/
static void
adapterdeviceevents_callback (void *data,
    HBA_WWN	PortWWN,
    HBA_UINT32	eventType,
    HBA_UINT32	fabricPortID)
{
	HBA_NPIVADAPTERCALLBACK_ELEM	*acbp;

	DEBUG(3, "AdapterDeviceEvent, port:%s, eventType:%d fabricPortID:0X%06x",
	    WWN2STR1(&PortWWN), eventType, fabricPortID);

	GRAB_MUTEX(&_hbaapi_APE_mutex);

	for(acbp = _hbaapi_adapterdeviceevents_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
Sun_HBA_RegisterForAdapterDeviceEvents (
    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_NPIVADAPTERCALLBACK_ELEM	*acbp;
	HBA_STATUS			status;
	HBA_LIBRARY_INFO		*lib_infop;
	HBA_HANDLE			vendorHandle;
	Sun_HBARegisterForAdapterDeviceEventsFunc
					registeredfunc;

	if (callbackHandle == NULL) {
		return(HBA_STATUS_ERROR_ARG);
	}

        NPIVCHECKLIBRARY();
	registeredfunc = (Sun_HBARegisterForAdapterDeviceEventsFunc)
                dlsym(lib_infop->hLibrary,
		    "Sun_fcRegisterForAdapterDeviceEvents");
	if (registeredfunc == NULL) {
		RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_ERROR_NOT_SUPPORTED);
	}

	acbp = (HBA_NPIVADAPTERCALLBACK_ELEM *)
		calloc(1, sizeof(HBA_NPIVADAPTERCALLBACK_ELEM));

	if(acbp == NULL) {
		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)(adapterdeviceevents_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_adapterdeviceevents_callback_list;
	_hbaapi_adapterdeviceevents_callback_list = acbp;
	RELEASE_MUTEX(&_hbaapi_APE_mutex);

	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, HBA_STATUS_OK);
}

HBA_STATUS
Sun_HBA_ForceLip(HBA_HANDLE handle, int *rval)
{
	HBA_STATUS		status;
	HBA_LIBRARY_INFO	*lib_infop;
	HBA_HANDLE		vendorHandle;

	Sun_HBADoForceLipFunc	DoForceLipFunc;

	DEBUG(2, "Sun_HBA_DoForceLip", 0, 0, 0);

	NPIVCHECKLIBRARY();
	DoForceLipFunc = (Sun_HBADoForceLipFunc)
		dlsym(lib_infop->hLibrary, "Sun_fcDoForceLip");
	if (DoForceLipFunc != NULL) {
		status = ((DoForceLipFunc)(vendorHandle, rval));
	} else {
		status = HBA_STATUS_ERROR_NOT_SUPPORTED;
	}
	RELEASE_MUTEX_RETURN(&_hbaapi_LL_mutex, status);
}