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