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