OpenSolaris_b135/lib/mpapi/libmpapi/common/mpapi.c

Compare this file to the similar file:
Show the results in this format:

/******************************************************************************
 *
 * Description
 * mpapi.c - Implements Multipath Management API Version 1.0 
 *
 * 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
 *
 *  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 iSCSI Management API and Multipath Management
 *	API header files.
 *
 * The Initial Developer of the Original Code is:
 *	Benjamin F. Kuo Troika Networks, Inc. (benk@troikanetworks.com)
 *	David Dillard	VERITAS Software(david.dillard@veritas.com)
 *	Jeff Ding 	Adaptec, Inc. (jding@corp.adaptec.com)
 *      Hyon Kim        Sun Microsystems(hyon.kim@sun.com)
 *
 * Contributor(s):
 *	Paul von Behren Sun Microsystems(paul.vonbehren@sun.com)
 *
 ******************************************************************************
 *
 *   Changes:
 *  1/15/2005	Implemented SNIA MP API specification 1.0 
 *  10/11/2005
 * 		- License location was specified in the header comment.
 *  	    	- validate_object() routine was updated per the latest
 *		  specification.
 *  		- is_zero_oid() routine was added.
 *  		- MP_GetObjectType() was updated with validate_object().
 *  		- pplist argument checking added in MP_GetMultipathLus().
 *  		- Corrected typo in MP_GetTaregetPortGroupProperties()
 *  		- MP_RegisterForObjectPropertyChanges() was updated with
 *		  is_zero_oid() routine.		
 *  		- MP_DeregisterForObjectPropertyChanges() was updated with
 *		  is_zero_oid() routine.		
 *		- MP_RegisterForObjectVisibilityChanges() was updated with
 *		  is_zero_oid() routine.		
 *		- MP_DeregisterForObjectVisibilityChanges() was updated with
 *		  is_zero_oid() routine.		
 *  		- Added stat() check in MP_RegisterPlugin() to validate the
 *		  the given plugin file name.
 *  		- Made MP_DeregisterPlugin() return MP_STATUS_UNKNOWN_FN
 *		  to mach the specification description.
 ******************************************************************************
 */

#include <sys/sem.h>
#include <dlfcn.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <pthread.h>
#include "mpapi.h"
#include "mpapi-sun.h"
#include "mpapi-plugin.h"

#define LIBRARY_SUPPORTED_MP_VERSION	1
#define LIBRARY_IMPLEMENTATION_VERSION	L"1.0.0"
#define LIBRARY_VENDOR			L"Sun Microsystems Inc."

#define LIBRARY_FILE_NAME               "libMPAPI.so"


MPPLUGININFO_T	plugintable[MP_MAX_NUM_PLUGINS];
pthread_mutex_t mp_lib_mutex = PTHREAD_MUTEX_INITIALIZER;

static int	number_of_plugins = -1;


void InitLibrary();
void ExitLibrary();
static int lock_register(int fd, int cmd, int type, off_t offset, int whence,
	    off_t len);
static int search_line(MP_CHAR *buf, size_t buflen, MP_CHAR *srch_id,
	    size_t id_len, int *write_offset, int *bytes_left);
static int is_zero_oid(MP_OID);

/**
 ******************************************************************************
 *
 * Validate the oid.
 *
 * - Return MP_STATUS_OBJECT_NOT_FOUND when no plugin is found or the ownerId 
 *      of input OID is not found.
 * - Return MP_STATUS_INVALID_OBJECT_TYPE when no plugin is found or
 *      the type of input OID is not one of legitimate types defined SNIA 
 *      Multipath Management spec.
 * - Return MP_STATUS_INVALID_PARAMETER when the type of input OID is
 *	legitimate but its object type doesn't match with the object type 
 *      argument.
 * - Otherwise return MP_STATUS_SUCCESS.
 *
 ******************************************************************************
 */
MP_STATUS validate_object(MP_OID obj, MP_OBJECT_TYPE objType,
    MP_UINT32 flag)
{

    if ((number_of_plugins == 0) ||
	(obj.ownerId > number_of_plugins || obj.ownerId <= 0)) {
	return (MP_STATUS_OBJECT_NOT_FOUND);
    } else if (obj.objectType < 0 || obj.objectType > MP_OBJECT_TYPE_MAX) {
	return (MP_STATUS_INVALID_OBJECT_TYPE);
    } else if (obj.objectType == MP_OBJECT_TYPE_PLUGIN) {
	if (obj.objectSequenceNumber != 0) {
	    return (MP_STATUS_OBJECT_NOT_FOUND);
	}
    }

    if (flag == MP_OBJECT_TYPE_MATCH) {
    	if (obj.objectType != objType) {
	    return (MP_STATUS_INVALID_PARAMETER);
        }
    }
    return (MP_STATUS_SUCCESS);
}

/**
 ******************************************************************************
 *
 * Check if an oid is ZERO_OID or not.
 *
 * - Return 1 if the input OID is ZERO_OID 
 *
 * - Return 0 if not.
 *
 ******************************************************************************
 */
static int is_zero_oid(MP_OID oid)
{

    if ((oid.objectType != MP_OBJECT_TYPE_UNKNOWN) || (oid.ownerId != 0) ||
	(oid.objectSequenceNumber != 0)) {
	return (0);
    }

    return (1);
}

/**
 ******************************************************************************
 *
 * Initialize by loading plugin libraries and calling Initialize routine.
 * Note: The build of libMPAPI.so should include a linker option to make this
 *	 routine executed when it is loaded.
 *
 * - This routine bypasses a plugin library if it is not found.
 * - The implementation of this routine is based on configuration file
 *   /etc/mpapi.conf that contains a list of plugin libraries.
 *
 ******************************************************************************
 */
void InitLibrary()
{
	FILE *mpconf;		
	int fd_mpconf;
	MP_WCHAR fullline[MAX_LINE_SIZE]; /* line read in from mpapi.conf */
	MP_WCHAR name[MAX_NAME_SIZE]; 	/* Read in from file mpapi.conf */
	char path[MAX_NAME_SIZE]; 	/* Read in from file mpapi.conf */
	char systemPath[MAX_NAME_SIZE], mpConfFilePath[MAX_NAME_SIZE];
	MP_WCHAR *charPtr;
	MP_WCHAR *sol;
	struct stat	stat_buf;

	MP_UINT32 i = 0;	/* index for plugin table */

	if(number_of_plugins != -1) {
		return;
	}

	(void) pthread_mutex_lock(&mp_lib_mutex);

	number_of_plugins = 0;

	/* Open configuration file from known location */
	strncpy(mpConfFilePath, "/etc/mpapi.conf", MAX_NAME_SIZE);

	if ((fd_mpconf = open(mpConfFilePath, O_RDONLY)) < 0) {
		(void) pthread_mutex_unlock(&mp_lib_mutex);
		return;
	}
	    
	if (lock_register(fd_mpconf, F_SETLKW, F_RDLCK, 0, SEEK_SET, 0) < 0) {
		close(fd_mpconf);
		(void) pthread_mutex_unlock(&mp_lib_mutex);
		return;
	}

	if ((mpconf = fdopen(fd_mpconf, "r")) == NULL) {
		lock_register(fd_mpconf, F_SETLK, F_UNLCK, 0, SEEK_SET, 0);
		close(fd_mpconf);
		(void) pthread_mutex_unlock(&mp_lib_mutex);
		return;
	}

	/* Read in each line and load library */
	while ((mpconf != NULL) &&
	    (charPtr = fgetws(fullline, MAX_LINE_SIZE, mpconf))) {
	    if ((*charPtr != L'#') && (*charPtr != L'\n')) {
		/* Take out the '\n' */
		if ((charPtr = wcschr(fullline, L'\n')) != NULL)
		    *charPtr = L'\0';

		charPtr = fullline;
		/* remove leading blank or taps. */
		while ((fullline[0] == L' ') || (fullline[0] == L'\t'))
			charPtr++;

		sol = charPtr;

		/*
		 * look for first tab or space. 
		 */
		if ((charPtr = wcschr(fullline, L'\t')) == NULL)
		    charPtr = wcschr(fullline, L' ');

		/* Set Null termination for library name if found */
		if (charPtr != NULL) {
		    *charPtr++ = L'\0';
		    wcsncpy(name, sol, MAX_NAME_SIZE);
			/* Skip space and tab until the next character found */
		    while ((*charPtr == L' ') || (*charPtr == L'\t'))
			charPtr++;
		} else {
		    continue;	/* May be invalid entry */
		}

		/* Copy library name and path */
		wcstombs(path, charPtr, MAX_NAME_SIZE);

		/*
		 * Continue to the next line if library name or path is
		 * invalid 
		 */
		if ((wcslen(name) == 0) ||
			(strlen(path) == 0))
		    continue;

		/* Load the plugin now */
		if (stat(path, &stat_buf) != -1) {
		    plugintable[i].hdlPlugin = dlopen(path, RTLD_LAZY);
		} else {
		    continue;
		}

		if (plugintable[i].hdlPlugin != NULL) {
		    InitializeFn PassFunc;
		    MP_STATUS status;

                    wcsncpy(plugintable[i].pluginName,
                        name, MAX_NAME_SIZE);
                    strncpy(plugintable[i].pluginPath,
                        path, MAX_NAME_SIZE);

		    plugintable[i].ownerId = i + 1;

		    PassFunc = (InitializeFn)
			 dlsym(plugintable[i].hdlPlugin, "Initialize");
		    if (PassFunc != NULL) {
			status = PassFunc(plugintable[i].ownerId);
		    }

		    i++;
		}
	    }
	}

	if (lock_register(fd_mpconf, F_SETLK, F_UNLCK, 0, SEEK_SET, 0) < 0) {
	    fclose(mpconf);
	    close(fd_mpconf);
	    (void) pthread_mutex_unlock(&mp_lib_mutex);
	    return;
	}
	fclose(mpconf);
	close(fd_mpconf);

	number_of_plugins = i;
	(void) pthread_mutex_unlock(&mp_lib_mutex);
}

