xref: /titanic_41/usr/src/lib/mpapi/libmpapi/common/mpapi.c (revision 2b24ab6b3865caeede9eeb9db6b83e1d89dcd1ea)
1 /******************************************************************************
2  *
3  * Description
4  * mpapi.c - Implements Multipath Management API Version 1.0
5  *
6  * License:
7  *  The contents of this file are subject to the SNIA Public License
8  *  Version 1.1 (the "License"); you may not use this file except in
9  *  compliance with the License. You may obtain a copy of the License at
10  *
11  *  http://mp-mgmt-api.sourceforge.net
12  *
13  *  Software distributed under the License is distributed on an "AS IS"
14  *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
15  *  the License for the specific language governing rights and limitations
16  *  under the License.
17  *
18  * The Original Code is  SNIA iSCSI Management API and Multipath Management
19  *	API header files.
20  *
21  * The Initial Developer of the Original Code is:
22  *	Benjamin F. Kuo Troika Networks, Inc. (benk@troikanetworks.com)
23  *	David Dillard	VERITAS Software(david.dillard@veritas.com)
24  *	Jeff Ding 	Adaptec, Inc. (jding@corp.adaptec.com)
25  *      Hyon Kim        Sun Microsystems(hyon.kim@sun.com)
26  *
27  * Contributor(s):
28  *	Paul von Behren Sun Microsystems(paul.vonbehren@sun.com)
29  *
30  ******************************************************************************
31  *
32  *   Changes:
33  *  1/15/2005	Implemented SNIA MP API specification 1.0
34  *  10/11/2005
35  * 		- License location was specified in the header comment.
36  *  	    	- validate_object() routine was updated per the latest
37  *		  specification.
38  *  		- is_zero_oid() routine was added.
39  *  		- MP_GetObjectType() was updated with validate_object().
40  *  		- pplist argument checking added in MP_GetMultipathLus().
41  *  		- Corrected typo in MP_GetTaregetPortGroupProperties()
42  *  		- MP_RegisterForObjectPropertyChanges() was updated with
43  *		  is_zero_oid() routine.
44  *  		- MP_DeregisterForObjectPropertyChanges() was updated with
45  *		  is_zero_oid() routine.
46  *		- MP_RegisterForObjectVisibilityChanges() was updated with
47  *		  is_zero_oid() routine.
48  *		- MP_DeregisterForObjectVisibilityChanges() was updated with
49  *		  is_zero_oid() routine.
50  *  		- Added stat() check in MP_RegisterPlugin() to validate the
51  *		  the given plugin file name.
52  *  		- Made MP_DeregisterPlugin() return MP_STATUS_UNKNOWN_FN
53  *		  to mach the specification description.
54  ******************************************************************************
55  */
56 
57 #include <sys/sem.h>
58 #include <dlfcn.h>
59 #include <stdarg.h>
60 #include <unistd.h>
61 #include <sys/stat.h>
62 #include <sys/types.h>
63 #include <sys/mman.h>
64 #include <errno.h>
65 #include <stdio.h>
66 #include <fcntl.h>
67 #include <time.h>
68 #include <pthread.h>
69 #include "mpapi.h"
70 #include "mpapi-sun.h"
71 #include "mpapi-plugin.h"
72 
73 #define LIBRARY_SUPPORTED_MP_VERSION	1
74 #define LIBRARY_IMPLEMENTATION_VERSION	L"1.0.0"
75 #define LIBRARY_VENDOR			L"Sun Microsystems Inc."
76 
77 #define LIBRARY_FILE_NAME               "libMPAPI.so"
78 
79 
80 MPPLUGININFO_T	plugintable[MP_MAX_NUM_PLUGINS];
81 pthread_mutex_t mp_lib_mutex = PTHREAD_MUTEX_INITIALIZER;
82 
83 static int	number_of_plugins = -1;
84 
85 
86 void InitLibrary();
87 void ExitLibrary();
88 static int lock_register(int fd, int cmd, int type, off_t offset, int whence,
89 	    off_t len);
90 static int search_line(MP_CHAR *buf, size_t buflen, MP_CHAR *srch_id,
91 	    size_t id_len, int *write_offset, int *bytes_left);
92 static int is_zero_oid(MP_OID);
93 
94 /**
95  ******************************************************************************
96  *
97  * Validate the oid.
98  *
99  * - Return MP_STATUS_OBJECT_NOT_FOUND when no plugin is found or the ownerId
100  *      of input OID is not found.
101  * - Return MP_STATUS_INVALID_OBJECT_TYPE when no plugin is found or
102  *      the type of input OID is not one of legitimate types defined SNIA
103  *      Multipath Management spec.
104  * - Return MP_STATUS_INVALID_PARAMETER when the type of input OID is
105  *	legitimate but its object type doesn't match with the object type
106  *      argument.
107  * - Otherwise return MP_STATUS_SUCCESS.
108  *
109  ******************************************************************************
110  */
111 MP_STATUS validate_object(MP_OID obj, MP_OBJECT_TYPE objType,
112     MP_UINT32 flag)
113 {
114 
115     if ((number_of_plugins == 0) ||
116 	(obj.ownerId > number_of_plugins || obj.ownerId <= 0)) {
117 	return (MP_STATUS_OBJECT_NOT_FOUND);
118     } else if (obj.objectType < 0 || obj.objectType > MP_OBJECT_TYPE_MAX) {
119 	return (MP_STATUS_INVALID_OBJECT_TYPE);
120     } else if (obj.objectType == MP_OBJECT_TYPE_PLUGIN) {
121 	if (obj.objectSequenceNumber != 0) {
122 	    return (MP_STATUS_OBJECT_NOT_FOUND);
123 	}
124     }
125 
126     if (flag == MP_OBJECT_TYPE_MATCH) {
127     	if (obj.objectType != objType) {
128 	    return (MP_STATUS_INVALID_PARAMETER);
129         }
130     }
131     return (MP_STATUS_SUCCESS);
132 }
133 
134 /**
135  ******************************************************************************
136  *
137  * Check if an oid is ZERO_OID or not.
138  *
139  * - Return 1 if the input OID is ZERO_OID
140  *
141  * - Return 0 if not.
142  *
143  ******************************************************************************
144  */
145 static int is_zero_oid(MP_OID oid)
146 {
147 
148     if ((oid.objectType != MP_OBJECT_TYPE_UNKNOWN) || (oid.ownerId != 0) ||
149 	(oid.objectSequenceNumber != 0)) {
150 	return (0);
151     }
152 
153     return (1);
154 }
155 
156 /**
157  ******************************************************************************
158  *
159  * Initialize by loading plugin libraries and calling Initialize routine.
160  * Note: The build of libMPAPI.so should include a linker option to make this
161  *	 routine executed when it is loaded.
162  *
163  * - This routine bypasses a plugin library if it is not found.
164  * - The implementation of this routine is based on configuration file
165  *   /etc/mpapi.conf that contains a list of plugin libraries.
166  *
167  ******************************************************************************
168  */
169 void InitLibrary()
170 {
171 	FILE *mpconf;
172 	int fd_mpconf;
173 	MP_WCHAR fullline[MAX_LINE_SIZE]; /* line read in from mpapi.conf */
174 	MP_WCHAR name[MAX_NAME_SIZE]; 	/* Read in from file mpapi.conf */
175 	char path[MAX_NAME_SIZE]; 	/* Read in from file mpapi.conf */
176 	char systemPath[MAX_NAME_SIZE], mpConfFilePath[MAX_NAME_SIZE];
177 	MP_WCHAR *charPtr;
178 	MP_WCHAR *sol;
179 	struct stat	stat_buf;
180 
181 	MP_UINT32 i = 0;	/* index for plugin table */
182 
183 	if(number_of_plugins != -1) {
184 		return;
185 	}
186 
187 	(void) pthread_mutex_lock(&mp_lib_mutex);
188 
189 	number_of_plugins = 0;
190 
191 	/* Open configuration file from known location */
192 	strncpy(mpConfFilePath, "/etc/mpapi.conf", MAX_NAME_SIZE);
193 
194 	if ((fd_mpconf = open(mpConfFilePath, O_RDONLY)) < 0) {
195 		(void) pthread_mutex_unlock(&mp_lib_mutex);
196 		return;
197 	}
198 
199 	if (lock_register(fd_mpconf, F_SETLKW, F_RDLCK, 0, SEEK_SET, 0) < 0) {
200 		close(fd_mpconf);
201 		(void) pthread_mutex_unlock(&mp_lib_mutex);
202 		return;
203 	}
204 
205 	if ((mpconf = fdopen(fd_mpconf, "r")) == NULL) {
206 		lock_register(fd_mpconf, F_SETLK, F_UNLCK, 0, SEEK_SET, 0);
207 		close(fd_mpconf);
208 		(void) pthread_mutex_unlock(&mp_lib_mutex);
209 		return;
210 	}
211 
212 	/* Read in each line and load library */
213 	while ((mpconf != NULL) &&
214 	    (charPtr = fgetws(fullline, MAX_LINE_SIZE, mpconf))) {
215 	    if ((*charPtr != L'#') && (*charPtr != L'\n')) {
216 		/* Take out the '\n' */
217 		if ((charPtr = wcschr(fullline, L'\n')) != NULL)
218 		    *charPtr = L'\0';
219 
220 		charPtr = fullline;
221 		/* remove leading blank or taps. */
222 		while ((fullline[0] == L' ') || (fullline[0] == L'\t'))
223 			charPtr++;
224 
225 		sol = charPtr;
226 
227 		/*
228 		 * look for first tab or space.
229 		 */
230 		if ((charPtr = wcschr(fullline, L'\t')) == NULL)
231 		    charPtr = wcschr(fullline, L' ');
232 
233 		/* Set Null termination for library name if found */
234 		if (charPtr != NULL) {
235 		    *charPtr++ = L'\0';
236 		    wcsncpy(name, sol, MAX_NAME_SIZE);
237 			/* Skip space and tab until the next character found */
238 		    while ((*charPtr == L' ') || (*charPtr == L'\t'))
239 			charPtr++;
240 		} else {
241 		    continue;	/* May be invalid entry */
242 		}
243 
244 		/* Copy library name and path */
245 		wcstombs(path, charPtr, MAX_NAME_SIZE);
246 
247 		/*
248 		 * Continue to the next line if library name or path is
249 		 * invalid
250 		 */
251 		if ((wcslen(name) == 0) ||
252 			(strlen(path) == 0))
253 		    continue;
254 
255 		/* Load the plugin now */
256 		if (stat(path, &stat_buf) != -1) {
257 		    plugintable[i].hdlPlugin = dlopen(path, RTLD_LAZY);
258 		} else {
259 		    continue;
260 		}
261 
262 		if (plugintable[i].hdlPlugin != NULL) {
263 		    InitializeFn PassFunc;
264 		    MP_STATUS status;
265 
266                     wcsncpy(plugintable[i].pluginName,
267                         name, MAX_NAME_SIZE);
268                     strncpy(plugintable[i].pluginPath,
269                         path, MAX_NAME_SIZE);
270 
271 		    plugintable[i].ownerId = i + 1;
272 
273 		    PassFunc = (InitializeFn)
274 			 dlsym(plugintable[i].hdlPlugin, "Initialize");
275 		    if (PassFunc != NULL) {
276 			status = PassFunc(plugintable[i].ownerId);
277 		    }
278 
279 		    i++;
280 		}
281 	    }
282 	}
283 
284 	if (lock_register(fd_mpconf, F_SETLK, F_UNLCK, 0, SEEK_SET, 0) < 0) {
285 	    fclose(mpconf);
286 	    close(fd_mpconf);
287 	    (void) pthread_mutex_unlock(&mp_lib_mutex);
288 	    return;
289 	}
290 	fclose(mpconf);
291 	close(fd_mpconf);
292 
293 	number_of_plugins = i;
294 	(void) pthread_mutex_unlock(&mp_lib_mutex);
295 }
296 
297 /**
298  ******************************************************************************
299  *
300  * Exit by calling Terminate routine of plugin libraries.
301  *
302  * Note: The build of libMPAPI.so should include a linker option to make this
303  *	 routine executed when it is unloaded.
304  *
305  ******************************************************************************
306  */
307 void ExitLibrary()
308 {
309     MP_UINT32 i, j;
310 
311     if(number_of_plugins == -1)
312         return;
313 
314     (void) pthread_mutex_lock(&mp_lib_mutex);
315     for (i = 0; i < number_of_plugins; i++) {
316         if (plugintable[i].hdlPlugin != NULL) {
317         TerminateFn ExitPassFunc;
318 
319         ExitPassFunc = (TerminateFn)
320             dlsym(plugintable[i].hdlPlugin, "Terminate");
321 
322         if (ExitPassFunc != NULL) {
323             ExitPassFunc();
324         }
325 
326         /* Unload plugin from memory */
327         dlclose(plugintable[i].hdlPlugin);
328         }
329     }
330 
331     number_of_plugins = -1;
332 
333     (void) pthread_mutex_unlock(&mp_lib_mutex);
334     (void) pthread_mutex_destroy(&mp_lib_mutex);
335 }
336 
337 /**
338  ******************************************************************************
339  *
340  * Gets the properties of the MP API library that is being used.
341  *
342  * @param pProps
343  *  A pointer to an @ref MP_LIBRARY_PROPERTIES structure allocated by
344  *  the caller.  On successful return this structure will contain the
345  *  properties of the MP library.
346  *
347  * @return An MP_STATUS indicating if the operation was successful or
348  *  if an error occurred.
349  *
350  * @retval MP_STATUS_SUCCESS
351  *  Returned if the library properties were successfully returned.
352  *
353  * @retval MP_STATUS_INVALID_PARAMETER Returned if @a pProps is NULL or
354  *  specifies a memory area to which data cannot be written.
355  *
356  ******************************************************************************
357  */
358 MP_STATUS MP_GetLibraryProperties(
359     MP_LIBRARY_PROPERTIES *pProps)
360 {
361     char mpPath[MAX_NAME_SIZE];
362 
363     if(pProps == NULL) {
364         return MP_STATUS_INVALID_PARAMETER;
365     }
366 
367     /* Fill in properties */
368     if (mbstowcs(pProps->buildTime, BUILD_TIME, 256) !=
369 	strlen(BUILD_TIME)) {
370 	return (MP_STATUS_INVALID_PARAMETER);
371     }
372     pProps->supportedMpVersion = LIBRARY_SUPPORTED_MP_VERSION;
373 
374     wcsncpy(pProps->implementationVersion,
375 	LIBRARY_IMPLEMENTATION_VERSION, MAX_NAME_SIZE);
376     wcsncpy(pProps->vendor, LIBRARY_VENDOR, MAX_NAME_SIZE);
377 
378     snprintf(pProps->fileName, MAX_NAME_SIZE, "%s",
379 	LIBRARY_FILE_NAME);
380 
381     return MP_STATUS_SUCCESS;
382 }
383 
384 
385 /**
386  ******************************************************************************
387  *
388  * Gets a list of the object IDs of all currently loaded plugins.
389  *
390  * @param ppList A pointer to a pointer to an @ref MP_OID_LIST.  On successful
391  *  return this will contain a pointer to an @ref MP_OID_LIST
392  *  which contains the object IDs of all of the plugins currently loaded
393  *  by the library.
394  * @return An MP_STATUS indicating if the operation was successful or if
395  * an error
396  *              occurred.
397  * @retval MP_SUCCESS Returned if the plugin ID list was successfully returned.
398  * @retval MP_STATUS_INVALID_PARAMETER Returned if @a ppList is NULL or
399  * specifies a memory area to which data cannot be written.
400  *
401  ******************************************************************************
402  */
403 MP_STATUS MP_GetPluginOidList(
404     MP_OID_LIST **ppList)
405 {
406     MP_UINT32  i;
407 
408     if (ppList == NULL)
409         return (MP_STATUS_INVALID_PARAMETER);
410 
411     (void) pthread_mutex_lock(&mp_lib_mutex);
412 
413     if (number_of_plugins == 0) {
414         *ppList = (MP_OID_LIST*)calloc(1, sizeof(MP_OID_LIST));
415     } else {
416         *ppList = (MP_OID_LIST*)calloc(1,
417         sizeof(MP_OID_LIST) + (number_of_plugins - 1)* sizeof(MP_OID) );
418     }
419 
420     if ((*ppList) == NULL) {
421     	(void) pthread_mutex_unlock(&mp_lib_mutex);
422         return (MP_STATUS_INSUFFICIENT_MEMORY);
423     }
424 
425     (*ppList)->oidCount = number_of_plugins;
426 
427     if (number_of_plugins != 0) {
428         for (i = 0; i < number_of_plugins; i++) {
429         (*ppList)->oids[i].objectType = MP_OBJECT_TYPE_PLUGIN;
430         (*ppList)->oids[i].ownerId = plugintable[i].ownerId;
431         (*ppList)->oids[i].objectSequenceNumber = 0;
432         }
433     }
434 
435     (void) pthread_mutex_unlock(&mp_lib_mutex);
436     return MP_STATUS_SUCCESS;
437 }
438 
439 /**
440  *******************************************************************************
441  *
442  * Gets the properties of the specified vendor plugin.
443  *
444  * @param  oid
445  *         The ID of the plugin whose properties are being retrieved.
446  *
447  * @param  pProps
448  *         A pointer to an @ref MP_PLUGIN_PROPERTIES structure allocated by
449  *         the caller.  On successful return this will contain the properties
450  *         of the plugin specified by pluginOid.
451  *
452  * @return An MP_STATUS indicating if the operation was successful or if an
453  *         error occurred.
454  *
455  * @retval MP_STATUS_SUCCESS
456  *         Returned if the plugin properties were successfully returned.
457  *
458  * @retval MP_STATUS_INVALID_OBJECT_TYPE
459  *         Returned if oid does not specify any valid object type.
460  *
461  * @retval MP_STATUS_OBJECT_NOT_FOUND
462  *         Returned if oid has an owner that is not currently known to
463  *     the system.
464  *
465  * @retval MP_STATUS_INVALID_PARAMETER
466  *         Returned if 'pProps' is NULL or specifies a memory area to
467  *         which data cannot be written.
468  *
469  *******************************************************************************
470  */
471 MP_STATUS MP_GetPluginProperties(
472     MP_OID pluginOid,
473     MP_PLUGIN_PROPERTIES *pProps)
474 {
475     MP_GetPluginPropertiesPluginFn PassFunc;
476     MP_UINT32 index;
477     MP_STATUS status;
478 
479     if(pProps == NULL)
480         return (MP_STATUS_INVALID_PARAMETER);
481 
482     if ((status = validate_object(pluginOid, MP_OBJECT_TYPE_PLUGIN,
483         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
484         return (status);
485     }
486 
487     (void) pthread_mutex_lock(&mp_lib_mutex);
488 
489     index = pluginOid.ownerId - 1;
490     if (plugintable[index].hdlPlugin != NULL) {
491         PassFunc = (MP_GetPluginPropertiesPluginFn)
492         dlsym(plugintable[index].hdlPlugin, "MP_GetPluginPropertiesPlugin");
493 
494         if (PassFunc != NULL) {
495             status = PassFunc(pProps);
496         } else {
497 	    status = MP_STATUS_UNSUPPORTED;
498         }
499     } else {
500         status = MP_STATUS_FAILED;
501     }
502 
503     (void) pthread_mutex_unlock(&mp_lib_mutex);
504     return status;
505 }
506 
507 /**
508  *******************************************************************************
509  *
510  * Gets the object ID for the plugin associated with the specified object ID.
511  *
512  * @param  oid
513  *         The object ID of an object that has been received from a previous
514  *         library call.
515  *
516  * @param  pPluginOid
517  *         A pointer to an MP_OID structure allocated by the caller.  On
518  *         successful return this will contain the object ID of the plugin
519  *         associated with the object specified by @a objectId.
520  *
521  * @return An MP_STATUS indicating if the operation was successful or if
522  *         an error occurred.
523  *
524  * @retval MP_STATUS_SUCCESS
525  *          Returned if the associated plugin ID was successfully returned.
526  *
527  * @retval MP_STATUS_OBJECT_NOT_FOUND
528  *          Returned if oid does not specify a plugin that is currently known to
529  *     the system.
530  *
531  * @retval MP_STATUS_INVALID_PARAMETER
532  *          Returned if 'oid' specifies an object not owned by a plugin or
533  *     if pPluginOid is NULL or specifies a memory area to which data
534  *     cannot be written.
535  *
536  * @retval MP_STATUS_INVALID_OBJECT_TYPE
537  *         Returned if 'oid' specifies an object with an invalid type.
538  *
539  *******************************************************************************
540  */
541 MP_STATUS MP_GetAssociatedPluginOid(
542     MP_OID objectId,
543     MP_OID *pPluginId)
544 {
545     MP_UINT32 i;
546     MP_STATUS status;
547 
548     if (pPluginId == NULL)
549         return (MP_STATUS_INVALID_PARAMETER);
550 
551     if ((status = validate_object(objectId, 0, MP_OBJECT_TYPE_ANY)) !=
552             MP_STATUS_SUCCESS) {
553         return (status);
554     }
555 
556     pPluginId->objectType = MP_OBJECT_TYPE_PLUGIN;
557     pPluginId->ownerId = objectId.ownerId;
558     pPluginId->objectSequenceNumber = 0;
559 
560     return (MP_STATUS_SUCCESS);
561 }
562 
563 /**
564  *******************************************************************************
565  *
566  * Gets the object type of an initialized object ID.
567  *
568  * @param  oid
569  *         The object ID of an object that has been received from a previous
570  *         library call.
571  *
572  * @param  pObjectType
573  *         A pointer to an MP_OBJECT_TYPE variable allocated by the caller.
574  *         On successful return this will contain the object type of oid.
575  *
576  * @return An MP_STATUS indicating if the operation was successful or
577  *         if an error occurred.
578  *
579  * @retval MP_STATUS_OBJECT_NOT_FOUND
580  *      Returned if oid has an owner that is not currently known to
581  *      the system.
582  *
583  * @retval MP_STATUS_INVALID_PARAMETER
584  *      Returned if oid does not specify any valid object type.
585  *
586  * @retval MP_STATUS_SUCCESS
587  *         Returned when the operation is successful.
588  *
589  *******************************************************************************
590  */
591 MP_STATUS MP_GetObjectType(
592     MP_OID oid,
593     MP_OBJECT_TYPE *pObjectType)
594 {
595     MP_STATUS status;
596 
597     if (pObjectType == NULL)
598         return MP_STATUS_INVALID_PARAMETER;
599 
600     if ((status = validate_object(oid, 0, MP_OBJECT_TYPE_ANY))
601 	!= MP_STATUS_SUCCESS) {
602         return (status);
603     }
604 
605     *pObjectType = oid.objectType;
606     return MP_STATUS_SUCCESS;
607 }
608 
609 /**
610  *******************************************************************************
611  *
612  * Gets a list of the object IDs of all the device product properties
613  *       associated with this plugin.
614  *
615  * @param  oid
616  *         The object ID of plugin.
617  *
618  * @param  ppList
619  *      A pointer to a pointer to an MP_OID_LIST structure.
620  *      On a successful return, this will contain a pointer to
621  *      an MP_OID_LIST that contains the object IDs of all the device
622  *      product descriptors associated with the specified plugin.
623  *
624  * @return An MP_STATUS indicating if the operation was successful or if
625  *         an error occurred.
626  *
627  * @retval MP_STATUS_SUCCESS
628  *         Returned when the operation is successful.
629  *
630  * @retval MP_STATUS_INVALID_PARAMETER
631  *      Returned if ppList pointer passed as placeholder for holding
632  *      the device product list is found to be invalid.
633  *
634  * @retval MP_STATUS_INVALID_OBJECT_TYPE
635  *         Returned if oid does not specify any valid object type.
636  *
637  * @retval MP_STATUS_FAILED
638  *         Returned when the plugin for the specified oid is not found.
639  *
640  * @retval MP_STATUS_INSUFFICIENT_MEMORY
641  *      Returned when memory allocation failure occurs
642  *
643  * @retval MP_STATUS_UNSUPPORTED
644  *      Returned when the API is not supported.
645  *
646  *******************************************************************************
647  */
648 MP_STATUS MP_GetDeviceProductOidList(
649     MP_OID oid,
650     MP_OID_LIST **ppList)
651 {
652     MP_GetDeviceProductOidListPluginFn PassFunc;
653     MP_UINT32 index;
654     MP_STATUS status;
655 
656     if (ppList == NULL)
657         return MP_STATUS_INVALID_PARAMETER;
658 
659     if ((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
660         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
661         return (status);
662     }
663 
664     (void) pthread_mutex_lock(&mp_lib_mutex);
665 
666     index = oid.ownerId - 1;
667     if (plugintable[index].hdlPlugin != NULL) {
668         PassFunc = (MP_GetDeviceProductOidListPluginFn)
669         dlsym(plugintable[index].hdlPlugin,
670         "MP_GetDeviceProductOidListPlugin");
671         if (PassFunc != NULL) {
672 	    status = PassFunc(ppList);
673         } else {
674 	    status = MP_STATUS_UNSUPPORTED;
675         }
676     } else {
677         status = MP_STATUS_FAILED;
678     }
679 
680     (void) pthread_mutex_unlock(&mp_lib_mutex);
681     return status;
682 }
683 
684 /**
685  *******************************************************************************
686  *
687  * Gets the device product properties of the specified plugin oid.
688  *
689  * @param  oid
690  *         The object ID of the plugin.
691  *
692  * @param  ppProps
693  *      A pointer to a pointer to an MP_DEVICE_PRODUCT_PROPERTIES structure
694  *      allocated by the caller. On successful return it will contain
695  *      a pointer to an MP_DEVICE_PRODUCT_PROPERTIES structure allocated
696  *      by the library.
697  *
698  * @return An MP_STATUS indicating if the operation was successful or if
699  *         an error occurred.
700  *
701  * @retval MP_STATUS_SUCCESS
702  *         Returned when the operation is successful.
703  *
704  * @retval MP_STATUS_INVALID_PARAMETER
705  *      Returned if ppProps pointer passed as placeholder for holding
706  *      the device product properties is found to be invalid.
707  *
708  * @retval MP_STATUS_INVALID_OBJECT_TYPE
709  *         Returned if oid does not specify any valid object type.
710  *
711  * @retval MP_STATUS_FAILED
712  *         Returned when the plugin for the specified oid is not found.
713  *
714  * @retval MP_STATUS_INSUFFICIENT_MEMORY
715  *      Returned when memory allocation failure occurs
716  *
717  * @retval MP_STATUS_UNSUPPORTED
718  *      Returned when the API is not supported.
719  *
720  *******************************************************************************
721  */
722 MP_STATUS MP_GetDeviceProductProperties(
723         MP_OID oid,
724         MP_DEVICE_PRODUCT_PROPERTIES *pProps)
725 {
726     MP_GetDeviceProductPropertiesFn PassFunc;
727     MP_UINT32 index;
728     MP_STATUS status;
729 
730     if (pProps == NULL)
731         return MP_STATUS_INVALID_PARAMETER;
732 
733     if ((status = validate_object(oid, MP_OBJECT_TYPE_DEVICE_PRODUCT,
734         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
735         return (status);
736     }
737 
738     (void) pthread_mutex_lock(&mp_lib_mutex);
739 
740     index = oid.ownerId - 1;
741     if (plugintable[index].hdlPlugin != NULL) {
742         PassFunc = (MP_GetDeviceProductPropertiesFn)
743         dlsym(plugintable[index].hdlPlugin,
744         "MP_GetDeviceProductProperties");
745 
746         if (PassFunc != NULL) {
747 	    status = PassFunc(oid, pProps);
748         } else {
749 	    status = MP_STATUS_UNSUPPORTED;
750         }
751     } else {
752         status = MP_STATUS_FAILED;
753     }
754 
755     (void) pthread_mutex_unlock(&mp_lib_mutex);
756     return status;
757 }
758 
759 /**
760  *******************************************************************************
761  *
762  * Gets a list of the object IDs of all the initiator ports associated
763  * with this plugin.
764  *
765  * @param  oid
766  *         The object ID of plugin.
767  *
768  * @param  ppList
769  *      A pointer to a pointer to an MP_OID_LIST structure.
770  *      On a successful return, this will contain a pointer to
771  *      an MP_OID_LIST that contains the object IDs of all the initiator
772  *      ports associated with the specified plugin.
773  *
774  * @return An MP_STATUS indicating if the operation was successful or if
775  *         an error occurred.
776  *
777  * @retval MP_STATUS_SUCCESS
778  *         Returned when the operation is successful.
779  *
780  * @retval MP_STATUS_INVALID_PARAMETER
781  *      Returned if ppList pointer passed as placeholder for holding
782  *      the initiator port list is found to be invalid.
783  *
784  * @retval MP_STATUS_INVALID_OBJECT_TYPE
785  *          Returned if oid does not specify any valid object type.
786  *
787  * @retval MP_STATUS_FAILED
788  *          Returned when the plugin for the specified oid is not found.
789  *
790  * @retval MP_STATUS_INSUFFICIENT_MEMORY
791  *      Returned when memory allocation failure occurs
792  *
793  * @retval MP_STATUS_UNSUPPORTED
794  *      Returned when the API is not supported.
795  *
796  *******************************************************************************
797  */
798 MP_STATUS MP_GetInitiatorPortOidList(
799         MP_OID oid,
800         MP_OID_LIST **ppList)
801 {
802     MP_GetInitiatorPortOidListPluginFn PassFunc;
803     MP_UINT32 index;
804     MP_STATUS status;
805 
806     if (ppList == NULL)
807         return MP_STATUS_INVALID_PARAMETER;
808 
809     if ((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
810         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
811         return (status);
812     }
813 
814     (void) pthread_mutex_lock(&mp_lib_mutex);
815 
816     index = oid.ownerId - 1;
817     if (plugintable[index].hdlPlugin != NULL) {
818         PassFunc = (MP_GetDeviceProductOidListPluginFn)
819         dlsym(plugintable[index].hdlPlugin, "MP_GetInitiatorPortOidListPlugin");
820 
821         if (PassFunc != NULL) {
822 	    status = PassFunc(ppList);
823         } else {
824 	    status = MP_STATUS_UNSUPPORTED;
825         }
826     } else {
827         status = MP_STATUS_FAILED;
828     }
829 
830     (void) pthread_mutex_unlock(&mp_lib_mutex);
831     return (status);
832 }
833 
834 /**
835  *******************************************************************************
836  *
837  * Gets the properties of the specified initiator port.
838  *
839  * @param  oid
840  *         The object ID of the initiator port.
841  *
842  * @param  pProps
843  *      A pointer to an MP_INITIATOR_PORT_PROPERTIES structure
844  *      allocated by the caller. On successful return, this structure
845  *      will contain the properties of the port specified by oid.
846  *
847  * @return An MP_STATUS indicating if the operation was successful or if
848  *         an error occurred.
849  *
850  * @retval MP_STATUS_SUCCESS
851  *         Returned when the operation is successful.
852  *
853  * @retval MP_STATUS_INVALID_PARAMETER
854  *      Returned if pProps is NULL or specifies a memory area to
855  *      which data cannot be written.
856  *
857  * @retval MP_STATUS_INVALID_OBJECT_TYPE
858  *          Returned if oid does not specify any valid object type.
859  *
860  * @retval MP_STATUS_OBJECT_NOT_FOUND
861  *          Returned if oid has an owner that is not currently known to
862  *      the system.
863  *
864  *******************************************************************************
865  */
866 MP_STATUS MP_GetInitiatorPortProperties(
867         MP_OID oid,
868         MP_INITIATOR_PORT_PROPERTIES *pProps)
869 {
870     MP_GetInitiatorPortPropertiesFn PassFunc;
871     MP_UINT32 index;
872     MP_STATUS status;
873 
874     if (pProps == NULL)
875         return MP_STATUS_INVALID_PARAMETER;
876 
877     if ((status = validate_object(oid, MP_OBJECT_TYPE_INITIATOR_PORT,
878         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
879         return (status);
880     }
881 
882     (void) pthread_mutex_lock(&mp_lib_mutex);
883 
884     index = oid.ownerId - 1;
885     if (plugintable[index].hdlPlugin != NULL) {
886         PassFunc = (MP_GetInitiatorPortPropertiesFn)
887         dlsym(plugintable[index].hdlPlugin,
888         "MP_GetInitiatorPortProperties");
889 
890         if (PassFunc != NULL) {
891 	    status = PassFunc(oid, pProps);
892         } else {
893 	    status = MP_STATUS_UNSUPPORTED;
894         }
895     } else {
896         status = MP_STATUS_FAILED;
897     }
898 
899     (void) pthread_mutex_unlock(&mp_lib_mutex);
900     return status;
901 }
902 
903 /**
904  *******************************************************************************
905  *
906  * Gets a list of multipath logical units associated to a plugin.
907  *
908  * @param  oid
909  *         The object ID of plugin.
910  *
911  * @param  ppList
912  *      A pointer to a pointer to an MP_OID_LIST structure.
913  *      On a successful return, this will contain a pointer to
914  *      an MP_OID_LIST that contains the object IDs of all the multipath
915  *      logical units associated with the specified plugin.
916  *
917  * @return An MP_STATUS indicating if the operation was successful or if
918  *         an error occurred.
919  *
920  * @retval MP_STATUS_SUCCESS
921  *         Returned when the operation is successful.
922  *
923  * @retval MP_STATUS_INVALID_PARAMETER
924  *      Returned if ppList pointer passed as placeholder for holding
925  *      the multipath logical unit list is found to be invalid.
926  *
927  * @retval MP_STATUS_INVALID_OBJECT_TYPE
928  *          Returned if oid does not specify any valid object type.
929  *
930  * @retval MP_STATUS_FAILED
931  *          Returned when the plugin for the specified oid is not found.
932  *
933  * @retval MP_STATUS_INSUFFICIENT_MEMORY
934  *      Returned when memory allocation failure occurs
935  *
936  * @retval MP_STATUS_UNSUPPORTED
937  *      Returned when the API is not supported.
938  *
939  *******************************************************************************
940  */
941 MP_STATUS MP_GetMultipathLus(
942         MP_OID oid,
943         MP_OID_LIST **ppList)
944 {
945     MP_UINT32 index;
946     MP_STATUS status;
947 
948     if (ppList == NULL)
949         return MP_STATUS_INVALID_PARAMETER;
950 
951     if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
952 	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
953 	((status = validate_object(oid, MP_OBJECT_TYPE_DEVICE_PRODUCT,
954         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
955         return (status);
956     }
957 
958     (void) pthread_mutex_lock(&mp_lib_mutex);
959 
960     index = oid.ownerId - 1;
961     if (plugintable[index].hdlPlugin != NULL) {
962 	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
963 	    MP_GetMultipathLusPluginFn PassFunc;
964 	    PassFunc = (MP_GetMultipathLusPluginFn)
965 	    dlsym(plugintable[index].hdlPlugin,
966         	"MP_GetMultipathLusPlugin");
967 
968 	    if (PassFunc != NULL) {
969 		status = PassFunc(ppList);
970 	    } else {
971 		status = MP_STATUS_UNSUPPORTED;
972 	    }
973 	} else if (oid.objectType == MP_OBJECT_TYPE_DEVICE_PRODUCT) {
974 	    MP_GetMultipathLusDevProdFn PassFunc;
975 	    PassFunc = (MP_GetMultipathLusDevProdFn)
976 	    dlsym(plugintable[index].hdlPlugin,
977         	"MP_GetMultipathLusDevProd");
978 
979 	    if (PassFunc != NULL) {
980 		status = PassFunc(oid, ppList);
981 	    } else {
982 		status = MP_STATUS_UNSUPPORTED;
983 	    }
984 	} else {
985 	    status = MP_STATUS_INVALID_PARAMETER;
986 	}
987     }
988 
989     (void) pthread_mutex_unlock(&mp_lib_mutex);
990     return (status);
991 }
992 
993 
994 /**
995  *******************************************************************************
996  *
997  * Gets the properties of the specified logical unit.
998  *
999  * @param  oid
1000  *         The object ID of the multipath logical unit.
1001  *
1002  * @param  pProps
1003  *      A pointer to an MP_MULTIPATH_LOGICAL_UNIT_PROPERTIES structure
1004  *      allocated by the caller. On successful return, this structure
1005  *      will contain the properties of the port specified by oid.
1006  *
1007  * @return An MP_STATUS indicating if the operation was successful or if
1008  *         an error occurred.
1009  *
1010  * @retval MP_STATUS_SUCCESS
1011  *         Returned when the operation is successful.
1012  *
1013  * @retval MP_STATUS_INVALID_PARAMETER
1014  *      Returned if pProps is NULL or specifies a memory area to
1015  *      which data cannot be written.
1016  *
1017  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1018  *          Returned if oid does not specify any valid object type.
1019  *
1020  * @retval MP_STATUS_OBJECT_NOT_FOUND
1021  *          Returned if oid has an owner that is not currently known to
1022  *      the system.
1023  *
1024  *******************************************************************************
1025  */
1026 MP_STATUS MP_GetMPLogicalUnitProperties(
1027         MP_OID oid,
1028         MP_MULTIPATH_LOGICAL_UNIT_PROPERTIES *pProps)
1029 {
1030     MP_GetMPLogicalUnitPropertiesFn PassFunc;
1031     MP_UINT32 index;
1032     MP_STATUS status;
1033 
1034     if (pProps == NULL)
1035         return MP_STATUS_INVALID_PARAMETER;
1036 
1037     if ((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
1038         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1039         return (status);
1040     }
1041 
1042     (void) pthread_mutex_lock(&mp_lib_mutex);
1043 
1044     index = oid.ownerId - 1;
1045     if (plugintable[index].hdlPlugin != NULL) {
1046         PassFunc = (MP_GetMPLogicalUnitPropertiesFn)
1047         dlsym(plugintable[index].hdlPlugin,
1048         "MP_GetMPLogicalUnitProperties");
1049 
1050         if (PassFunc != NULL) {
1051 	    status = PassFunc(oid, pProps);
1052         } else {
1053 	    status = MP_STATUS_UNSUPPORTED;
1054         }
1055     } else {
1056         status = MP_STATUS_FAILED;
1057     }
1058 
1059     (void) pthread_mutex_unlock(&mp_lib_mutex);
1060     return (status);
1061 }
1062 
1063 /**
1064  *******************************************************************************
1065  *
1066  * Gets a list of the object IDs of all the path logical units associated
1067  * with the specified multipath logical unit, initiator port, or target port.
1068  *
1069  * @param  oid
1070  *         The object ID of multipath logical unit, initiator port, or
1071  *     target port.
1072  *
1073  * @param  ppList
1074  *      A pointer to a pointer to an MP_OID_LIST structure.
1075  *      On a successful return, this will contain a pointer to
1076  *      an MP_OID_LIST that contains the object IDs of all the mp path
1077  *      logical units associated with the specified OID.
1078  *
1079  * @return An MP_STATUS indicating if the operation was successful or if
1080  *         an error occurred.
1081  *
1082  * @retval MP_STATUS_SUCCESS
1083  *         Returned when the operation is successful.
1084  *
1085  * @retval MP_STATUS_INVALID_PARAMETER
1086  *      Returned if ppList pointer passed as placeholder for holding
1087  *      the device product list is found to be invalid.
1088  *
1089  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1090  *          Returned if oid does not specify any valid object type.
1091  *
1092  * @retval MP_STATUS_FAILED
1093  *          Returned when the plugin for the specified oid is not found.
1094  *
1095  * @retval MP_STATUS_INSUFFICIENT_MEMORY
1096  *      Returned when memory allocation failure occurs
1097  *
1098  * @retval MP_STATUS_OBJECT_NOT_FOUND
1099  *      Returned if oid has an owner that is not currently known to
1100  *      the system.
1101  *
1102  *******************************************************************************
1103  */
1104 MP_STATUS MP_GetAssociatedPathOidList(
1105         MP_OID oid,
1106         MP_OID_LIST **ppList)
1107 {
1108     MP_GetAssociatedPathOidListFn PassFunc;
1109     MP_UINT32 index;
1110     MP_STATUS status;
1111 
1112     if (ppList == NULL)
1113         return MP_STATUS_INVALID_PARAMETER;
1114 
1115     if (((status = validate_object(oid, MP_OBJECT_TYPE_INITIATOR_PORT,
1116         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
1117 	((status = validate_object(oid, MP_OBJECT_TYPE_TARGET_PORT,
1118         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
1119 	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
1120         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
1121         return (status);
1122     }
1123 
1124     (void) pthread_mutex_lock(&mp_lib_mutex);
1125 
1126     index = oid.ownerId - 1;
1127     if (plugintable[index].hdlPlugin != NULL) {
1128         PassFunc = (MP_GetAssociatedPathOidListFn)
1129         dlsym(plugintable[index].hdlPlugin,
1130         "MP_GetAssociatedPathOidList");
1131 
1132         if (PassFunc != NULL) {
1133 	    status = PassFunc(oid, ppList);
1134         } else {
1135 	    status = MP_STATUS_UNSUPPORTED;
1136         }
1137     } else {
1138         status = MP_STATUS_FAILED;
1139     }
1140 
1141     (void) pthread_mutex_unlock(&mp_lib_mutex);
1142     return (status);
1143 }
1144 
1145 /**
1146  *******************************************************************************
1147  *
1148  * Gets the properties of the specified path logical unit.
1149  *
1150  * @param  oid
1151  *         The object ID of the path logical unit.
1152  *
1153  * @param  pProps
1154  *      A pointer to an MP_PATH_LOGICAL_UNIT_PROPERTIES structure
1155  *      allocated by the caller. On successful return, this structure
1156  *      will contain the properties of the port specified by oid.
1157  *
1158  * @return An MP_STATUS indicating if the operation was successful or if
1159  *         an error occurred.
1160  *
1161  * @retval MP_STATUS_SUCCESS
1162  *         Returned when the operation is successful.
1163  *
1164  * @retval MP_STATUS_INVALID_PARAMETER
1165  *      Returned if pProps is NULL or specifies a memory area to
1166  *      which data cannot be written.
1167  *
1168  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1169  *          Returned if oid does not specify any valid object type.
1170  *
1171  * @retval MP_STATUS_OBJECT_NOT_FOUND
1172  *          Returned if oid has an owner that is not currently known to
1173  *      the system.
1174  *
1175  *******************************************************************************
1176  */
1177 MP_STATUS MP_GetPathLogicalUnitProperties(
1178         MP_OID oid,
1179         MP_PATH_LOGICAL_UNIT_PROPERTIES *pProps)
1180 {
1181     MP_GetPathLogicalUnitPropertiesFn PassFunc;
1182     MP_UINT32 index;
1183     MP_STATUS status;
1184 
1185     if (pProps == NULL)
1186         return MP_STATUS_INVALID_PARAMETER;
1187 
1188     if ((status = validate_object(oid, MP_OBJECT_TYPE_PATH_LU,
1189         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1190         return (status);
1191     }
1192 
1193     (void) pthread_mutex_lock(&mp_lib_mutex);
1194 
1195     index = oid.ownerId - 1;
1196     if (plugintable[index].hdlPlugin != NULL) {
1197         PassFunc = (MP_GetPathLogicalUnitPropertiesFn)
1198         dlsym(plugintable[index].hdlPlugin,
1199         "MP_GetPathLogicalUnitProperties");
1200 
1201         if (PassFunc != NULL) {
1202 	    status = PassFunc(oid, pProps);
1203         } else {
1204 	    status = MP_STATUS_UNSUPPORTED;
1205         }
1206     } else {
1207         status = MP_STATUS_FAILED;
1208     }
1209 
1210     (void) pthread_mutex_unlock(&mp_lib_mutex);
1211     return (status);
1212 }
1213 
1214 /**
1215  *******************************************************************************
1216  *
1217  * Gets a list of the object IDs of all the target port group associated
1218  * with the specified multipath logical unit.
1219  *
1220  * @param  oid
1221  *         The object ID of the multiple logical unit.
1222  *
1223  * @param  ppList
1224  *      A pointer to a pointer to an MP_OID_LIST structure.
1225  *      On a successful return, this will contain a pointer to
1226  *      an MP_OID_LIST that contains the object IDs of all the target
1227  *      port group associated with the specified multipath logical unit.
1228  *
1229  * @return An MP_STATUS indicating if the operation was successful or if
1230  *         an error occurred.
1231  *
1232  * @retval MP_STATUS_SUCCESS
1233  *         Returned when the operation is successful.
1234  *
1235  * @retval MP_STATUS_INVALID_PARAMETER
1236  *      Returned if ppList pointer passed as placeholder for holding
1237  *      the target port group list is found to be invalid.
1238  *
1239  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1240  *          Returned if oid does not specify any valid object type.
1241  *
1242  * @retval MP_STATUS_FAILED
1243  *          Returned when the plugin for the specified oid is not found.
1244  *
1245  * @retval MP_STATUS_INSUFFICIENT_MEMORY
1246  *      Returned when memory allocation failure occurs
1247  *
1248  *
1249  *******************************************************************************
1250  */
1251 MP_STATUS MP_GetAssociatedTPGOidList(
1252         MP_OID oid,
1253         MP_OID_LIST **ppList)
1254 {
1255     MP_GetAssociatedTPGOidListFn PassFunc;
1256     MP_UINT32 index;
1257     MP_STATUS status;
1258 
1259     if (ppList == NULL)
1260         return MP_STATUS_INVALID_PARAMETER;
1261 
1262     if ((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
1263         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1264         return (status);
1265     }
1266 
1267     (void) pthread_mutex_lock(&mp_lib_mutex);
1268 
1269     index = oid.ownerId - 1;
1270     if (plugintable[index].hdlPlugin != NULL) {
1271         PassFunc = (MP_GetAssociatedTPGOidListFn)
1272         dlsym(plugintable[index].hdlPlugin,
1273         "MP_GetAssociatedTPGOidList");
1274 
1275         if (PassFunc != NULL) {
1276 	    status = PassFunc(oid, ppList);
1277         } else {
1278 	    status = MP_STATUS_UNSUPPORTED;
1279         }
1280     } else {
1281         status = MP_STATUS_FAILED;
1282     }
1283 
1284     (void) pthread_mutex_unlock(&mp_lib_mutex);
1285     return (status);
1286 }
1287 
1288 /**
1289  *******************************************************************************
1290  *
1291  * Gets the properties of the specified target port group.
1292  *
1293  * @param  oid
1294  *         The object ID of the target port group.
1295  *
1296  * @param  pProps
1297  *      A pointer to an MP_TARGET_PORT_GROUP_PROPERTIES structure
1298  *      allocated by the caller. On successful return, this structure
1299  *      will contain the properties of the port specified by oid.
1300  *
1301  * @return An MP_STATUS indicating if the operation was successful or if
1302  *         an error occurred.
1303  *
1304  * @retval MP_STATUS_SUCCESS
1305  *         Returned when the operation is successful.
1306  *
1307  * @retval MP_STATUS_INVALID_PARAMETER
1308  *      Returned if pProps is NULL or specifies a memory area to
1309  *      which data cannot be written.
1310  *
1311  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1312  *          Returned if oid does not specify any valid object type.
1313  *
1314  * @retval MP_STATUS_OBJECT_NOT_FOUND
1315  *          Returned if oid has an owner that is not currently known to
1316  *      the system.
1317  *
1318  *******************************************************************************
1319  */
1320 MP_STATUS MP_GetTargetPortGroupProperties(
1321         MP_OID oid,
1322         MP_TARGET_PORT_GROUP_PROPERTIES *pProps)
1323 {
1324     MP_GetTargetPortGroupPropertiesFn PassFunc;
1325     MP_UINT32 index;
1326     MP_STATUS status;
1327 
1328     if (pProps == NULL)
1329         return MP_STATUS_INVALID_PARAMETER;
1330 
1331     if ((status = validate_object(oid, MP_OBJECT_TYPE_TARGET_PORT_GROUP,
1332         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1333         return (status);
1334     }
1335 
1336     (void) pthread_mutex_lock(&mp_lib_mutex);
1337 
1338     index = oid.ownerId - 1;
1339     if (plugintable[index].hdlPlugin != NULL) {
1340         PassFunc = (MP_GetTargetPortGroupPropertiesFn)
1341         dlsym(plugintable[index].hdlPlugin,
1342         "MP_GetTargetPortGroupProperties");
1343 
1344         if (PassFunc != NULL) {
1345 	    status = PassFunc(oid, pProps);
1346         } else {
1347 	    status = MP_STATUS_UNSUPPORTED;
1348         }
1349     } else {
1350         status = MP_STATUS_FAILED;
1351     }
1352 
1353     (void) pthread_mutex_unlock(&mp_lib_mutex);
1354     return (status);
1355 }
1356 
1357 /**
1358  *******************************************************************************
1359  *
1360  * Gets a list of multipath logical units associated with the specific target
1361  *  port group.
1362  *
1363  * @param  oid
1364  *         The object ID of the target port group.
1365  *
1366  * @param  ppList
1367  *      A pointer to a pointer to an MP_OID_LIST structure.
1368  *      On a successful return, this will contain a pointer to
1369  *      an MP_OID_LIST that contains the object IDs of all the multipath
1370  *      logical units associated with the specified target port group.
1371  *
1372  * @return An MP_STATUS indicating if the operation was successful or if
1373  *         an error occurred.
1374  *
1375  * @retval MP_STATUS_SUCCESS
1376  *         Returned when the operation is successful.
1377  *
1378  * @retval MP_STATUS_INVALID_PARAMETER
1379  *      Returned if ppList pointer passed as placeholder for holding
1380  *      the multipath logical unit list is found to be invalid.
1381  *
1382  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1383  *          Returned if oid does not specify any valid object type.
1384  *
1385  * @retval MP_STATUS_FAILED
1386  *          Returned when the plugin for the specified oid is not found.
1387  *
1388  * @retval MP_STATUS_INSUFFICIENT_MEMORY
1389  *      Returned when memory allocation failure occurs
1390  *
1391  *******************************************************************************
1392  */
1393 MP_STATUS MP_GetMPLuOidListFromTPG(
1394         MP_OID oid,
1395         MP_OID_LIST **ppList)
1396 {
1397     MP_GetMPLuOidListFromTPGFn PassFunc;
1398     MP_UINT32 index;
1399     MP_STATUS status;
1400 
1401     if (ppList == NULL)
1402         return MP_STATUS_INVALID_PARAMETER;
1403 
1404     if ((status = validate_object(oid, MP_OBJECT_TYPE_TARGET_PORT_GROUP,
1405         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1406         return (status);
1407     }
1408 
1409     (void) pthread_mutex_lock(&mp_lib_mutex);
1410 
1411     index = oid.ownerId - 1;
1412     if (plugintable[index].hdlPlugin != NULL) {
1413         PassFunc = (MP_GetMPLuOidListFromTPGFn)
1414         dlsym(plugintable[index].hdlPlugin,
1415         "MP_GetMPLuOidListFromTPG");
1416 
1417         if (PassFunc != NULL) {
1418 	    status = PassFunc(oid, ppList);
1419         } else {
1420 	    status = MP_STATUS_UNSUPPORTED;
1421         }
1422     } else {
1423         status = MP_STATUS_FAILED;
1424     }
1425 
1426     (void) pthread_mutex_unlock(&mp_lib_mutex);
1427     return (status);
1428 }
1429 
1430 /**
1431  *******************************************************************************
1432  *
1433  * Gets a list of the object IDs of all the proprietary load balance
1434  * algorithms associated with this plugin.
1435  *
1436  * @param  oid
1437  *         The object ID of the plugin.
1438  *
1439  * @param  ppList
1440  *      A pointer to a pointer to an MP_OID_LIST structure.
1441  *      On a successful return, this will contain a pointer to
1442  *      an MP_OID_LIST that contains the object IDs of all the proprietary
1443  *      load balance algorithms associated with the specified plugin.
1444  *
1445  * @return An MP_STATUS indicating if the operation was successful or if
1446  *         an error occurred.
1447  *
1448  * @retval MP_STATUS_SUCCESS
1449  *         Returned when the operation is successful.
1450  *
1451  * @retval MP_STATUS_INVALID_PARAMETER
1452  *      Returned if ppList pointer passed as placeholder for holding
1453  *      the proprietary load balance oid list is found to be invalid.
1454  *
1455  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1456  *          Returned if oid does not specify any valid object type.
1457  *
1458  * @retval MP_STATUS_FAILED
1459  *          Returned when the plugin for the specified oid is not found.
1460  *
1461  * @retval MP_STATUS_INSUFFICIENT_MEMORY
1462  *      Returned when memory allocation failure occurs
1463  *
1464  * @retval MP_STATUS_UNSUPPORTED
1465  *      Returned when the API is not supported.
1466  *
1467  *******************************************************************************
1468  */
1469 MP_STATUS MP_GetProprietaryLoadBalanceOidList(
1470         MP_OID oid,
1471         MP_OID_LIST **ppList)
1472 {
1473     MP_GetProprietaryLoadBalanceOidListPluginFn PassFunc;
1474     MP_UINT32 index;
1475     MP_STATUS status;
1476 
1477     if (ppList == NULL)
1478         return MP_STATUS_INVALID_PARAMETER;
1479 
1480     if ((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
1481         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1482         return (status);
1483     }
1484 
1485     (void) pthread_mutex_lock(&mp_lib_mutex);
1486 
1487     index = oid.ownerId - 1;
1488     if (plugintable[index].hdlPlugin != NULL) {
1489         PassFunc = (MP_GetProprietaryLoadBalanceOidListPluginFn)
1490         dlsym(plugintable[index].hdlPlugin,
1491         "MP_GetProprietaryLoadBalanceOidListPlugin");
1492 
1493         if (PassFunc != NULL) {
1494 	    status = PassFunc(ppList);
1495         } else {
1496 	    status = MP_STATUS_UNSUPPORTED;
1497         }
1498     } else {
1499         status = MP_STATUS_FAILED;
1500     }
1501 
1502     (void) pthread_mutex_unlock(&mp_lib_mutex);
1503     return (status);
1504 }
1505 
1506 /**
1507  *******************************************************************************
1508  *
1509  * Gets the properties of the specified load balance properties structure.
1510  *
1511  * @param  oid
1512  *         The object ID of the load balance properties structure.
1513  *
1514  * @param  pProps
1515  *      A pointer to an MP_LOAD_BALANCE_PROPRIETARY_TYPE structure
1516  *      allocated by the caller. On successful return, this structure
1517  *      will contain the properties of the proprietary load balance algorithm
1518  *	specified by oid.
1519  *
1520  * @return An MP_STATUS indicating if the operation was successful or if
1521  *         an error occurred.
1522  *
1523  * @retval MP_STATUS_SUCCESS
1524  *         Returned when the operation is successful.
1525  *
1526  * @retval MP_STATUS_INVALID_PARAMETER
1527  *      Returned if pProps is NULL or specifies a memory area to
1528  *      which data cannot be written.
1529  *
1530  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1531  *          Returned if oid does not specify any valid object type.
1532  *
1533  * @retval MP_STATUS_OBJECT_NOT_FOUND
1534  *          Returned if oid has an owner that is not currently known to
1535  *      the system.
1536  *
1537  *******************************************************************************
1538  */
1539 MP_STATUS MP_GetProprietaryLoadBalanceProperties (
1540         MP_OID oid,
1541         MP_PROPRIETARY_LOAD_BALANCE_PROPERTIES *pProps)
1542 {
1543     MP_GetProprietaryLoadBalancePropertiesFn PassFunc;
1544     MP_UINT32 index;
1545     MP_STATUS status;
1546 
1547     if (pProps == NULL)
1548         return MP_STATUS_INVALID_PARAMETER;
1549 
1550     if ((status = validate_object(oid, MP_OBJECT_TYPE_PROPRIETARY_LOAD_BALANCE,
1551         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1552         return (status);
1553     }
1554 
1555     (void) pthread_mutex_lock(&mp_lib_mutex);
1556 
1557     index = oid.ownerId - 1;
1558     if (plugintable[index].hdlPlugin != NULL) {
1559         PassFunc = (MP_GetProprietaryLoadBalancePropertiesFn)
1560         dlsym(plugintable[index].hdlPlugin,
1561         "MP_GetProprietaryLoadBalanceProperties");
1562 
1563         if (PassFunc != NULL) {
1564 	    status = PassFunc(oid, pProps);
1565         } else {
1566 	    status = MP_STATUS_UNSUPPORTED;
1567         }
1568     } else {
1569         status = MP_STATUS_FAILED;
1570     }
1571 
1572     (void) pthread_mutex_unlock(&mp_lib_mutex);
1573     return (status);
1574 }
1575 
1576 /**
1577  *******************************************************************************
1578  *
1579  * Gets a list of the object IDs of the target ports in the specified target
1580  * port group.
1581  *
1582  * @param  oid
1583  *         The object ID of the target port group.
1584  *
1585  * @param  ppList
1586  *      A pointer to a pointer to an MP_OID_LIST structure.
1587  *      On a successful return, this will contain a pointer to
1588  *      an MP_OID_LIST that contains the object IDs of all the target ports
1589  *      associated with the specified target port group.
1590  *
1591  * @return An MP_STATUS indicating if the operation was successful or if
1592  *         an error occurred.
1593  *
1594  * @retval MP_STATUS_SUCCESS
1595  *         Returned when the operation is successful.
1596  *
1597  * @retval MP_STATUS_INVALID_PARAMETER
1598  *      Returned if ppList pointer passed as placeholder for holding
1599  *      the multipath logical unit list is found to be invalid.
1600  *
1601  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1602  *          Returned if oid does not specify any valid object type.
1603  *
1604  * @retval MP_STATUS_FAILED
1605  *          Returned when the plugin for the specified oid is not found.
1606  *
1607  * @retval MP_STATUS_INSUFFICIENT_MEMORY
1608  *      Returned when memory allocation failure occurs
1609  *
1610  *******************************************************************************
1611  */
1612 MP_STATUS MP_GetTargetPortOidList(
1613         MP_OID oid,
1614         MP_OID_LIST **ppList)
1615 {
1616     MP_GetTargetPortOidListFn PassFunc;
1617     MP_UINT32 index;
1618     MP_STATUS status;
1619 
1620     if (ppList == NULL)
1621         return MP_STATUS_INVALID_PARAMETER;
1622 
1623     if ((status = validate_object(oid, MP_OBJECT_TYPE_TARGET_PORT_GROUP,
1624         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1625         return (status);
1626     }
1627 
1628     (void) pthread_mutex_lock(&mp_lib_mutex);
1629 
1630     index = oid.ownerId - 1;
1631     if (plugintable[index].hdlPlugin != NULL) {
1632         PassFunc = (MP_GetTargetPortOidListFn)
1633         dlsym(plugintable[index].hdlPlugin,
1634         "MP_GetTargetPortOidList");
1635 
1636         if (PassFunc != NULL) {
1637 	    status = PassFunc(oid, ppList);
1638         } else {
1639 	    status = MP_STATUS_UNSUPPORTED;
1640         }
1641     } else {
1642         status = MP_STATUS_FAILED;
1643     }
1644 
1645     (void) pthread_mutex_unlock(&mp_lib_mutex);
1646     return (status);
1647 }
1648 
1649 /**
1650  *******************************************************************************
1651  *
1652  * Gets the properties of the specified target port.
1653  *
1654  * @param  oid
1655  *         The object ID of the target port.
1656  *
1657  * @param  pProps
1658  *      A pointer to an MP_TARGET_PORT_PROPERTIES structure
1659  *      allocated by the caller. On successful return, this structure
1660  *      will contain the properties of the port specified by oid.
1661  *
1662  * @return An MP_STATUS indicating if the operation was successful or if
1663  *         an error occurred.
1664  *
1665  * @retval MP_STATUS_SUCCESS
1666  *         Returned when the operation is successful.
1667  *
1668  * @retval MP_STATUS_INVALID_PARAMETER
1669  *      Returned if pProps is NULL or specifies a memory area to
1670  *      which data cannot be written.
1671  *
1672  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1673  *          Returned if oid does not specify any valid object type.
1674  *
1675  * @retval MP_STATUS_OBJECT_NOT_FOUND
1676  *          Returned if oid has an owner that is not currently known to
1677  *      the system.
1678  *
1679  *******************************************************************************
1680  */
1681 MP_STATUS MP_GetTargetPortProperties(
1682         MP_OID oid,
1683         MP_TARGET_PORT_PROPERTIES *pProps)
1684 {
1685     MP_GetTargetPortPropertiesFn PassFunc;
1686     MP_UINT32 index;
1687     MP_STATUS status;
1688 
1689     if (pProps == NULL)
1690         return MP_STATUS_INVALID_PARAMETER;
1691 
1692     if ((status = validate_object(oid, MP_OBJECT_TYPE_TARGET_PORT,
1693         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1694         return (status);
1695     }
1696 
1697     (void) pthread_mutex_lock(&mp_lib_mutex);
1698 
1699     index = oid.ownerId - 1;
1700     if (plugintable[index].hdlPlugin != NULL) {
1701         PassFunc = (MP_GetTargetPortPropertiesFn)
1702         dlsym(plugintable[index].hdlPlugin,
1703         "MP_GetTargetPortProperties");
1704 
1705         if (PassFunc != NULL) {
1706 	    status = PassFunc(oid, pProps);
1707         } else {
1708 	    status = MP_STATUS_UNSUPPORTED;
1709         }
1710     } else {
1711         status = MP_STATUS_FAILED;
1712     }
1713 
1714     (void) pthread_mutex_unlock(&mp_lib_mutex);
1715     return (status);
1716 }
1717 
1718 
1719 /**
1720  *******************************************************************************
1721  *
1722  * Assign a multipath logical unit to a target port group.
1723  *
1724  * @param  tpgOid
1725  *      An MP_TARGET_PORT_GROUP oid. The target port group currently in
1726  *      active access state that the administrator would like the LU
1727  *      assigned to.
1728  *
1729  * @param  luOid
1730  *      An MP_MULTIPATH_LOGICAL_UNIT oid.
1731  *
1732  * @return An MP_STATUS indicating if the operation was successful or if
1733  *         an error occurred.
1734  *
1735  * @retval MP_STATUS_SUCCESS
1736  *         Returned when the operation is successful.
1737  *
1738  * @retval MP_STATUS_INVALID_PARAMETER
1739  *      Returned when luOid is not associated with tpgOid.
1740  *
1741  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1742  *          Returned if oid does not specify any valid object type.
1743  *
1744  * @retval MP_STATUS_OBJECT_NOT_FOUND
1745  *          Returned if oid has an owner that is not currently known to
1746  *      the system.
1747  *
1748  *******************************************************************************
1749  */
1750 MP_STATUS MP_AssignLogicalUnitToTPG(
1751         MP_OID tpgOid,
1752         MP_OID luOid)
1753 {
1754     MP_AssignLogicalUnitToTPGFn PassFunc;
1755     MP_UINT32 index;
1756     MP_STATUS status;
1757 
1758     if (luOid.ownerId != tpgOid.ownerId) {
1759         return (MP_STATUS_INVALID_PARAMETER);
1760     }
1761 
1762     if ((status = validate_object(tpgOid, MP_OBJECT_TYPE_TARGET_PORT_GROUP,
1763         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1764         return (status);
1765     }
1766 
1767     if ((status = validate_object(luOid, MP_OBJECT_TYPE_MULTIPATH_LU,
1768         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1769         return (status);
1770     }
1771 
1772     (void) pthread_mutex_lock(&mp_lib_mutex);
1773 
1774     index = tpgOid.ownerId - 1;
1775     if (plugintable[index].hdlPlugin != NULL) {
1776         PassFunc = (MP_AssignLogicalUnitToTPGFn)
1777         dlsym(plugintable[index].hdlPlugin,
1778         "MP_AssignLogicalUnitToTPG");
1779 
1780         if (PassFunc != NULL) {
1781             status = PassFunc(tpgOid, luOid);
1782         } else {
1783             status = MP_STATUS_UNSUPPORTED;
1784         }
1785     } else {
1786         status = MP_STATUS_FAILED;
1787     }
1788 
1789     (void) pthread_mutex_unlock(&mp_lib_mutex);
1790     return (status);
1791 }
1792 
1793 /**
1794  *******************************************************************************
1795  *
1796  * Manually override the path for a logical unit. The path exclusively used to
1797  * access the logical unit until cleared.
1798  *
1799  * @param  logicalUnitOid
1800  *      The object ID of the multipath logical unit.
1801  *
1802  * @param  pathOid
1803  *      The object ID of the path logical unit.
1804  *
1805  * @return An MP_STATUS indicating if the operation was successful or if
1806  *         an error occurred.
1807  *
1808  * @retval MP_STATUS_SUCCESS
1809  *         Returned when the operation is successful.
1810  *
1811  * @retval MP_STATUS_INVALID_PARAMETER
1812  *      Returned if the oid of the object is not valid
1813  *
1814  * @retval MP_STATUS_UNSUPPORTED
1815  *      Returned when the implementation does not support the API
1816  *
1817  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1818  *          Returned if oid does not specify any valid object type.
1819  *
1820  * @retval MP_STATUS_PATH_NONOPERATIONAL
1821  *          Returned when the driver cannot communicate through selected path.
1822  *
1823  *******************************************************************************
1824  */
1825 MP_STATUS MP_SetOverridePath(
1826     MP_OID logicalUnitOid,
1827     MP_OID pathOid)
1828 {
1829     MP_SetOverridePathFn PassFunc;
1830     MP_UINT32 index;
1831     MP_STATUS status;
1832 
1833     if ((status = validate_object(logicalUnitOid, MP_OBJECT_TYPE_MULTIPATH_LU,
1834         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1835         return (status);
1836     }
1837     if ((status = validate_object(pathOid, MP_OBJECT_TYPE_PATH_LU,
1838         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1839         return (status);
1840     }
1841 
1842     (void) pthread_mutex_lock(&mp_lib_mutex);
1843 
1844     index = pathOid.ownerId - 1;
1845     if (plugintable[index].hdlPlugin != NULL) {
1846         PassFunc = (MP_SetOverridePathFn)
1847         dlsym(plugintable[index].hdlPlugin,
1848         "MP_SetOverridePath");
1849 
1850         if (PassFunc != NULL) {
1851 	    status = PassFunc(logicalUnitOid, pathOid);
1852         } else {
1853 	    status = MP_STATUS_UNSUPPORTED;
1854         }
1855     } else {
1856         status = MP_STATUS_FAILED;
1857     }
1858 
1859     (void) pthread_mutex_unlock(&mp_lib_mutex);
1860     return (status);
1861 }
1862 
1863 /**
1864  *******************************************************************************
1865  *
1866  * Cancel a path override and re-enable load balancing.
1867  *
1868  * @param  luOid
1869  *         An MP_MULTIPATH_LOGICAL_UNIT oid.
1870  *
1871  * @return An MP_STATUS indicating if the operation was successful or if
1872  *         an error occurred.
1873  *
1874  * @retval MP_STATUS_SUCCESS
1875  *         Returned when the operation is successful.
1876  *
1877  * @retval MP_STATUS_INVALID_PARAMETER
1878  *      Returned if MP_MULTIPATH_LOGICAL_UNIT with the luOid is not found.
1879  *
1880  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1881  *          Returned if oid does not specify any valid object type.
1882  *
1883  * @retval MP_STATUS_OBJECT_NOT_FOUND
1884  *          Returned if oid has an owner that is not currently known to
1885  *      the system.
1886  *
1887  *******************************************************************************
1888  */
1889 MP_STATUS MP_CancelOverridePath(
1890         MP_OID luOid)
1891 {
1892     MP_CancelOverridePathFn PassFunc;
1893     MP_UINT32 index;
1894     MP_STATUS status;
1895 
1896     if ((status = validate_object(luOid, MP_OBJECT_TYPE_MULTIPATH_LU,
1897         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
1898         return (status);
1899     }
1900 
1901     (void) pthread_mutex_lock(&mp_lib_mutex);
1902 
1903     index = luOid.ownerId - 1;
1904     if (plugintable[index].hdlPlugin != NULL) {
1905         PassFunc = (MP_CancelOverridePathFn)
1906         dlsym(plugintable[index].hdlPlugin,
1907         "MP_CancelOverridePath");
1908 
1909         if (PassFunc != NULL) {
1910 	    status = PassFunc(luOid);
1911         } else {
1912 	    status = MP_STATUS_UNSUPPORTED;
1913         }
1914     } else {
1915         status = MP_STATUS_FAILED;
1916     }
1917 
1918     (void) pthread_mutex_unlock(&mp_lib_mutex);
1919     return (status);
1920 }
1921 
1922 /**
1923  *******************************************************************************
1924  *
1925  * Enables Auto-failback.
1926  *
1927  * @param  oid
1928  *      The oid of the plugin.
1929  *
1930  * @return An MP_STATUS indicating if the operation was successful or if
1931  *         an error occurred.
1932  *
1933  * @retval MP_STATUS_SUCCESS
1934  *         Returned when the operation is successful.
1935  *
1936  * @retval MP_STATUS_INVALID_PARAMETER
1937  *      Returned if oid is NULL or specifies a memory area that is not
1938  *	a valid plugin oid.
1939  *
1940  * @retval MP_STATUS_INVALID_OBJECT_TYPE
1941  *          Returned if oid does not specify any valid object type.
1942  *
1943  *******************************************************************************
1944  */
1945 MP_STATUS MP_EnableAutoFailback(
1946     MP_OID oid)
1947 {
1948     MP_UINT32 index;
1949     MP_STATUS status;
1950 
1951     if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
1952 	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
1953 	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
1954         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
1955         return (status);
1956     }
1957 
1958     (void) pthread_mutex_lock(&mp_lib_mutex);
1959 
1960     index = oid.ownerId - 1;
1961     if (plugintable[index].hdlPlugin != NULL) {
1962 	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
1963 	    MP_EnableAutoFailbackPluginFn PassFunc;
1964 	    PassFunc = (MP_EnableAutoFailbackPluginFn)
1965 	    dlsym(plugintable[index].hdlPlugin,
1966         	"MP_EnableAutoFailbackPlugin");
1967 
1968 	    if (PassFunc != NULL) {
1969 		status = PassFunc();
1970 	    } else {
1971 		status = MP_STATUS_UNSUPPORTED;
1972 	    }
1973 	} else if (oid.objectType == MP_OBJECT_TYPE_MULTIPATH_LU) {
1974 	    MP_EnableAutoFailbackLuFn PassFunc;
1975 	    PassFunc = (MP_EnableAutoFailbackLuFn)
1976 	    dlsym(plugintable[index].hdlPlugin,
1977         	"MP_EnableAutoFailbackLu");
1978 
1979 	    if (PassFunc != NULL) {
1980 		status = PassFunc(oid);
1981 	    } else {
1982 		status = MP_STATUS_UNSUPPORTED;
1983 	    }
1984 	} else {
1985 	    status = MP_STATUS_INVALID_PARAMETER;
1986 	}
1987     }
1988 
1989     (void) pthread_mutex_unlock(&mp_lib_mutex);
1990     return (status);
1991 }
1992 
1993 /**
1994  *******************************************************************************
1995  *
1996  * Enables Auto-probing.
1997  *
1998  * @param  oid
1999  *      The oid of the plugin or the multipath logical unit.
2000  *
2001  * @return An MP_STATUS indicating if the operation was successful or if
2002  *         an error occurred.
2003  *
2004  * @retval MP_STATUS_SUCCESS
2005  *         Returned when the operation is successful.
2006  *
2007  * @retval MP_STATUS_INVALID_PARAMETER
2008  *      Returned if oid is NULL or specifies a memory area that is not
2009  *      a valid plugin oid.
2010  *
2011  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2012  *          Returned if oid does not specify any valid object type.
2013  *
2014  *******************************************************************************
2015  */
2016 MP_STATUS MP_EnableAutoProbing(
2017     MP_OID oid)
2018 {
2019     MP_UINT32 index;
2020     MP_STATUS status;
2021 
2022     if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
2023 	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
2024 	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
2025         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
2026         return (status);
2027     }
2028 
2029     (void) pthread_mutex_lock(&mp_lib_mutex);
2030 
2031     index = oid.ownerId - 1;
2032     if (plugintable[index].hdlPlugin != NULL) {
2033 	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
2034 	    MP_EnableAutoProbingPluginFn PassFunc;
2035 	    PassFunc = (MP_EnableAutoProbingPluginFn)
2036 	    dlsym(plugintable[index].hdlPlugin,
2037         	"MP_EnableAutoProbingPlugin");
2038 
2039 	    if (PassFunc != NULL) {
2040 		status = PassFunc();
2041 	    } else {
2042 		status = MP_STATUS_UNSUPPORTED;
2043 	    }
2044 	} else if (oid.objectType == MP_OBJECT_TYPE_MULTIPATH_LU) {
2045 	    MP_EnableAutoProbingLuFn PassFunc;
2046 	    PassFunc = (MP_EnableAutoProbingLuFn)
2047 	    dlsym(plugintable[index].hdlPlugin,
2048         	"MP_EnableAutoProbingLu");
2049 
2050 	    if (PassFunc != NULL) {
2051 		status = PassFunc(oid);
2052 	    } else {
2053 		status = MP_STATUS_UNSUPPORTED;
2054 	    }
2055 	} else {
2056 	    status = MP_STATUS_INVALID_PARAMETER;
2057 	}
2058     }
2059 
2060     (void) pthread_mutex_unlock(&mp_lib_mutex);
2061     return (status);
2062 }
2063 
2064 /**
2065  *******************************************************************************
2066  *
2067  * Disables Auto-failback.
2068  *
2069  * @param  oid
2070  *      The oid of the plugin.
2071  *
2072  * @return An MP_STATUS indicating if the operation was successful or if
2073  *         an error occurred.
2074  *
2075  * @retval MP_STATUS_SUCCESS
2076  *         Returned when the operation is successful.
2077  *
2078  * @retval MP_STATUS_INVALID_PARAMETER
2079  *      Returned if oid is NULL or specifies a memory area that is not
2080  *      a valid plugin oid.
2081  *
2082  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2083  *          Returned if oid does not specify any valid object type.
2084  *
2085  *******************************************************************************
2086  */
2087 MP_STATUS MP_DisableAutoFailback(
2088     MP_OID oid)
2089 {
2090     MP_UINT32 index;
2091     MP_STATUS status;
2092 
2093     if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
2094 	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
2095 	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
2096         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
2097         return (status);
2098     }
2099 
2100     (void) pthread_mutex_lock(&mp_lib_mutex);
2101 
2102     index = oid.ownerId - 1;
2103     if (plugintable[index].hdlPlugin != NULL) {
2104 	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
2105 	    MP_DisableAutoFailbackPluginFn PassFunc;
2106 	    PassFunc = (MP_DisableAutoFailbackPluginFn)
2107 	    dlsym(plugintable[index].hdlPlugin,
2108         	"MP_DisableAutoFailbackPlugin");
2109 
2110 	    if (PassFunc != NULL) {
2111 		status = PassFunc();
2112 	    } else {
2113 		status = MP_STATUS_UNSUPPORTED;
2114 	    }
2115 	} else if (oid.objectType == MP_OBJECT_TYPE_MULTIPATH_LU) {
2116 	    MP_DisableAutoFailbackLuFn PassFunc;
2117 	    PassFunc = (MP_DisableAutoFailbackLuFn)
2118 	    dlsym(plugintable[index].hdlPlugin,
2119         	"MP_DisableAutoFailbackLu");
2120 
2121 	    if (PassFunc != NULL) {
2122 		status = PassFunc(oid);
2123 	    } else {
2124 		status = MP_STATUS_UNSUPPORTED;
2125 	    }
2126 	} else {
2127 	    status = MP_STATUS_INVALID_PARAMETER;
2128 	}
2129     }
2130 
2131     (void) pthread_mutex_unlock(&mp_lib_mutex);
2132     return (status);
2133 }
2134 
2135 /**
2136  *******************************************************************************
2137  *
2138  * Disables Auto-probing.
2139  *
2140  * @param  oid
2141  *      The oid of the plugin or the multipath logical unit.
2142  *
2143  * @return An MP_STATUS indicating if the operation was successful or if
2144  *         an error occurred.
2145  *
2146  * @retval MP_STATUS_SUCCESS
2147  *         Returned when the operation is successful.
2148  *
2149  * @retval MP_STATUS_INVALID_PARAMETER
2150  *      Returned if oid is NULL or specifies a memory area that is not
2151  *      a valid plugin oid.
2152  *
2153  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2154  *          Returned if oid does not specify any valid object type.
2155  *
2156  *******************************************************************************
2157  */
2158 MP_STATUS MP_DisableAutoProbing(
2159     MP_OID oid)
2160 {
2161     MP_UINT32 index;
2162     MP_STATUS status;
2163 
2164     if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
2165 	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
2166 	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
2167         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
2168         return (status);
2169     }
2170 
2171     (void) pthread_mutex_lock(&mp_lib_mutex);
2172 
2173     index = oid.ownerId - 1;
2174     if (plugintable[index].hdlPlugin != NULL) {
2175 	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
2176 	    MP_DisableAutoProbingPluginFn PassFunc;
2177 	    PassFunc = (MP_DisableAutoProbingPluginFn)
2178 	    dlsym(plugintable[index].hdlPlugin,
2179         	"MP_DisableAutoProbingPlugin");
2180 
2181 	    if (PassFunc != NULL) {
2182 		status = PassFunc();
2183 	    } else {
2184 		status = MP_STATUS_UNSUPPORTED;
2185 	    }
2186 	} else if (oid.objectType == MP_OBJECT_TYPE_MULTIPATH_LU) {
2187 	    MP_DisableAutoFailbackLuFn PassFunc;
2188 	    PassFunc = (MP_DisableAutoProbingLuFn)
2189 	    dlsym(plugintable[index].hdlPlugin,
2190         	"MP_DisableAutoProbingLu");
2191 
2192 	    if (PassFunc != NULL) {
2193 		status = PassFunc(oid);
2194 	    } else {
2195 		status = MP_STATUS_UNSUPPORTED;
2196 	    }
2197 	} else {
2198 	    status = MP_STATUS_INVALID_PARAMETER;
2199 	}
2200     }
2201 
2202     (void) pthread_mutex_unlock(&mp_lib_mutex);
2203     return (status);
2204 }
2205 
2206 /**
2207  *******************************************************************************
2208  *
2209  * Enables a path. This API may cause failover in a logical unit with
2210  * asymmetric access.
2211  *
2212  * @param  oid
2213  *      The oid of the path.
2214  *
2215  * @return An MP_STATUS indicating if the operation was successful or if
2216  *         an error occurred.
2217  *
2218  * @retval MP_STATUS_SUCCESS
2219  *         Returned when the operation is successful.
2220  *
2221  * @retval MP_STATUS_INVALID_PARAMETER
2222  *      Returned if oid is NULL or specifies a memory area that is not
2223  *      a valid path oid.
2224  *
2225  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2226  *          Returned if oid does not specify any valid object type.
2227  *
2228  *******************************************************************************
2229  */
2230 MP_STATUS MP_EnablePath(
2231     MP_OID oid)
2232 {
2233     MP_EnablePathFn PassFunc;
2234     MP_UINT32 index;
2235     MP_STATUS status;
2236 
2237     if ((status = validate_object(oid, MP_OBJECT_TYPE_PATH_LU,
2238         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
2239         return (status);
2240     }
2241 
2242     (void) pthread_mutex_lock(&mp_lib_mutex);
2243 
2244     index = oid.ownerId - 1;
2245     if (plugintable[index].hdlPlugin != NULL) {
2246         PassFunc = (MP_EnablePathFn)
2247         dlsym(plugintable[index].hdlPlugin,
2248         "MP_EnablePath");
2249 
2250         if (PassFunc != NULL) {
2251 	    status = PassFunc(oid);
2252         } else {
2253 	    status = MP_STATUS_UNSUPPORTED;
2254         }
2255     } else {
2256         status = MP_STATUS_FAILED;
2257     }
2258 
2259     (void) pthread_mutex_unlock(&mp_lib_mutex);
2260     return (status);
2261 }
2262 
2263 /**
2264  *******************************************************************************
2265  *
2266  * Disables a path. This API may cause failover in a logical unit with
2267  * asymmetric access. This API may cause a logical unit to become unavailable.
2268  *
2269  * @param  oid
2270  *      The oid of the path.
2271  *
2272  * @return An MP_STATUS indicating if the operation was successful or if
2273  *         an error occurred.
2274  *
2275  * @retval MP_STATUS_SUCCESS
2276  *         Returned when the operation is successful.
2277  *
2278  * @retval MP_STATUS_INVALID_PARAMETER
2279  *      Returned if oid is NULL or specifies a memory area that is not
2280  *      a valid path oid.
2281  *
2282  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2283  *          Returned if oid does not specify any valid object type.
2284  *
2285  *******************************************************************************
2286  */
2287 MP_STATUS MP_DisablePath(
2288     MP_OID oid)
2289 {
2290     MP_DisablePathFn PassFunc;
2291     MP_UINT32 index;
2292     MP_STATUS status;
2293 
2294     if ((status = validate_object(oid, MP_OBJECT_TYPE_PATH_LU,
2295         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
2296         return (status);
2297     }
2298 
2299     (void) pthread_mutex_lock(&mp_lib_mutex);
2300 
2301     index = oid.ownerId - 1;
2302     if (plugintable[index].hdlPlugin != NULL) {
2303         PassFunc = (MP_DisablePathFn)
2304         dlsym(plugintable[index].hdlPlugin,
2305         "MP_DisablePath");
2306 
2307         if (PassFunc != NULL) {
2308 	    status = PassFunc(oid);
2309         } else {
2310 	    status = MP_STATUS_UNSUPPORTED;
2311         }
2312     } else {
2313         status = MP_STATUS_FAILED;
2314     }
2315 
2316     (void) pthread_mutex_unlock(&mp_lib_mutex);
2317     return (status);
2318 }
2319 
2320 /**
2321  *******************************************************************************
2322  *
2323  * Set the multipath logical unit s load balancing policy.
2324  *
2325  * @param  logicalUnitoid
2326  *      The object ID of the multipath logical unit.
2327  *
2328  * @param  loadBanlance
2329  *      The desired load balance policy for the specified logical unit.
2330  *
2331  * @return An MP_STATUS indicating if the operation was successful or if
2332  *         an error occurred.
2333  *
2334  * @retval MP_STATUS_SUCCESS
2335  *         Returned when the operation is successful.
2336  *
2337  * @retval MP_STATUS_INVALID_PARAMETER
2338  *      Returned if no MP_MULTIPATH_LOGICAL_UNIT associated with
2339  *      @ref ligicalUnitrOid is found or invalid MP_LOAD_BALANCE_TYPE is
2340  *      specified.
2341  *
2342  * @retval MP_STATUS_FAILED
2343  *      Returned when the specified loadBalance type cannot be handled
2344  *      by the plugin.
2345  *
2346  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2347  *          Returned if oid does not specify any valid object type.
2348  *
2349  *******************************************************************************
2350  */
2351 MP_STATUS MP_SetLogicalUnitLoadBalanceType(
2352     MP_OID logicalUnitOid,
2353     MP_LOAD_BALANCE_TYPE loadBalance)
2354 {
2355     MP_SetLogicalUnitLoadBalanceTypeFn PassFunc;
2356     MP_UINT32 index;
2357     MP_STATUS status;
2358 
2359     if ((status = validate_object(logicalUnitOid,
2360         MP_OBJECT_TYPE_MULTIPATH_LU,
2361         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
2362         return (status);
2363     }
2364 
2365     (void) pthread_mutex_lock(&mp_lib_mutex);
2366 
2367     index = logicalUnitOid.ownerId - 1;
2368     if (plugintable[index].hdlPlugin != NULL) {
2369         PassFunc = (MP_SetLogicalUnitLoadBalanceTypeFn)
2370         dlsym(plugintable[index].hdlPlugin,
2371         "MP_SetLogicalUnitLoadBalanceType");
2372 
2373         if (PassFunc != NULL) {
2374 	    status = PassFunc(logicalUnitOid, loadBalance);
2375         } else {
2376 	    status = MP_STATUS_UNSUPPORTED;
2377         }
2378     } else {
2379         status = MP_STATUS_FAILED;
2380     }
2381 
2382     (void) pthread_mutex_unlock(&mp_lib_mutex);
2383     return (status);
2384 }
2385 
2386 /**
2387  *******************************************************************************
2388  *
2389  * Set the weight to be assigned to a particular path.
2390  *
2391  * @param  pathOid
2392  *      The object ID of the path logical unit.
2393  *
2394  * @param  weight
2395  *      weight that will be assigned to the path logical unit.
2396  *
2397  * @return An MP_STATUS indicating if the operation was successful or if
2398  *         an error occurred.
2399  *
2400  * @retval MP_STATUS_SUCCESS
2401  *         Returned when the operation is successful.
2402  *
2403  * @retval MP_STATUS_OBJECT_NOT_FOUND
2404  *      Returned when the MP Path specified by the PathOid could not be
2405  *      found.
2406  *
2407  * @retval MP_STATUS_UNSUPPORTED
2408  *      Returned when the implementation does not support the API
2409  *
2410  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2411  *          Returned if oid does not specify any valid object type.
2412  *
2413  * @retval MP_STATUS_FAILED
2414  *          Returned when the operation failed.
2415  *
2416  * @retval MP_STATUS_PATH_NONOPERATIONAL
2417  *          Returned when the driver cannot communicate through selected path.
2418  *
2419  * @retval MP_STATUS_INVALID_WEIGHT
2420  *          Returned when the weight parameter is greater than the plugin's
2421  *      maxWeight property.
2422  *
2423  *******************************************************************************
2424  */
2425 MP_STATUS MP_SetPathWeight(
2426     MP_OID pathOid,
2427     MP_UINT32 weight)
2428 {
2429     MP_SetPathWeightFn PassFunc;
2430     MP_UINT32 index;
2431     MP_STATUS status;
2432 
2433     if ((status = validate_object(pathOid, MP_OBJECT_TYPE_PATH_LU,
2434         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
2435         return (status);
2436     }
2437 
2438     (void) pthread_mutex_lock(&mp_lib_mutex);
2439 
2440     index = pathOid.ownerId - 1;
2441     if (plugintable[index].hdlPlugin != NULL) {
2442         PassFunc = (MP_SetPathWeightFn)
2443         dlsym(plugintable[index].hdlPlugin,
2444         "MP_SetPathWeight");
2445 
2446         if (PassFunc != NULL) {
2447 	    status = PassFunc(pathOid, weight);
2448         } else {
2449 	    status = MP_STATUS_UNSUPPORTED;
2450         }
2451     } else {
2452         status = MP_STATUS_FAILED;
2453     }
2454 
2455     (void) pthread_mutex_unlock(&mp_lib_mutex);
2456     return (status);
2457 }
2458 
2459 /**
2460  *******************************************************************************
2461  *
2462  * Set the default load balance policy for the plugin.
2463  *
2464  * @param  oid
2465  *      The object ID of the plugin
2466  *
2467  * @param  loadBalance
2468  *      The desired default load balance policy for the specified plugin.
2469  *
2470  * @return An MP_STATUS indicating if the operation was successful or if
2471  *         an error occurred.
2472  *
2473  * @retval MP_STATUS_SUCCESS
2474  *         Returned when the operation is successful.
2475  *
2476  * @retval MP_STATUS_OBJECT_NOT_FOUND
2477  *      Returned when the the plugin specified by @ref oid could not be
2478  *      found.
2479  *
2480  * @retval MP_STATUS_INVALID_PARAMETER
2481  *      Returned if the oid of the object is not valid.
2482  *
2483  * @retval MP_STATUS_UNSUPPORTED
2484  *      Returned when the implementation does not support the API
2485  *
2486  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2487  *          Returned if oid does not specify any valid object type.
2488  *
2489  * @retval MP_STATUS_FAILED
2490  *          Returned when the specified loadBalance type cannot be handled
2491  *      by the plugin.
2492  *
2493  *******************************************************************************
2494  */
2495 MP_STATUS MP_SetPluginLoadBalanceType(
2496     MP_OID oid,
2497     MP_LOAD_BALANCE_TYPE loadBalance)
2498 {
2499     MP_SetPluginLoadBalanceTypePluginFn PassFunc;
2500     MP_UINT32 index;
2501     MP_STATUS status;
2502 
2503     if ((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
2504         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
2505         return (status);
2506     }
2507 
2508     (void) pthread_mutex_lock(&mp_lib_mutex);
2509 
2510     index = oid.ownerId - 1;
2511     if (plugintable[index].hdlPlugin != NULL) {
2512         PassFunc = (MP_SetPluginLoadBalanceTypePluginFn)
2513         dlsym(plugintable[index].hdlPlugin,
2514         "MP_SetPluginLoadBalanceTypePlugin");
2515 
2516         if (PassFunc != NULL) {
2517 	    status = PassFunc(loadBalance);
2518         } else {
2519 	    status = MP_STATUS_UNSUPPORTED;
2520         }
2521     } else {
2522         status = MP_STATUS_FAILED;
2523     }
2524 
2525     (void) pthread_mutex_unlock(&mp_lib_mutex);
2526     return (status);
2527 }
2528 
2529 /**
2530  *******************************************************************************
2531  *
2532  * Set the failback polling rates. Setting both rates to zero disables polling.
2533  *
2534  * @param  pluginOid
2535  *      The object ID of the plugin or multipath lu.
2536  *
2537  * @param  pollingRate
2538  *      The value to be set in MP_PLUGIN_PROPERTIES currentPollingRate.or
2539  *	MP_MULTIPATH_LOGICAL_UNIT_PROPERTIES pollingRate.
2540  *
2541  * @return An MP_STATUS indicating if the operation was successful or if
2542  *         an error occurred.
2543  *
2544  * @retval MP_STATUS_SUCCESS
2545  *         Returned when the operation is successful.
2546  *
2547  * @retval MP_STATUS_OBJECT_NOT_FOUND
2548  *      Returned when the the plugin specified by @ref oid could not be
2549  *      found.
2550  *
2551  * @retval MP_STATUS_INVALID_PARAMETER
2552  *      Returned if one of the polling values is outside the range
2553  *      supported by the driver.
2554  *
2555  * @retval MP_STATUS_UNSUPPORTED
2556  *      Returned when the implementation does not support the API
2557  *
2558  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2559  *          Returned if oid does not specify any valid object type.
2560  *
2561  *******************************************************************************
2562  */
2563 MP_STATUS MP_SetFailbackPollingRate(
2564     MP_OID oid,
2565     MP_UINT32 pollingRate)
2566 {
2567     MP_UINT32 index;
2568     MP_STATUS status;
2569 
2570     if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
2571 	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
2572 	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
2573         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
2574         return (status);
2575     }
2576 
2577     (void) pthread_mutex_lock(&mp_lib_mutex);
2578 
2579     index = oid.ownerId - 1;
2580     if (plugintable[index].hdlPlugin != NULL) {
2581 	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
2582 	    MP_SetFailbackPollingRatePluginFn PassFunc;
2583 	    PassFunc = (MP_SetFailbackPollingRatePluginFn)
2584 	    dlsym(plugintable[index].hdlPlugin,
2585         	"MP_SetFailbackPollingRatePlugin");
2586 
2587 	    if (PassFunc != NULL) {
2588 		status = PassFunc(pollingRate);
2589 	    } else {
2590 		status = MP_STATUS_UNSUPPORTED;
2591 	    }
2592 	} else if (oid.objectType == MP_OBJECT_TYPE_MULTIPATH_LU) {
2593 	    MP_SetFailbackPollingRateLuFn PassFunc;
2594 	    PassFunc = (MP_SetFailbackPollingRateLuFn)
2595 	    dlsym(plugintable[index].hdlPlugin,
2596         	"MP_SetFailbackPollingRateLu");
2597 
2598 	    if (PassFunc != NULL) {
2599 		status = PassFunc(oid, pollingRate);
2600 	    } else {
2601 		status = MP_STATUS_UNSUPPORTED;
2602 	    }
2603 	} else {
2604 	    status = MP_STATUS_INVALID_PARAMETER;
2605 	}
2606     }
2607 
2608     (void) pthread_mutex_unlock(&mp_lib_mutex);
2609     return (status);
2610 }
2611 
2612 /**
2613  *******************************************************************************
2614  *
2615  * Set the probing polling rates. Setting both rates to zero disables polling.
2616  *
2617  * @param  pluginOid
2618  *      The object ID of either the plugin or a multipath logical unit.
2619  *
2620  * @param  pollingRate
2621  *      The value to be set in MP_PLUGIN_PROPERTIES current pollingRate or
2622  *	MP_MULTIPATH_LOGICAL_UNIT_PROPERTIES pollingRate.
2623  *
2624  * @return An MP_STATUS indicating if the operation was successful or if
2625  *         an error occurred.
2626  *
2627  * @retval MP_STATUS_SUCCESS
2628  *         Returned when the operation is successful.
2629  *
2630  * @retval MP_STATUS_OBJECT_NOT_FOUND
2631  *      Returned when the the plugin specified by @ref oid could not be
2632  *      found.
2633  *
2634  * @retval MP_STATUS_INVALID_PARAMETER
2635  *      Returned if one of the polling values is outside the range
2636  *      supported by the driver.
2637  *
2638  * @retval MP_STATUS_UNSUPPORTED
2639  *      Returned when the implementation does not support the API
2640  *
2641  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2642  *          Returned if oid does not specify any valid object type.
2643  *
2644  *******************************************************************************
2645  */
2646 MP_STATUS MP_SetProbingPollingRate(
2647     MP_OID    oid,
2648     MP_UINT32 pollingRate)
2649 {
2650     MP_UINT32 index;
2651     MP_STATUS status;
2652 
2653     if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
2654 	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
2655 	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
2656         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
2657         return (status);
2658     }
2659 
2660     (void) pthread_mutex_lock(&mp_lib_mutex);
2661 
2662     index = oid.ownerId - 1;
2663     if (plugintable[index].hdlPlugin != NULL) {
2664 	if (oid.objectType == MP_OBJECT_TYPE_PLUGIN) {
2665 	    MP_SetProbingPollingRatePluginFn PassFunc;
2666 	    PassFunc = (MP_SetProbingPollingRatePluginFn)
2667 	    dlsym(plugintable[index].hdlPlugin,
2668         	"MP_SetProbingPollingRatePlugin");
2669 
2670 	    if (PassFunc != NULL) {
2671 		status = PassFunc(pollingRate);
2672 	    } else {
2673 		status = MP_STATUS_UNSUPPORTED;
2674 	    }
2675 	} else if (oid.objectType == MP_OBJECT_TYPE_MULTIPATH_LU) {
2676 	    MP_SetProbingPollingRateLuFn PassFunc;
2677 	    PassFunc = (MP_SetProbingPollingRateLuFn)
2678 	    dlsym(plugintable[index].hdlPlugin,
2679         	"MP_SetProbingPollingRateLu");
2680 
2681 	    if (PassFunc != NULL) {
2682 		status = PassFunc(oid, pollingRate);
2683 	    } else {
2684 		status = MP_STATUS_UNSUPPORTED;
2685 	    }
2686 	} else {
2687 	    status = MP_STATUS_INVALID_PARAMETER;
2688 	}
2689     }
2690 
2691     (void) pthread_mutex_unlock(&mp_lib_mutex);
2692     return (status);
2693 }
2694 
2695 /**
2696  *******************************************************************************
2697  *
2698  * Set proprietary properties in supported object instances.
2699  *
2700  * @param  pluginOid
2701  *      The object ID of MP_LOAD_BALANCE_PROPRIETARY_TYPE, MP_PLUGIN_PROPERTIES
2702  *	or MP_MULTIPATH_LOGICAL_UNIT_PROPERTIES.
2703  *
2704  * @param  count
2705  *	   The number of valid items in pPropertyList.
2706  *
2707  * @param  pPropertyList
2708  *	   A pointer to an array of property name/value pairs. This array must
2709  *	   contain the same number of elements as count.
2710  *
2711  * @return An MP_STATUS indicating if the operation was successful or if
2712  *         an error occurred.
2713  *
2714  * @retval MP_STATUS_SUCCESS
2715  *         Returned when the operation is successful.
2716  *
2717  * @retval MP_STATUS_OBJECT_NOT_FOUND
2718  *      Returned when the the plugin specified by @ref oid could not be
2719  *      found.
2720  *
2721  * @retval MP_STATUS_INVALID_PARAMETER
2722  *      Returned if one of the polling values is outside the range
2723  *      supported by the driver.
2724  *
2725  * @retval MP_STATUS_UNSUPPORTED
2726  *      Returned when the implementation does not support the API
2727  *
2728  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2729  *          Returned if oid does not specify any valid object type.
2730  *
2731  *******************************************************************************
2732  */
2733 MP_STATUS MP_SetProprietaryProperties(
2734     MP_OID    oid,
2735     MP_UINT32 count,
2736     MP_PROPRIETARY_PROPERTY *pPropertyList)
2737 {
2738     MP_SetProprietaryPropertiesFn PassFunc;
2739     MP_UINT32 index;
2740     MP_STATUS status;
2741 
2742     if (((status = validate_object(oid, MP_OBJECT_TYPE_PLUGIN,
2743 	MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
2744 	((status = validate_object(oid, MP_OBJECT_TYPE_MULTIPATH_LU,
2745         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) &&
2746 	((status = validate_object(oid, MP_OBJECT_TYPE_PROPRIETARY_LOAD_BALANCE,
2747         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS)) {
2748         return (status);
2749     }
2750 
2751     (void) pthread_mutex_lock(&mp_lib_mutex);
2752 
2753     index = oid.ownerId - 1;
2754     if (plugintable[index].hdlPlugin != NULL) {
2755         PassFunc = (MP_SetProprietaryPropertiesFn)
2756         dlsym(plugintable[index].hdlPlugin,
2757         "MP_SetProprietaryProperties");
2758 
2759         if (PassFunc != NULL) {
2760 	    status = PassFunc(oid, count, pPropertyList);
2761         } else {
2762 	    status = MP_STATUS_UNSUPPORTED;
2763         }
2764     } else {
2765         status = MP_STATUS_FAILED;
2766     }
2767 
2768     (void) pthread_mutex_unlock(&mp_lib_mutex);
2769     return (status);
2770 }
2771 
2772 /**
2773  *******************************************************************************
2774  *
2775  * Set the access state for a list of target port groups. This allows
2776  * a client to force a failover or failback to a desired set of target port
2777  * groups.
2778  *
2779  * @param  luOid
2780  *      The object ID of the logical unit where the command is sent.
2781  *
2782  * @param  count
2783  *      The number of valid items in the pTpgStateList.
2784  *
2785  * @param  pTpgStateList
2786  *      A pointer to an array of TPG/access-state values. This array must
2787  *      contain the same number of elements as @ref count.
2788  *
2789  * @return An MP_STATUS indicating if the operation was successful or if
2790  *         an error occurred.
2791  *
2792  * @retval MP_STATUS_SUCCESS
2793  *         Returned when the operation is successful.
2794  *
2795  * @retval MP_STATUS_OBJECT_NOT_FOUND
2796  *      Returned when the MP_MULTIPATH_LOGICAL_UNIT associated with @ref
2797  *      oid could not be found.
2798  *
2799  * @retval MP_STATUS_INVALID_PARAMETER
2800  *      Returned if pTpgStateList is null or if one of the TPGs referenced
2801  *      in the list is not associated with the specified MP logical unit.
2802  *
2803  * @retval MP_STATUS_UNSUPPORTED
2804  *      Returned when the implementation does not support the API
2805  *
2806  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2807  *          Returned if oid does not specify any valid object type.
2808  *
2809  * @retval MP_STATUS_ACCESS_STATE_INVALID
2810  *         Returned if the target device returns a status indicating the caller
2811  *     is attempting to establish an illegal combination of access states.
2812  *
2813  * @retval MP_STATUS_FAILED
2814  *          Returned if the underlying interface failed the commend for some
2815  *      reason other than MP_STATUS_ACCESS_STATE_INVALID
2816  *
2817  *******************************************************************************
2818  */
2819 MP_STATUS MP_SetTPGAccess(
2820     MP_OID luOid,
2821     MP_UINT32 count,
2822     MP_TPG_STATE_PAIR *pTpgStateList)
2823 {
2824     MP_SetTPGAccessFn PassFunc;
2825     MP_UINT32 index;
2826     MP_STATUS status;
2827 
2828     if ((status = validate_object(luOid, MP_OBJECT_TYPE_MULTIPATH_LU,
2829         MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
2830         return (status);
2831     }
2832 
2833     (void) pthread_mutex_lock(&mp_lib_mutex);
2834 
2835     index = luOid.ownerId - 1;
2836     if (plugintable[index].hdlPlugin != NULL) {
2837         PassFunc = (MP_SetTPGAccessFn)
2838         dlsym(plugintable[index].hdlPlugin,
2839         "MP_SetTPGAccess");
2840 
2841         if (PassFunc != NULL) {
2842 	    status = PassFunc(luOid, count, pTpgStateList);
2843         } else {
2844 	    status = MP_STATUS_UNSUPPORTED;
2845         }
2846     } else {
2847         status = MP_STATUS_FAILED;
2848     }
2849 
2850     (void) pthread_mutex_unlock(&mp_lib_mutex);
2851     return (status);
2852 }
2853 
2854 /**
2855  *******************************************************************************
2856  *
2857  * Registers a client function that is to be called
2858  * whenever the property of an an object changes.
2859  *
2860  * @param  pClientFn,
2861  *      A pointer to an MP_OBJECT_PROPERTY_FN function defined by the
2862  *      client. On successful return this function will be called to
2863  *      inform the client of objects that have had one or more properties
2864  *      change.
2865  *
2866  * @param  objectType
2867  *      The type of object the client wishes to deregister for
2868  *      property change callbacks. If null, then all objects types are
2869  *      deregistered.
2870  *
2871  * @param  pCallerData
2872  *      A pointer that is passed to the callback routine with each event.
2873  *      This may be used by the caller to correlate the event to source of
2874  *      the registration.
2875  *
2876  * @return An MP_STATUS indicating if the operation was successful or if
2877  *         an error occurred.
2878  *
2879  * @retval MP_STATUS_SUCCESS
2880  *         Returned when the operation is successful.
2881  *
2882  * @retval MP_STATUS_INVALID_PARAMETER
2883  *      Returned if pClientFn is NULL or specifies a memory area
2884  *      that is not executable.
2885  *
2886  * @retval MP_STATUS_FN_REPLACED
2887  *      Returned when an existing client function is replaced with the one
2888  *      specified in pClientFn.
2889  *
2890  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2891  *          Returned if oid does not specify any valid object type.
2892  *
2893  *******************************************************************************
2894  */
2895 MP_STATUS MP_RegisterForObjectPropertyChanges(
2896     MP_OBJECT_PROPERTY_FN pClientFn,
2897     MP_OBJECT_TYPE objectType,
2898     void *pCallerData,
2899     MP_OID pluginOid)
2900 {
2901     MP_RegisterForObjectPropertyChangesPluginFn PassFunc;
2902     MP_UINT32 i;
2903     MP_UINT32 index;
2904     MP_STATUS status;
2905 
2906     if (pClientFn == NULL) {
2907         return (MP_STATUS_INVALID_PARAMETER);
2908     }
2909 
2910     if (objectType > MP_OBJECT_TYPE_MAX) {
2911         return (MP_STATUS_INVALID_OBJECT_TYPE);
2912     }
2913 
2914     if (!(is_zero_oid(pluginOid))) {
2915 	if ((status = validate_object(pluginOid, MP_OBJECT_TYPE_PLUGIN,
2916 	    MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
2917 	    return (status);
2918 	}
2919     }
2920 
2921     (void) pthread_mutex_lock(&mp_lib_mutex);
2922 
2923     if (is_zero_oid(pluginOid)) {
2924 	for (i = 0; i < number_of_plugins; i++) {
2925 	    if (plugintable[i].hdlPlugin != NULL) {
2926 		PassFunc = (MP_RegisterForObjectPropertyChangesPluginFn)
2927 		dlsym(plugintable[i].hdlPlugin,
2928 		"MP_RegisterForObjectPropertyChangesPlugin");
2929 	    }
2930 
2931 	    if (PassFunc != NULL) {
2932 		status =
2933 		     PassFunc(pClientFn, objectType, pCallerData);
2934 		/* ignore an error and continue */
2935 	    }
2936 	}
2937     } else {
2938 	index = pluginOid.ownerId - 1;
2939 	if (plugintable[index].hdlPlugin != NULL) {
2940 		PassFunc = (MP_RegisterForObjectPropertyChangesPluginFn)
2941 		dlsym(plugintable[index].hdlPlugin,
2942 		"MP_RegisterForObjectPropertyChangesPlugin");
2943 	}
2944 
2945 	if (PassFunc != NULL) {
2946 	    status = PassFunc(pClientFn, objectType, pCallerData);
2947 	}
2948     }
2949     (void) pthread_mutex_unlock(&mp_lib_mutex);
2950     return (status);
2951 }
2952 
2953 /**
2954  *******************************************************************************
2955  *
2956  * Deregisters a previously registered client function that is to be invoked
2957  * whenever an object's property changes.
2958  *
2959  * @param  pClientFn,
2960  *      A pointer to an MP_OBJECT_PROPERTY_FN function defined by the
2961  *      client that was previously registered using
2962  *      the MP_RegisterForObjectPropertyChanges API. On successful return
2963  *      this function will no longer be called to inform the client of
2964  *      object property changes.
2965  *
2966  * @param  objectType
2967  *      The type of object the client wishes to deregister for
2968  *      property change callbacks. If null, then all objects types are
2969  *      deregistered.
2970  *
2971  * @return An MP_STATUS indicating if the operation was successful or if
2972  *         an error occurred.
2973  *
2974  * @retval MP_STATUS_SUCCESS
2975  *         Returned when the operation is successful.
2976  *
2977  * @retval MP_STATUS_INVALID_PARAMETER
2978  *      Returned if pClientFn is NULL or specifies a memory area
2979  *      that is not executable.
2980  *
2981  * @retval MP_STATUS_UNKNOWN_FN
2982  *      Returned if pClientFn is not the same as the previously registered
2983  *      function.
2984  *
2985  * @retval MP_STATUS_INVALID_OBJECT_TYPE
2986  *          Returned if oid does not specify any valid object type.
2987  *
2988  * @retval MP_STATUS_FAILED
2989  *          Returned if pClientFn deregistration is not possible at this time.
2990  *
2991  *******************************************************************************
2992  */
2993 MP_STATUS MP_DeregisterForObjectPropertyChanges(
2994     MP_OBJECT_PROPERTY_FN pClientFn,
2995     MP_OBJECT_TYPE objectType,
2996     MP_OID pluginOid)
2997 {
2998     MP_DeregisterForObjectPropertyChangesPluginFn PassFunc;
2999     MP_UINT32 i;
3000     MP_UINT32 index;
3001     MP_STATUS status;
3002 
3003     if (pClientFn == NULL) {
3004         return (MP_STATUS_INVALID_PARAMETER);
3005     }
3006 
3007     if (objectType > MP_OBJECT_TYPE_MAX) {
3008         return (MP_STATUS_INVALID_OBJECT_TYPE);
3009     }
3010 
3011     if (!(is_zero_oid(pluginOid))) {
3012 	if ((status = validate_object(pluginOid, MP_OBJECT_TYPE_PLUGIN,
3013 	    MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
3014 	    return (status);
3015 	}
3016     }
3017 
3018     (void) pthread_mutex_lock(&mp_lib_mutex);
3019 
3020     if (is_zero_oid(pluginOid)) {
3021 	for (i = 0; i < number_of_plugins; i++) {
3022 	    if (plugintable[i].hdlPlugin != NULL) {
3023 		PassFunc = (MP_DeregisterForObjectPropertyChangesPluginFn)
3024 		dlsym(plugintable[i].hdlPlugin,
3025 		"MP_DeregisterForObjectPropertyChangesPlugin");
3026 	    }
3027 
3028 	    if (PassFunc != NULL) {
3029 		status = PassFunc(pClientFn, objectType);
3030 	    }
3031 	}
3032     } else {
3033 	index = pluginOid.ownerId - 1;
3034 	if (plugintable[index].hdlPlugin != NULL) {
3035 		PassFunc = (MP_DeregisterForObjectPropertyChangesPluginFn)
3036 		dlsym(plugintable[index].hdlPlugin,
3037 		"MP_DeregisterForObjectPropertyChangesPlugin");
3038 	}
3039 
3040 	if (PassFunc != NULL) {
3041 	    status = PassFunc(pClientFn, objectType);
3042 	}
3043     }
3044     (void) pthread_mutex_unlock(&mp_lib_mutex);
3045     return (status);
3046 }
3047 
3048 /**
3049  *******************************************************************************
3050  *
3051  * Registers a client function that is to be called
3052  * whenever a high level object appears or disappears.
3053  *
3054  * @param  pClientFn,
3055  *      A pointer to an MP_OBJECT_VISIBILITY_FN function defined by the
3056  *      client. On successful return this function will be called to
3057  *      inform the client of objects whose visibility has changed.
3058  *
3059  * @param  objectType
3060  *      The type of object the client wishes to deregister for
3061  *      property change callbacks. If null, then all objects types are
3062  *      deregistered.
3063  *
3064  * @param  pCallerData
3065  *      A pointer that is passed to the callback routine with each event.
3066  *      This may be used by the caller to correlate the event to source of
3067  *      the registration.
3068  *
3069  * @return An MP_STATUS indicating if the operation was successful or if
3070  *         an error occurred.
3071  *
3072  * @retval MP_STATUS_SUCCESS
3073  *         Returned when the operation is successful.
3074  *
3075  * @retval MP_STATUS_INVALID_PARAMETER
3076  *      Returned if pClientFn is NULL or specifies a memory area
3077  *      that is not executable.
3078  *
3079  * @retval MP_STATUS_FN_REPLACED
3080  *      Returned when an existing client function is replaced with the one
3081  *      specified in pClientFn.
3082  *
3083  * @retval MP_STATUS_INVALID_OBJECT_TYPE
3084  *          Returned if objectType does not specify any valid object type.
3085  *
3086  *******************************************************************************
3087  */
3088 MP_STATUS MP_RegisterForObjectVisibilityChanges(
3089     MP_OBJECT_VISIBILITY_FN pClientFn,
3090     MP_OBJECT_TYPE objectType,
3091     void *pCallerData,
3092     MP_OID pluginOid)
3093 {
3094     MP_RegisterForObjectVisibilityChangesPluginFn PassFunc;
3095     MP_UINT32 i;
3096     MP_UINT32 index;
3097     MP_STATUS status;
3098 
3099     if (pClientFn == NULL) {
3100         return (MP_STATUS_INVALID_PARAMETER);
3101     }
3102 
3103     if (objectType > MP_OBJECT_TYPE_MAX) {
3104         return (MP_STATUS_INVALID_OBJECT_TYPE);
3105     }
3106 
3107     if (!(is_zero_oid(pluginOid))) {
3108 	if ((status = validate_object(pluginOid, MP_OBJECT_TYPE_PLUGIN,
3109 	    MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
3110 	    return (status);
3111 	}
3112     }
3113 
3114     (void) pthread_mutex_lock(&mp_lib_mutex);
3115 
3116     if (is_zero_oid(pluginOid)) {
3117 	for (i = 0; i < number_of_plugins; i++) {
3118 	    if (plugintable[i].hdlPlugin != NULL) {
3119 	    PassFunc = (MP_RegisterForObjectVisibilityChangesPluginFn)
3120 		dlsym(plugintable[i].hdlPlugin,
3121 		"MP_RegisterForObjectVisibilityChangesPlugin");
3122 	    }
3123 
3124 	    if (PassFunc != NULL) {
3125 		status = PassFunc(pClientFn, objectType, pCallerData);
3126 		/* ignore an error and continue. */
3127 	    }
3128 	}
3129     } else {
3130 	    index = pluginOid.ownerId - 1;
3131 	    if (plugintable[index].hdlPlugin != NULL) {
3132 	    PassFunc = (MP_RegisterForObjectVisibilityChangesPluginFn)
3133 		dlsym(plugintable[index].hdlPlugin,
3134 		"MP_RegisterForObjectVisibilityChangesPlugin");
3135 	    }
3136 
3137 	    if (PassFunc != NULL) {
3138 		status = PassFunc(pClientFn, objectType, pCallerData);
3139 	    }
3140     }
3141     (void) pthread_mutex_unlock(&mp_lib_mutex);
3142     return (status);
3143 
3144 }
3145 
3146 /**
3147  *******************************************************************************
3148  *
3149  * Deregisters a previously registered client function that is to be invoked
3150  * whenever a high level object appears or disappears.
3151  *
3152  * @param  pClientFn,
3153  *      A pointer to an MP_OBJECT_VISIBILITY_FN function defined by the
3154  *      client that was previously registered using
3155  *      the MP_RegisterForObjectVisibilityChanges API. On successful return
3156  *      this function will no longer be called to inform the client of
3157  *      object property changes.
3158  *
3159  * @param  objectType
3160  *      The type of object the client wishes to deregister for visibility
3161  *      change callbacks. If null, then all objects types are
3162  *      deregistered.
3163  *
3164  * @return An MP_STATUS indicating if the operation was successful or if
3165  *         an error occurred.
3166  *
3167  * @retval MP_STATUS_SUCCESS
3168  *         Returned when the operation is successful.
3169  *
3170  * @retval MP_STATUS_INVALID_PARAMETER
3171  *      Returned if pClientFn is NULL or specifies a memory area
3172  *      that is not executable.
3173  *
3174  * @retval MP_STATUS_UNKNOWN_FN
3175  *      Returned if pClientFn is not the same as the previously registered
3176  *      function.
3177  *
3178  * @retval MP_STATUS_INVALID_OBJECT_TYPE
3179  *          Returned if objectType does not specify any valid object type.
3180  *
3181  * @retval MP_STATUS_FAILED
3182  *          Returned if pClientFn deregistration is not possible at this time.
3183  *
3184  *******************************************************************************
3185  */
3186 MP_STATUS MP_DeregisterForObjectVisibilityChanges(
3187     MP_OBJECT_VISIBILITY_FN pClientFn,
3188     MP_OBJECT_TYPE objectType,
3189     MP_OID pluginOid)
3190 {
3191     MP_DeregisterForObjectVisibilityChangesPluginFn PassFunc;
3192     MP_UINT32 i;
3193     MP_UINT32 index;
3194     MP_STATUS status;
3195 
3196     if (pClientFn == NULL) {
3197         return (MP_STATUS_INVALID_PARAMETER);
3198     }
3199 
3200     if (objectType > MP_OBJECT_TYPE_MAX) {
3201         return (MP_STATUS_INVALID_OBJECT_TYPE);
3202     }
3203 
3204     if (!(is_zero_oid(pluginOid))) {
3205 	if ((status = validate_object(pluginOid, MP_OBJECT_TYPE_PLUGIN,
3206 	    MP_OBJECT_TYPE_MATCH)) != MP_STATUS_SUCCESS) {
3207 	    return (status);
3208 	}
3209     }
3210 
3211     (void) pthread_mutex_lock(&mp_lib_mutex);
3212 
3213     if (is_zero_oid(pluginOid)) {
3214 	for (i = 0; i < number_of_plugins; i++) {
3215 	    if (plugintable[i].hdlPlugin != NULL) {
3216 		PassFunc = (MP_DeregisterForObjectVisibilityChangesPluginFn)
3217 		    dlsym(plugintable[i].hdlPlugin,
3218 		    "MP_DeregisterForObjectVisibilityChangesPlugin");
3219 		if (PassFunc != NULL) {
3220 		    status = PassFunc(pClientFn, objectType);
3221 		}
3222 	    }
3223 	}
3224     } else  {
3225 	    index = pluginOid.ownerId - 1;
3226 	    if (plugintable[index].hdlPlugin != NULL) {
3227 		PassFunc = (MP_DeregisterForObjectVisibilityChangesPluginFn)
3228 		    dlsym(plugintable[index].hdlPlugin,
3229 		    "MP_DeregisterForObjectVisibilityChangesPlugin");
3230 		if (PassFunc != NULL) {
3231 		    status = PassFunc(pClientFn, objectType);
3232 		}
3233 	    }
3234     }
3235 
3236     (void) pthread_mutex_unlock(&mp_lib_mutex);
3237     return (status);
3238 }
3239 
3240 /**
3241  *******************************************************************************
3242  *
3243  * Compare two Oids for equality to see whether they refer to the same object.
3244  *
3245  * @param  oid1
3246  *          Oid to compare.
3247  *
3248  * @param  oid2
3249  *          Oid to compare.
3250  *
3251  * @return An MP_STATUS indicating if the operation was successful or if
3252  *         an error occurred.
3253  *
3254  * @retval MP_STATUS_SUCCESS
3255  *         Returned when the two Oids do refer to the same object.
3256  *
3257  * @retval MP_STATUS_FAILED
3258  *      Returned if the Oids don't compare.
3259  *
3260  *******************************************************************************
3261  */
3262 MP_STATUS MP_CompareOIDs(
3263         MP_OID oid1,
3264     MP_OID oid2)
3265 {
3266     if ((oid1.objectType == oid2.objectType) && (oid1.ownerId == oid2.ownerId)
3267     	&& (oid1.objectSequenceNumber == oid2.objectSequenceNumber)) {
3268     	return (MP_STATUS_SUCCESS);
3269     } else {
3270     	return (MP_STATUS_FAILED);
3271     }
3272 }
3273 
3274 /**
3275  *******************************************************************************
3276  *
3277  * Frees memory returned by an MP API.
3278  *
3279  * @param  pOidList
3280  *      A pointer to the memory returned by an MP API. On successful
3281         return, the allocated memory is freed.
3282  *
3283  * @return An MP_STATUS indicating if the operation was successful or if
3284  *         an error occurred.
3285  *
3286  * @retval MP_STATUS_SUCCESS
3287  *         Returned when pPluginId is deregistered successfully.
3288  *
3289  * @retval MP_STATUS_INVALID_PARAMETER
3290  *      Returned if pMemory is NULL or specifies a memory area to which
3291  *      data cannot be written.
3292  *
3293  *******************************************************************************
3294  */
3295 MP_STATUS MP_FreeOidList(MP_OID_LIST *pOidList)
3296 {
3297 	if (pOidList == NULL) {
3298 	    return (MP_STATUS_INVALID_PARAMETER);
3299 	}
3300 
3301 	free(pOidList);
3302 
3303 	return (MP_STATUS_SUCCESS);
3304 }
3305 
3306 static MP_CHAR *HDR =
3307 "#\n"
3308 "# This file contains names and references to MP API plugin libraries\n"
3309 "#\n"
3310 "#  Do NOT manually edit this file\n"
3311 "#\n"
3312 "# Format:\n"
3313 "#\n"
3314 "# <library ID>  <library pathname>\n"
3315 "#\n";
3316 
3317 #define CLEANUP_N_RET(fd, ret)  \
3318 	if (lock_register(fd, F_SETLK, F_UNLCK, 0, SEEK_SET, 0) < 0) { \
3319 		close(fd); \
3320 		return (MP_STATUS_FAILED); \
3321 	} \
3322 	close(fd); \
3323 	return (ret)
3324 
3325 /*
3326  * This function sets an advisory lock on the file pointed to by the argument
3327  * fd, which is a file descriptor. The lock is set using fcntl() which uses
3328  * flock structure.
3329  */
3330 static int
3331 lock_register(int fd, int cmd, int type, off_t offset, int whence, off_t len)
3332 {
3333     struct flock lock;
3334 
3335     lock.l_type = type;
3336     lock.l_start = offset;
3337     lock.l_whence = whence;
3338     lock.l_len = len;
3339 
3340     return (fcntl(fd, cmd, &lock));
3341 }
3342 
3343 /*
3344  * This function searches for "srch_str" (of length "slen") in "buf" (of length
3345  * "buflen"). If it is not found, "write_offset" has the offset in "buf" where
3346  * "srch_str" would have to be added in "buf". If "srch_str" is found in "buf",
3347  * "write_offset" has its offset in "buf"
3348  *
3349  * ARGUMENTS :
3350  * buf		- buffer to search in
3351  * buflen	- length of buffer
3352  * srch_id	- id to search
3353  * id_len	- length of srch_id
3354  * write_offset	- Set in function on exit
3355  *		- It is the offset in buf where srch_str is or should be
3356  * bytes_left	- Set in function on exit
3357  *		- It is the # of bytes left beyond write_offset in buf
3358  * RETURN VALUES :
3359  * Zero - "srch_id" found in "buf"... "write_offset" has offset in "buf"
3360  * != 0 - "srch_str" NOT found in "buf" ... "write_offset" points to the end of
3361  *	    "buf".
3362  */
3363 static int
3364 search_line(MP_CHAR *buf, size_t buflen, MP_CHAR *srch_id, size_t id_len,
3365 		int *write_offset, int *bytes_left)
3366 {
3367 	int	retval, sizeof_conf_hdr = strlen(HDR);
3368 	MP_CHAR	*sol;		/* Pointer to Start-Of-Line */
3369 	MP_CHAR	*cur_pos;	/* current position */
3370 
3371 	*bytes_left = buflen;
3372 	*write_offset = 0;
3373 
3374 	if (buf == NULL || buflen <= 0)
3375 		return (-1);
3376 
3377 	if (srch_id == NULL || id_len <= 0)
3378 		return (0);
3379 
3380 	sol = cur_pos = buf;
3381 
3382 	/*
3383 	 * mp conf file should not be edited but takes care of
3384 	 * any extra white space when parsing the line.
3385 	 *
3386 	 * The line should have id + delimiter + name + newline.
3387 	 */
3388 	while (*bytes_left >= (id_len + 3)) {
3389 	    /* skip leading blank or space. */
3390 	    while ((*cur_pos == ' ') || (*cur_pos == '\t')) {
3391 		cur_pos++;
3392 	    }
3393 
3394 	    if (strncmp(cur_pos, srch_id, id_len) == 0) {
3395 		/* id matched. */
3396 		cur_pos += id_len;
3397 
3398 		while (*cur_pos != '\n') {
3399 		    cur_pos++;
3400 		}
3401 		*write_offset = (sol - buf);
3402 		*bytes_left = buflen - ((cur_pos + 1) - buf);
3403 		return (0);
3404 	    } else {
3405 		/* move to the next line */
3406 		while (*cur_pos != '\n') {
3407 		    cur_pos++;
3408 		}
3409 		*bytes_left = buflen - ((cur_pos + 1) - buf);
3410 	    }
3411 	    sol = cur_pos = cur_pos + 1;
3412 	}
3413 
3414 	/* Given strings are not found. */
3415 	*write_offset = buflen;
3416 	return (-1);
3417 }
3418 
3419 /**
3420  *******************************************************************************
3421  *
3422  * Registers a plugin with common library.  The implementation of this routine
3423  * is based on configuration file /etc/mpapi.conf that contains a list of
3424  * plugin libraries.
3425  *
3426  * @param  pPluginId
3427  *	    A pointer to the key name shall be the reversed domain name of
3428  *	    the vendor followed by followed by the vendor specific name for
3429  *	    the plugin that uniquely identifies the plugin.  Should be NULL
3430  *	    terminated.
3431  *
3432  * @param  pFileName
3433  *	    The full path to the plugin library.
3434  *	    Should be NULL terminated.
3435  *
3436  * @return An MP_STATUS indicating if the operation was successful or if
3437  *         an error occurred.
3438  *
3439  * @retval MP_STATUS_SUCCESS
3440  *         Returned when pPluginId is deregistered successfully.
3441  *
3442  * @retval MP_STATUS_INVALID_PARAMETER
3443  *      Returned if pPluginId is NULL or specifies a memory area that
3444  *      is not executable.
3445  *
3446  * @retval MP_STATUS_FAILED
3447  *          Returned if pClientFn deregistration is not possible at this time.
3448  *
3449  *******************************************************************************
3450  */
3451 MP_STATUS MP_RegisterPlugin(
3452 	MP_WCHAR *pPluginId,
3453 	char *pFileName)
3454 {
3455 	int mpconf, bytes_left, write_offset;
3456 	MP_CHAR fullline[MAX_LINE_SIZE]; /* Full line to add to mpapi.conf */
3457 	MP_CHAR *mpconf_buf;
3458 	MP_CHAR pluginid[MAX_NAME_SIZE];
3459 	char systemPath[MAX_NAME_SIZE], mpConfFilePath[MAX_NAME_SIZE];
3460 	MP_UINT32   new_file_flag = 0;
3461 	MP_UINT32   sizeof_conf_hdr = strlen(HDR);
3462 	struct stat	stbuf;
3463 
3464 	if ((pPluginId == NULL) || (pFileName == NULL)) {
3465 	    return (MP_STATUS_INVALID_PARAMETER);
3466 	}
3467 
3468 	if (stat(pFileName, &stbuf) != 0) {
3469 	    return (MP_STATUS_INVALID_PARAMETER);
3470 	}
3471 
3472 	if (wcstombs(pluginid, pPluginId, MAX_NAME_SIZE) != wcslen(pPluginId)) {
3473 	    return (MP_STATUS_INVALID_PARAMETER);
3474 	}
3475 
3476 	*fullline = '\0';
3477 	strncpy(fullline, pluginid, MAX_NAME_SIZE);
3478 	/* add tab */
3479 	strncat(fullline, "\t", MAX_LINE_SIZE - strlen(pluginid));
3480 	strncat(fullline, pFileName, MAX_LINE_SIZE - strlen(pluginid) - 1);
3481 	/* add a new line. */
3482 	strncat(fullline, "\n",
3483 	    MAX_LINE_SIZE - strlen(pluginid) - strlen(pFileName) -1);
3484 
3485 	/* Open configuration file from known location */
3486 	strncpy(mpConfFilePath, "/etc/mpapi.conf", MAX_NAME_SIZE);
3487 
3488 	if ((chmod(mpConfFilePath, S_IRUSR|S_IRGRP|S_IROTH) == -1) &&
3489 		(errno == ENOENT))  {
3490 	    new_file_flag = 1;
3491 	}
3492 
3493 	if ((mpconf = open(mpConfFilePath, O_RDWR | O_CREAT)) == -1) {
3494 		return (MP_STATUS_FAILED);
3495 	}
3496 
3497 	if (fchmod(mpconf, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
3498 	    close(mpconf);
3499 	    return (MP_STATUS_FAILED);
3500 	}
3501 
3502 	if (lock_register(mpconf, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0) < 0) {
3503 	    close(mpconf);
3504 	    return (MP_STATUS_FAILED);
3505 	}
3506 
3507 	if (fstat(mpconf, &stbuf) == -1) {
3508 	    CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
3509 	}
3510 
3511 	if ((new_file_flag) || (stbuf.st_size == 0)) {
3512 	    if (write(mpconf, HDR, sizeof_conf_hdr) !=
3513 		sizeof_conf_hdr) {
3514 		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
3515 	    }
3516 
3517 	    if (pwrite(mpconf, fullline, strlen(fullline),
3518 		sizeof_conf_hdr) !=
3519 		strlen(fullline)) {
3520 		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
3521 	    }
3522 	    CLEANUP_N_RET(mpconf, MP_STATUS_SUCCESS);
3523 	}
3524 
3525 	if ((mpconf_buf = (MP_CHAR *)mmap(0, stbuf.st_size,
3526 		PROT_READ | PROT_WRITE,
3527 		MAP_SHARED, mpconf, 0)) == MAP_FAILED) {
3528 	    CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
3529 	}
3530 
3531 	if (search_line(mpconf_buf, stbuf.st_size,
3532 	    pluginid, strlen(pluginid), &write_offset, &bytes_left) == 0) {
3533 	    /* found a match. */
3534 	    munmap((void *)mpconf_buf, stbuf.st_size);
3535 	    CLEANUP_N_RET(mpconf, MP_STATUS_SUCCESS);
3536 	} else {
3537 	    munmap((void *)mpconf_buf, stbuf.st_size);
3538 	    /* append the fullline to the mpconf. */
3539 	    if (pwrite(mpconf, fullline, strlen(fullline),
3540 		write_offset) !=
3541 		strlen(fullline)) {
3542 		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
3543 	    } else {
3544 		CLEANUP_N_RET(mpconf, MP_STATUS_SUCCESS);
3545 	    }
3546 	}
3547 }
3548 
3549 /**
3550  *******************************************************************************
3551  *
3552  * Deregisters a plugin from the common library.  This routine is based on
3553  * configuration file /etc/mpapi.conf that contains a list of plugin libraries.
3554  *
3555  * @param  pPluginId
3556  *      A pointer to a Plugin ID previously registered using
3557  *      the MP_RegisterPlugin API..
3558  *
3559  * @return An MP_STATUS indicating if the operation was successful or if
3560  *         an error occurred.
3561  *
3562  * @retval MP_STATUS_SUCCESS
3563  *         Returned when pPluginId is deregistered successfully.
3564  *
3565  * @retval MP_STATUS_INVALID_PARAMETER
3566  *      Returned if pPluginId is NULL or specifies a memory area that
3567  *      is not executable.
3568  *
3569  * @retval MP_STATUS_FAILED
3570  *          Returned if pClientFn deregistration is not possible at this time.
3571  *
3572  *******************************************************************************
3573  */
3574 MP_STATUS MP_DeregisterPlugin(
3575     MP_WCHAR *pPluginId)
3576 {
3577 	int mpconf, tmp_mpconf, bytes_left, write_offset;
3578 	char systemPath[MAX_NAME_SIZE], mpConfFilePath[MAX_NAME_SIZE],
3579 	    tmp_mpConfFilePath[MAX_NAME_SIZE + sizeof(pid_t)];
3580 	MP_CHAR    pluginid[MAX_NAME_SIZE];
3581 	MP_CHAR    *mpconf_buf;
3582 	MP_UINT32   sizeof_conf_hdr = strlen(HDR);
3583 	struct stat	stbuf;
3584 
3585 	if (pPluginId == NULL) {
3586 	    return (MP_STATUS_INVALID_PARAMETER);
3587 	}
3588 
3589 	if (wcstombs(pluginid, pPluginId, MAX_NAME_SIZE) != wcslen(pPluginId)) {
3590 	    return (MP_STATUS_INVALID_PARAMETER);
3591 	}
3592 
3593 	/* Open configuration file from known location */
3594 	strncpy(mpConfFilePath, "/etc/mpapi.conf", MAX_NAME_SIZE);
3595 
3596 	if ((chmod(mpConfFilePath, S_IRUSR|S_IRGRP|S_IROTH) == -1) &&
3597 		(errno == ENOENT))  {
3598 	    /* no file found */
3599 	    return (MP_STATUS_UNKNOWN_FN);
3600 	}
3601 
3602 	if ((mpconf = open(mpConfFilePath, O_RDWR)) == -1) {
3603 		return (MP_STATUS_FAILED);
3604 	}
3605 
3606 	if (fchmod(mpconf, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
3607 	    close(mpconf);
3608 	    return (MP_STATUS_FAILED);
3609 	}
3610 
3611 	if (lock_register(mpconf, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0) < 0) {
3612 	    close(mpconf);
3613 	    return (MP_STATUS_FAILED);
3614 	}
3615 
3616 	if (fstat(mpconf, &stbuf) == -1) {
3617 	    CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
3618 	}
3619 
3620 	if (stbuf.st_size == 0) {
3621 	    CLEANUP_N_RET(mpconf, MP_STATUS_SUCCESS);
3622 	}
3623 
3624 	if ((mpconf_buf = (MP_CHAR *)mmap(0, stbuf.st_size,
3625 		PROT_READ | PROT_WRITE,
3626 		MAP_SHARED, mpconf, 0)) == MAP_FAILED) {
3627 	    CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
3628 	}
3629 
3630 	if (search_line(mpconf_buf, stbuf.st_size, pluginid, strlen(pluginid),
3631 		&write_offset, &bytes_left) != 0) {
3632 	    munmap((void *)mpconf_buf, stbuf.st_size);
3633 	    CLEANUP_N_RET(mpconf, MP_STATUS_UNKNOWN_FN);
3634 	} else {
3635 	    /*
3636 	     * found a match.
3637 	     * construct temp file name using pid.
3638 	     */
3639 	    (void) snprintf(tmp_mpConfFilePath, MAX_NAME_SIZE,
3640 		"%s%ld", "/etc/mpapi.conf", getpid());
3641 
3642 	    if ((tmp_mpconf = open(tmp_mpConfFilePath,
3643 		O_RDWR|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR)) < 0) {
3644 		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
3645 	    }
3646 
3647 	    if (write(tmp_mpconf, mpconf_buf, write_offset) != write_offset) {
3648 		close(tmp_mpconf);
3649 		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
3650 	    }
3651 
3652 	    if (pwrite(tmp_mpconf, mpconf_buf + (stbuf.st_size - bytes_left),
3653 		bytes_left, write_offset) != bytes_left) {
3654 		close(tmp_mpconf);
3655 		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
3656 	    }
3657 
3658 	    close(tmp_mpconf);
3659 	    munmap((void *)mpconf_buf, stbuf.st_size);
3660 
3661 	    /* rename temp file to mpConfFile before unlock and close. */
3662 	    if (rename(tmp_mpConfFilePath, mpConfFilePath) != 0) {
3663 		CLEANUP_N_RET(mpconf, MP_STATUS_FAILED);
3664 	    } else {
3665 		CLEANUP_N_RET(mpconf, MP_STATUS_SUCCESS);
3666 	    }
3667 	}
3668 }
3669