[RFC][PATCH 1/3] persistent management feature for multipath-tools

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Resending this patch as somehow it did not show up in dm-devel mailing list sent in previous post.

This patch adds new cli utility 'mpathpersist' in multipath-tools for mpath persistent management. 
 
Signed-off-by: Vijay Chauhan <Vijay.chauhan@xxxxxxxxxx>
Reviewed-by: Bob Stankey <Robert.stankey@xxxxxxxxxx>
Reviewed-by: Babu Moger <Babu.moger@xxxxxxxxxx>
Reviewed-by: Yanling Q <Yanling.Q@xxxxxxxxxx>

---
diff -uprN multipath-tools-orig/libmpathpersist/Makefile multipath-tools/libmpathpersist/Makefile
--- multipath-tools-orig/libmpathpersist/Makefile	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/libmpathpersist/Makefile	2011-12-20 00:15:04.000000000 +0530
@@ -0,0 +1,51 @@
+# Makefile
+#
+BUILD = glibc
+include ../Makefile.inc
+
+INSTALL_PROGRAM = install
+
+SONAME=0
+DEVLIB = libmpathpersist.so
+LIBS = $(DEVLIB).$(SONAME)
+
+
+CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) 
+LIBDEPS +=  -lpthread -ldevmapper -ldl -L$(multipathdir) -lmultipath -lsysfs
+
+OBJS = mpath_persist.o mpath_updatepr.o mpath_pr_ioctl.o 
+
+all: $(LIBS)
+
+
+$(LIBS): 
+	$(CC) -Wall -fPIC -c $(CFLAGS) *.c 
+	$(CC)  -shared $(LIBDEPS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS)
+	ln -s $(LIBS) $(DEVLIB)
+	$(GZIP) mpath_persistent_reserve_in.3 > mpath_persistent_reserve_in.3.gz	
+	$(GZIP) mpath_persistent_reserve_out.3 > mpath_persistent_reserve_out.3.gz	
+
+install: $(LIBS)
+	$(INSTALL_PROGRAM) -d $(DESTDIR)$(syslibdir)
+	$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(syslibdir)/$(LIBS)
+	$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(syslibdir)
+	$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(man3dir)
+	$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)/usr/include/
+	$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)/usr/share/doc/mpathpersist/
+	ln -sf $(DESTDIR)$(syslibdir)/$(LIBS) $(DESTDIR)$(syslibdir)/$(DEVLIB)
+	install -m 644 mpath_persistent_reserve_in.3.gz $(DESTDIR)$(man3dir)	
+	install -m 644 mpath_persistent_reserve_out.3.gz $(DESTDIR)$(man3dir)	
+	install -m 644 mpath_persist.h $(DESTDIR)/usr/include/
+	install -m 644 README $(DESTDIR)/usr/share/doc/mpathpersist/
+
+uninstall:
+	rm -f $(DESTDIR)$(syslibdir)/$(LIBS)
+	rm $(DESTDIR)$(mandir)/mpath_persistent_reserve_in.3.gz	
+	rm $(DESTDIR)$(mandir)/mpath_persistent_reserve_out.3.gz	
+	rm $(DESTDIR)/usr/share/doc/mpathpersist/README
+
+clean:
+	rm -f core *.a *.o 
+	rm -f libmpathpersist.so.0
+	rm -f libmpathpersist.so
+	rm -f mpath_persistent_reserve_in.3.gz mpath_persistent_reserve_out.3.gz
diff -uprN multipath-tools-orig/libmpathpersist/mpath_persist.c multipath-tools/libmpathpersist/mpath_persist.c
--- multipath-tools-orig/libmpathpersist/mpath_persist.c	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/libmpathpersist/mpath_persist.c	2011-12-20 00:15:04.000000000 +0530
@@ -0,0 +1,897 @@
+#include "mpath_persist.h"
+#include <libdevmapper.h>
+#include <defaults.h>
+#include <sys/stat.h>
+#include <linux/kdev_t.h>
+#include <fcntl.h>
+#include <vector.h>
+#include <checkers.h>
+#include <structs.h>
+#include <structs_vec.h>
+
+#include <prio.h>
+#include <unistd.h>
+#include <devmapper.h>
+#include <debug.h>
+#include <config.h>
+#include <switchgroup.h>
+#include <discovery.h>
+#include <dmparser.h>
+#include <ctype.h>
+#include <propsel.h>
+#include <sysfs.h>
+
+#include "mpathpr.h"
+#include "mpath_pr_ioctl.h"
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define __STDC_FORMAT_MACROS 1
+
+
+int
+mpath_lib_init (void)
+{
+	if (load_config(DEFAULT_CONFIGFILE)){
+		condlog(0, "Failed to initialize multipath config.");
+		return 1;
+	}
+
+	if (sysfs_init(conf->sysfs_dir, FILE_NAME_SIZE)){
+		condlog(0, "Failed. mpathpersist needs sysfs mounted");
+		exit(1);
+	}
+	return 0;
+}
+
+int
+mpath_lib_exit (void)
+{
+	dm_lib_release();
+	dm_lib_exit();
+	cleanup_prio();
+	cleanup_checkers();
+	free_config(conf);
+	conf = NULL;
+	return 0;
+}
+
+static int
+updatepaths (struct multipath * mpp)
+{
+	int i, j;
+	struct pathgroup * pgp;
+	struct path * pp;
+
+	if (!mpp->pg)
+		return 0;
+
+	vector_foreach_slot (mpp->pg, pgp, i){
+		if (!pgp->paths)
+			continue;
+
+		vector_foreach_slot (pgp->paths, pp, j){
+			if (!strlen(pp->dev)){
+				if (devt2devname(pp->dev, FILE_NAME_SIZE,
+							pp->dev_t)){
+					/*
+					 * path is not in sysfs anymore
+					 */
+					pp->state = PATH_DOWN;
+					continue;
+				}
+				pp->mpp = mpp;
+				pathinfo(pp, conf->hwtable, DI_ALL);
+				continue;
+			}
+			pp->mpp = mpp;
+			if (pp->state == PATH_UNCHECKED ||
+					pp->state == PATH_WILD)
+				pathinfo(pp, conf->hwtable, DI_CHECKER);
+
+			if (pp->priority == PRIO_UNDEF)
+				pathinfo(pp, conf->hwtable, DI_PRIO);
+		}
+	}
+	return 0;
+}
+
+int 
+mpath_prin_activepath (struct multipath *mpp, int rq_servact,
+	struct prin_resp * resp, int noisy)
+{
+	int i,j, ret;
+	struct pathgroup *pgp = NULL;
+	struct path *pp = NULL;
+	char dev[FILE_NAME_SIZE];
+
+	vector_foreach_slot (mpp->pg, pgp, j){
+		vector_foreach_slot (pgp->paths, pp, i){
+			if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
+				condlog(2, "%s: %s not available. Skip.", mpp->wwid, dev);
+				condlog(3, "%s: status = %d.", mpp->wwid, pp->state);
+				continue;
+			}
+
+			condlog(3, "%s: sending PR IN command to %s ", mpp->wwid, dev);
+			ret = mpath_send_prin_activePath(pp->dev, rq_servact, resp, noisy);
+			return ret ;
+		}
+	}
+	return MPATH_PR_DMMP_ERROR;	
+}
+
+int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp *resp, int noisy, int verbose)
+{
+	struct stat info;
+	vector curmp = NULL;
+	vector pathvec = NULL;
+	char * alias;
+	struct multipath * mpp;
+	int map_present;
+	int major, minor;
+	int ret;
+
+	conf->verbosity = verbose;
+
+	if (fstat( fd, &info) != 0){
+		condlog(0, "stat error %d", fd);
+		return MPATH_PR_FILE_ERROR;
+	} 
+	if(!S_ISBLK(info.st_mode)){
+		condlog(0, "Failed to get major:minor. fd = %d", fd);
+		return MPATH_PR_FILE_ERROR;
+	}
+
+	major = (int)MAJOR(info.st_rdev);
+	minor = (int)MINOR(info.st_rdev);	
+	condlog(4, "Device %d:%d:  ", major, minor);
+
+	/* get alias from major:minor*/
+	alias = dm_mapname(major, minor);
+	if (!alias){
+		condlog(0, "%d:%d failed to get device alias.", major, minor);
+		return MPATH_PR_DMMP_ERROR;
+	}
+
+	condlog(3, "alias = %s", alias);
+	map_present = dm_map_present(alias);
+	if (map_present && dm_type(alias, TGT_MPATH) <= 0){
+		condlog( 0, "%s: not a multipath device.", alias);
+		ret = MPATH_PR_DMMP_ERROR;
+		goto out;
+	}
+
+	/*
+	 * allocate core vectors to store paths and multipaths
+	 */
+	curmp = vector_alloc ();
+	pathvec = vector_alloc ();
+
+	if (!curmp || !pathvec){
+		condlog (0, "%s: vector allocation failed.", alias);
+		ret = MPATH_PR_DMMP_ERROR;
+		goto out;
+	}
+
+	/* get info of all paths from the dm device	*/
+	if (get_mpvec (curmp, pathvec, alias)){
+		condlog(0, "%s: failed to get device info.", alias);
+		ret = MPATH_PR_DMMP_ERROR;
+		goto out1;
+	}
+
+	mpp = find_mp_by_alias(curmp, alias);
+	if (!mpp){
+		condlog(0, "%s: devmap not registered.", alias);
+		ret = MPATH_PR_DMMP_ERROR;
+		goto out1;
+	}
+
+	ret = mpath_prin_activepath(mpp, rq_servact, resp, noisy);
+
+out1:
+	free_multipathvec(curmp, KEEP_PATHS);
+	free_pathvec(pathvec, FREE_PATHS);	
+out:
+	FREE(alias);
+	return ret; 						
+}
+
+int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
+		unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy, int verbose)
+{
+
+	struct stat info;
+
+	vector curmp = NULL;
+	vector pathvec = NULL;
+
+	char * alias;
+	struct multipath * mpp;
+	int map_present;
+	int major, minor;
+	int ret;
+	int j;
+	unsigned char *keyp;
+	uint64_t prkey;		
+
+	conf->verbosity = verbose;
+
+	if (fstat( fd, &info) != 0){
+		condlog(0, "stat error fd=%d", fd);
+		return MPATH_PR_FILE_ERROR;
+	}
+
+	if(!S_ISBLK(info.st_mode)){
+		condlog(3, "Failed to get major:minor. fd=%d", fd);
+		return MPATH_PR_FILE_ERROR;	
+	}	
+
+	major = (int)MAJOR(info.st_rdev);
+	minor = (int)MINOR(info.st_rdev);
+	condlog(4, "Device  %d:%d", major, minor);
+
+	/* get WWN of the device from major:minor*/
+	alias = dm_mapname(major, minor);
+	if (!alias){
+		ret = MPATH_PR_DMMP_ERROR;
+		goto out;
+	}
+
+	condlog(3, "alias = %s", alias);
+	map_present = dm_map_present(alias);
+
+	if (map_present && dm_type(alias, TGT_MPATH) <= 0){
+		condlog(3, "%s: not a multipath device.", alias);
+		ret = MPATH_PR_DMMP_ERROR;
+		goto out;
+	}
+
+	/*
+	 * allocate core vectors to store paths and multipaths
+	 */
+	curmp = vector_alloc ();
+	pathvec = vector_alloc ();
+
+	 if (!curmp || !pathvec){
+                condlog (0, "%s: vector allocation failed.", alias);
+                ret = MPATH_PR_DMMP_ERROR;
+                goto out;
+        }
+
+	/* get info of all paths from the dm device     */
+	if (get_mpvec(curmp, pathvec, alias)){
+		condlog(0, "%s: failed to get device info.", alias);
+		ret = MPATH_PR_DMMP_ERROR;
+		goto out;
+	}
+
+	mpp = find_mp_by_alias(curmp, alias);
+
+	if (!mpp) {
+		condlog(0, "%s: devmap not registered.", alias);
+		ret = MPATH_PR_DMMP_ERROR;
+		goto out1;
+	}
+
+	select_reservation_key(mpp);
+
+	switch(rq_servact)
+	{
+		case MPATH_PROUT_REG_SA: 
+		case MPATH_PROUT_REG_IGN_SA:  
+			ret= mpath_prout_reg(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
+			break;
+		case MPATH_PROUT_RES_SA :  
+		case MPATH_PROUT_PREE_SA :  
+		case MPATH_PROUT_PREE_AB_SA :  
+		case MPATH_PROUT_CLEAR_SA:  
+			ret = mpath_prout_common(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
+			break;
+		case MPATH_PROUT_REL_SA:
+			ret = mpath_prout_rel(mpp, rq_servact, rq_scope, rq_type, paramp, noisy);
+			break;
+		default:
+			ret = MPATH_PR_OTHER;
+			goto out1;
+	}
+
+	if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_REG_SA) ||
+				(rq_servact ==  MPATH_PROUT_REG_IGN_SA)))
+	{
+		keyp=paramp->sa_key;
+		prkey = 0;
+		for (j = 0; j < 8; ++j) {
+			if (j > 0)
+				prkey <<= 8;
+			prkey |= *keyp;
+			++keyp;
+		}
+		if (prkey == 0)
+			update_prflag(alias, "unset", noisy);
+		else
+			update_prflag(alias, "set", noisy);
+	} else {
+		if ((ret == MPATH_PR_SUCCESS) && ((rq_servact == MPATH_PROUT_CLEAR_SA) || 
+					(rq_servact == MPATH_PROUT_PREE_AB_SA ))){
+			update_prflag(alias, "unset", noisy);
+		}
+	}
+out1:
+	free_multipathvec(curmp, KEEP_PATHS);
+	free_pathvec(pathvec, FREE_PATHS);
+
+out:
+	FREE(alias);
+	return ret; 
+}
+
+int
+get_mpvec (vector curmp, vector pathvec, char * refwwid)
+{
+	int i;
+	struct multipath *mpp;
+	char params[PARAMS_SIZE], status[PARAMS_SIZE];
+
+	if (dm_get_maps (curmp)){
+		return 1;
+	}
+
+	vector_foreach_slot (curmp, mpp, i){
+		/*
+		 * discard out of scope maps
+		 */
+		if (mpp->alias && refwwid && strncmp (mpp->alias, refwwid, WWID_SIZE)){
+			free_multipath (mpp, KEEP_PATHS);
+			vector_del_slot (curmp, i);
+			i--;
+			continue;
+		}
+
+		dm_get_map(mpp->alias, &mpp->size, params);
+		condlog(3, "params = %s", params);
+		dm_get_status(mpp->alias, status);
+                condlog(3, "status = %s", status);
+		disassemble_map (pathvec, params, mpp);
+		
+		/*
+		 * disassemble_map() can add new paths to pathvec.
+		 * If not in "fast list mode", we need to fetch information
+		 * about them
+		 */
+		updatepaths(mpp);
+		mpp->bestpg = select_path_group (mpp);
+		disassemble_status (status, mpp);
+
+	}
+	return MPATH_PR_SUCCESS ;
+}
+
+void * mpath_prin_pthread_fn (void *p)
+{
+	int ret;
+	struct prin_param * pparam = (struct prin_param *)p;
+
+	ret = prin_do_scsi_ioctl(pparam->dev, pparam->rq_servact, pparam->resp,  pparam->noisy);
+	pparam->status = ret;	
+	pthread_exit(NULL);	
+}
+
+int mpath_send_prin_activePath (char * dev, int rq_servact, struct prin_resp * resp, int noisy)
+{
+
+	struct prin_param param;
+	int rc;
+
+	param.rq_servact = rq_servact; 
+	param.resp = resp;
+	param.noisy = noisy;
+	param.status = MPATH_PR_OTHER;
+
+	rc = prin_do_scsi_ioctl(dev, rq_servact, resp,  noisy);
+	
+	return (rc);
+}
+
+int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
+	unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
+{
+
+	int i, j;
+	struct pathgroup *pgp = NULL;
+	struct path *pp = NULL;
+	int rollback = 0;
+	int active_pathcount=0;	
+	int rc;
+	int count=0;
+	int status = MPATH_PR_SUCCESS;
+	uint64_t sa_key;	
+
+	if (!mpp)
+		return MPATH_PR_DMMP_ERROR; 
+
+	active_pathcount = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
+
+	if (active_pathcount == 0) {
+		condlog (0, "%s: no path available", mpp->wwid);
+		return MPATH_PR_DMMP_ERROR;
+	}
+
+	if ( paramp->sa_flags & MPATH_F_ALL_TG_PT_MASK ) {
+		condlog (1, "Warning: ALL_TG_PT is set. Configuration not supported");
+	}
+
+	struct threadinfo thread[active_pathcount];
+
+	memset(thread, 0, sizeof(thread));
+
+	/* init thread parameter */
+	for (i =0; i< active_pathcount; i++){
+		thread[i].param.rq_servact = rq_servact;
+		thread[i].param.rq_scope = rq_scope;
+		thread[i].param.rq_type = rq_type;
+		thread[i].param.paramp = paramp;
+		thread[i].param.noisy = noisy;
+		thread[i].param.status = -1;
+
+		condlog (3, "THRED ID [%d] INFO]", i);
+		condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
+		condlog (3, "rq_scope=%d ", thread[i].param.rq_scope); 
+		condlog (3, "rq_type=%d ", thread[i].param.rq_type);  
+		condlog (3, "rkey="); 
+		condlog (3, "paramp->sa_flags =%02x ", thread[i].param.paramp->sa_flags); 
+		condlog (3, "noisy=%d ", thread[i].param.noisy); 
+		condlog (3, "status=%d ", thread[i].param.status); 
+	}
+
+	pthread_attr_t attr;
+	pthread_attr_init(&attr);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+	vector_foreach_slot (mpp->pg, pgp, j){
+		vector_foreach_slot (pgp->paths, pp, i){
+			if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
+				condlog (1, "%s: %s path not up. Skip.", mpp->wwid, pp->dev);
+				continue;
+			}
+			strncpy(thread[count].param.dev, pp->dev, FILE_NAME_SIZE);
+
+			if (count && (thread[count].param.paramp->sa_flags & MPATH_F_SPEC_I_PT_MASK)){
+				/*
+				 * Clearing SPEC_I_PT as transportids are already registered by now.
+				 */
+				thread[count].param.paramp->sa_flags &= (~MPATH_F_SPEC_I_PT_MASK);
+			}
+
+			condlog (3, "%s: sending PR OUT command to %s", mpp->wwid, pp->dev);
+
+			rc = pthread_create(&thread[count].id, &attr, mpath_prout_pthread_fn, (void *)(&thread[count].param));
+			if (rc){
+				condlog (0, "%s: failed to create thread %d", mpp->wwid, rc);
+			}
+			count = count +1;
+		}
+	}
+	for( i=0; i < active_pathcount ; i++){
+		rc = pthread_join(thread[i].id, NULL);
+		if (rc){
+			condlog (0, "%s: Thread[%d] failed to join thread %d", mpp->wwid, i, rc);
+		}
+		if (!rollback && (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)){
+			rollback = 1;
+			sa_key = 0;
+			for (i = 0; i < 8; ++i){
+				if (i > 0)
+					sa_key <<= 8;
+				sa_key |= paramp->sa_key[i];
+			}
+			status = MPATH_PR_RESERV_CONFLICT ;
+		}
+		if (!rollback && (status == MPATH_PR_SUCCESS)){
+			status = thread[i].param.status;
+		}
+	}
+	if (rollback && ((rq_servact == MPATH_PROUT_REG_SA) && sa_key != 0 )){
+		condlog (3, "%s: ERROR: initiating PR OUT rollback", mpp->wwid);
+		for( i=0 ; i < active_pathcount ; i++){
+			if((thread[i].param.status == MPATH_PR_SUCCESS) &&
+					((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
+				memcpy(&thread[i].param.paramp->key, &thread[i].param.paramp->sa_key, 8);
+				memset(&thread[i].param.paramp->sa_key, 0, 8);
+				thread[i].param.status = MPATH_PR_SUCCESS;
+				rc = pthread_create(&thread[i].id, &attr, mpath_prout_pthread_fn, 
+						(void *)(&thread[count].param));
+				if (rc){
+					condlog (0, "%s: failed to create thread for rollback. %d",  mpp->wwid, rc);
+				}
+			}
+		}
+		for(i=0; i < active_pathcount ; i++){
+			rc = pthread_join(thread[i].id, NULL);
+			if (rc){
+				condlog (3, "%s: failed to join thread while rolling back %d",
+						mpp->wwid, i);
+			}
+		}
+	}
+
+	pthread_attr_destroy(&attr);
+	return (status);
+}
+
+void * mpath_prout_pthread_fn(void *p)
+{
+	int ret;
+	struct prout_param * param = (struct prout_param *)p;
+
+	ret = prout_do_scsi_ioctl( param->dev,param->rq_servact, param->rq_scope,
+			param->rq_type, param->paramp, param->noisy);
+	param->status = ret;
+	pthread_exit(NULL);
+}
+
+int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
+        unsigned int rq_type, struct prout_param_descriptor* paramp, int noisy)
+{
+	int i,j, ret;
+	struct pathgroup *pgp = NULL;
+	struct path *pp = NULL;
+	struct path *pptemp = NULL;
+	char dev[FILE_NAME_SIZE];
+
+	vector_foreach_slot (mpp->pg, pgp, j){
+		vector_foreach_slot (pgp->paths, pp, i){
+			if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
+				condlog (1, "%s: %s path not up. Skip", mpp->wwid, dev); 
+				continue;
+			}
+
+			condlog (3, "%s: sending prout command to %s", mpp->wwid, dev);
+			ret = send_prout_activePath(pp->dev, rq_servact, rq_scope, rq_type, 
+					paramp, noisy); 
+			pptemp = pp;
+			return ret ;
+		}
+	}
+	return MPATH_PR_SUCCESS;
+}
+
+int send_prout_activePath(char * dev, int rq_servact, int rq_scope,
+	unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
+{
+	struct prout_param param;
+	param.rq_servact = rq_servact;
+	param.rq_scope  = rq_scope;
+	param.rq_type   = rq_type;
+	param.paramp    = paramp;
+	param.noisy = noisy;
+	param.status = -1;
+
+	pthread_t thread;
+	pthread_attr_t attr;
+	int rc;
+
+	/* Initialize and set thread joinable attribute */
+	pthread_attr_init(&attr);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+	rc = pthread_create(&thread, &attr, mpath_prout_pthread_fn, (void *)(&param));
+	if (rc){
+		condlog (3, "%s: failed to create thread %d", dev, rc);
+		exit(-1);
+	}
+	/* Free attribute and wait for the other threads */
+	pthread_attr_destroy(&attr);
+	rc = pthread_join(thread, NULL);
+
+	return (rc);
+}
+
+int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
+        unsigned int rq_type, struct prout_param_descriptor * paramp, int noisy)
+{
+	int i, j, k;
+	int num = 0;
+	struct pathgroup *pgp = NULL;
+	struct path *pp = NULL;
+	char dev[FILE_NAME_SIZE];
+	int active_pathcount = 0;
+	pthread_attr_t attr;
+	int rc, found = 0;;
+	int count = 0;
+	int status = MPATH_PR_SUCCESS;
+	struct prin_resp resp;
+	struct prout_param_descriptor *pamp;
+	struct prin_resp *pr_buff;
+	int result = 0, length;
+	struct transportid *pptr;	
+
+	if (!mpp)
+		return MPATH_PR_DMMP_ERROR;
+
+	active_pathcount = pathcount (mpp, PATH_UP) + pathcount (mpp, PATH_GHOST);
+
+	struct threadinfo thread[active_pathcount];
+
+	for (i = 0; i < active_pathcount; i++){
+		thread[i].param.rq_servact = rq_servact;
+		thread[i].param.rq_scope = rq_scope;
+		thread[i].param.rq_type = rq_type;
+		thread[i].param.paramp = paramp;
+		thread[i].param.noisy = noisy;
+		thread[i].param.status = -1;
+
+		condlog (3, " path count = %d", i);
+		condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
+		condlog (3, "rq_scope=%d ", thread[i].param.rq_scope);
+		condlog (3, "rq_type=%d ", thread[i].param.rq_type);
+		for (k = 0; k < 8; k++)
+			printf ("paramp=%02x ", thread[i].param.paramp->key[k]);
+		for (k = 0; k < 8; k++)
+			printf ("paramp=%02x ", thread[i].param.paramp->sa_key[k]);
+
+		condlog (3, "paramp->sa_flags =%02x ",
+				thread[i].param.paramp->sa_flags);
+		condlog (3, "noisy=%d ", thread[i].param.noisy);
+		condlog (3, "status=%d ", thread[i].param.status);
+	}
+
+	pthread_attr_init (&attr);
+	pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
+
+	vector_foreach_slot (mpp->pg, pgp, j){
+		vector_foreach_slot (pgp->paths, pp, i){
+			if (!((pp->state == PATH_UP) || (pp->state == PATH_GHOST))){
+				condlog (1, "%s: %s path not up.", mpp->wwid, dev);
+				continue;
+			}
+			
+			strncpy(thread[count].param.dev, pp->dev, FILE_NAME_SIZE);
+
+			condlog (3, "%s: sending prout command to %s", mpp->wwid, dev);
+
+			rc = pthread_create (&thread[count].id, &attr, mpath_prout_pthread_fn,
+					(void *) (&thread[count].param));
+			if (rc){
+				condlog (0, "%s: failed to create thread. %d",  mpp->wwid, rc);
+			}
+			count = count + 1;
+		}
+	}
+	pthread_attr_destroy (&attr);
+	for (i = 0; i < active_pathcount; i++){
+		rc = pthread_join (thread[i].id, NULL);
+		if (rc){
+			condlog (1, "%s: failed to join thread.  %d",  mpp->wwid,  rc);
+		}
+	}
+
+	for (i = 0; i < active_pathcount; i++){
+		/*  check thread status here and return the status */
+
+		if (thread[i].param.status == MPATH_PR_RESERV_CONFLICT)
+			status = MPATH_PR_RESERV_CONFLICT;
+		else if (status == MPATH_PR_SUCCESS
+				&& thread[i].param.status != MPATH_PR_RESERV_CONFLICT)
+			status = thread[i].param.status;
+	}
+
+	result = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
+	if (result != MPATH_PR_SUCCESS){
+		condlog (0, "%s: prin read reservation command failed.", mpp->wwid);
+		return MPATH_PR_OTHER;
+	}
+
+	num = resp.prin_descriptor.prin_readresv.additional_length / 8;
+	if (num == 0){
+		return MPATH_PR_SUCCESS;	
+	}
+	condlog (3, "%s: Path holding reservation is not avialable.", mpp->wwid);
+
+	pr_buff =  mpath_alloc_prin_response(MPATH_PRIN_RFSTAT_SA);
+	if (!pr_buff){
+		condlog (0, "%s: failed to  alloc prin response buffer.", mpp->wwid);	
+		return MPATH_PR_OTHER;
+	}
+
+	result =
+		mpath_prin_activepath (mpp, MPATH_PRIN_RFSTAT_SA, pr_buff, noisy);
+
+	if (result != MPATH_PR_SUCCESS){
+		condlog (0,  "%s: prin read full status command failed.",  mpp->wwid);
+		goto out;
+	}
+
+	num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
+	if (0 == num){
+		goto out;
+	}
+	length = sizeof (struct prout_param_descriptor) + (sizeof (struct transportid *));
+
+	pamp = (struct prout_param_descriptor *)malloc (length);
+	if (!pamp){
+		condlog (0, "%s: failed to alloc prout parameter.", mpp->wwid);
+		goto out1;
+	}
+
+	memset(pamp, 0, length);
+
+	pamp->trnptid_list[0] = (struct transportid *) malloc (sizeof (struct transportid));
+	if (!pamp->trnptid_list[0]){
+		condlog (0, "%s: failed to alloc prout transportid.", mpp->wwid);
+		goto out1;
+	}
+
+	if (mpp->reservation_key ){
+		memcpy (pamp->key, mpp->reservation_key, 8);
+		condlog (3, "%s: reservation key set.", mpp->wwid);
+	}
+
+	mpath_prout_common (mpp, MPATH_PROUT_CLEAR_SA, rq_scope, rq_type, pamp,
+			noisy);
+
+	pamp->num_transportid = 1;
+	pptr=pamp->trnptid_list[0];
+
+	for (i = 0; i < num; i++){
+		if (mpp->reservation_key && 
+			memcmp(pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key,
+			mpp->reservation_key, 8)){	
+			/*register with tarnsport id*/
+			memset(pamp, 0, length);
+			pamp->trnptid_list[0] = pptr;
+			memset (pamp->trnptid_list[0], 0, sizeof (struct transportid));
+			memcpy (pamp->sa_key,
+					pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
+			pamp->sa_flags = MPATH_F_SPEC_I_PT_MASK;
+			pamp->num_transportid = 1;
+
+			memcpy (pamp->trnptid_list[0],
+					&pr_buff->prin_descriptor.prin_readfd.descriptors[i]->trnptid,
+					sizeof (struct transportid));
+			result = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
+					pamp, noisy);
+
+			pamp->sa_flags = 0;
+			memcpy (pamp->key, pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key, 8);
+			memset (pamp->sa_key, 0, 8);
+			pamp->num_transportid = 0;
+			result = mpath_prout_common (mpp, MPATH_PROUT_REG_SA, 0, rq_type,
+					pamp, noisy);
+		}
+		else
+		{
+			if (mpp->reservation_key)
+				found = 1;
+		}
+
+
+	}
+
+	if (found){
+		memset (pamp, 0, length);
+		memcpy (pamp->sa_key, mpp->reservation_key, 8);
+		memset (pamp->key, 0, 8);
+		mpath_prout_reg(mpp, MPATH_PROUT_REG_SA, rq_scope, rq_type, pamp, noisy);	
+	}
+
+
+	free(pptr);
+out1:
+	free (pamp);
+out:
+	free (pr_buff);
+	return (status);
+}
+
+void * mpath_alloc_prin_response(int prin_sa)
+{
+	void * ptr = NULL;
+	int size=0;
+	switch (prin_sa)
+	{
+		case MPATH_PRIN_RKEY_SA:
+			size = sizeof(struct prin_readdescr);
+			ptr = malloc(size);
+			memset(ptr, 0, size);
+			break;
+		case MPATH_PRIN_RRES_SA:
+			size = sizeof(struct prin_resvdescr);
+			ptr = malloc(size);
+			memset(ptr, 0, size);
+			break;
+		case MPATH_PRIN_RCAP_SA:
+			size=sizeof(struct prin_capdescr);
+			ptr = malloc(size);
+			memset(ptr, 0, size);
+			break;
+		case MPATH_PRIN_RFSTAT_SA:
+			size = sizeof(struct print_fulldescr_list) + 
+				sizeof(struct prin_fulldescr *)*MPATH_MX_TIDS;
+			ptr = malloc(size);
+			memset(ptr, 0, size);
+			break;
+	}
+	return ptr;
+}
+
+int update_map_pr(struct multipath *mpp)
+{
+	int noisy=0;
+	struct prin_resp *resp;
+	int i,j, ret, isFound;
+	unsigned char *keyp;
+	uint64_t prkey;
+
+	resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
+	if (!resp)
+	{
+		condlog(0,"%s : failed to alloc resp in update_map_pr", mpp->alias);
+		return MPATH_PR_OTHER;
+	}
+	ret = mpath_prin_activepath(mpp, MPATH_PRIN_RKEY_SA, resp, noisy);
+
+	if (ret != MPATH_PR_SUCCESS )
+	{
+		condlog(0,"%s : PR IN Read keys Service Action Failed Error=%d", mpp->alias, ret);
+		free(resp);
+		return  ret;
+	}
+
+	if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
+	{
+		condlog(0,"%s: No key found. Device may not be registered. ", mpp->alias);
+		free(resp);
+		return MPATH_PR_SUCCESS;
+	}
+
+	if (mpp->reservation_key)
+	{
+		prkey = 0;
+		keyp = mpp->reservation_key;
+		for (j = 0; j < 8; ++j) {
+			if (j > 0)
+				prkey <<= 8;
+			prkey |= *keyp;
+			++keyp;
+		}
+		condlog(2, "%s: Multipath  reservation_key: 0x%" PRIx64 " ", mpp->alias, prkey);
+	}
+	else
+	{
+		condlog(1, "%s: reservation_key not set in multiapth.conf", mpp->alias);
+		free(resp);
+		return MPATH_PR_DMMP_ERROR;
+	}
+
+	isFound =0;
+
+	for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
+	{
+		condlog(2, "%s: PR IN READKEYS[%d]  reservation key:", mpp->alias, i);
+		dumpHex((char *)&resp->prin_descriptor.prin_readkeys.key_list[i*8], 8 , 1);
+
+		if (!memcmp(mpp->reservation_key, &resp->prin_descriptor.prin_readkeys.key_list[i*8], 8))
+		{
+
+			condlog(2, "%s: reservation key found in prin readkeys response", mpp->alias);
+			isFound =1;
+		}
+	}
+
+	if (isFound)
+	{
+		mpp->prflag = 1;
+		condlog(2, "%s: prflag flag set.", mpp->alias );
+	}
+
+	free(resp);
+	return MPATH_PR_SUCCESS;
+}
+
+
+
diff -uprN multipath-tools-orig/libmpathpersist/mpath_persistent_reserve_in.3 multipath-tools/libmpathpersist/mpath_persistent_reserve_in.3
--- multipath-tools-orig/libmpathpersist/mpath_persistent_reserve_in.3	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/libmpathpersist/mpath_persistent_reserve_in.3	2011-12-20 00:15:04.000000000 +0530
@@ -0,0 +1,80 @@
+.\"
+.TH MPATH_PERSISTENT_RESERVE_IN 3  2011-04-08 "Linux Manpage" 
+.SH NAME
+mpath_persistent_reserve_in
+.SH SYNOPSIS
+.B #include <mpath_persist.h>
+.sp
+.BI "int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp *resp, int noisy, int verbose)"
+.sp
+.SH DESCRIPTION
+The function in the
+.BR mpath_persistent_reserve_in ()
+sends PRIN command to the DM device and gets the response.
+.br
+.BI Parameters:
+.br
+.I fd
+.B The file descriptor of a multipath device. Input argument.
+.br
+.I rq_servact
+.B PRIN command service action. Input argument
+.br
+.I resp
+.B The response from PRIN service action. The caller should manage the memory allocation of this structure
+.br
+.I noisy
+.B Turn on debugging trace: Input argument. 0->Disable, 1->Enable
+.br
+.I verbose
+.B Set verbosity level. Input argument. value:[0-3]. 0->Crits and Errors, 1->Warnings, 2->Info, 3->Debug
+.br
+
+.SH "RETURNS"
+.I MPATH_PR_SUCCESS
+.B if PR command successful
+.br
+.I MPATH_PR_SYNTAX_ERROR        
+.B if  syntax error or invalid parameter
+.br
+.I MPATH_PR_SENSE_NOT_READY     
+.B  if command fails with [sk,asc,ascq: 0x2,*,*]
+.br
+.I MPATH_PR_SENSE_MEDIUM_ERROR
+.B  if command fails with [sk,asc,ascq: 0x3,*,*]
+.br
+.I MPATH_PR_SENSE_HARDWARE_ERROR
+.B  if command fails with [sk,asc,ascq: 0x4,*,*]
+.br
+.I MPATH_PR_SENSE_INVALID_OP
+.B  if command fails with [sk,asc,ascq: 0x5,0x20,0x0]
+.br
+.I MPATH_PR_ILLEGAL_REQ
+.B  if command fails with [sk,asc,ascq: 0x5,*,*]
+.br
+.I MPATH_PR_SENSE_UNIT_ATTENTION
+.B  if command fails with [sk,asc,ascq: 0x6,*,*]
+.br
+.I MPATH_PR_SENSE_ABORTED_COMMAND
+.B  if command fails with [sk,asc,ascq: 0xb,*,*]
+.br
+.I MPATH_PR_NO_SENSE
+.B  if command fails with [sk,asc,ascq: 0x0,*,*]
+.br
+.I MPATH_PR_SENSE_MALFORMED  
+.B if command fails with SCSI command malformed
+.br
+.I MPATH_PR_FILE_ERROR
+.B if command fails while accessing file (device node) problems(e.g. not found)
+.br
+.I MPATH_PR_DMMP_ERROR
+.B if Device Mapper related error.(e.g Error in getting dm info) 
+.br
+.I MPATH_PR_OTHER
+.B if other error/warning has occurred(e.g transport or driver error)
+.br
+
+
+.SH "SEE ALSO"
+.I  mpath_persistent_reserve_out      mpathpersist     /usr/share/doc/mpathpersist/README
+.br
diff -uprN multipath-tools-orig/libmpathpersist/mpath_persistent_reserve_out.3 multipath-tools/libmpathpersist/mpath_persistent_reserve_out.3
--- multipath-tools-orig/libmpathpersist/mpath_persistent_reserve_out.3	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/libmpathpersist/mpath_persistent_reserve_out.3	2011-12-20 00:15:04.000000000 +0530
@@ -0,0 +1,92 @@
+.\"
+.TH MPATH_PERSISTENT_RESERVE_OUT 3  2011-04-08 "Linux Manpage" 
+.SH NAME
+mpath_persistent_reserve_out
+.SH SYNOPSIS
+.B #include <mpath_persist.h>
+.sp
+.BI "int mpath_persistent_reserve_out (int fd, int rq_servact, struct prin_resp *resp, int noisy, int verbose)"
+.sp
+.SH DESCRIPTION
+The function in the
+.BR mpath_persistent_reserve_out ()
+sends PR OUT command to the DM device and gets the response.
+.br
+.BI Parameters:
+.br
+.I fd 
+.B The file descriptor of a multipath device. Input argument.
+.br
+.I rq_servact
+.B PROUT command service action. Input argument
+.br
+.I rq_scope
+.B Persistent reservation scope. The value should be always LU_SCOPE (0h).
+.br
+.I rq_type
+.B Persistent reservation type. The valid values of persistent reservation types are
+      5h (Write exclusive - registrants only)
+      8h (Exclusive access - registrants only)
+      7h (Write exclusive - All registrants)
+      8h (Exclusive access - All registrants).
+.br
+.I paramp
+.B PROUT command parameter data. The paramp is a struct which describes PROUT parameter list. Caller should manage the memory allocation of this structure.
+.br
+.I noisy
+.B Turn on debugging trace: Input argument. 0->Disable, 1->Enable.
+.br
+.I verbose
+.B Set verbosity level. Input argument. value: 0 to 3. 0->Crits and Errors, 1->Warnings, 2->Info, 3->Debug
+
+.SH "RETURNS"
+.I MPATH_PR_SUCCESS
+.B if PR command successful else returns any one of the status mentioned below
+.br
+.I MPATH_PR_SYNTAX_ERROR        
+.B if  syntax error or invalid parameter
+.br
+.I MPATH_PR_SENSE_NOT_READY     
+.B  if command fails with [sk,asc,ascq: 0x2,*,*]
+.br
+.I MPATH_PR_SENSE_MEDIUM_ERROR
+.B  if command fails with [sk,asc,ascq: 0x3,*,*]
+.br
+.I MPATH_PR_SENSE_HARDWARE_ERROR
+.B  if command fails with [sk,asc,ascq: 0x4,*,*]
+.br
+.I MPATH_PR_SENSE_INVALID_OP
+.B  if command fails with [sk,asc,ascq: 0x5,0x20,0x0]
+.br
+.I MPATH_PR_ILLEGAL_REQ
+.B  if command fails with [sk,asc,ascq: 0x5,*,*]
+.br
+.I MPATH_PR_SENSE_UNIT_ATTENTION
+.B  if command fails with [sk,asc,ascq: 0x6,*,*]
+.br
+.I MPATH_PR_SENSE_ABORTED_COMMAND
+.B  if command fails with [sk,asc,ascq: 0xb,*,*]
+.br
+.I MPATH_PR_NO_SENSE
+.B  if command fails with [sk,asc,ascq: 0x0,*,*]
+.br
+.I MPATH_PR_SENSE_MALFORMED  
+.B if command fails with SCSI command malformed
+.br
+.I MPATH_PR_RESERV_CONFLICT
+.B if command fails with reservation conflict
+.br
+.I MPATH_PR_FILE_ERROR
+.B if command fails while accessing file (device node) problems(e.g. not found)
+.br
+.I MPATH_PR_DMMP_ERROR
+.B if Device Mapper related error.(e.g Error in getting dm info) 
+.br
+.I MPATH_PR_OTHER
+.B if other error/warning has occurred(e.g transport or driver error)
+.br
+
+
+.SH "SEE ALSO"
+.I  mpath_persistent_reserve_in		mpathpersist     /usr/share/doc/mpathpersist/README
+.br
diff -uprN multipath-tools-orig/libmpathpersist/mpath_persist.h multipath-tools/libmpathpersist/mpath_persist.h
--- multipath-tools-orig/libmpathpersist/mpath_persist.h	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/libmpathpersist/mpath_persist.h	2011-12-20 00:15:04.000000000 +0530
@@ -0,0 +1,241 @@
+/* version - 1.0 */
+
+#ifndef MPATH_PERSIST_LIB_H
+#define MPATH_PERSIST_LIB_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+#define MPATH_MAX_PARAM_LEN	8192
+
+#define MPATH_MX_TIDS 		32	  /* Max number of transport ids"*/
+#define MPATH_MX_TID_LEN	256	  /* Max lenght of transport id */
+
+/* PRIN Service Actions */
+#define MPATH_PRIN_RKEY_SA	0x00	   /* READ KEYS SA*/
+#define MPATH_PRIN_RRES_SA	0x01	   /* READ RESERVATION  SA*/
+#define MPATH_PRIN_RCAP_SA	0x02	   /* REPORT CAPABILITIES SA*/
+#define MPATH_PRIN_RFSTAT_SA	0x03	   /* READ FULL STATUS SA*/
+
+/* PROUT Service Actions */
+#define MPATH_PROUT_REG_SA	0x00	    /* REGISTER SA */
+#define MPATH_PROUT_RES_SA	0x01	    /* RESERVE SA*/
+#define MPATH_PROUT_REL_SA	0x02	    /* RELEASE SA*/
+#define MPATH_PROUT_CLEAR_SA	0x03	    /* CLEAR SA*/
+#define MPATH_PROUT_PREE_SA	0x04	    /* PREEMPT SA*/
+#define MPATH_PROUT_PREE_AB_SA	0x05	    /* PREEMPT AND ABORT SA*/
+#define MPATH_PROUT_REG_IGN_SA	0x06	    /* REGISTER AND IGNORE EXISTING KEY SA*/
+#define MPATH_PROUT_REG_MOV_SA	0x07	    /* REGISTER AND MOVE SA*/
+
+#define MPATH_LU_SCOPE		0x00	    /* LU_SCOPE */
+
+/* Persistent reservations type */
+#define MPATH_PRTPE_WE	 	0x01	    /* Write Exclusive */
+#define MPATH_PRTPE_EA 		0x03	    /* Exclusive Access*/
+#define MPATH_PRTPE_WE_RO 	0x05	    /* WriteExclusive Registrants Only */
+#define MPATH_PRTPE_EA_RO 	0x06	    /* Exclusive Access. Registrants Only*/
+#define MPATH_PRTPE_WE_AR	0x07	    /* Write Exclusive. All Registrants*/
+#define MPATH_PRTPE_EA_AR 	0x08	    /* Exclusive Access. All Registrants */
+
+
+/* PR RETURN_STATUS */
+#define MPATH_PR_SUCCESS 		0
+#define MPATH_PR_SYNTAX_ERROR		1   /*  syntax error or invalid parameter */
+					    /* status for check condition */
+#define MPATH_PR_SENSE_NOT_READY 	2   /*	[sk,asc,ascq: 0x2,*,*] */
+#define MPATH_PR_SENSE_MEDIUM_ERROR	3   /*	[sk,asc,ascq: 0x3,*,*] */
+#define MPATH_PR_SENSE_HARDWARE_ERROR	4   /*	[sk,asc,ascq: 0x4,*,*] */
+#define MPATH_PR_ILLEGAL_REQ 		5   /*	[sk,asc,ascq: 0x5,*,*]*/
+#define MPATH_PR_SENSE_UNIT_ATTENTION	6   /*	[sk,asc,ascq: 0x6,*,*] */
+#define MPATH_PR_SENSE_INVALID_OP	7   /* 	[sk,asc,ascq: 0x5,0x20,0x0]*/
+#define MPATH_PR_SENSE_ABORTED_COMMAND  8   /*  [sk,asc,ascq: 0xb,*,*] */
+#define MPATH_PR_NO_SENSE		9   /*	[sk,asc,ascq: 0x0,*,*] */
+
+#define MPATH_PR_SENSE_MALFORMED	10  /* Response to SCSI command malformed */
+#define MPATH_PR_RESERV_CONFLICT	11  /* Reservation conflict on the device */
+#define MPATH_PR_FILE_ERROR		12  /* file (device node) problems(e.g. not found)*/
+#define MPATH_PR_DMMP_ERROR		13  /* DMMP related error.(e.g Error in getting dm info */
+#define MPATH_PR_OTHER			14  /*other error/warning has occurred(transport
+					      or driver error) */
+
+/* PR MASK */
+#define MPATH_F_APTPL_MASK		0x01	/* APTPL MASK*/
+#define MPATH_F_ALL_TG_PT_MASK		0x04	/* ALL_TG_PT MASK*/
+#define MPATH_F_SPEC_I_PT_MASK		0x08	/* SPEC_I_PT MASK*/
+#define MPATH_PR_TYPE_MASK 		0x0f	/* TYPE MASK*/
+#define MPATH_PR_SCOPE_MASK		0xf0	/* SCOPE MASK*/
+
+/*Transport ID PROTOCOL IDENTIFIER values */
+#define MPATH_PROTOCOL_ID_FC		0x00
+#define MPATH_PROTOCOL_ID_ISCSI		0x05
+#define MPATH_PROTOCOL_ID_SAS		0x06
+
+
+/*Transport ID FORMATE CODE */
+#define MPATH_WWUI_DEVICE_NAME		0x00	/* World wide unique initiator device name */
+#define MPATH_WWUI_PORT_IDENTIFIER	0x40	/* World wide unique initiator port identifier	*/
+
+
+
+
+struct prin_readdescr
+{
+	uint32_t prgeneration;
+	uint32_t additional_length;	/* The value should be either 0 or divisible by 8.
+					   0 indicates no registered reservation key. */
+	uint8_t	 key_list[MPATH_MAX_PARAM_LEN];
+};
+
+struct prin_resvdescr
+{
+	uint32_t prgeneration;
+	uint32_t additional_length;	/* The value should be either 0 or 10h. 0 indicates
+					   there is no reservation held. 10h indicates the
+					   key[8] and scope_type have valid values */
+	uint8_t  key[8];
+	uint32_t _obsolete;
+	uint8_t  _reserved;
+	uint8_t  scope_type;            /* Use PR SCOPE AND TYPE MASK specified above */
+	uint16_t _obsolete1;
+};
+
+struct prin_capdescr
+{
+	uint16_t length;
+	uint8_t  flags[2];
+	uint16_t pr_type_mask;
+	uint16_t _reserved;
+};
+
+struct transportid
+{
+	uint8_t format_code;
+	uint8_t protocol_id;
+	union {
+		uint8_t n_port_name[8];	/* FC transport*/
+		uint8_t sas_address[8];	/* SAS transport */
+		uint8_t iscsi_name[256]; /* ISCSI  transport */
+	};
+};
+
+struct prin_fulldescr
+{
+	uint8_t key[8];
+	uint8_t flag; 			/* All_tg_pt and reservation holder */
+	uint8_t scope_type;		/* Use PR SCOPE AND TYPE MASK specified above.
+					   Meaningful only for reservation holder */
+	uint16_t rtpi;
+	struct transportid trnptid;
+};
+
+struct print_fulldescr_list
+{
+	uint32_t prgeneration;
+	uint32_t number_of_descriptor;
+	uint8_t private_buffer[MPATH_MAX_PARAM_LEN]; /*Private buffer for list storage*/
+	struct prin_fulldescr *descriptors[];
+};
+
+struct prin_resp
+{
+	union
+	{
+		struct prin_readdescr prin_readkeys; /* for PRIN read keys SA*/
+		struct prin_resvdescr prin_readresv; /* for PRIN read reservation SA*/
+		struct prin_capdescr  prin_readcap;  /* for PRIN Report Capabilities SA*/
+		struct print_fulldescr_list prin_readfd;   /* for PRIN read full status SA*/
+	}prin_descriptor;
+};
+
+struct prout_param_descriptor { 	/* PROUT parameter descriptor */
+	uint8_t	 key[8];
+	uint8_t	 sa_key[8];
+	uint32_t _obsolete;
+	uint8_t	 sa_flags;
+	uint8_t _reserved;
+	uint16_t _obsolete1;
+	uint8_t  private_buffer[MPATH_MAX_PARAM_LEN]; /*private buffer for list storage*/
+	uint32_t num_transportid;	/* Number of Transport ID listed in trnptid_list[]*/
+	struct transportid *trnptid_list[];
+};
+
+
+/* Function declarations */
+
+/*
+ * DESCRIPTION :
+ *	Initialize device mapper multipath configuration. This function must be invoked first
+ *	before performing reservation management functions.
+ * RESTRICTIONS:
+ *
+ * RETURNS: 0->Success, 1->Failed.
+ */
+extern int mpath_lib_init (void );
+
+
+/*
+ * DESCRIPTION :
+ *	Release device mapper multipath configuration. This function must be invoked after
+ *	performing reservation management functions.
+ * RESTRICTIONS:
+ *
+ * RETURNS: 0->Success, 1->Failed.
+ */
+extern int mpath_lib_exit (void );
+
+
+/*
+ * DESCRIPTION :
+ * This function sends PRIN command to the DM device and get the response.
+ *
+ * @fd:	The file descriptor of a multipath device. Input argument.
+ * @rq_servact: PRIN command service action. Input argument
+ * @resp: The response from PRIN service action. The resp is a struct specified below. The caller should
+ * 	manage the memory allocation of this struct
+ * @noisy: Turn on debugging trace: Input argument. 0->Disable, 1->Enable
+ * @verbose: Set verbosity level. Input argument. value:[0-3]. 0->disabled, 3->Max verbose
+ *
+ * RESTRICTIONS:
+ *
+ * RETURNS: MPATH_PR_SUCCESS if PR command successful else returns any of the PR status (specified
+ *	 above).
+ *
+ */
+extern int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp *resp,
+		int noisy, int verbose);
+
+/*
+ * DESCRIPTION :
+ * This function sends PROUT command to the DM device and get the response.
+ *
+ * @fd: The file descriptor of a multipath device. Input argument.
+ * @rq_servact: PROUT command service action. Input argument
+ * @rq_scope: Persistent reservation scope. The value should be always LU_SCOPE (0h).
+ * @rq_type: Persistent reservation type. The valid values of persistent reservation types are
+ *	5h (Write exclusive - registrants only)
+ *	8h (Exclusive access - registrants only)
+ *	7h (Write exclusive - All registrants)
+ *	8h (Exclusive access - All registrants).
+ * @paramp: PROUT command parameter data. The paramp is a struct which describes PROUT
+ * 	    parameter list. The caller should manage the memory allocation of this struct.
+ * @noisy: Turn on debugging trace: Input argument.0->Disable, 1->Enable.
+ * @verbose: Set verbosity level. Input argument. value:0 to 3. 0->disabled, 3->Max verbose
+ *
+ * RESTRICTIONS:
+ *
+ * RETURNS: MPATH_PR_SUCCESS if PR command successful else returns any of the status specified
+ *       above in RETURN_STATUS.
+ */
+extern int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope,
+		unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy,
+		int verbose);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /*MPATH_PERSIST_LIB_H*/
diff -uprN multipath-tools-orig/libmpathpersist/mpathpr.h multipath-tools/libmpathpersist/mpathpr.h
--- multipath-tools-orig/libmpathpersist/mpathpr.h	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/libmpathpersist/mpathpr.h	2011-12-20 00:15:04.000000000 +0530
@@ -0,0 +1,55 @@
+#ifndef MPATHPR_H
+#define MPATHPR_H
+
+struct prin_param {
+	char dev[FILE_NAME_SIZE];
+        int rq_servact;
+        struct prin_resp *resp;
+        int noisy;
+        int status;
+};
+
+struct prout_param {
+	char dev[FILE_NAME_SIZE];
+        int rq_servact;
+        int rq_scope;
+        unsigned int rq_type;
+        struct prout_param_descriptor  *paramp;
+        int noisy;
+        int status;
+};
+
+struct threadinfo {
+        int status;
+        pthread_t id;
+        struct prout_param param;
+};
+
+
+struct config * conf;
+
+
+int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int noisy);
+int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
+                unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
+void * _mpath_pr_update (void *arg);
+int mpath_send_prin_activePath (char * dev, int rq_servact, struct prin_resp * resp, int noisy);
+int get_mpvec (vector curmp, vector pathvec, char * refwwid);
+void * mpath_prout_pthread_fn(void *p);
+void dumpHex(const char* , int len, int no_ascii);
+
+int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
+        unsigned int rq_type,  struct prout_param_descriptor * paramp, int noisy);
+int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope,
+        unsigned int rq_type,  struct prout_param_descriptor * paramp, int noisy);
+int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
+        unsigned int rq_type,  struct prout_param_descriptor * paramp, int noisy);
+int send_prout_activePath(char * dev, int rq_servact, int rq_scope,
+        unsigned int rq_type,   struct prout_param_descriptor * paramp, int noisy);
+
+int update_prflag(char * arg1, char * arg2, int noisy);
+void * mpath_alloc_prin_response(int prin_sa);
+int update_map_pr(struct multipath *mpp);
+int devt2devname (char *devname, int devname_len, char *devt);
+
+#endif  
diff -uprN multipath-tools-orig/libmpathpersist/mpath_pr_ioctl.c multipath-tools/libmpathpersist/mpath_pr_ioctl.c
--- multipath-tools-orig/libmpathpersist/mpath_pr_ioctl.c	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/libmpathpersist/mpath_pr_ioctl.c	2011-12-20 00:15:04.000000000 +0530
@@ -0,0 +1,572 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <scsi/sg.h>
+#include <scsi/scsi.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include "mpath_pr_ioctl.h" 
+#include <mpath_persist.h> 
+
+#include <debug.h>
+
+#define FILE_NAME_SIZE          256
+
+#define TIMEOUT 2000
+#define MAXRETRY 5
+
+int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp *resp, int noisy);
+void mpath_format_readkeys(struct prin_resp *pr_buff, int len , int noisy);
+void mpath_format_readfullstatus(struct prin_resp *pr_buff, int len, int noisy);
+int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr, SenseData_t Sensedata, int noisy);
+void dumpHex(const char* str, int len, int no_ascii);
+int prout_do_scsi_ioctl( char * dev, int rq_servact, int rq_scope,
+                unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy);
+uint32_t  format_transportids(struct prout_param_descriptor *paramp);
+void mpath_reverse_uint32_byteorder(uint32_t *num);
+void mpath_reverse_uint16_byteorder(uint16_t *num);
+void decode_transport_id(struct prin_fulldescr *fdesc, unsigned char * p, int length);
+int get_prin_length(int rq_servact);
+int mpath_isLittleEndian(void);
+
+
+int prout_do_scsi_ioctl(char * dev, int rq_servact, int rq_scope,
+                unsigned int rq_type, struct prout_param_descriptor *paramp, int noisy)
+{
+
+	int status, paramlen = 24, ret = 0;
+	uint32_t translen=0;
+	int retry = MAXRETRY;
+	SenseData_t Sensedata;
+	struct sg_io_hdr io_hdr;
+	char devname[FILE_NAME_SIZE];
+	int fd = -1;
+
+	snprintf(devname, FILE_NAME_SIZE, "/dev/%s",dev);
+	fd = open(devname, O_WRONLY);
+	if(fd < 0){
+		condlog (1, "%s: unable to open device.", dev);
+		return MPATH_PR_FILE_ERROR;
+	}
+
+	unsigned char cdb[MPATH_PROUT_CMDLEN] =
+	{MPATH_PROUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+
+	if (paramp->sa_flags & MPATH_F_SPEC_I_PT_MASK)
+	{
+		translen = format_transportids(paramp);
+		paramlen = 24 + translen;
+	}	
+	else
+		paramlen = 24;
+
+	condlog(3, "%s: parameter length =%d", dev, paramlen);
+	if ( rq_servact > 0)
+		cdb[1] = (unsigned char)(rq_servact & 0x1f);
+	cdb[2] = (((rq_scope & 0xf) << 4) | (rq_type & 0xf));
+	cdb[7] = (unsigned char)((paramlen >> 8) & 0xff);
+	cdb[8] = (unsigned char)(paramlen & 0xff);
+
+retry :
+	condlog(3, "%s: rq_servact = %d", dev, rq_servact); 
+	condlog(3, "%s: rq_scope = %d ", dev, rq_scope);
+	condlog(3, "%s: rq_type = %d ", dev, rq_type);
+	condlog(3, "%s: paramlen = %d", dev, paramlen);
+
+	if (noisy)
+	{
+		condlog(3, "%s: Persistent Reservation OUT parameter:", dev);
+		dumpHex((const char *)paramp, paramlen,1);
+	}
+
+	memset(&Sensedata, 0, sizeof(SenseData_t));
+	memset(&io_hdr,0 , sizeof( struct sg_io_hdr));
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = MPATH_PROUT_CMDLEN;
+	io_hdr.cmdp = cdb;
+	io_hdr.sbp = (void *)&Sensedata;
+	io_hdr.mx_sb_len = sizeof (SenseData_t);
+	io_hdr.timeout = TIMEOUT;
+
+	if (paramlen > 0) {
+		io_hdr.dxferp = (void *)paramp;
+		io_hdr.dxfer_len = paramlen;
+		io_hdr.dxfer_direction = SG_DXFER_TO_DEV ;
+	}
+	else {
+		io_hdr.dxfer_direction = SG_DXFER_NONE;
+	}
+	ret = ioctl(fd, SG_IO, &io_hdr);
+	if (ret < 0)
+	{
+		condlog(0, "%s: ioctl failed %d", dev, ret);
+		close(fd);
+		return ret;
+	}
+
+	condlog(2, "%s: Duration=%u (ms)", dev, io_hdr.duration);
+
+	status = mpath_translate_response(dev, io_hdr, Sensedata, noisy);
+	condlog(3, "%s: status = %d", dev, status);
+
+	if (status == MPATH_PR_SENSE_UNIT_ATTENTION && (retry > 0))
+	{
+		--retry;
+		condlog(2, "%s: retrying for Unit Attention. Remaining retries = %d", 
+			dev, retry);
+		goto retry;
+	}
+
+	if (((status == MPATH_PR_SENSE_NOT_READY )&& (Sensedata.ASC == 0x04)&&
+				(Sensedata.ASCQ == 0x07))&& (retry > 0))
+	{
+		usleep(1000);
+		--retry;
+		condlog(2, "%s: retrying for sense 02/04/07."
+			" Remaining retries = %d", dev, retry);
+		goto retry;
+	}
+
+	close(fd);	
+	return status;
+}
+
+uint32_t  format_transportids(struct prout_param_descriptor *paramp)
+{
+	int i = 0, len;	
+	uint32_t buff_offset = 4;
+	memset(paramp->private_buffer, 0, MPATH_MAX_PARAM_LEN);
+	for (i=0; i < paramp->num_transportid; i++ )
+	{
+		paramp->private_buffer[buff_offset] = (uint8_t)((paramp->trnptid_list[i]->format_code & 0xff)|
+							(paramp->trnptid_list[i]->protocol_id & 0xff));
+		buff_offset += 1;
+		switch(paramp->trnptid_list[i]->protocol_id)
+		{
+			case MPATH_PROTOCOL_ID_FC:
+				buff_offset += 7;
+				memcpy(&paramp->private_buffer[buff_offset], &paramp->trnptid_list[i]->n_port_name, 8);
+				buff_offset +=8 ;
+				buff_offset +=8 ;
+				break;
+			case MPATH_PROTOCOL_ID_SAS:
+				buff_offset += 3;
+				memcpy(&paramp->private_buffer[buff_offset], &paramp->trnptid_list[i]->sas_address, 8);
+				buff_offset += 12;
+				break;
+			case MPATH_PROTOCOL_ID_ISCSI:
+				buff_offset += 1;
+				len = (paramp->trnptid_list[i]->iscsi_name[1] & 0xff)+2;	
+				memcpy(&paramp->private_buffer[buff_offset], &paramp->trnptid_list[i]->iscsi_name,len);
+				buff_offset += len ; 
+				break;
+		}
+
+	}
+	buff_offset -= 4; 
+	paramp->private_buffer[0] = (unsigned char)((buff_offset >> 24) & 0xff);
+	paramp->private_buffer[1] = (unsigned char)((buff_offset >> 16) & 0xff);
+	paramp->private_buffer[2] = (unsigned char)((buff_offset >> 8) & 0xff);
+	paramp->private_buffer[3] = (unsigned char)(buff_offset & 0xff);
+	buff_offset += 4; 
+	return buff_offset;	
+}
+
+void mpath_format_readkeys( struct prin_resp *pr_buff, int len, int noisy)
+{
+        mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.prgeneration);
+        mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.additional_length);
+}
+
+void mpath_format_readresv(struct prin_resp *pr_buff, int len, int noisy)
+{
+
+        mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.prgeneration);
+        mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readkeys.additional_length);
+
+        return;
+}
+
+void mpath_format_reportcapabilities(struct prin_resp *pr_buff, int len, int noisy)
+{
+        mpath_reverse_uint16_byteorder(&pr_buff->prin_descriptor.prin_readcap.length);
+        mpath_reverse_uint16_byteorder(&pr_buff->prin_descriptor.prin_readcap.pr_type_mask);
+
+        return;
+}
+
+void mpath_format_readfullstatus(struct prin_resp *pr_buff, int len, int noisy)
+{
+	int num, k, tid_len_len=0;
+	uint32_t fdesc_count=0;
+	unsigned char *p;
+	char  *ppbuff;
+	uint32_t additional_length;
+
+
+	mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readfd.prgeneration);
+	mpath_reverse_uint32_byteorder(&pr_buff->prin_descriptor.prin_readfd.number_of_descriptor);
+
+	if (0 == pr_buff->prin_descriptor.prin_readfd.number_of_descriptor)
+	{
+		return ;
+	}
+
+
+	if (pr_buff->prin_descriptor.prin_readfd.number_of_descriptor == 0)
+	{
+		condlog(2, "No registration or resrvation found.");
+		return;
+	}
+
+	additional_length = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;
+
+	char tempbuff[MPATH_MAX_PARAM_LEN];
+	struct prin_fulldescr fdesc;
+	memset(&fdesc, 0, sizeof(struct prin_fulldescr));
+
+	memcpy( tempbuff, pr_buff->prin_descriptor.prin_readfd.private_buffer,MPATH_MAX_PARAM_LEN );
+	memset(&pr_buff->prin_descriptor.prin_readfd.private_buffer, 0, MPATH_MAX_PARAM_LEN);
+
+	p =(unsigned char *)tempbuff;
+	ppbuff = (char *)pr_buff->prin_descriptor.prin_readfd.private_buffer;
+
+	for (k = 0; k < additional_length; k += num, p += num) {
+		memcpy(&fdesc.key, p, 8 );
+		fdesc.flag = p[12];
+		fdesc.scope_type =  p[13];
+		fdesc.rtpi = ((p[18] << 8) | p[19]);
+
+		tid_len_len = ((p[20] << 24) | (p[21] << 16) |
+				(p[22] << 8) | p[23]);
+
+		if (tid_len_len > 0)
+			decode_transport_id( &fdesc, &p[24], tid_len_len);
+
+		num = 24 + tid_len_len;
+		memcpy(ppbuff, &fdesc, sizeof(struct prin_fulldescr));
+		pr_buff->prin_descriptor.prin_readfd.descriptors[fdesc_count]= (struct prin_fulldescr *)ppbuff;
+		ppbuff += sizeof(struct prin_fulldescr);
+		++fdesc_count;
+	}
+
+	pr_buff->prin_descriptor.prin_readfd.number_of_descriptor = fdesc_count;
+
+	return;
+}
+
+void
+decode_transport_id(struct prin_fulldescr *fdesc, unsigned char * p, int length)
+{
+	int num, k;
+	int jump;
+	for (k = 0, jump = 24; k < length; k += jump, p += jump) {
+		fdesc->trnptid.format_code = ((p[0] >> 6) & 0x3);
+		fdesc->trnptid.protocol_id = (p[0] & 0xf);
+		switch (fdesc->trnptid.protocol_id) {
+			case MPATH_PROTOCOL_ID_FC:
+				memcpy(&fdesc->trnptid.n_port_name, &p[8], 8);
+				jump = 24;
+				break;
+			case MPATH_PROTOCOL_ID_ISCSI:
+				num = ((p[2] << 8) | p[3]);
+				memcpy(&fdesc->trnptid.iscsi_name, &p[4], num);
+				jump = (((num + 4) < 24) ? 24 : num + 4);
+				break;
+			case MPATH_PROTOCOL_ID_SAS:
+				memcpy(&fdesc->trnptid.sas_address, &p[4], 8);
+				jump = 24;
+				break;
+			default:
+				jump = 24;
+				break;
+		}
+	}
+}
+
+int prin_do_scsi_ioctl(char * dev, int rq_servact, struct prin_resp * resp, int noisy)
+{
+
+	int ret, status, got, fd;
+	int mx_resp_len;
+	SenseData_t Sensedata;
+	int retry = MAXRETRY;
+	struct sg_io_hdr io_hdr;
+	char devname[FILE_NAME_SIZE];
+	unsigned char cdb[MPATH_PRIN_CMDLEN] =
+	{MPATH_PRIN_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+	snprintf(devname, FILE_NAME_SIZE, "/dev/%s",dev);
+        fd = open(devname, O_WRONLY);
+        if(fd < 0){
+        	condlog(0, "%s: Unable to open device ", dev);
+		return MPATH_PR_FILE_ERROR;
+         }
+
+	mx_resp_len =  sizeof(struct prin_readdescr);
+	cdb[1] = (unsigned char)(rq_servact & 0x1f);
+	cdb[7] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+	cdb[8] = (unsigned char)(mx_resp_len & 0xff);
+
+retry :
+	memset(&Sensedata, 0, sizeof(SenseData_t));
+	memset(&io_hdr,0 , sizeof( struct sg_io_hdr));
+
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = MPATH_PRIN_CMDLEN;
+	io_hdr.mx_sb_len = sizeof (SenseData_t);
+	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+	io_hdr.cmdp = cdb;
+	io_hdr.sbp = (void *)&Sensedata;
+	io_hdr.timeout = TIMEOUT;
+
+	mx_resp_len = get_prin_length(rq_servact);
+
+
+	io_hdr.dxfer_len = mx_resp_len;
+	io_hdr.dxferp = (void *)resp;
+
+	ret =ioctl(fd, SG_IO, &io_hdr);
+	if (ret < 0){
+		condlog(0, "%s: IOCTL failed %d", dev, ret);
+		status = MPATH_PR_OTHER;
+		goto out;
+	}
+
+	got = mx_resp_len - io_hdr.resid;
+
+	condlog(2, "%s: duration = %u (ms)", dev, io_hdr.duration);
+
+	status = mpath_translate_response(dev, io_hdr, Sensedata, noisy);
+
+	if (status == MPATH_PR_SENSE_UNIT_ATTENTION && (retry > 0))
+	{
+		--retry;
+		condlog(2, "%s: retrying for Unit Attention. Remaining retries = %d", dev, retry);
+		goto retry;
+	}
+
+	if (((status == MPATH_PR_SENSE_NOT_READY )&& (Sensedata.ASC == 0x04)&&
+				(Sensedata.ASCQ == 0x07))&& (retry > 0))
+	{
+		usleep(1000);
+		--retry;
+		condlog(2, "%s: retrying for 02/04/07. Remaining retries = %d", dev, retry);
+		goto retry;
+	}
+
+	if (status != MPATH_PR_SUCCESS)
+		goto out;
+
+	if (noisy)
+		dumpHex((const char *)resp, got , 1);
+
+
+	switch (rq_servact)
+	{
+		case MPATH_PRIN_RKEY_SA :
+			mpath_format_readkeys(resp, got, noisy);
+			break;
+		case MPATH_PRIN_RRES_SA :
+			mpath_format_readresv(resp, got, noisy);
+			break;
+		case MPATH_PRIN_RCAP_SA :
+			mpath_format_reportcapabilities(resp, got, noisy);
+			break;
+		case MPATH_PRIN_RFSTAT_SA :
+			mpath_format_readfullstatus(resp, got, noisy);
+	}
+
+out:
+	close(fd);
+	return status;
+}
+
+int mpath_translate_response (char * dev, struct sg_io_hdr io_hdr, SenseData_t Sensedata, int noisy)
+{
+	condlog(3, "%s: status driver:%02x host:%02x scsi:%02x", dev, 
+			io_hdr.driver_status, io_hdr.host_status ,io_hdr.status);
+	io_hdr.status &= 0x7e;
+	if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
+			(0 == io_hdr.driver_status))
+	{
+		return MPATH_PR_SUCCESS;
+	}
+
+	switch(io_hdr.status)
+	{
+		case SAM_STAT_GOOD:
+			break;
+		case SAM_STAT_CHECK_CONDITION:
+			condlog(2, "%s: Sense_Key=%02x, ASC=%02x ASCQ=%02x", dev,
+					Sensedata.Sense_Key, Sensedata.ASC, Sensedata.ASCQ);
+			switch(Sensedata.Sense_Key)
+			{
+				case NO_SENSE:
+					return MPATH_PR_NO_SENSE;
+				case RECOVERED_ERROR:
+					return MPATH_PR_SUCCESS;
+				case NOT_READY:
+					return MPATH_PR_SENSE_NOT_READY;
+				case MEDIUM_ERROR:
+					return MPATH_PR_SENSE_MEDIUM_ERROR;
+				case BLANK_CHECK:
+					return MPATH_PR_OTHER;
+				case HARDWARE_ERROR:
+					return MPATH_PR_SENSE_HARDWARE_ERROR;
+				case ILLEGAL_REQUEST:
+					return MPATH_PR_ILLEGAL_REQ;
+				case UNIT_ATTENTION:
+					return MPATH_PR_SENSE_UNIT_ATTENTION;
+				case DATA_PROTECT:
+				case COPY_ABORTED:
+					return MPATH_PR_OTHER;
+				case ABORTED_COMMAND:
+					return MPATH_PR_SENSE_ABORTED_COMMAND;
+
+				default :
+					return MPATH_PR_OTHER;
+			}
+		case SAM_STAT_RESERVATION_CONFLICT:
+			return MPATH_PR_RESERV_CONFLICT;
+
+		default :
+			return  MPATH_PR_OTHER;
+	}
+
+	switch(io_hdr.host_status)
+	{
+		case DID_OK :
+			break;
+		default :
+			return MPATH_PR_OTHER;
+	}
+	switch(io_hdr.driver_status)
+	{
+		case DRIVER_OK:
+			break;
+		default :
+			return MPATH_PR_OTHER;
+	}
+	return MPATH_PR_SUCCESS;
+}
+
+int mpath_isLittleEndian()
+{
+	int num = 1;
+	if(*(char *)&num == 1)
+	{
+		condlog(2, "Little-Endian");
+	}
+	else
+	{
+		condlog(2, "Big-Endian");
+	}
+	return 0;
+}
+
+void mpath_reverse_uint16_byteorder(uint16_t *num)
+{
+	uint16_t byte0, byte1;
+
+	byte0 = (*num & 0x000000FF) >>  0 ;
+	byte1 = (*num & 0x0000FF00) >>  8 ;
+
+	*num = ((byte0 << 8) | (byte1 << 0));
+}
+
+void mpath_reverse_uint32_byteorder(uint32_t *num)
+{
+	uint32_t byte0, byte1, byte2, byte3;
+
+	byte0 = (*num & 0x000000FF) >>  0 ;
+	byte1 = (*num & 0x0000FF00) >>  8 ;
+	byte2 = (*num & 0x00FF0000) >> 16 ;
+	byte3 = (*num & 0xFF000000) >> 24 ;
+
+	*num = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | (byte3 << 0));
+}
+
+void mpath_reverse_8bytes_order(char * var)
+{
+	char byte[8];
+
+	int i;
+	for(i=0 ; i < 8 ; i++ )
+	{
+		byte[i] = var[i];
+	}
+	for(i=0 ; i < 8 ; i++ )
+	{
+		var[7 - i] = byte[i];
+	}
+}
+
+void
+dumpHex(const char* str, int len, int log)
+{
+	const char * p = str;
+	const char * formatstr;
+	unsigned char c;
+	char buff[82];
+	const int bpstart = 5;
+	int bpos = bpstart;
+	int  k;
+
+	if (len <= 0)
+		return;
+	formatstr = (0 == log) ? "%.76s\n" : "%.56s\n";
+	memset(buff, ' ', 80);
+	buff[80] = '\0';
+	for (k = 0; k < len; k++) {
+		c = *p++;
+		bpos += 3;
+		if (bpos == (bpstart + (9 * 3)))
+			bpos++;
+		sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c);
+		buff[bpos + 2] = ' ';
+		if ((k > 0) && (0 == ((k + 1) % 16))) {
+			if (log)
+				condlog(0, "%.76s" , buff);
+			else
+				printf("%.76s" , buff);
+			bpos = bpstart;
+			memset(buff, ' ', 80);
+		}
+	}
+	if (bpos > bpstart) {
+		buff[bpos + 2] = '\0';
+		if (log)
+			condlog(0, "%s", buff);
+		else
+			printf("%s\n" , buff);
+	}
+	return;
+}
+
+int get_prin_length(int rq_servact)
+{
+        int mx_resp_len;
+        switch (rq_servact)
+        {
+                case MPATH_PRIN_RKEY_SA:
+                        mx_resp_len =  sizeof(struct prin_readdescr);
+                        break;
+                case MPATH_PRIN_RRES_SA :
+                        mx_resp_len =  sizeof(struct prin_resvdescr);
+                        break;
+                case MPATH_PRIN_RCAP_SA :
+                        mx_resp_len = sizeof(struct prin_capdescr);
+                        break;
+                case MPATH_PRIN_RFSTAT_SA:
+                        mx_resp_len = sizeof(struct print_fulldescr_list) + sizeof(struct prin_fulldescr *)*32;
+                        break;
+        }
+        return mx_resp_len;
+}
diff -uprN multipath-tools-orig/libmpathpersist/mpath_pr_ioctl.h multipath-tools/libmpathpersist/mpath_pr_ioctl.h
--- multipath-tools-orig/libmpathpersist/mpath_pr_ioctl.h	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/libmpathpersist/mpath_pr_ioctl.h	2011-12-20 00:15:04.000000000 +0530
@@ -0,0 +1,111 @@
+#define MPATH_XFER_HOST_DEV              0   /*data transfer from initiator to target */
+#define MPATH_XFER_DEV_HOST              1   /*data transfer from target to initiator */
+#define MPATH_XFER_NONE                  2   /*no data transfer */
+#define MPATH_XFER_UNKNOWN               3   /*data transfer direction is unknown */
+
+#if 0
+static const char * pr_type_strs[] = {
+    "obsolete [0]",
+    "Write Exclusive",
+    "obsolete [2]",
+    "Exclusive Access",
+    "obsolete [4]",
+    "Write Exclusive, registrants only",
+    "Exclusive Access, registrants only",
+    "Write Exclusive, all registrants",
+    "Exclusive Access, all registrants",
+    "obsolete [9]", "obsolete [0xa]", "obsolete [0xb]", "obsolete [0xc]",
+    "obsolete [0xd]", "obsolete [0xe]", "obsolete [0xf]",
+};
+#endif
+
+typedef unsigned int     LWORD;     /* unsigned numeric, bit patterns */
+typedef unsigned char    BYTE;      /* unsigned numeric, bit patterns */
+
+typedef struct SenseData
+{
+    BYTE        Error_Code;
+    BYTE        Segment_Number; /* not applicable to DAC */
+    BYTE        Sense_Key;
+    BYTE        Information[ 4 ];
+    BYTE        Additional_Len;
+    LWORD       Command_Specific_Info;
+    BYTE        ASC;
+    BYTE        ASCQ;
+    BYTE        Field_Replaceable_Unit;
+    BYTE        Sense_Key_Specific_Info[ 3 ];
+    BYTE        Recovery_Action[ 2 ];
+    BYTE        Total_Errors;
+    BYTE        Total_Retries;
+    BYTE        ASC_Stack_1;
+    BYTE        ASCQ_Stack_1;
+    BYTE        ASC_Stack_2;
+    BYTE        ASCQ_Stack_2;
+    BYTE        Additional_FRU_Info[ 8 ];
+    BYTE        Error_Specific_Info[ 3 ];
+    BYTE        Error_Detection_Point[ 4 ];
+    BYTE        Original_CDB[10];
+    BYTE        Host_ID;
+    BYTE        Host_Descriptor[ 2 ];
+    BYTE        Serial_Number[ 16 ];
+    BYTE        Array_SW_Revision[ 4 ];
+    BYTE        Data_Xfer_Operation;
+    BYTE        LUN_Number;
+    BYTE        LUN_Status;
+    BYTE        Drive_ID;
+    BYTE        Xfer_Start_Drive_ID;
+    BYTE        Drive_SW_Revision[ 4 ];
+    BYTE        Drive_Product_ID[ 16 ];
+    BYTE        PowerUp_Status[ 2 ];
+    BYTE        RAID_Level;
+    BYTE        Drive_Sense_ID[ 2 ];
+    BYTE        Drive_Sense_Data[ 32 ];
+    BYTE        Reserved2[24];
+} SenseData_t;
+
+#define MPATH_PRIN_CMD 0x5e
+#define MPATH_PRIN_CMDLEN 10
+#define MPATH_PROUT_CMD 0x5f
+#define MPATH_PROUT_CMDLEN 10
+
+#define  DID_OK	0x00
+/*
+ *  Status codes
+ */
+#define SAM_STAT_GOOD            0x00
+#define SAM_STAT_CHECK_CONDITION 0x02
+#define SAM_STAT_CONDITION_MET   0x04
+#define SAM_STAT_BUSY            0x08
+#define SAM_STAT_INTERMEDIATE    0x10
+#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14
+#define SAM_STAT_RESERVATION_CONFLICT 0x18
+#define SAM_STAT_COMMAND_TERMINATED 0x22        /* obsolete in SAM-3 */
+#define SAM_STAT_TASK_SET_FULL   0x28
+#define SAM_STAT_ACA_ACTIVE      0x30
+#define SAM_STAT_TASK_ABORTED    0x40
+
+#define STATUS_MASK          0x3e
+
+/*
+ *  SENSE KEYS
+ */
+
+#define NO_SENSE            0x00
+#define RECOVERED_ERROR     0x01
+#define NOT_READY           0x02
+#define MEDIUM_ERROR        0x03
+#define HARDWARE_ERROR      0x04
+#define ILLEGAL_REQUEST     0x05
+#define UNIT_ATTENTION      0x06
+#define DATA_PROTECT        0x07
+#define BLANK_CHECK         0x08
+#define COPY_ABORTED        0x0a
+#define ABORTED_COMMAND     0x0b
+#define VOLUME_OVERFLOW     0x0d
+#define MISCOMPARE          0x0e
+
+
+/* Driver status */
+#define DRIVER_OK 0x00
+
+
diff -uprN multipath-tools-orig/libmpathpersist/mpath_updatepr.c multipath-tools/libmpathpersist/mpath_updatepr.c
--- multipath-tools-orig/libmpathpersist/mpath_updatepr.c	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/libmpathpersist/mpath_updatepr.c	2011-12-20 00:15:04.000000000 +0530
@@ -0,0 +1,50 @@
+#include<stdio.h>
+#include<unistd.h>
+#include <errno.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <debug.h>
+#include "memory.h"
+#include "../libmultipath/uxsock.h"
+
+unsigned long mem_allocated;    /* Total memory used in Bytes */
+
+int update_prflag(char * arg1, char * arg2, int noisy)
+{
+	int fd;
+	char str[64];
+	char *reply;
+	size_t len;
+	int ret = 0;
+
+	fd = ux_socket_connect("/var/run/multipathd.sock");
+	if (fd == -1) {
+		condlog (0, "ux socket connect error");
+		return 1 ;
+	}
+
+	snprintf(str,sizeof(str),"map %s %s", arg1, arg2);
+	condlog (2, "%s: pr flag message=%s", arg1, str);
+	send_packet(fd, str, strlen(str) + 1);
+	recv_packet(fd, &reply, &len);
+
+	condlog (2, "%s: message=%s reply=%s", arg1, str, reply);
+	if (!reply || strncmp(reply,"ok", 2) == 0)
+		ret = -1;
+	else if (strncmp(reply, "fail", 4) == 0)
+		ret = -2;
+	else{
+		ret = atoi(reply);
+	}
+
+	free(reply);
+	return ret;
+}
diff -uprN multipath-tools-orig/libmpathpersist/README multipath-tools/libmpathpersist/README
--- multipath-tools-orig/libmpathpersist/README	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/libmpathpersist/README	2011-12-20 00:15:04.000000000 +0530
@@ -0,0 +1,212 @@
+Updated: 06/27/2011                           
+================================================================
+
+Contents
+================================================================
+1. OS Support
+2. Installation Instructions
+   2.1 Requirements and assumptions 
+   2.2 Installation of rpms 
+   2.3 mpathpersist library and device mapper multipath tools  post-Installation
+3. mpathpersist library  usages
+4. mpath_persist Header file
+5. mpathpersist Utility
+6. Restrictions
+7. Reference 
+8. GPL License
+
+1. OS Support
+	mpathpersist library  and utility is supported on following Linux distributions:
+		RHEL5 Update 6 (x86)
+		RHEL5 Update 6 (x86_64)
+
+2. Installation Instructions:
+   2.1. Requirements and assumptions 
+	Requirements and assumptions before mpathpersist library and device mapper multipath 
+	tools package installation:
+	a. It's assumed that the host system on which mpathpersist library and device mapper 
+		multipath tool are being installed has supported configuration for device mapper multipath.    
+	b. User must have root privilege while installing rpms.
+	c. Ensure multipathd daemon is not running. multipathd daemon can be stopped with following instruction: 
+		# /etc/init.d/multipathd stop
+   2.2 Installation of rpms 
+	a. Install mpathpersist library
+		# rpm -Uvh libmpathpersist-<version>.<arch>.rpm
+	b.   Install kpartx rpm 
+		#  rpm -Uvh kpartx-<version>.<arch>.rpm
+	c. Install 
+		# rpm -Uvh device-mapper-multipath-<version>.<arch>.rpm 
+
+   2.3 mpathpersist library and device mapper multipath tools  post-Installation
+	a. Restart multipathd daemon 
+		# /etc/init.d/multipathd start
+
+3. mpathpersist library  usages
+	mpathpersist library provides four APIs for managing persistent reservation on device mapper multipath 
+	device. libmpathpersist.so is a link pointing to libmpathpersist.so.X [X is a library version].  
+	mpathpersist  Library  APIs.
+
+	a. int mpath_lib_init (void )
+	DESCRIPTION :
+	Initialize device mapper multipath configuration. This function must be	invoked first before performing 
+	reservation management functions.
+
+	RETURNS: 
+	0->Success, 1->Failed	
+	Note: mpath_lib_init function must be called at the start of the usage of PR management APIs (such as 
+	mpath_persistent_reserve_in or mpath_persistent_reserve_out). This function is responsible for initializing 
+	config table. (Any dynamic allocation done by mpath_lib_init function will be de-allocated only by mpath_lib_exit API).
+
+		
+	b.	int mpath_lib_exit (void )
+	DESCRIPTION:
+	Release device mapper multipath configuration. This function must be invoked after performing 
+	reservation management functions.
+
+	RETURNS: 
+	0->Success, 1->Failed.
+
+	Note: mpath_lib_exit function must be called at the end of the usage of PR management APIs (such as 
+	mpath_persistent_reserve_in or mpath_persistent_reserve_out). This function is responsible for freeing
+	up the dynamic allocation made by mpath_lib_init function.
+
+	c. int mpath_persistent_reserve_in (int fd, int rq_servact, struct prin_resp *resp, int noisy, int verbose)
+	DESCRIPTION:
+	The function in the mpath_persistent_reserve_in() sends PRIN command to the DM device and gets the response.
+
+	PARAMETERS:
+	fd - The file descriptor of a multipath device. Input argument.
+	rq_servact  -  PRIN command service action. Input argument
+	resp - The response from PRIN service action. The caller should manage the memory allocation of this structure
+	noisy - Turn on debugging trace: Input argument. 0->Disable, 1->Enable
+        verbose -  Set verbosity level. Input argument. value:[0-3]. 0->Crits and Errors, 1->Warnings, 2->Info, 3->Debug
+
+	RETURNS
+        MPATH_PR_SUCCESS if PR command successful
+        MPATH_PR_SYNTAX_ERROR if syntax error or invalid parameter
+        MPATH_PR_SENSE_NOT_READY if command fails with [sk,asc,ascq: 0x2,*,*]
+        MPATH_PR_SENSE_MEDIUM_ERROR if command fails with [sk,asc,ascq: 0x3,*,*]
+        MPATH_PR_SENSE_HARDWARE_ERROR if command fails with [sk,asc,ascq: 0x4,*,*]
+        MPATH_PR_SENSE_INVALID_OP if command fails with [sk,asc,ascq: 0x5,0x20,0x0]
+        MPATH_PR_ILLEGAL_REQ if command fails with [sk,asc,ascq: 0x5,*,*]
+        MPATH_PR_SENSE_UNIT_ATTENTION if command fails with [sk,asc,ascq: 0x6,*,*]
+        MPATH_PR_SENSE_ABORTED_COMMAND if command fails with [sk,asc,ascq: 0xb,*,*]
+        MPATH_PR_NO_SENSE if command fails with [sk,asc,ascq: 0x0,*,*]
+        MPATH_PR_SENSE_MALFORMED if command fails with SCSI command malformed
+        MPATH_PR_FILE_ERROR if command fails while accessing file (device node) problems(e.g. not found)
+        MPATH_PR_DMMP_ERROR if Device Mapper related error.(e.g Error in getting dm info)
+        MPATH_PR_OTHER if other error/warning has occurred(e.g transport or driver error)
+ 
+	d. int mpath_persistent_reserve_out ( int fd, int rq_servact, int rq_scope, unsigned int rq_type, 
+	   	struct rout_param_descriptor *paramp, int noisy, int verbose)
+	DESCRIPTION
+	The function in the mpath_persistent_reserve_out() sends PR OUT command to the DM device and gets the response.
+	PARAMETERS:
+	fd - The file descriptor of a multipath device. Input argument.
+	rq_servact  - PROUT command service action. Input argument
+	rq_scope - Persistent reservation scope. The value should be always LU_SCOPE (0h).
+	rq_type - Persistent reservation type. The valid values of persistent reservation types are
+             5h (Write exclusive - registrants only)
+             8h (Exclusive access - registrants only)
+             7h (Write exclusive - All registrants)
+             8h (Exclusive access - All registrants).
+	paramp - PROUT  command  parameter  data.  The paramp is a struct which describes PROUT parameter list. Caller should 
+		 manage the memory  allocation of this structure. noisy Turn on debugging trace: Input argument. 0->Disable, 1->Enable. 
+	verbose - Set verbosity level. Input argument. value: 0 to 3. 0->Crits and Errors, 1->Warnings, 2->Info, 3->Debug
+
+
+4. mpath_persist Header file
+
+	Macro definitions
+	-------------------
+	#define MPATH_MX_TIDS           32        /* Max number of transport ids*/
+	#define MPATH_MX_TID_LEN        256       /* Max lenght of transport id */
+
+	Maximum 32 transport ids can be passed as parameter for persistent reserve out command. Length of each 
+	transport id should not exceed 256 bytes. FC, ISCSI and SAS are the only supported transport protocols.
+	Transport id for the respective transport protocol (i.e n_port_name[8], sas_address[8], iscsi_name[256]) 
+	should be well formated as defined in SCSI Primary Commands . 3[T10.org]. 
+
+	struct transportid
+	{
+	        uint8_t format_code;
+	        uint8_t protocol_id;
+	        union {
+	                uint8_t n_port_name[8]; /* FC transport*/
+	                uint8_t sas_address[8]; /* SAS transport */
+        	        uint8_t iscsi_name[256]; /* ISCSI  transport */
+        	};
+	};
+
+
+	PROUT parameter descriptor:
+	struct prout_param_descriptor {        
+	        uint8_t  key[8];
+	        uint8_t  sa_key[8];
+	        uint32_t _obsolete;
+	        uint8_t  sa_flags;
+	        uint8_t _reserved;
+	        uint16_t _obsolete1;
+	        uint8_t  private_buffer[MPATH_MAX_PARAM_LEN]; /*private buffer for list storage*/
+	        uint32_t num_transportid;       /* Number of Transport ID listed in trnptid_list[]*/
+	        struct transportid *trnptid_list[];
+	};
+
+	Example: Total length of memory allocation for struct prout_param_descriptor should be calculated 
+	as following : 
+	sizeof(struct prout_param_descriptor) + (sizeof(struct transportid *)*(MPATH_MX_TIDS ))
+	[here MPATH_MX_TIDS is the max number of transport ids]
+
+
+	Note : Application using libmpathpersist needs to carefully allocate the prout parameter descriptor
+	while using transport descriptor ( if the user needs to mention transport id) as the flexible array 
+	structure memeber. 
+
+
+	Note: Number of transport ids allocated  must be also mentioned in num_transportid structure memeber.
+
+
+5. mpathpersist utility usages example:
+	PROUT Register service action: 
+	# mpathpersist --out --register --param-sark=123abc --prout-type=5 /dev/mapper/mpath9
+
+	PROUT Reserve service action
+	# mpathpersist --out --reserve --param-rk=123abc --prout-type=5	/dev/mapper/mpath9
+
+	PROUT Release service action
+	# mpathpersist --out --release --param-rk=123abc --prout-type=5 /dev/mapper/mpath9
+
+	PROUT Unregister service action
+	# mpathpersist --out --register --param-rk=123abc --prout-type=5 /dev/mapper/mpath9
+
+	PROUT clear service action
+	mpathpersist --out --clear --param-rk=123abc --prout-type=5 /dev/mapper/mpath9
+
+	PROUT Preempt and abort service action
+	# mpathpersist --out --preempt-abort --param-rk=123abc --paramsark=789def --prout-type=5 /dev/mapper/mpath9
+
+	PROUT Preempt
+	# mpathpersist --out --preempt-abort --param-rk=0 --paramsark=789def --prout-type=5 /dev/mapper/mpath9
+
+	PRIN read key
+	# mpathpersist -i -k /dev/mapper/mpath9
+
+	PRIN PRIN  read reservation
+	# mpathpersist -i -r /dev/mapper/mpath9
+
+
+6. Restrictions
+	- Physical paths should not be used for persistent management.
+	- Reservation key provided to mpathpersist utility/libmpathpersist should match with key mentioned in
+	  multipath.conf.
+	- Supported on RHEL5 Update 6. 
+	- ALL_TG_PT flag is set to 0 for PROUT command.
+
+7. Reference 
+	- man page 
+		a. mpath_persistent_reserve_in
+		b. mpath_persistent_reserve_out
+		c. mpathpersist
+	
+8. GPL License
+	mpathpersist library and utility  carry GPL License.
diff -uprN multipath-tools-orig/mpathpersist/main.c multipath-tools/mpathpersist/main.c
--- multipath-tools-orig/mpathpersist/main.c	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/mpathpersist/main.c	2011-12-20 00:27:13.000000000 +0530
@@ -0,0 +1,808 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <checkers.h>
+#include <vector.h>
+#include <structs.h>
+#include <getopt.h>
+#include <mpath_persist.h>
+#include "main.h"
+#include <pthread.h>
+#include <ctype.h>
+#include <string.h>
+
+static const char * pr_type_strs[] = {
+	"obsolete [0]",
+	"Write Exclusive",
+	"obsolete [2]",
+	"Exclusive Access",
+	"obsolete [4]",
+	"Write Exclusive, registrants only",
+	"Exclusive Access, registrants only",
+	"Write Exclusive, all registrants",
+	"Exclusive Access, all registrants",
+	"obsolete [9]", "obsolete [0xa]", "obsolete [0xb]", "obsolete [0xc]",
+	"obsolete [0xd]", "obsolete [0xe]", "obsolete [0xf]",
+};
+
+int get_transportids_length(unsigned char * transportid_arr, int max_transportid, int num_transportids);
+void mpath_print_buf_readcap(struct prin_resp *pr_buff); 
+void mpath_print_buf_readfullstat(struct prin_resp *pr_buff);
+void mpath_print_buf_readresv(struct prin_resp *pr_buff);
+void mpath_print_buf_readkeys(struct prin_resp *pr_buff);
+void dumpHex(const char* str, int len, int no_ascii);
+void * mpath_alloc_prin_response(int prin_sa);	
+void mpath_print_transport_id(struct prin_fulldescr *fdesc);
+int construct_transportid(const char * inp, struct transportid transid[], int num_transportids);
+
+int logsink;
+
+int main (int argc, char * argv[])
+{
+	int fd, c, res;
+	const char *device_name = NULL;
+	int num_prin_sa = 0;
+	int num_prout_sa = 0;
+	int num_prout_param = 0;
+	int prin_flag = 0;
+	int prout_flag = 0;
+	int ret = 0;
+	int hex = 0;
+	uint64_t param_sark = 0;
+	unsigned int prout_type = 0;
+	int param_alltgpt = 0;
+	int param_aptpl = 0;
+	uint64_t param_rk = 0;
+	unsigned int param_rtp = 0;
+	int num_transportids = 0;
+	struct transportid transportids[MPATH_MX_TIDS];
+	int prout = 1;
+	int prin = 1;
+	int prin_sa = -1;
+	int prout_sa = -1;
+	int verbose = 0;
+	int loglevel = 0;
+	int noisy = 0;
+	int num_transport =0;
+	void *resp = NULL;
+	struct transportid * tmp; 
+
+	if (optind == argc)
+	{
+
+		fprintf (stderr, "No parameter used\n");
+		usage ();
+		exit (1);
+	}
+
+	if (getuid () != 0)
+	{
+		fprintf (stderr, "need to be root\n");
+		exit (1);
+	}
+
+
+	mpath_lib_init();
+	memset(transportids,0,MPATH_MX_TIDS);
+
+	while (1)
+	{
+		int option_index = 0;
+
+		c = getopt_long (argc, argv, "v:Cd:hHioZK:S:PAT:skrGILcRX:",
+				long_options, &option_index);
+		if (c == -1)
+			break;
+
+		switch (c)
+		{
+			case 'v':
+				if (1 != sscanf (optarg, "%d", &loglevel))
+				{
+					fprintf (stderr, "bad argument to '--verbose'\n");
+					return MPATH_PR_SYNTAX_ERROR;
+				}
+				break;
+
+			case 'C':
+				prout_sa = MPATH_PROUT_CLEAR_SA;
+				++num_prout_sa;
+				break;
+
+			case 'd':
+				device_name = optarg;
+				break;
+
+			case 'h':
+				usage ();
+				return 0;
+
+			case 'H':
+				hex=1;
+				break;
+
+			case 'i':
+				prin_flag = 1;
+				break;
+
+			case 'o':
+				prout_flag = 1;
+				break;
+
+			case 'Z':
+				param_aptpl = 1;
+				++num_prout_param;
+				break;
+			case 'K':
+				if (1 != sscanf (optarg, "%" SCNx64 "", &param_rk))
+				{
+					fprintf (stderr, "bad argument to '--param-rk'\n");
+					return MPATH_PR_SYNTAX_ERROR;
+				}
+				++num_prout_param;
+				break;
+
+			case 'S':
+				if (1 != sscanf (optarg, "%" SCNx64 "", &param_sark))
+				{
+					fprintf (stderr, "bad argument to '--param-sark'\n");
+					return MPATH_PR_SYNTAX_ERROR;
+				}
+				++num_prout_param;
+				break;
+
+			case 'P':
+				prout_sa = MPATH_PROUT_PREE_SA;
+				++num_prout_sa;
+				break;
+
+			case 'A':
+				prout_sa = MPATH_PROUT_PREE_AB_SA;
+				++num_prout_sa;
+				break;
+
+			case 'T':
+				if (1 != sscanf (optarg, "%x", &prout_type))
+				{
+					fprintf (stderr, "bad argument to '--prout-type'\n");
+					return MPATH_PR_SYNTAX_ERROR;
+				}
+				++num_prout_param;
+				break;
+
+			case 's':
+				prin_sa = MPATH_PRIN_RFSTAT_SA;
+				++num_prin_sa;
+				break;
+
+			case 'k':
+				prin_sa = MPATH_PRIN_RKEY_SA;
+				++num_prin_sa;
+				break;
+
+			case 'r':
+				prin_sa = MPATH_PRIN_RRES_SA;
+				++num_prin_sa;
+				break;
+
+			case 'G':
+				prout_sa = MPATH_PROUT_REG_SA;
+				++num_prout_sa;
+				break;
+
+			case 'I':
+				prout_sa = MPATH_PROUT_REG_IGN_SA;
+				++num_prout_sa;
+				break;
+
+			case 'L':
+				prout_sa = MPATH_PROUT_REL_SA;
+				++num_prout_sa;
+				break;
+
+			case 'c':
+				prin_sa = MPATH_PRIN_RCAP_SA;
+				++num_prin_sa;
+				break;
+
+			case 'R':
+				prout_sa = MPATH_PROUT_RES_SA;
+				++num_prout_sa;
+				break;
+
+			case 'X':
+				if (0 != construct_transportid(optarg, transportids, num_transport)) {
+					fprintf(stderr, "bad argument to '--transport-id'\n");
+					return MPATH_PR_SYNTAX_ERROR;
+				}
+
+				++num_transport;
+				break;
+
+			default:
+				fprintf(stderr, "unrecognised switch " "code 0x%x ??\n", c);	
+				usage ();
+				ret = MPATH_PR_SYNTAX_ERROR;
+				goto out;
+		}
+	}
+
+	if (optind < argc)
+	{
+
+		if (NULL == device_name)
+		{
+			device_name = argv[optind];
+			++optind;
+		}
+		if (optind < argc)
+		{
+			for (; optind < argc; ++optind)
+				fprintf (stderr, "Unexpected extra argument: %s\n", argv[optind]);
+			usage ();
+			ret = MPATH_PR_SYNTAX_ERROR;
+			goto out;
+		}
+	}
+
+	/* set verbosity */
+	noisy = (loglevel >= 3) ? 1: 0;
+	verbose	= (loglevel >= 3)? 3: loglevel;
+
+	if ((prout_flag + prin_flag) == 0)
+	{
+		fprintf (stderr, "choose either '--in' or '--out' \n");
+		usage ();
+		ret = MPATH_PR_SYNTAX_ERROR;
+		goto out;
+	}
+	if ((prout_flag + prin_flag) > 1)
+	{
+		fprintf (stderr, "choose either '--in' or '--out' \n");
+		usage ();
+		ret = MPATH_PR_SYNTAX_ERROR;
+		goto out;
+	}
+	else if (prout_flag)
+	{				/* syntax check on PROUT arguments */
+		prin = 0;
+		if ((1 != num_prout_sa) || (0 != num_prin_sa))
+		{
+			fprintf (stderr, " For Persistent Reserve Out only one "
+					"appropriate\n service action must be "
+					"chosen \n");
+			ret = MPATH_PR_SYNTAX_ERROR;
+			goto out;
+		}
+	}
+	else if (prin_flag)
+	{				/* syntax check on PRIN arguments */
+		prout = 0;
+		if (num_prout_sa > 0)
+		{
+			fprintf (stderr, " When a service action for Persistent "
+					"Reserve Out is chosen the\n"
+					" '--out' option must be given \n");
+			ret = MPATH_PR_SYNTAX_ERROR;
+			goto out;
+		}
+		if (0 == num_prin_sa)
+		{
+			fprintf (stderr,
+					" No service action given for Persistent Reserve IN\n");
+			usage();
+			ret = MPATH_PR_SYNTAX_ERROR;
+		}
+		else if (num_prin_sa > 1)
+		{
+			fprintf (stderr, " Too many service actions given; choose "
+					"one only\n");
+			usage();
+			ret = MPATH_PR_SYNTAX_ERROR;
+		}
+	}
+	else
+	{
+		usage ();
+		ret = MPATH_PR_SYNTAX_ERROR;
+		goto out;
+	}
+
+	if ((param_rtp) && (MPATH_PROUT_REG_MOV_SA != prout_sa))
+	{
+		fprintf (stderr, " --relative-target-port"
+				" only useful with --register-move\n");
+		usage ();
+		ret = MPATH_PR_SYNTAX_ERROR;
+		goto out;
+	}
+
+	if (((MPATH_PROUT_RES_SA == prout_sa) ||
+				(MPATH_PROUT_REL_SA == prout_sa) ||
+				(MPATH_PROUT_PREE_SA == prout_sa) ||
+				(MPATH_PROUT_PREE_AB_SA == prout_sa)) &&
+			(0 == prout_type)) {
+		fprintf(stderr, "Warning: --prout-type probably needs to be "
+				"given\n");
+	}
+	if ((verbose > 2) && num_transportids)
+	{
+		fprintf (stderr, "number of tranport-ids decoded from "
+				"command line : %d\n", num_transportids);
+	}
+
+	if (device_name == NULL)
+	{
+		fprintf (stderr, "No device name given \n");
+		usage ();
+		ret = MPATH_PR_SYNTAX_ERROR;
+		goto out;
+	}
+
+	/* open device */
+	if ((fd = open (device_name, O_WRONLY)) < 0)
+	{
+		fprintf (stderr, "%s: error opening file (rw) fd=%d\n",
+				device_name, fd);
+		ret = MPATH_PR_FILE_ERROR;
+		goto out;
+	}
+
+
+	if (prin)
+	{
+		resp = mpath_alloc_prin_response(prin_sa);
+		if (!resp)
+		{
+			fprintf (stderr, "failed to allocate PRIN response buffer\n");
+			ret = MPATH_PR_OTHER;
+			goto out;
+		}
+
+		ret = mpath_persistent_reserve_in (fd, prin_sa, resp, noisy, verbose);
+		if (ret != MPATH_PR_SUCCESS )
+		{
+			fprintf (stderr, "Persistent Reserve IN command failed\n");
+			goto out;	
+		}
+
+		switch(prin_sa)
+		{			
+			case MPATH_PRIN_RKEY_SA: 
+				mpath_print_buf_readkeys(resp);		
+				break;
+			case MPATH_PRIN_RRES_SA: 
+				mpath_print_buf_readresv(resp);
+				break;
+			case MPATH_PRIN_RCAP_SA:
+				mpath_print_buf_readcap(resp);		
+				break;
+			case MPATH_PRIN_RFSTAT_SA:
+				mpath_print_buf_readfullstat(resp);		
+				break;
+		}
+		free(resp);
+	}
+	else if (prout)
+	{
+		int j; 
+		int t_arr_len=0;
+		struct prout_param_descriptor *paramp;
+		t_arr_len = MPATH_MX_TID_LEN * num_transport;
+
+		paramp= malloc(sizeof(struct prout_param_descriptor) + (sizeof(struct transportid *)*(MPATH_MX_TIDS )));
+		
+		memset(paramp, 0, sizeof(struct prout_param_descriptor) + (sizeof(struct transportid *)*(MPATH_MX_TIDS)));
+
+		for (j = 7; j >= 0; --j) {
+			paramp->key[j] = (param_rk & 0xff);
+			param_rk >>= 8;
+		}
+
+		for (j = 7; j >= 0; --j) {
+			paramp->sa_key[j] = (param_sark & 0xff);
+			param_sark >>= 8;
+		}
+
+		if (param_alltgpt)
+			paramp->sa_flags |= 0x4;
+		if (param_aptpl)
+			paramp->sa_flags |= 0x1;
+
+		if (num_transport) 
+		{
+			paramp->sa_flags |= MPATH_F_SPEC_I_PT_MASK;
+			paramp->num_transportid = num_transport;
+			for (j = 0 ; j < num_transport; j++)
+			{
+				paramp->trnptid_list[j] = (struct transportid *)malloc(sizeof(struct transportid));
+				memcpy(paramp->trnptid_list[j], &transportids[j],sizeof(struct transportid));
+			}
+		}
+
+		/* PROUT commands other than 'register and move' */
+		ret = mpath_persistent_reserve_out (fd, prout_sa, 0, prout_type,
+				paramp, noisy, verbose);
+		for (j = 0 ; j < num_transport; j++)
+		{
+			tmp = paramp->trnptid_list[j];
+			free(tmp);
+		}
+		free(paramp);
+	}
+
+	if (ret != MPATH_PR_SUCCESS)
+	{
+		switch(ret)
+		{
+			case MPATH_PR_SENSE_UNIT_ATTENTION:
+				printf("persistent reserve out: scsi status: Unit Attention\n");
+				break;
+			case MPATH_PR_RESERV_CONFLICT:
+				printf("persistent reserve out: scsi status: Reservation Conflict\n");
+				break;
+		}
+		printf("PR out: command failed\n");
+	}
+
+	res = close (fd);
+	if (res < 0)
+	{
+		mpath_lib_exit();
+		return MPATH_PR_FILE_ERROR;
+	}
+
+out :
+	mpath_lib_exit();
+
+	return (ret >= 0) ? ret : MPATH_PR_OTHER;
+}
+
+int
+get_transportids_length(unsigned char * transportid_arr, int max_transportid, int num_transportids)
+{
+	int compact_len = 0;
+	unsigned char * ucp = transportid_arr;
+	int k, off, protocol_id, len;
+	for (k = 0, off = 0; ((k < num_transportids) && (k < max_transportid));
+			++k, off += MPATH_MX_TID_LEN) {
+		protocol_id = ucp[off] & 0xf;
+		if (5 == protocol_id) {
+			len = (ucp[off + 2] << 8) + ucp[off + 3] + 4;
+			if (len < 24)
+				len = 24;
+			if (off > compact_len)
+				memmove(ucp + compact_len, ucp + off, len);
+			compact_len += len;
+
+		} else {
+			if (off > compact_len)
+				memmove(ucp + compact_len, ucp + off, 24);
+			compact_len += 24;
+		}
+	}
+
+	return compact_len;
+}
+
+void mpath_print_buf_readkeys( struct prin_resp *pr_buff)
+{
+	int i,j,k, num;
+	unsigned char *keyp;
+	uint64_t prkey;
+	printf("  PR generation=0x%x, ", pr_buff->prin_descriptor.prin_readkeys.prgeneration);
+
+	num = pr_buff->prin_descriptor.prin_readkeys.additional_length / 8;
+	if (0 == num) {
+		printf("	0 registered reservation key.\n");
+		return;
+	}
+	else if (1 == num)
+		printf("	1 registered reservation key follows:\n");
+	else
+		printf("	%d registered reservation keys follow:\n", num);
+
+
+	keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[0];
+	for (i = 0; i < num ; i++)
+	{
+		prkey = 0;
+		for (j = 0; j < 8; ++j) {
+
+			if (j > 0)
+				prkey <<= 8;
+			prkey |= keyp[j];
+		}
+		printf("    0x%" PRIx64 "\n", prkey);
+		k=8*i+j;
+		keyp = (unsigned char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[k];
+	}
+}
+
+void mpath_print_buf_readresv( struct prin_resp *pr_buff)
+{
+	int j, num, scope=0, type=0;
+	unsigned char *keyp;
+	uint64_t prkey;	
+
+	num = pr_buff->prin_descriptor.prin_readresv.additional_length / 8;
+	if (0 == num)
+	{
+		printf("  PR generation=0x%x, there is NO reservation held \n", pr_buff->prin_descriptor.prin_readresv.prgeneration);
+		return ;
+	}
+	else
+		printf("  PR generation=0x%x, Reservation follows:\n", pr_buff->prin_descriptor.prin_readresv.prgeneration);
+	keyp = (unsigned  char *)&pr_buff->prin_descriptor.prin_readkeys.key_list[0]; 
+	prkey = 0;
+	for (j = 0; j < 8; ++j) {
+		if (j > 0)
+			prkey <<= 8;
+		prkey |= keyp[j];
+	}
+
+	printf("   Key = 0x%" PRIx64 "\n", prkey);
+
+	scope = (pr_buff->prin_descriptor.prin_readresv.scope_type >> 4) &  0x0f;
+	type = pr_buff->prin_descriptor.prin_readresv.scope_type & 0x0f;
+
+	if (scope == 0)	
+		printf("  scope = LU_SCOPE, type = %s", pr_type_strs[type]);
+	else
+		printf("  scope = %d, type = %s", scope, pr_type_strs[type]);
+
+	printf("\n");
+
+}
+
+void mpath_print_buf_readcap( struct prin_resp *pr_buff)
+{
+	if ( pr_buff->prin_descriptor.prin_readcap.length <= 2 ) {
+		fprintf(stderr, "Unexpected response for PRIN Report "
+				"Capabilities\n");
+		return; //MALFORMED;
+	}
+
+	printf("Report capabilities response:\n");
+
+	printf("  Compatible Reservation Handling(CRH): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x10));
+	printf("  Specify Initiator Ports Capable(SIP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x8));
+	printf("  All Target Ports Capable(ATP_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0] & 0x4 ));
+	printf("  Persist Through Power Loss Capable(PTPL_C): %d\n",!!(pr_buff->prin_descriptor.prin_readcap.flags[0]));
+	printf("  Type Mask Valid(TMV): %d\n", !!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80));
+	printf("  Allow Commands: %d\n", !!(( pr_buff->prin_descriptor.prin_readcap.flags[1] >> 4) & 0x7));
+	printf("  Persist Through Power Loss Active(PTPL_A): %d\n",
+			!!(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x1));
+
+	if(pr_buff->prin_descriptor.prin_readcap.flags[1] & 0x80)
+	{
+		printf("    Support indicated in Type mask:\n");
+
+		printf("      %s: %d\n", pr_type_strs[7], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x80);
+		printf("      %s: %d\n", pr_type_strs[6], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x40);
+		printf("      %s: %d\n", pr_type_strs[5], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x20);
+		printf("      %s: %d\n", pr_type_strs[3], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x8);
+		printf("      %s: %d\n", pr_type_strs[1], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x2);
+		printf("      %s: %d\n", pr_type_strs[8], pr_buff->prin_descriptor.prin_readcap.pr_type_mask & 0x100);
+	}
+}
+
+void mpath_print_buf_readfullstat( struct prin_resp *pr_buff)
+{
+
+	int i,j, num;
+	uint64_t  prkey;
+	uint16_t  rel_pt_addr;
+	unsigned char * keyp;
+
+	num = pr_buff->prin_descriptor.prin_readfd.number_of_descriptor;	
+	if (0 == num)
+	{
+		printf("  PR generation=0x%x \n", pr_buff->prin_descriptor.prin_readfd.prgeneration);
+		return ;
+	}
+	else
+		printf("  PR generation=0x%x \n", pr_buff->prin_descriptor.prin_readfd.prgeneration);
+
+	for (i = 0 ; i < num; i++)
+	{
+		keyp = (unsigned  char *)&pr_buff->prin_descriptor.prin_readfd.descriptors[i]->key;
+
+		prkey = 0;
+		for (j = 0; j < 8; ++j) {
+			if (j > 0)
+				prkey <<= 8;
+			prkey |= *keyp;
+			++keyp;
+		}
+		printf("   Key = 0x%" PRIx64 "\n", prkey);
+
+		if (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->flag & 0x02)	
+			printf("      All target ports bit set\n");
+		else {
+			printf("      All target ports bit clear\n");
+
+			rel_pt_addr = pr_buff->prin_descriptor.prin_readfd.descriptors[i]->rtpi;
+			printf("      Relative port address: 0x%x\n",
+					rel_pt_addr);
+		}
+
+		if (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->flag & 0x1) {
+			printf("      << Reservation holder >>\n");
+			j = ((pr_buff->prin_descriptor.prin_readfd.descriptors[i]->scope_type>> 4) & 0xf);
+			if (0 == j)
+				printf("      scope: LU_SCOPE, ");
+			else
+				printf("      scope: %d ", j);
+			j = (pr_buff->prin_descriptor.prin_readfd.descriptors[i]->scope_type & 0xf);
+			printf(" type: %s\n", pr_type_strs[j]);
+		} else
+			printf("      not reservation holder\n");
+		mpath_print_transport_id(pr_buff->prin_descriptor.prin_readfd.descriptors[i]);
+	}
+}
+
+static void usage()
+{
+	fprintf(stderr,
+			"Usage: mpathpersist [OPTIONS] [DEVICE]\n"
+			" Options:\n"
+			"    --verbose|-v level         verbosity level\n"
+			"                   0           Critical messages\n"
+			"                   1           Error messages\n"
+			"                   2           Warning messages\n"
+			"                   3           Informational messages\n"
+			"                   4           Informational messages with trace enabled\n"
+			"    --clear|-C                 PR Out: Clear\n"
+			"    --device=DEVICE|-d DEVICE  query or change DEVICE\n"
+			"    --help|-h                  output this usage message\n"
+			"    --hex|-H                   output response in hex\n"
+			"    --in|-i                    request PR In command \n"
+			"    --out|-o                   request PR Out command\n"
+			"    --param-aptpl|-Z           PR Out parameter 'APTPL'\n"
+			"    --read-keys|-k             PR In: Read Keys\n"
+			"    --param-sark=SARK|-S SARK  PR Out parameter service "
+			"action\n"
+			"                               reservation key (SARK is in "
+			"hex)\n"
+			"    --preempt|-P               PR Out: Preempt\n"
+			"    --preempt-abort|-A         PR Out: Preempt and Abort\n"
+			"    --prout-type=TYPE|-T TYPE  PR Out command type\n"
+			"    --read-status|-s           PR In: Read Full Status\n"
+			"    --read-keys|-k             PR In: Read Keys\n"
+			"    --read-reservation|-r      PR In: Read Reservation\n"
+			"    --register|-G              PR Out: Register\n"
+			"    --register-ignore|-I       PR Out: Register and Ignore\n"
+			"    --release|-L               PR Out: Release\n"
+			"    --report-capabilities|-c   PR In: Report Capabilities\n"
+			"    --reserve|-R               PR Out: Reserve\n"
+			"    --transport-id=TIDS|-X TIDS  TransportIDs can be mentioned \n"
+			"                               in several forms\n"
+			" Examples:\n"
+			"     mpathpersist --out --register --param-sark=123abc --prout-type=5 /dev/mapper/mpath9\n"
+			"     mpathpersist -i -k /dev/mapper/mpath9\n"	);
+}
+
+void
+mpath_print_transport_id(struct prin_fulldescr *fdesc)
+{
+	switch (fdesc->trnptid.protocol_id) {
+		case MPATH_PROTOCOL_ID_FC:
+			printf("   FCP-2 ");
+			if (0 != fdesc->trnptid.format_code)
+				printf(" [Unexpected format code: %d]\n", 
+						fdesc->trnptid.format_code);
+			dumpHex((const char *)fdesc->trnptid.n_port_name, 8, 0);
+			break;
+		case MPATH_PROTOCOL_ID_ISCSI:
+			printf("   iSCSI ");
+			if (0 == fdesc->trnptid.format_code) {
+				printf("name: %.*s\n", (int)sizeof(fdesc->trnptid.iscsi_name),
+					fdesc->trnptid.iscsi_name);
+			}else if (1 == fdesc->trnptid.format_code){
+				printf("world wide unique port id: %.*s\n",
+						(int)sizeof(fdesc->trnptid.iscsi_name),
+						fdesc->trnptid.iscsi_name);
+			}else {
+				printf("  [Unexpected format code: %d]\n", fdesc->trnptid.format_code);
+				dumpHex((const char *)fdesc->trnptid.iscsi_name,
+					 (int)sizeof(fdesc->trnptid.iscsi_name), 0);
+			}
+			break;
+		case MPATH_PROTOCOL_ID_SAS:
+			printf("   SAS ");
+			 if (0 != fdesc->trnptid.format_code)
+                                printf(" [Unexpected format code: %d]\n",
+                                                fdesc->trnptid.format_code);
+                        dumpHex((const char *)fdesc->trnptid.sas_address, 8, 0);
+			break;
+		default:
+			return;
+	}
+}
+
+int
+construct_transportid(const char * lcp, struct transportid transid[], int num_transportids)
+{
+	unsigned char * tidp;
+	int k = 0;
+	int j, n, b, c, len, alen;
+	const char * ecp;
+	const char * isip;
+
+	if ((0 == memcmp("fcp,", lcp, 4)) ||
+			(0 == memcmp("FCP,", lcp, 4))) {
+		lcp += 4;
+		k = strspn(lcp, "0123456789aAbBcCdDeEfF");
+
+		len = strlen(lcp);
+		if (len != k) {
+			fprintf(stderr, "badly formed symbolic FCP TransportID: %s\n",
+					lcp);
+			return 1;
+		}
+		transid[num_transportids].format_code = MPATH_PROTOCOL_ID_FC;
+		transid[num_transportids].protocol_id = MPATH_WWUI_DEVICE_NAME;
+		for (k = 0, j = 0, b = 0; k < 16; ++k) {
+			c = lcp[k];
+			if (isdigit(c))
+				n = c - 0x30;
+			else if (isupper(c))
+				n = c - 0x37;
+			else
+				n = c - 0x57;
+			if (k & 1) {
+				transid[num_transportids].n_port_name[j] = b | n;
+				++j;
+			} else
+				b = n << 4;
+		}
+		goto my_cont_b;
+	}
+	if ((0 == memcmp("sas,", lcp, 4)) || (0 == memcmp("SAS,", lcp, 4))) {
+		lcp += 4;
+		k = strspn(lcp, "0123456789aAbBcCdDeEfF");
+		len =strlen(lcp);
+		if (len != k) {
+			fprintf(stderr, "badly formed symbolic SAS TransportID: %s\n",
+					lcp);
+			return 1;
+		}
+		transid[num_transportids].format_code = MPATH_PROTOCOL_ID_SAS;
+		transid[num_transportids].protocol_id = MPATH_WWUI_DEVICE_NAME;
+		memcpy(&transid[num_transportids].sas_address, lcp, 8);
+
+		goto my_cont_b;
+	}
+	if (0 == memcmp("iqn.", lcp, 4)) {
+		ecp = strpbrk(lcp, " \t");
+		isip = strstr(lcp, ",i,0x");
+		if (ecp && (isip > ecp))
+			isip = NULL;
+		len = ecp ? (ecp - lcp) : (int)strlen(lcp);
+		memset(&tidp, 0, 24);
+		transid[num_transportids].format_code = (isip ? MPATH_WWUI_PORT_IDENTIFIER:MPATH_WWUI_DEVICE_NAME);
+		transid[num_transportids].protocol_id = MPATH_PROTOCOL_ID_ISCSI;
+		alen = len + 1; /* at least one trailing null */
+		if (alen < 20)
+			alen = 20;
+		else if (0 != (alen % 4))
+			alen = ((alen / 4) + 1) * 4;
+		if (alen > 241) { /* sam5r02.pdf A.2 (Annex) */
+			fprintf(stderr, "iSCSI name too long, alen=%d\n", alen);
+			return 0;
+		}
+		transid[num_transportids].iscsi_name[1] = alen & 0xff;
+		memcpy(&transid[num_transportids].iscsi_name[2], lcp, len);
+		goto my_cont_b;
+	}
+my_cont_b:
+	if (k >= MPATH_MAX_PARAM_LEN) {
+		fprintf(stderr, "build_transportid: array length exceeded\n");
+		return 1;
+	}
+	return 0;
+}
+
diff -uprN multipath-tools-orig/mpathpersist/main.h multipath-tools/mpathpersist/main.h
--- multipath-tools-orig/mpathpersist/main.h	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/mpathpersist/main.h	2011-12-20 00:15:04.000000000 +0530
@@ -0,0 +1,28 @@
+static struct option long_options[] = {
+	{"verbose", 1, 0, 'v'},
+	{"clear", 0, 0, 'C'},
+	{"device", 1, 0, 'd'},
+	{"help", 0, 0, 'h'},
+	{"hex", 0, 0, 'H'},
+	{"in", 0, 0, 'i'},
+	{"out", 0, 0, 'o'},
+	{"param-aptpl", 0, 0, 'Z'},
+	{"param-rk", 1, 0, 'K'},
+	{"param-sark", 1, 0, 'S'},
+	{"preempt", 0, 0, 'P'},
+	{"preempt-abort", 0, 0, 'A'},
+	{"prout-type", 1, 0, 'T'},
+	{"read-full-status", 0, 0, 's'},
+	{"read-keys", 0, 0, 'k'},
+	{"read-reservation", 0, 0, 'r'},
+	{"register", 0, 0, 'G'},
+	{"register-ignore", 0, 0, 'I'},
+	{"release", 0, 0, 'L'},
+	{"report-capabilities", 0, 0, 'c'},		
+	{"reserve", 0, 0, 'R'},
+	{"transport-id", 1, 0, 'X'},
+	{0, 0, 0, 0}
+};
+
+static void usage(void);
+
diff -uprN multipath-tools-orig/mpathpersist/Makefile multipath-tools/mpathpersist/Makefile
--- multipath-tools-orig/mpathpersist/Makefile	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/mpathpersist/Makefile	2011-12-20 00:15:04.000000000 +0530
@@ -0,0 +1,30 @@
+# Makefile
+#
+include ../Makefile.inc
+
+OBJS = main.o 
+
+CFLAGS += -I$(multipathdir) -I$(mpathpersistdir) 
+LDFLAGS += -lpthread -ldevmapper -lsysfs -L$(mpathpersistdir) -lmpathpersist -L$(multipathdir) -lmultipath 
+
+EXEC = mpathpersist
+
+all: $(EXEC)
+
+$(EXEC): $(OBJS)
+	$(CC) -g $(OBJS) -o $(EXEC) $(LDFLAGS) $(CFLAGS)
+	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
+	
+install:
+	install -d $(DESTDIR)$(bindir)
+	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
+	install -d $(DESTDIR)$(mandir)
+	install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
+	
+clean:
+	rm -f *.o $(EXEC)
+	rm -f mpathpersist.8.gz
+
+uninstall:
+	rm $(DESTDIR)$(bindir)/$(EXEC)
+	rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
diff -uprN multipath-tools-orig/mpathpersist/mpathpersist.8 multipath-tools/mpathpersist/mpathpersist.8
--- multipath-tools-orig/mpathpersist/mpathpersist.8	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools/mpathpersist/mpathpersist.8	2011-12-20 00:15:04.000000000 +0530
@@ -0,0 +1,96 @@
+.\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.39.2.
+.TH MPATHPERSIST  "8" "April 2011" "mpathpersist" "User Commands"
+.SH NAME
+mpathpersist
+.SH SYNOPSIS
+.B mpathpersist
+[\fIOPTIONS\fR] [\fIDEVICE\fR]
+.SH DESCRIPTION
+.IP
+Options:
+.TP
+\fB\-\-verbose\fR|\-v level
+verbosity level
+.TP
+0
+Critical and error messages
+.TP
+1
+Warning messages
+.TP
+2
+Informational messages
+.TP
+3
+Informational messages with trace enabled
+.TP
+\fB\-\-clear\fR|\-C
+PR Out: Clear
+.TP
+\fB\-\-device\fR=\fIDEVICE\fR|\-d DEVICE
+query or change DEVICE
+.TP
+\fB\-\-help\fR|\-h
+output this usage message
+.TP
+\fB\-\-hex\fR|\-H
+output response in hex
+.TP
+\fB\-\-in\fR|\-i
+request PR In command
+.TP
+\fB\-\-out\fR|\-o
+request PR Out command
+.TP
+\fB\-\-param\-aptpl\fR|\-Z
+PR Out parameter 'APTPL'
+.TP
+\fB\-\-read\-keys\fR|\-k
+PR In: Read Keys
+.TP
+\fB\-\-param\-sark\fR=\fISARK\fR|\-S SARK
+PR Out parameter service action
+reservation key (SARK is in hex)
+.TP
+\fB\-\-preempt\fR|\-P
+PR Out: Preempt
+.TP
+\fB\-\-preempt\-abort\fR|\-A
+PR Out: Preempt and Abort
+.TP
+\fB\-\-prout\-type\fR=\fITYPE\fR|\-T TYPE
+PR Out command type
+.TP
+\fB\-\-read\-status\fR|\-s
+PR In: Read Full Status
+.TP
+\fB\-\-read\-keys\fR|\-k
+PR In: Read Keys
+.TP
+\fB\-\-read\-reservation\fR|\-r
+PR In: Read Reservation
+.TP
+\fB\-\-register\fR|\-G
+PR Out: Register
+.TP
+\fB\-\-register\-ignore\fR|\-I
+PR Out: Register and Ignore
+.TP
+\fB\-\-release\fR|\-L
+PR Out: Release
+.TP
+\fB\-\-report\-capabilities\fR|\-c
+PR In: Report Capabilities
+.TP
+\fB\-\-reserve\fR|\-R
+PR Out: Reserve
+.TP
+\fB\-\-transport\-id\fR=\fITIDS\fR|\-X TIDS
+TransportIDs can be mentioned
+in several forms
+.IP
+Examples:
+.IP
+mpathpersist \fB\-\-out\fR \fB\-\-register\fR \fB\-\-param\-sark\fR=\fI123abc\fR \fB\-\-prout\-type\fR=\fI5\fR /dev/mapper/mpath9
+mpathpersist \fB\-i\fR \fB\-k\fR /dev/mapper/mpath9
+.PP
--

  

--
dm-devel mailing list
dm-devel@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/dm-devel


[Index of Archives]     [DM Crypt]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Packaging]     [Fedora SELinux]     [Yosemite Discussion]     [KDE Users]     [Fedora Docs]

  Powered by Linux