/**
 ******************************************************************************
 *
 * Exit by calling Terminate routine of plugin libraries.
 *
 * Note: The build of libMPAPI.so should include a linker option to make this
 *	 routine executed when it is unloaded.
 *
 ******************************************************************************
 */
void ExitLibrary()
{
    MP_UINT32 i, j;

    if(number_of_plugins == -1)
        return;

    (void) pthread_mutex_lock(&mp_lib_mutex);
    for (i = 0; i < number_of_plugins; i++) {
        if (plugintable[i].hdlPlugin != NULL) {
        TerminateFn ExitPassFunc;

        ExitPassFunc = (TerminateFn)
            dlsym(plugintable[i].hdlPlugin, "Terminate");

        if (ExitPassFunc != NULL) {
            ExitPassFunc();
        }

        /* Unload plugin from memory */
        dlclose(plugintable[i].hdlPlugin);
        }
    }

    number_of_plugins = -1;

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    (void) pthread_mutex_destroy(&mp_lib_mutex);
}

/**
 ******************************************************************************
 *
 * Gets the properties of the MP API library that is being used.
 *
 * @param pProps
 *  A pointer to an @ref MP_LIBRARY_PROPERTIES structure allocated by
 *  the caller.  On successful return this structure will contain the
 *  properties of the MP library.
 *
 * @return An MP_STATUS indicating if the operation was successful or
 *  if an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *  Returned if the library properties were successfully returned.
 *
 * @retval MP_STATUS_INVALID_PARAMETER Returned if @a pProps is NULL or
 *  specifies a memory area to which data cannot be written.
 *
 ******************************************************************************
 */
MP_STATUS MP_GetLibraryProperties(
    MP_LIBRARY_PROPERTIES *pProps)
{
    char mpPath[MAX_NAME_SIZE];

    if(pProps == NULL) {
        return MP_STATUS_INVALID_PARAMETER;
    }

    /* Fill in properties */
    if (mbstowcs(pProps->buildTime, BUILD_TIME, 256) !=
	strlen(BUILD_TIME)) {
	return (MP_STATUS_INVALID_PARAMETER);
    }
    pProps->supportedMpVersion = LIBRARY_SUPPORTED_MP_VERSION;

    wcsncpy(pProps->implementationVersion,
	LIBRARY_IMPLEMENTATION_VERSION, MAX_NAME_SIZE);
    wcsncpy(pProps->vendor, LIBRARY_VENDOR, MAX_NAME_SIZE);

    snprintf(pProps->fileName, MAX_NAME_SIZE, "%s",
	LIBRARY_FILE_NAME);

    return MP_STATUS_SUCCESS;
}


/**
 ******************************************************************************
 *
 * Gets a list of the object IDs of all currently loaded plugins.
 *
 * @param ppList A pointer to a pointer to an @ref MP_OID_LIST.  On successful
 *  return this will contain a pointer to an @ref MP_OID_LIST
 *  which contains the object IDs of all of the plugins currently loaded
 *  by the library.
 * @return An MP_STATUS indicating if the operation was successful or if
 * an error
 *              occurred.
 * @retval MP_SUCCESS Returned if the plugin ID list was successfully returned.
 * @retval MP_STATUS_INVALID_PARAMETER Returned if @a ppList is NULL or
 * specifies a memory area to which data cannot be written.
 *
 ******************************************************************************
 */
MP_STATUS MP_GetPluginOidList(
    MP_OID_LIST **ppList)
{
    MP_UINT32  i;

    if (ppList == NULL)
        return (MP_STATUS_INVALID_PARAMETER);

    (void) pthread_mutex_lock(&mp_lib_mutex);

    if (number_of_plugins == 0) {
        *ppList = (MP_OID_LIST*)calloc(1, sizeof(MP_OID_LIST));
    } else {
        *ppList = (MP_OID_LIST*)calloc(1,
        sizeof(MP_OID_LIST) + (number_of_plugins - 1)* sizeof(MP_OID) );
    }

    if ((*ppList) == NULL) {
    	(void) pthread_mutex_unlock(&mp_lib_mutex);
        return (MP_STATUS_INSUFFICIENT_MEMORY);
    }

    (*ppList)->oidCount = number_of_plugins;

    if (number_of_plugins != 0) {
        for (i = 0; i < number_of_plugins; i++) {
        (*ppList)->oids[i].objectType = MP_OBJECT_TYPE_PLUGIN;
        (*ppList)->oids[i].ownerId = plugintable[i].ownerId;
        (*ppList)->oids[i].objectSequenceNumber = 0;
        }
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return MP_STATUS_SUCCESS;
}

/**
 *******************************************************************************
 *
 * Gets the properties of the specified vendor plugin.
 *
 * @param  oid
 *         The ID of the plugin whose properties are being retrieved.
 *
 * @param  pProps
 *         A pointer to an @ref MP_PLUGIN_PROPERTIES structure allocated by
 *         the caller.  On successful return this will contain the properties
 *         of the plugin specified by pluginOid.
 *
 * @return An MP_STATUS indicating if the operation was successful or if an
 *         error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned if the plugin properties were successfully returned.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *         Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *         Returned if oid has an owner that is not currently known to
 *     the system.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *         Returned if 'pProps' is NULL or specifies a memory area to
 *         which data cannot be written.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetPluginProperties(
    MP_OID pluginOid,
    MP_PLUGIN_PROPERTIES *pProps)
{
    MP_GetPluginPropertiesPluginFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if(pProps == NULL)
        return (MP_STATUS_INVALID_PARAMETER);

    if ((status = validate_object(pluginOid, MP_OBJECT_TYPE_PLUGIN,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = pluginOid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetPluginPropertiesPluginFn)
        dlsym(plugintable[index].hdlPlugin, "MP_GetPluginPropertiesPlugin");

        if (PassFunc != NULL) {
            status = PassFunc(pProps);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return status;
}

/**
 *******************************************************************************
 *
 * Gets the object ID for the plugin associated with the specified object ID.
 *
 * @param  oid
 *         The object ID of an object that has been received from a previous
 *         library call.
 *
 * @param  pPluginOid
 *         A pointer to an MP_OID structure allocated by the caller.  On
 *         successful return this will contain the object ID of the plugin
 *         associated with the object specified by @a objectId.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *          Returned if the associated plugin ID was successfully returned.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *          Returned if oid does not specify a plugin that is currently known to
 *     the system.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *          Returned if 'oid' specifies an object not owned by a plugin or
 *     if pPluginOid is NULL or specifies a memory area to which data
 *     cannot be written.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *         Returned if 'oid' specifies an object with an invalid type.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetAssociatedPluginOid(
    MP_OID objectId,
    MP_OID *pPluginId)
{
    MP_UINT32 i;
    MP_STATUS status;

    if (pPluginId == NULL)
        return (MP_STATUS_INVALID_PARAMETER);

    if ((status = validate_object(objectId, 0, MP_OBJECT_TYPE_ANY)) !=
            MP_STATUS_SUCCESS) {
        return (status);
    }

    pPluginId->objectType = MP_OBJECT_TYPE_PLUGIN;
    pPluginId->ownerId = objectId.ownerId;
    pPluginId->objectSequenceNumber = 0;

    return (MP_STATUS_SUCCESS);
}

/**
 *******************************************************************************
 *
 * Gets the object type of an initialized object ID.
 *
 * @param  oid
 *         The object ID of an object that has been received from a previous
 *         library call.
 *
 * @param  pObjectType
 *         A pointer to an MP_OBJECT_TYPE variable allocated by the caller.
 *         On successful return this will contain the object type of oid.
 *
 * @return An MP_STATUS indicating if the operation was successful or
 *         if an error occurred.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *      Returned if oid has an owner that is not currently known to
 *      the system.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetObjectType(
    MP_OID oid,
    MP_OBJECT_TYPE *pObjectType)
{
    MP_STATUS status;

    if (pObjectType == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, 0, MP_OBJECT_TYPE_ANY))
	!= MP_STATUS_SUCCESS) {
        return (status);
    }

    *pObjectType = oid.objectType;
    return MP_STATUS_SUCCESS;
}

/**
 *******************************************************************************
 *
 * Gets a list of the object IDs of all the device product properties
 *       associated with this plugin.
 *
 * @param  oid
 *         The object ID of plugin.
 *
 * @param  ppList
 *      A pointer to a pointer to an MP_OID_LIST structure.
 *      On a successful return, this will contain a pointer to
 *      an MP_OID_LIST that contains the object IDs of all the device
 *      product descriptors associated with the specified plugin.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if ppList pointer passed as placeholder for holding
 *      the device product list is found to be invalid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *         Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_FAILED
 *         Returned when the plugin for the specified oid is not found.
 *
 * @retval MP_STATUS_INSUFFICIENT_MEMORY
 *      Returned when memory allocation failure occurs
 *
 * @retval MP_STATUS_UNSUPPORTED
 *      Returned when the API is not supported.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetDeviceProductOidList(
    MP_OID oid,
    MP_OID_LIST **ppList)
{
    MP_GetDeviceProductOidListPluginFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (ppList == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetDeviceProductOidListPluginFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_GetDeviceProductOidListPlugin");
        if (PassFunc != NULL) {
	    status = PassFunc(ppList);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return status;
}

/**
 *******************************************************************************
 *
 * Gets the device product properties of the specified plugin oid.
 *
 * @param  oid
 *         The object ID of the plugin.
 *
 * @param  ppProps
 *      A pointer to a pointer to an MP_DEVICE_PRODUCT_PROPERTIES structure
 *      allocated by the caller. On successful return it will contain
 *      a pointer to an MP_DEVICE_PRODUCT_PROPERTIES structure allocated
 *      by the library.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if ppProps pointer passed as placeholder for holding
 *      the device product properties is found to be invalid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *         Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_FAILED
 *         Returned when the plugin for the specified oid is not found.
 *
 * @retval MP_STATUS_INSUFFICIENT_MEMORY
 *      Returned when memory allocation failure occurs
 *
 * @retval MP_STATUS_UNSUPPORTED
 *      Returned when the API is not supported.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetDeviceProductProperties(
        MP_OID oid,
        MP_DEVICE_PRODUCT_PROPERTIES *pProps)
{
    MP_GetDeviceProductPropertiesFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (pProps == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_DEVICE_PRODUCT,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetDeviceProductPropertiesFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_GetDeviceProductProperties");

        if (PassFunc != NULL) {
	    status = PassFunc(oid, pProps);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return status;
}

/**
 *******************************************************************************
 *
 * Gets a list of the object IDs of all the initiator ports associated
 * with this plugin.
 *
 * @param  oid
 *         The object ID of plugin.
 *
 * @param  ppList
 *      A pointer to a pointer to an MP_OID_LIST structure.
 *      On a successful return, this will contain a pointer to
 *      an MP_OID_LIST that contains the object IDs of all the initiator
 *      ports associated with the specified plugin.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if ppList pointer passed as placeholder for holding
 *      the initiator port list is found to be invalid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_FAILED
 *          Returned when the plugin for the specified oid is not found.
 *
 * @retval MP_STATUS_INSUFFICIENT_MEMORY
 *      Returned when memory allocation failure occurs
 *
 * @retval MP_STATUS_UNSUPPORTED
 *      Returned when the API is not supported.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetInitiatorPortOidList(
        MP_OID oid,
        MP_OID_LIST **ppList)
{
    MP_GetInitiatorPortOidListPluginFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (ppList == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetDeviceProductOidListPluginFn)
        dlsym(plugintable[index].hdlPlugin, "MP_GetInitiatorPortOidListPlugin");

        if (PassFunc != NULL) {
	    status = PassFunc(ppList);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Gets the properties of the specified initiator port.
 *
 * @param  oid
 *         The object ID of the initiator port.
 *
 * @param  pProps
 *      A pointer to an MP_INITIATOR_PORT_PROPERTIES structure
 *      allocated by the caller. On successful return, this structure
 *      will contain the properties of the port specified by oid.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pProps is NULL or specifies a memory area to
 *      which data cannot be written.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *          Returned if oid has an owner that is not currently known to
 *      the system.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetInitiatorPortProperties(
        MP_OID oid,
        MP_INITIATOR_PORT_PROPERTIES *pProps)
{
    MP_GetInitiatorPortPropertiesFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (pProps == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_INITIATOR_PORT,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetInitiatorPortPropertiesFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_GetInitiatorPortProperties");

        if (PassFunc != NULL) {
	    status = PassFunc(oid, pProps);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return status;
}

/**
 *******************************************************************************
 *
 * Gets a list of multipath logical units associated to a plugin.
 *
 * @param  oid
 *         The object ID of plugin.
 *
 * @param  ppList
 *      A pointer to a pointer to an MP_OID_LIST structure.
 *      On a successful return, this will contain a pointer to
 *      an MP_OID_LIST that contains the object IDs of all the multipath
 *      logical units associated with the specified plugin.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if ppList pointer passed as placeholder for holding
 *      the multipath logical unit list is found to be invalid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_FAILED
 *          Returned when the plugin for the specified oid is not found.
 *
 * @retval MP_STATUS_INSUFFICIENT_MEMORY
 *      Returned when memory allocation failure occurs
 *
 * @retval MP_STATUS_UNSUPPORTED
 *      Returned when the API is not supported.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetMultipathLus(
        MP_OID oid,
        MP_OID_LIST **ppList)
{
    MP_UINT32 index;
    MP_STATUS status;

    if (ppList == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
	((status = validate_object(oid, MP_OBJECT_TYPE_DEVICE_PRODUCT,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
	    MP_GetMultipathLusPluginFn PassFunc;
	    PassFunc = (MP_GetMultipathLusPluginFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_GetMultipathLusPlugin");

	    if (PassFunc != NULL) {
		status = PassFunc(ppList);
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else if (oid.objectType == MP_OBJECT_TYPE_DEVICE_PRODUCT) {
	    MP_GetMultipathLusDevProdFn PassFunc;
	    PassFunc = (MP_GetMultipathLusDevProdFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_GetMultipathLusDevProd");

	    if (PassFunc != NULL) {
		status = PassFunc(oid, ppList);
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else {
	    status = MP_STATUS_INVALID_PARAMETER;
	}
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}


/**
 *******************************************************************************
 *
 * Gets the properties of the specified logical unit.
 *
 * @param  oid
 *         The object ID of the multipath logical unit.
 *
 * @param  pProps
 *      A pointer to an MP_MULTIPATH_LOGICAL_UNIT_PROPERTIES structure
 *      allocated by the caller. On successful return, this structure
 *      will contain the properties of the port specified by oid.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pProps is NULL or specifies a memory area to
 *      which data cannot be written.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *          Returned if oid has an owner that is not currently known to
 *      the system.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetMPLogicalUnitProperties(
        MP_OID oid,
        MP_MULTIPATH_LOGICAL_UNIT_PROPERTIES *pProps)
{
    MP_GetMPLogicalUnitPropertiesFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (pProps == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetMPLogicalUnitPropertiesFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_GetMPLogicalUnitProperties");

        if (PassFunc != NULL) {
	    status = PassFunc(oid, pProps);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Gets a list of the object IDs of all the path logical units associated
 * with the specified multipath logical unit, initiator port, or target port.
 *
 * @param  oid
 *         The object ID of multipath logical unit, initiator port, or
 *     target port.
 *
 * @param  ppList
 *      A pointer to a pointer to an MP_OID_LIST structure.
 *      On a successful return, this will contain a pointer to
 *      an MP_OID_LIST that contains the object IDs of all the mp path
 *      logical units associated with the specified OID.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if ppList pointer passed as placeholder for holding
 *      the device product list is found to be invalid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_FAILED
 *          Returned when the plugin for the specified oid is not found.
 *
 * @retval MP_STATUS_INSUFFICIENT_MEMORY
 *      Returned when memory allocation failure occurs
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *      Returned if oid has an owner that is not currently known to
 *      the system.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetAssociatedPathOidList(
        MP_OID oid,
        MP_OID_LIST **ppList)
{
    MP_GetAssociatedPathOidListFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (ppList == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if (((status = validate_object(oid, MP_OBJECT_TYPE_INITIATOR_PORT,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
	((status = validate_object(oid, MP_OBJECT_TYPE_TARGET_PORT,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetAssociatedPathOidListFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_GetAssociatedPathOidList");

        if (PassFunc != NULL) {
	    status = PassFunc(oid, ppList);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Gets the properties of the specified path logical unit.
 *
 * @param  oid
 *         The object ID of the path logical unit.
 *
 * @param  pProps
 *      A pointer to an MP_PATH_LOGICAL_UNIT_PROPERTIES structure
 *      allocated by the caller. On successful return, this structure
 *      will contain the properties of the port specified by oid.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pProps is NULL or specifies a memory area to
 *      which data cannot be written.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *          Returned if oid has an owner that is not currently known to
 *      the system.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetPathLogicalUnitProperties(
        MP_OID oid,
        MP_PATH_LOGICAL_UNIT_PROPERTIES *pProps)
{
    MP_GetPathLogicalUnitPropertiesFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (pProps == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_PATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetPathLogicalUnitPropertiesFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_GetPathLogicalUnitProperties");

        if (PassFunc != NULL) {
	    status = PassFunc(oid, pProps);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Gets a list of the object IDs of all the target port group associated
 * with the specified multipath logical unit.
 *
 * @param  oid
 *         The object ID of the multiple logical unit.
 *
 * @param  ppList
 *      A pointer to a pointer to an MP_OID_LIST structure.
 *      On a successful return, this will contain a pointer to
 *      an MP_OID_LIST that contains the object IDs of all the target
 *      port group associated with the specified multipath logical unit.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if ppList pointer passed as placeholder for holding
 *      the target port group list is found to be invalid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_FAILED
 *          Returned when the plugin for the specified oid is not found.
 *
 * @retval MP_STATUS_INSUFFICIENT_MEMORY
 *      Returned when memory allocation failure occurs
 *
 *
 *******************************************************************************
 */
MP_STATUS MP_GetAssociatedTPGOidList(
        MP_OID oid,
        MP_OID_LIST **ppList)
{
    MP_GetAssociatedTPGOidListFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (ppList == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetAssociatedTPGOidListFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_GetAssociatedTPGOidList");

        if (PassFunc != NULL) {
	    status = PassFunc(oid, ppList);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Gets the properties of the specified target port group.
 *
 * @param  oid
 *         The object ID of the target port group.
 *
 * @param  pProps
 *      A pointer to an MP_TARGET_PORT_GROUP_PROPERTIES structure
 *      allocated by the caller. On successful return, this structure
 *      will contain the properties of the port specified by oid.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pProps is NULL or specifies a memory area to
 *      which data cannot be written.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *          Returned if oid has an owner that is not currently known to
 *      the system.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetTargetPortGroupProperties(
        MP_OID oid,
        MP_TARGET_PORT_GROUP_PROPERTIES *pProps)
{
    MP_GetTargetPortGroupPropertiesFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (pProps == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_TARGET_PORT_GROUP,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetTargetPortGroupPropertiesFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_GetTargetPortGroupProperties");

        if (PassFunc != NULL) {
	    status = PassFunc(oid, pProps);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Gets a list of multipath logical units associated with the specific target
 *  port group.
 *
 * @param  oid
 *         The object ID of the target port group.
 *
 * @param  ppList
 *      A pointer to a pointer to an MP_OID_LIST structure.
 *      On a successful return, this will contain a pointer to
 *      an MP_OID_LIST that contains the object IDs of all the multipath
 *      logical units associated with the specified target port group.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if ppList pointer passed as placeholder for holding
 *      the multipath logical unit list is found to be invalid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_FAILED
 *          Returned when the plugin for the specified oid is not found.
 *
 * @retval MP_STATUS_INSUFFICIENT_MEMORY
 *      Returned when memory allocation failure occurs
 *
 *******************************************************************************
 */
MP_STATUS MP_GetMPLuOidListFromTPG(
        MP_OID oid,
        MP_OID_LIST **ppList)
{
    MP_GetMPLuOidListFromTPGFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (ppList == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_TARGET_PORT_GROUP,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetMPLuOidListFromTPGFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_GetMPLuOidListFromTPG");

        if (PassFunc != NULL) {
	    status = PassFunc(oid, ppList);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Gets a list of the object IDs of all the proprietary load balance
 * algorithms associated with this plugin.
 *
 * @param  oid
 *         The object ID of the plugin.
 *
 * @param  ppList
 *      A pointer to a pointer to an MP_OID_LIST structure.
 *      On a successful return, this will contain a pointer to
 *      an MP_OID_LIST that contains the object IDs of all the proprietary
 *      load balance algorithms associated with the specified plugin.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if ppList pointer passed as placeholder for holding
 *      the proprietary load balance oid list is found to be invalid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_FAILED
 *          Returned when the plugin for the specified oid is not found.
 *
 * @retval MP_STATUS_INSUFFICIENT_MEMORY
 *      Returned when memory allocation failure occurs
 *
 * @retval MP_STATUS_UNSUPPORTED
 *      Returned when the API is not supported.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetProprietaryLoadBalanceOidList(
        MP_OID oid,
        MP_OID_LIST **ppList)
{
    MP_GetProprietaryLoadBalanceOidListPluginFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (ppList == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetProprietaryLoadBalanceOidListPluginFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_GetProprietaryLoadBalanceOidListPlugin");

        if (PassFunc != NULL) {
	    status = PassFunc(ppList);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Gets the properties of the specified load balance properties structure.
 *
 * @param  oid
 *         The object ID of the load balance properties structure.
 *
 * @param  pProps
 *      A pointer to an MP_LOAD_BALANCE_PROPRIETARY_TYPE structure
 *      allocated by the caller. On successful return, this structure
 *      will contain the properties of the proprietary load balance algorithm
 *	specified by oid.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pProps is NULL or specifies a memory area to
 *      which data cannot be written.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *          Returned if oid has an owner that is not currently known to
 *      the system.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetProprietaryLoadBalanceProperties (
        MP_OID oid,
        MP_PROPRIETARY_LOAD_BALANCE_PROPERTIES *pProps)
{
    MP_GetProprietaryLoadBalancePropertiesFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (pProps == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_PROPRIETARY_LOAD_BALANCE,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetProprietaryLoadBalancePropertiesFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_GetProprietaryLoadBalanceProperties");

        if (PassFunc != NULL) {
	    status = PassFunc(oid, pProps);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Gets a list of the object IDs of the target ports in the specified target
 * port group.
 *
 * @param  oid
 *         The object ID of the target port group.
 *
 * @param  ppList
 *      A pointer to a pointer to an MP_OID_LIST structure.
 *      On a successful return, this will contain a pointer to
 *      an MP_OID_LIST that contains the object IDs of all the target ports
 *      associated with the specified target port group.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if ppList pointer passed as placeholder for holding
 *      the multipath logical unit list is found to be invalid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_FAILED
 *          Returned when the plugin for the specified oid is not found.
 *
 * @retval MP_STATUS_INSUFFICIENT_MEMORY
 *      Returned when memory allocation failure occurs
 *
 *******************************************************************************
 */
MP_STATUS MP_GetTargetPortOidList(
        MP_OID oid,
        MP_OID_LIST **ppList)
{
    MP_GetTargetPortOidListFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (ppList == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_TARGET_PORT_GROUP,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetTargetPortOidListFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_GetTargetPortOidList");

        if (PassFunc != NULL) {
	    status = PassFunc(oid, ppList);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Gets the properties of the specified target port.
 *
 * @param  oid
 *         The object ID of the target port.
 *
 * @param  pProps
 *      A pointer to an MP_TARGET_PORT_PROPERTIES structure
 *      allocated by the caller. On successful return, this structure
 *      will contain the properties of the port specified by oid.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pProps is NULL or specifies a memory area to
 *      which data cannot be written.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *          Returned if oid has an owner that is not currently known to
 *      the system.
 *
 *******************************************************************************
 */
MP_STATUS MP_GetTargetPortProperties(
        MP_OID oid,
        MP_TARGET_PORT_PROPERTIES *pProps)
{
    MP_GetTargetPortPropertiesFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (pProps == NULL)
        return MP_STATUS_INVALID_PARAMETER;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_TARGET_PORT,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_GetTargetPortPropertiesFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_GetTargetPortProperties");

        if (PassFunc != NULL) {
	    status = PassFunc(oid, pProps);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}


/**
 *******************************************************************************
 *
 * Assign a multipath logical unit to a target port group.
 *
 * @param  tpgOid
 *      An MP_TARGET_PORT_GROUP oid. The target port group currently in
 *      active access state that the administrator would like the LU
 *      assigned to.
 *
 * @param  luOid
 *      An MP_MULTIPATH_LOGICAL_UNIT oid.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned when luOid is not associated with tpgOid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *          Returned if oid has an owner that is not currently known to
 *      the system.
 *
 *******************************************************************************
 */
MP_STATUS MP_AssignLogicalUnitToTPG(
        MP_OID tpgOid,
        MP_OID luOid)
{
    MP_AssignLogicalUnitToTPGFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (luOid.ownerId != tpgOid.ownerId) {
        return (MP_STATUS_INVALID_PARAMETER);
    }

    if ((status = validate_object(tpgOid, MP_OBJECT_TYPE_TARGET_PORT_GROUP,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    if ((status = validate_object(luOid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = tpgOid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_AssignLogicalUnitToTPGFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_AssignLogicalUnitToTPG");

        if (PassFunc != NULL) {
            status = PassFunc(tpgOid, luOid);
        } else {
            status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Manually override the path for a logical unit. The path exclusively used to
 * access the logical unit until cleared.
 *
 * @param  logicalUnitOid
 *      The object ID of the multipath logical unit.
 *
 * @param  pathOid
 *      The object ID of the path logical unit.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if the oid of the object is not valid
 *
 * @retval MP_STATUS_UNSUPPORTED
 *      Returned when the implementation does not support the API
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_PATH_NONOPERATIONAL
 *          Returned when the driver cannot communicate through selected path.
 *
 *******************************************************************************
 */
MP_STATUS MP_SetOverridePath(
    MP_OID logicalUnitOid,
    MP_OID pathOid)
{
    MP_SetOverridePathFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if ((status = validate_object(logicalUnitOid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }
    if ((status = validate_object(pathOid, MP_OBJECT_TYPE_PATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = pathOid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_SetOverridePathFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_SetOverridePath");

        if (PassFunc != NULL) {
	    status = PassFunc(logicalUnitOid, pathOid);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Cancel a path override and re-enable load balancing.
 *
 * @param  luOid
 *         An MP_MULTIPATH_LOGICAL_UNIT oid.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if MP_MULTIPATH_LOGICAL_UNIT with the luOid is not found.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *          Returned if oid has an owner that is not currently known to
 *      the system.
 *
 *******************************************************************************
 */
MP_STATUS MP_CancelOverridePath(
        MP_OID luOid)
{
    MP_CancelOverridePathFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if ((status = validate_object(luOid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = luOid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_CancelOverridePathFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_CancelOverridePath");

        if (PassFunc != NULL) {
	    status = PassFunc(luOid);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Enables Auto-failback.
 *
 * @param  oid
 *      The oid of the plugin.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if oid is NULL or specifies a memory area that is not
 *	a valid plugin oid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 *******************************************************************************
 */
MP_STATUS MP_EnableAutoFailback(
    MP_OID oid)
{
    MP_UINT32 index;
    MP_STATUS status;

    if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
	    MP_EnableAutoFailbackPluginFn PassFunc;
	    PassFunc = (MP_EnableAutoFailbackPluginFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_EnableAutoFailbackPlugin");

	    if (PassFunc != NULL) {
		status = PassFunc();
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else if (oid.objectType == MP_OBJECT_TYPE_MULTIPATH_LU) {
	    MP_EnableAutoFailbackLuFn PassFunc;
	    PassFunc = (MP_EnableAutoFailbackLuFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_EnableAutoFailbackLu");

	    if (PassFunc != NULL) {
		status = PassFunc(oid);
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else {
	    status = MP_STATUS_INVALID_PARAMETER;
	}
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Enables Auto-probing.
 *
 * @param  oid
 *      The oid of the plugin or the multipath logical unit.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if oid is NULL or specifies a memory area that is not
 *      a valid plugin oid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 *******************************************************************************
 */
MP_STATUS MP_EnableAutoProbing(
    MP_OID oid)
{
    MP_UINT32 index;
    MP_STATUS status;

    if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
	    MP_EnableAutoProbingPluginFn PassFunc;
	    PassFunc = (MP_EnableAutoProbingPluginFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_EnableAutoProbingPlugin");

	    if (PassFunc != NULL) {
		status = PassFunc();
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else if (oid.objectType == MP_OBJECT_TYPE_MULTIPATH_LU) {
	    MP_EnableAutoProbingLuFn PassFunc;
	    PassFunc = (MP_EnableAutoProbingLuFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_EnableAutoProbingLu");

	    if (PassFunc != NULL) {
		status = PassFunc(oid);
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else {
	    status = MP_STATUS_INVALID_PARAMETER;
	}
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Disables Auto-failback.
 *
 * @param  oid
 *      The oid of the plugin.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if oid is NULL or specifies a memory area that is not
 *      a valid plugin oid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 *******************************************************************************
 */
MP_STATUS MP_DisableAutoFailback(
    MP_OID oid)
{
    MP_UINT32 index;
    MP_STATUS status;

    if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
	    MP_DisableAutoFailbackPluginFn PassFunc;
	    PassFunc = (MP_DisableAutoFailbackPluginFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_DisableAutoFailbackPlugin");

	    if (PassFunc != NULL) {
		status = PassFunc();
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else if (oid.objectType == MP_OBJECT_TYPE_MULTIPATH_LU) {
	    MP_DisableAutoFailbackLuFn PassFunc;
	    PassFunc = (MP_DisableAutoFailbackLuFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_DisableAutoFailbackLu");

	    if (PassFunc != NULL) {
		status = PassFunc(oid);
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else {
	    status = MP_STATUS_INVALID_PARAMETER;
	}
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Disables Auto-probing.
 *
 * @param  oid
 *      The oid of the plugin or the multipath logical unit.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if oid is NULL or specifies a memory area that is not
 *      a valid plugin oid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 *******************************************************************************
 */
MP_STATUS MP_DisableAutoProbing(
    MP_OID oid)
{
    MP_UINT32 index;
    MP_STATUS status;

    if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
	    MP_DisableAutoProbingPluginFn PassFunc;
	    PassFunc = (MP_DisableAutoProbingPluginFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_DisableAutoProbingPlugin");

	    if (PassFunc != NULL) {
		status = PassFunc();
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else if (oid.objectType == MP_OBJECT_TYPE_MULTIPATH_LU) {
	    MP_DisableAutoFailbackLuFn PassFunc;
	    PassFunc = (MP_DisableAutoProbingLuFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_DisableAutoProbingLu");

	    if (PassFunc != NULL) {
		status = PassFunc(oid);
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else {
	    status = MP_STATUS_INVALID_PARAMETER;
	}
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Enables a path. This API may cause failover in a logical unit with
 * asymmetric access.
 *
 * @param  oid
 *      The oid of the path.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if oid is NULL or specifies a memory area that is not
 *      a valid path oid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 *******************************************************************************
 */
MP_STATUS MP_EnablePath(
    MP_OID oid)
{
    MP_EnablePathFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_PATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_EnablePathFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_EnablePath");

        if (PassFunc != NULL) {
	    status = PassFunc(oid);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Disables a path. This API may cause failover in a logical unit with
 * asymmetric access. This API may cause a logical unit to become unavailable.
 *
 * @param  oid
 *      The oid of the path.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if oid is NULL or specifies a memory area that is not
 *      a valid path oid.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 *******************************************************************************
 */
MP_STATUS MP_DisablePath(
    MP_OID oid)
{
    MP_DisablePathFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_PATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_DisablePathFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_DisablePath");

        if (PassFunc != NULL) {
	    status = PassFunc(oid);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Set the multipath logical unit s load balancing policy.
 *
 * @param  logicalUnitoid
 *      The object ID of the multipath logical unit.
 *
 * @param  loadBanlance
 *      The desired load balance policy for the specified logical unit.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if no MP_MULTIPATH_LOGICAL_UNIT associated with
 *      @ref ligicalUnitrOid is found or invalid MP_LOAD_BALANCE_TYPE is
 *      specified.
 *
 * @retval MP_STATUS_FAILED
 *      Returned when the specified loadBalance type cannot be handled
 *      by the plugin.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 *******************************************************************************
 */
MP_STATUS MP_SetLogicalUnitLoadBalanceType(
    MP_OID logicalUnitOid,
    MP_LOAD_BALANCE_TYPE loadBalance)
{
    MP_SetLogicalUnitLoadBalanceTypeFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if ((status = validate_object(logicalUnitOid,
        MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = logicalUnitOid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_SetLogicalUnitLoadBalanceTypeFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_SetLogicalUnitLoadBalanceType");

        if (PassFunc != NULL) {
	    status = PassFunc(logicalUnitOid, loadBalance);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Set the weight to be assigned to a particular path.
 *
 * @param  pathOid
 *      The object ID of the path logical unit.
 *
 * @param  weight
 *      weight that will be assigned to the path logical unit.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *      Returned when the MP Path specified by the PathOid could not be
 *      found.
 *
 * @retval MP_STATUS_UNSUPPORTED
 *      Returned when the implementation does not support the API
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_FAILED
 *          Returned when the operation failed.
 *
 * @retval MP_STATUS_PATH_NONOPERATIONAL
 *          Returned when the driver cannot communicate through selected path.
 *
 * @retval MP_STATUS_INVALID_WEIGHT
 *          Returned when the weight parameter is greater than the plugin's
 *      maxWeight property.
 *
 *******************************************************************************
 */
MP_STATUS MP_SetPathWeight(
    MP_OID pathOid,
    MP_UINT32 weight)
{
    MP_SetPathWeightFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if ((status = validate_object(pathOid, MP_OBJECT_TYPE_PATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = pathOid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_SetPathWeightFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_SetPathWeight");

        if (PassFunc != NULL) {
	    status = PassFunc(pathOid, weight);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Set the default load balance policy for the plugin.
 *
 * @param  oid
 *      The object ID of the plugin
 *
 * @param  loadBalance
 *      The desired default load balance policy for the specified plugin.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *      Returned when the the plugin specified by @ref oid could not be
 *      found.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if the oid of the object is not valid.
 *
 * @retval MP_STATUS_UNSUPPORTED
 *      Returned when the implementation does not support the API
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_FAILED
 *          Returned when the specified loadBalance type cannot be handled
 *      by the plugin.
 *
 *******************************************************************************
 */
MP_STATUS MP_SetPluginLoadBalanceType(
    MP_OID oid,
    MP_LOAD_BALANCE_TYPE loadBalance)
{
    MP_SetPluginLoadBalanceTypePluginFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if ((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_SetPluginLoadBalanceTypePluginFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_SetPluginLoadBalanceTypePlugin");

        if (PassFunc != NULL) {
	    status = PassFunc(loadBalance);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Set the failback polling rates. Setting both rates to zero disables polling.
 *
 * @param  pluginOid
 *      The object ID of the plugin or multipath lu.
 *
 * @param  pollingRate
 *      The value to be set in MP_PLUGIN_PROPERTIES currentPollingRate.or
 *	MP_MULTIPATH_LOGICAL_UNIT_PROPERTIES pollingRate.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *      Returned when the the plugin specified by @ref oid could not be
 *      found.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if one of the polling values is outside the range
 *      supported by the driver.
 *
 * @retval MP_STATUS_UNSUPPORTED
 *      Returned when the implementation does not support the API
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 *******************************************************************************
 */
MP_STATUS MP_SetFailbackPollingRate(
    MP_OID oid,
    MP_UINT32 pollingRate)
{
    MP_UINT32 index;
    MP_STATUS status;

    if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
	    MP_SetFailbackPollingRatePluginFn PassFunc;
	    PassFunc = (MP_SetFailbackPollingRatePluginFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_SetFailbackPollingRatePlugin");

	    if (PassFunc != NULL) {
		status = PassFunc(pollingRate);
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else if (oid.objectType == MP_OBJECT_TYPE_MULTIPATH_LU) {
	    MP_SetFailbackPollingRateLuFn PassFunc;
	    PassFunc = (MP_SetFailbackPollingRateLuFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_SetFailbackPollingRateLu");

	    if (PassFunc != NULL) {
		status = PassFunc(oid, pollingRate);
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else {
	    status = MP_STATUS_INVALID_PARAMETER;
	}
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Set the probing polling rates. Setting both rates to zero disables polling.
 *
 * @param  pluginOid
 *      The object ID of either the plugin or a multipath logical unit.
 *
 * @param  pollingRate
 *      The value to be set in MP_PLUGIN_PROPERTIES current pollingRate or
 *	MP_MULTIPATH_LOGICAL_UNIT_PROPERTIES pollingRate.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *      Returned when the the plugin specified by @ref oid could not be
 *      found.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if one of the polling values is outside the range
 *      supported by the driver.
 *
 * @retval MP_STATUS_UNSUPPORTED
 *      Returned when the implementation does not support the API
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 *******************************************************************************
 */
MP_STATUS MP_SetProbingPollingRate(
    MP_OID    oid,
    MP_UINT32 pollingRate)
{
    MP_UINT32 index;
    MP_STATUS status;

    if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
	    MP_SetProbingPollingRatePluginFn PassFunc;
	    PassFunc = (MP_SetProbingPollingRatePluginFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_SetProbingPollingRatePlugin");

	    if (PassFunc != NULL) {
		status = PassFunc(pollingRate);
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else if (oid.objectType == MP_OBJECT_TYPE_MULTIPATH_LU) {
	    MP_SetProbingPollingRateLuFn PassFunc;
	    PassFunc = (MP_SetProbingPollingRateLuFn)
	    dlsym(plugintable[index].hdlPlugin,
        	"MP_SetProbingPollingRateLu");

	    if (PassFunc != NULL) {
		status = PassFunc(oid, pollingRate);
	    } else {
		status = MP_STATUS_UNSUPPORTED;
	    }
	} else {
	    status = MP_STATUS_INVALID_PARAMETER;
	}
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Set proprietary properties in supported object instances.
 *
 * @param  pluginOid
 *      The object ID of MP_LOAD_BALANCE_PROPRIETARY_TYPE, MP_PLUGIN_PROPERTIES
 *	or MP_MULTIPATH_LOGICAL_UNIT_PROPERTIES.
 *
 * @param  count
 *	   The number of valid items in pPropertyList.
 *
 * @param  pPropertyList
 *	   A pointer to an array of property name/value pairs. This array must
 *	   contain the same number of elements as count.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *      Returned when the the plugin specified by @ref oid could not be
 *      found.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if one of the polling values is outside the range
 *      supported by the driver.
 *
 * @retval MP_STATUS_UNSUPPORTED
 *      Returned when the implementation does not support the API
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 *******************************************************************************
 */
MP_STATUS MP_SetProprietaryProperties(
    MP_OID    oid,
    MP_UINT32 count,
    MP_PROPRIETARY_PROPERTY *pPropertyList)
{
    MP_SetProprietaryPropertiesFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
	((status = validate_object(oid, MP_OBJECT_TYPE_PROPRIETARY_LOAD_BALANCE,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = oid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_SetProprietaryPropertiesFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_SetProprietaryProperties");

        if (PassFunc != NULL) {
	    status = PassFunc(oid, count, pPropertyList);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Set the access state for a list of target port groups. This allows
 * a client to force a failover or failback to a desired set of target port
 * groups.
 *
 * @param  luOid
 *      The object ID of the logical unit where the command is sent.
 *
 * @param  count
 *      The number of valid items in the pTpgStateList.
 *
 * @param  pTpgStateList
 *      A pointer to an array of TPG/access-state values. This array must
 *      contain the same number of elements as @ref count.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_OBJECT_NOT_FOUND
 *      Returned when the MP_MULTIPATH_LOGICAL_UNIT associated with @ref
 *      oid could not be found.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pTpgStateList is null or if one of the TPGs referenced
 *      in the list is not associated with the specified MP logical unit.
 *
 * @retval MP_STATUS_UNSUPPORTED
 *      Returned when the implementation does not support the API
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_ACCESS_STATE_INVALID
 *         Returned if the target device returns a status indicating the caller
 *     is attempting to establish an illegal combination of access states.
 *
 * @retval MP_STATUS_FAILED
 *          Returned if the underlying interface failed the commend for some
 *      reason other than MP_STATUS_ACCESS_STATE_INVALID
 *
 *******************************************************************************
 */
MP_STATUS MP_SetTPGAccess(
    MP_OID luOid,
    MP_UINT32 count,
    MP_TPG_STATE_PAIR *pTpgStateList)
{
    MP_SetTPGAccessFn PassFunc;
    MP_UINT32 index;
    MP_STATUS status;

    if ((status = validate_object(luOid, MP_OBJECT_TYPE_MULTIPATH_LU,
        MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
        return (status);
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    index = luOid.ownerId - 1;
    if (plugintable[index].hdlPlugin != NULL) {
        PassFunc = (MP_SetTPGAccessFn)
        dlsym(plugintable[index].hdlPlugin,
        "MP_SetTPGAccess");

        if (PassFunc != NULL) {
	    status = PassFunc(luOid, count, pTpgStateList);
        } else {
	    status = MP_STATUS_UNSUPPORTED;
        }
    } else {
        status = MP_STATUS_FAILED;
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Registers a client function that is to be called
 * whenever the property of an an object changes.
 *
 * @param  pClientFn,
 *      A pointer to an MP_OBJECT_PROPERTY_FN function defined by the
 *      client. On successful return this function will be called to
 *      inform the client of objects that have had one or more properties
 *      change.
 *
 * @param  objectType
 *      The type of object the client wishes to deregister for
 *      property change callbacks. If null, then all objects types are
 *      deregistered.
 *
 * @param  pCallerData
 *      A pointer that is passed to the callback routine with each event.
 *      This may be used by the caller to correlate the event to source of
 *      the registration.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pClientFn is NULL or specifies a memory area
 *      that is not executable.
 *
 * @retval MP_STATUS_FN_REPLACED
 *      Returned when an existing client function is replaced with the one
 *      specified in pClientFn.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 *******************************************************************************
 */
MP_STATUS MP_RegisterForObjectPropertyChanges(
    MP_OBJECT_PROPERTY_FN pClientFn,
    MP_OBJECT_TYPE objectType,
    void *pCallerData,
    MP_OID pluginOid)
{
    MP_RegisterForObjectPropertyChangesPluginFn PassFunc;
    MP_UINT32 i;
    MP_UINT32 index;
    MP_STATUS status;

    if (pClientFn == NULL) {
        return (MP_STATUS_INVALID_PARAMETER);
    }

    if (objectType > MP_OBJECT_TYPE_MAX) {
        return (MP_STATUS_INVALID_OBJECT_TYPE);
    }

    if (!(is_zero_oid(pluginOid))) {
	if ((status = validate_object(pluginOid, MP_OBJECT_TYPE_PLUGIN,
	    MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
	    return (status);
	}
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    if (is_zero_oid(pluginOid)) {
	for (i = 0; i < number_of_plugins; i++) {
	    if (plugintable[i].hdlPlugin != NULL) {
		PassFunc = (MP_RegisterForObjectPropertyChangesPluginFn)
		dlsym(plugintable[i].hdlPlugin,
		"MP_RegisterForObjectPropertyChangesPlugin");
	    }

	    if (PassFunc != NULL) {
		status =
		     PassFunc(pClientFn, objectType, pCallerData);
		/* ignore an error and continue */
	    }
	}
    } else {
	index = pluginOid.ownerId - 1;
	if (plugintable[index].hdlPlugin != NULL) {
		PassFunc = (MP_RegisterForObjectPropertyChangesPluginFn)
		dlsym(plugintable[index].hdlPlugin,
		"MP_RegisterForObjectPropertyChangesPlugin");
	}

	if (PassFunc != NULL) {
	    status = PassFunc(pClientFn, objectType, pCallerData);
	}
    }
    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Deregisters a previously registered client function that is to be invoked
 * whenever an object's property changes.
 *
 * @param  pClientFn,
 *      A pointer to an MP_OBJECT_PROPERTY_FN function defined by the
 *      client that was previously registered using
 *      the MP_RegisterForObjectPropertyChanges API. On successful return
 *      this function will no longer be called to inform the client of
 *      object property changes.
 *
 * @param  objectType
 *      The type of object the client wishes to deregister for
 *      property change callbacks. If null, then all objects types are
 *      deregistered.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pClientFn is NULL or specifies a memory area
 *      that is not executable.
 *
 * @retval MP_STATUS_UNKNOWN_FN
 *      Returned if pClientFn is not the same as the previously registered
 *      function.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if oid does not specify any valid object type.
 *
 * @retval MP_STATUS_FAILED
 *          Returned if pClientFn deregistration is not possible at this time.
 *
 *******************************************************************************
 */
MP_STATUS MP_DeregisterForObjectPropertyChanges(
    MP_OBJECT_PROPERTY_FN pClientFn,
    MP_OBJECT_TYPE objectType,
    MP_OID pluginOid)
{
    MP_DeregisterForObjectPropertyChangesPluginFn PassFunc;
    MP_UINT32 i;
    MP_UINT32 index;
    MP_STATUS status;

    if (pClientFn == NULL) {
        return (MP_STATUS_INVALID_PARAMETER);
    }

    if (objectType > MP_OBJECT_TYPE_MAX) {
        return (MP_STATUS_INVALID_OBJECT_TYPE);
    }

    if (!(is_zero_oid(pluginOid))) {
	if ((status = validate_object(pluginOid, MP_OBJECT_TYPE_PLUGIN,
	    MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
	    return (status);
	}
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    if (is_zero_oid(pluginOid)) {
	for (i = 0; i < number_of_plugins; i++) {
	    if (plugintable[i].hdlPlugin != NULL) {
		PassFunc = (MP_DeregisterForObjectPropertyChangesPluginFn)
		dlsym(plugintable[i].hdlPlugin,
		"MP_DeregisterForObjectPropertyChangesPlugin");
	    }

	    if (PassFunc != NULL) {
		status = PassFunc(pClientFn, objectType);
	    }
	}
    } else {
	index = pluginOid.ownerId - 1;
	if (plugintable[index].hdlPlugin != NULL) {
		PassFunc = (MP_DeregisterForObjectPropertyChangesPluginFn)
		dlsym(plugintable[index].hdlPlugin,
		"MP_DeregisterForObjectPropertyChangesPlugin");
	}

	if (PassFunc != NULL) {
	    status = PassFunc(pClientFn, objectType);
	}
    }
    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Registers a client function that is to be called
 * whenever a high level object appears or disappears.
 *
 * @param  pClientFn,
 *      A pointer to an MP_OBJECT_VISIBILITY_FN function defined by the
 *      client. On successful return this function will be called to
 *      inform the client of objects whose visibility has changed.
 *
 * @param  objectType
 *      The type of object the client wishes to deregister for
 *      property change callbacks. If null, then all objects types are
 *      deregistered.
 *
 * @param  pCallerData
 *      A pointer that is passed to the callback routine with each event.
 *      This may be used by the caller to correlate the event to source of
 *      the registration.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pClientFn is NULL or specifies a memory area
 *      that is not executable.
 *
 * @retval MP_STATUS_FN_REPLACED
 *      Returned when an existing client function is replaced with the one
 *      specified in pClientFn.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if objectType does not specify any valid object type.
 *
 *******************************************************************************
 */
MP_STATUS MP_RegisterForObjectVisibilityChanges(
    MP_OBJECT_VISIBILITY_FN pClientFn,
    MP_OBJECT_TYPE objectType,
    void *pCallerData,
    MP_OID pluginOid)
{
    MP_RegisterForObjectVisibilityChangesPluginFn PassFunc;
    MP_UINT32 i;
    MP_UINT32 index;
    MP_STATUS status;

    if (pClientFn == NULL) {
        return (MP_STATUS_INVALID_PARAMETER);
    }

    if (objectType > MP_OBJECT_TYPE_MAX) {
        return (MP_STATUS_INVALID_OBJECT_TYPE);
    }

    if (!(is_zero_oid(pluginOid))) {
	if ((status = validate_object(pluginOid, MP_OBJECT_TYPE_PLUGIN,
	    MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
	    return (status);
	}
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    if (is_zero_oid(pluginOid)) {
	for (i = 0; i < number_of_plugins; i++) {
	    if (plugintable[i].hdlPlugin != NULL) {
	    PassFunc = (MP_RegisterForObjectVisibilityChangesPluginFn)
		dlsym(plugintable[i].hdlPlugin,
		"MP_RegisterForObjectVisibilityChangesPlugin");
	    }

	    if (PassFunc != NULL) {
		status = PassFunc(pClientFn, objectType, pCallerData);
		/* ignore an error and continue. */
	    }
	}
    } else {
	    index = pluginOid.ownerId - 1;
	    if (plugintable[index].hdlPlugin != NULL) {
	    PassFunc = (MP_RegisterForObjectVisibilityChangesPluginFn)
		dlsym(plugintable[index].hdlPlugin,
		"MP_RegisterForObjectVisibilityChangesPlugin");
	    }

	    if (PassFunc != NULL) {
		status = PassFunc(pClientFn, objectType, pCallerData);
	    }
    }
    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);

}

/**
 *******************************************************************************
 *
 * Deregisters a previously registered client function that is to be invoked
 * whenever a high level object appears or disappears.
 *
 * @param  pClientFn,
 *      A pointer to an MP_OBJECT_VISIBILITY_FN function defined by the
 *      client that was previously registered using
 *      the MP_RegisterForObjectVisibilityChanges API. On successful return
 *      this function will no longer be called to inform the client of
 *      object property changes.
 *
 * @param  objectType
 *      The type of object the client wishes to deregister for visibility
 *      change callbacks. If null, then all objects types are
 *      deregistered.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the operation is successful.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pClientFn is NULL or specifies a memory area
 *      that is not executable.
 *
 * @retval MP_STATUS_UNKNOWN_FN
 *      Returned if pClientFn is not the same as the previously registered
 *      function.
 *
 * @retval MP_STATUS_INVALID_OBJECT_TYPE
 *          Returned if objectType does not specify any valid object type.
 *
 * @retval MP_STATUS_FAILED
 *          Returned if pClientFn deregistration is not possible at this time.
 *
 *******************************************************************************
 */
MP_STATUS MP_DeregisterForObjectVisibilityChanges(
    MP_OBJECT_VISIBILITY_FN pClientFn,
    MP_OBJECT_TYPE objectType,
    MP_OID pluginOid)
{
    MP_DeregisterForObjectVisibilityChangesPluginFn PassFunc;
    MP_UINT32 i;
    MP_UINT32 index;
    MP_STATUS status;

    if (pClientFn == NULL) {
        return (MP_STATUS_INVALID_PARAMETER);
    }

    if (objectType > MP_OBJECT_TYPE_MAX) {
        return (MP_STATUS_INVALID_OBJECT_TYPE);
    }

    if (!(is_zero_oid(pluginOid))) {
	if ((status = validate_object(pluginOid, MP_OBJECT_TYPE_PLUGIN,
	    MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
	    return (status);
	}
    }

    (void) pthread_mutex_lock(&mp_lib_mutex);

    if (is_zero_oid(pluginOid)) {
	for (i = 0; i < number_of_plugins; i++) {
	    if (plugintable[i].hdlPlugin != NULL) {
		PassFunc = (MP_DeregisterForObjectVisibilityChangesPluginFn)
		    dlsym(plugintable[i].hdlPlugin,
		    "MP_DeregisterForObjectVisibilityChangesPlugin");
		if (PassFunc != NULL) {
		    status = PassFunc(pClientFn, objectType);
		}
	    }
	}
    } else  {
	    index = pluginOid.ownerId - 1;
	    if (plugintable[index].hdlPlugin != NULL) {
		PassFunc = (MP_DeregisterForObjectVisibilityChangesPluginFn)
		    dlsym(plugintable[index].hdlPlugin,
		    "MP_DeregisterForObjectVisibilityChangesPlugin");
		if (PassFunc != NULL) {
		    status = PassFunc(pClientFn, objectType);
		}
	    }
    }

    (void) pthread_mutex_unlock(&mp_lib_mutex);
    return (status);
}

/**
 *******************************************************************************
 *
 * Compare two Oids for equality to see whether they refer to the same object.
 *
 * @param  oid1
 *          Oid to compare.
 *
 * @param  oid2
 *          Oid to compare.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when the two Oids do refer to the same object.
 *
 * @retval MP_STATUS_FAILED
 *      Returned if the Oids don't compare.
 *
 *******************************************************************************
 */
MP_STATUS MP_CompareOIDs(
        MP_OID oid1,
    MP_OID oid2)
{
    if ((oid1.objectType == oid2.objectType) && (oid1.ownerId == oid2.ownerId)
    	&& (oid1.objectSequenceNumber == oid2.objectSequenceNumber)) {
    	return (MP_STATUS_SUCCESS);
    } else {
    	return (MP_STATUS_FAILED);
    }
}

/**
 *******************************************************************************
 *
 * Frees memory returned by an MP API.
 *
 * @param  pOidList
 *      A pointer to the memory returned by an MP API. On successful
        return, the allocated memory is freed.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when pPluginId is deregistered successfully.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pMemory is NULL or specifies a memory area to which
 *      data cannot be written.
 *
 *******************************************************************************
 */
MP_STATUS MP_FreeOidList(MP_OID_LIST *pOidList)
{
	if (pOidList == NULL) {
	    return (MP_STATUS_INVALID_PARAMETER);
	}
	
	free(pOidList);

	return (MP_STATUS_SUCCESS);
}

static MP_CHAR *HDR =
"#\n" 
"# This file contains names and references to MP API plugin libraries\n"
"#\n"
"#  Do NOT manually edit this file\n" 
"#\n"
"# Format:\n"
"#\n"
"# <library ID>  <library pathname>\n"
"#\n";

#define CLEANUP_N_RET(fd, ret)  \
	if (lock_register(fd, F_SETLK, F_UNLCK, 0, SEEK_SET, 0) < 0) { \
		close(fd); \
		return (MP_STATUS_FAILED); \
	} \
	close(fd); \
	return (ret)
	
/*
 * This function sets an advisory lock on the file pointed to by the argument
 * fd, which is a file descriptor. The lock is set using fcntl() which uses
 * flock structure.
 */
static int
lock_register(int fd, int cmd, int type, off_t offset, int whence, off_t len)
{
    struct flock lock;

    lock.l_type = type;
    lock.l_start = offset;
    lock.l_whence = whence;
    lock.l_len = len;

    return (fcntl(fd, cmd, &lock));
}

/*
 * This function searches for "srch_str" (of length "slen") in "buf" (of length
 * "buflen"). If it is not found, "write_offset" has the offset in "buf" where
 * "srch_str" would have to be added in "buf". If "srch_str" is found in "buf",
 * "write_offset" has its offset in "buf"
 *
 * ARGUMENTS :
 * buf		- buffer to search in
 * buflen	- length of buffer
 * srch_id	- id to search
 * id_len	- length of srch_id
 * write_offset	- Set in function on exit
 *		- It is the offset in buf where srch_str is or should be
 * bytes_left	- Set in function on exit
 *		- It is the # of bytes left beyond write_offset in buf
 * RETURN VALUES :
 * Zero - "srch_id" found in "buf"... "write_offset" has offset in "buf"
 * != 0 - "srch_str" NOT found in "buf" ... "write_offset" points to the end of
 *	    "buf".
 */
static int
search_line(MP_CHAR *buf, size_t buflen, MP_CHAR *srch_id, size_t id_len,
		int *write_offset, int *bytes_left)
{
	int	retval, sizeof_conf_hdr = strlen(HDR);
	MP_CHAR	*sol;		/* Pointer to Start-Of-Line */
	MP_CHAR	*cur_pos;	/* current position */

	*bytes_left = buflen;
	*write_offset = 0;

	if (buf == NULL || buflen <= 0)
		return (-1);	

	if (srch_id == NULL || id_len <= 0)
		return (0);	

	sol = cur_pos = buf;

	/*
	 * mp conf file should not be edited but takes care of 
	 * any extra white space when parsing the line.
	 *
	 * The line should have id + delimiter + name + newline.
	 */
	while (*bytes_left >= (id_len + 3)) {
	    /* skip leading blank or space. */
	    while ((*cur_pos == ' ') || (*cur_pos == '\t')) {
		cur_pos++;
	    }

	    if (strncmp(cur_pos, srch_id, id_len) == 0) {
		/* id matched. */
		cur_pos += id_len;

		while (*cur_pos != '\n') {
		    cur_pos++;
		}
		*write_offset = (sol - buf);
		*bytes_left = buflen - ((cur_pos + 1) - buf);
		return (0);
	    } else {
		/* move to the next line */
		while (*cur_pos != '\n') {
		    cur_pos++;
		}
		*bytes_left = buflen - ((cur_pos + 1) - buf);
	    }
	    sol = cur_pos = cur_pos + 1;
	} 	

	/* Given strings are not found. */
	*write_offset = buflen;
	return (-1);
}

/**
 *******************************************************************************
 *
 * Registers a plugin with common library.  The implementation of this routine
 * is based on configuration file /etc/mpapi.conf that contains a list of 
 * plugin libraries.
 *
 * @param  pPluginId
 *	    A pointer to the key name shall be the reversed domain name of
 *	    the vendor followed by followed by the vendor specific name for
 *	    the plugin that uniquely identifies the plugin.  Should be NULL
 *	    terminated.
 *
 * @param  pFileName
 *	    The full path to the plugin library.
 *	    Should be NULL terminated.
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when pPluginId is deregistered successfully.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pPluginId is NULL or specifies a memory area that
 *      is not executable.
 *
 * @retval MP_STATUS_FAILED
 *          Returned if pClientFn deregistration is not possible at this time.
 *
 *******************************************************************************
 */
MP_STATUS MP_RegisterPlugin(
	MP_WCHAR *pPluginId,
	char *pFileName)
{
	int mpconf, bytes_left, write_offset;
	MP_CHAR fullline[MAX_LINE_SIZE]; /* Full line to add to mpapi.conf */
	MP_CHAR *mpconf_buf;
	MP_CHAR pluginid[MAX_NAME_SIZE];
	char systemPath[MAX_NAME_SIZE], mpConfFilePath[MAX_NAME_SIZE];
	MP_UINT32   new_file_flag = 0;
	MP_UINT32   sizeof_conf_hdr = strlen(HDR);
	struct stat	stbuf;
	
	if ((pPluginId == NULL) || (pFileName == NULL)) {
	    return (MP_STATUS_INVALID_PARAMETER);
	}

	if (stat(pFileName, &stbuf) != 0) {
	    return (MP_STATUS_INVALID_PARAMETER);
	}

	if (wcstombs(pluginid, pPluginId, MAX_NAME_SIZE) != wcslen(pPluginId)) {
	    return (MP_STATUS_INVALID_PARAMETER);
	}

	*fullline = '\0';
	strncpy(fullline, pluginid, MAX_NAME_SIZE);
	/* add tab */
	strncat(fullline, "\t", MAX_LINE_SIZE - strlen(pluginid));
	strncat(fullline, pFileName, MAX_LINE_SIZE - strlen(pluginid) - 1);
	/* add a new line. */
	strncat(fullline, "\n",
	    MAX_LINE_SIZE - strlen(pluginid) - strlen(pFileName) -1);
	
	/* Open configuration file from known location */
	strncpy(mpConfFilePath, "/etc/mpapi.conf", MAX_NAME_SIZE);

	if ((chmod(mpConfFilePath, S_IRUSR|S_IRGRP|S_IROTH) == -1) &&
		(errno == ENOENT))  {
	    new_file_flag = 1;
	}
    
	if ((mpconf = open(mpConfFilePath, O_RDWR | O_CREAT)) == -1) {
		return (MP_STATUS_FAILED);
	}

	if (fchmod(mpconf, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
	    close(mpconf);
	    return (MP_STATUS_FAILED);
	}

	if (lock_register(mpconf, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0) < 0) {
	    close(mpconf);
	    return (MP_STATUS_FAILED);
	}

	if (fstat(mpconf, &stbuf) == -1) {
	    CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
	}

	if ((new_file_flag) || (stbuf.st_size == 0)) {
	    if (write(mpconf, HDR, sizeof_conf_hdr) !=
		sizeof_conf_hdr) {
		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
	    }

	    if (pwrite(mpconf, fullline, strlen(fullline),
		sizeof_conf_hdr) !=
		strlen(fullline)) {
		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
	    }
	    CLEANUP_N_RET(mpconf, MP_STATUS_SUCCESS);
	}

	if ((mpconf_buf = (MP_CHAR *)mmap(0, stbuf.st_size,
		PROT_READ | PROT_WRITE,
		MAP_SHARED, mpconf, 0)) == MAP_FAILED) {
	    CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
	}

	if (search_line(mpconf_buf, stbuf.st_size,
	    pluginid, strlen(pluginid), &write_offset, &bytes_left) == 0) {
	    /* found a match. */
	    munmap((void *)mpconf_buf, stbuf.st_size);
	    CLEANUP_N_RET(mpconf, MP_STATUS_SUCCESS);
	} else {
	    munmap((void *)mpconf_buf, stbuf.st_size);
	    /* append the fullline to the mpconf. */
	    if (pwrite(mpconf, fullline, strlen(fullline),
		write_offset) !=
		strlen(fullline)) {
		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
	    } else {
		CLEANUP_N_RET(mpconf, MP_STATUS_SUCCESS);
	    }
	}
}

/**
 *******************************************************************************
 *
 * Deregisters a plugin from the common library.  This routine is based on
 * configuration file /etc/mpapi.conf that contains a list of plugin libraries.
 *
 * @param  pPluginId
 *      A pointer to a Plugin ID previously registered using
 *      the MP_RegisterPlugin API..
 *
 * @return An MP_STATUS indicating if the operation was successful or if
 *         an error occurred.
 *
 * @retval MP_STATUS_SUCCESS
 *         Returned when pPluginId is deregistered successfully.
 *
 * @retval MP_STATUS_INVALID_PARAMETER
 *      Returned if pPluginId is NULL or specifies a memory area that
 *      is not executable.
 *
 * @retval MP_STATUS_FAILED
 *          Returned if pClientFn deregistration is not possible at this time.
 *
 *******************************************************************************
 */
MP_STATUS MP_DeregisterPlugin(
    MP_WCHAR *pPluginId)
{
	int mpconf, tmp_mpconf, bytes_left, write_offset;
	char systemPath[MAX_NAME_SIZE], mpConfFilePath[MAX_NAME_SIZE],
	    tmp_mpConfFilePath[MAX_NAME_SIZE + sizeof(pid_t)];
	MP_CHAR    pluginid[MAX_NAME_SIZE];
	MP_CHAR    *mpconf_buf;
	MP_UINT32   sizeof_conf_hdr = strlen(HDR);
	struct stat	stbuf;

	if (pPluginId == NULL) {
	    return (MP_STATUS_INVALID_PARAMETER);
	}

	if (wcstombs(pluginid, pPluginId, MAX_NAME_SIZE) != wcslen(pPluginId)) {
	    return (MP_STATUS_INVALID_PARAMETER);
	}

	/* Open configuration file from known location */
	strncpy(mpConfFilePath, "/etc/mpapi.conf", MAX_NAME_SIZE);

	if ((chmod(mpConfFilePath, S_IRUSR|S_IRGRP|S_IROTH) == -1) &&
		(errno == ENOENT))  {
	    /* no file found */
	    return (MP_STATUS_UNKNOWN_FN);
	}
    
	if ((mpconf = open(mpConfFilePath, O_RDWR)) == -1) {
		return (MP_STATUS_FAILED);
	}

	if (fchmod(mpconf, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
	    close(mpconf);
	    return (MP_STATUS_FAILED);
	}

	if (lock_register(mpconf, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0) < 0) {
	    close(mpconf);
	    return (MP_STATUS_FAILED);
	}

	if (fstat(mpconf, &stbuf) == -1) {
	    CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
	}

	if (stbuf.st_size == 0) {
	    CLEANUP_N_RET(mpconf, MP_STATUS_SUCCESS);
	}

	if ((mpconf_buf = (MP_CHAR *)mmap(0, stbuf.st_size,
		PROT_READ | PROT_WRITE,
		MAP_SHARED, mpconf, 0)) == MAP_FAILED) {
	    CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
	}

	if (search_line(mpconf_buf, stbuf.st_size, pluginid, strlen(pluginid),
		&write_offset, &bytes_left) != 0) {
	    munmap((void *)mpconf_buf, stbuf.st_size);
	    CLEANUP_N_RET(mpconf, MP_STATUS_UNKNOWN_FN);
	} else {
	    /*
	     * found a match.
	     * construct temp file name using pid.
	     */
	    (void) snprintf(tmp_mpConfFilePath, MAX_NAME_SIZE,
		"%s%ld", "/etc/mpapi.conf", getpid());

	    if ((tmp_mpconf = open(tmp_mpConfFilePath,
		O_RDWR|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR)) < 0) {
		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
	    }

	    if (write(tmp_mpconf, mpconf_buf, write_offset) != write_offset) {
		close(tmp_mpconf);
		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
	    }

	    if (pwrite(tmp_mpconf, mpconf_buf + (stbuf.st_size - bytes_left),
		bytes_left, write_offset) != bytes_left) {
		close(tmp_mpconf);
		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
	    }

	    close(tmp_mpconf);
	    munmap((void *)mpconf_buf, stbuf.st_size);

	    /* rename temp file to mpConfFile before unlock and close. */
	    if (rename(tmp_mpConfFilePath, mpConfFilePath) != 0) {
		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
	    } else {
		CLEANUP_N_RET(mpconf, MP_STATUS_SUCCESS);
	    }
	}
}