[dm-devel] [PATCH 1/3][RESEND]multipath-tools: Add mpathpersist utility and libmpathpersist library for mpath pr management

Chauhan, Vijay Vijay.Chauhan at netapp.com
Thu Jan 19 19:21:04 UTC 2012


This patch adds new cli utility 'mpathpersist' in multipath-tools for managing pr on mpath device.

Signed-off-by: Vijay Chauhan <Vijay.chauhan at netapp.com>
Reviewed-by: Bob Stankey <Robert.stankey at netapp.com> 
Reviewed-by: Babu Moger <Babu.moger at netapp.com>
Reviewed-by: Yanling Q <Yanling.Q at netapp.com>

---
diff -uprN multipath-tools-orig/libmpathpersist/Makefile multipath-tools/libmpathpersist/Makefile
--- multipath-tools-orig/libmpathpersist/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ multipath-tools/libmpathpersist/Makefile	2012-01-17 06:07:41.000000000 -0500
@@ -0,0 +1,49 @@
+# 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/
+
+uninstall:
+	rm -f $(DESTDIR)$(syslibdir)/$(LIBS)
+	rm $(DESTDIR)$(mandir)/mpath_persistent_reserve_in.3.gz	
+	rm $(DESTDIR)$(mandir)/mpath_persistent_reserve_out.3.gz	
+
+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	1969-12-31 19:00:00.000000000 -0500
+++ multipath-tools/libmpathpersist/mpath_persist.c	2012-01-12 11:53:01.000000000 -0500
@@ -0,0 +1,880 @@
+#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, 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;
+
+	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, pp->dev);
+				condlog(3, "%s: status = %d.", mpp->wwid, pp->state);
+				continue;
+			}
+
+			condlog(3, "%s: sending pr in command to %s ", mpp->wwid, pp->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){
+		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(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;
+
+	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;
+			}
+
+			condlog (3, "%s: sending pr out command to %s", mpp->wwid, pp->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;
+
+	memset(&thread, 0, sizeof(thread));
+	strncpy(param.dev, dev, FILE_NAME_SIZE);
+	/* 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 (param.status);
+}
+
+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;
+	int num = 0;
+	struct pathgroup *pgp = NULL;
+	struct path *pp = NULL;
+	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 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];
+	memset(thread, 0, sizeof(thread));
+	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);
+		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, pp->dev);
+				continue;
+			}
+			
+			strncpy(thread[count].param.dev, pp->dev, FILE_NAME_SIZE);
+			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;
+		}
+	}
+	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;
+	}
+
+	status = mpath_prin_activepath (mpp, MPATH_PRIN_RRES_SA, &resp, noisy);
+	if (status != MPATH_PR_SUCCESS){
+		condlog (0, "%s: pr in read reservation command failed.", mpp->wwid);
+		return MPATH_PR_OTHER;
+	}
+
+	num = resp.prin_descriptor.prin_readresv.additional_length / 8;
+	if (num == 0){
+		condlog (2, "%s: Path holding reservation is released.", mpp->wwid);
+		return MPATH_PR_SUCCESS;	
+	}
+	condlog (2, "%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 pr in response buffer.", mpp->wwid);	
+		return MPATH_PR_OTHER;
+	}
+
+	status = mpath_prin_activepath (mpp, MPATH_PRIN_RFSTAT_SA, pr_buff, noisy);
+
+	if (status != MPATH_PR_SUCCESS){
+		condlog (0,  "%s: pr in 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 pr out 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 pr out 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));
+			status = 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;
+			status = 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);
+		status = 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;
+
+	if (!mpp->reservation_key)
+	{
+		/* Nothing to do. Assuming pr mgmt feature is disabled*/
+		condlog(3, "%s: reservation_key not set in multiapth.conf", mpp->alias);
+		return MPATH_PR_SUCCESS;
+	}
+
+	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;
+	}
+
+	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);
+
+	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 pr in 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	1969-12-31 19:00:00.000000000 -0500
+++ multipath-tools/libmpathpersist/mpath_persistent_reserve_in.3	2012-01-12 11:53:01.000000000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ multipath-tools/libmpathpersist/mpath_persistent_reserve_out.3	2012-01-12 11:53:01.000000000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ multipath-tools/libmpathpersist/mpath_persist.h	2012-01-12 11:53:01.000000000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ multipath-tools/libmpathpersist/mpathpr.h	2012-01-12 11:53:01.000000000 -0500
@@ -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, 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	1969-12-31 19:00:00.000000000 -0500
+++ multipath-tools/libmpathpersist/mpath_pr_ioctl.c	2012-01-12 11:53:01.000000000 -0500
@@ -0,0 +1,571 @@
+#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;
+
+	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	1969-12-31 19:00:00.000000000 -0500
+++ multipath-tools/libmpathpersist/mpath_pr_ioctl.h	2012-01-12 11:53:01.000000000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ multipath-tools/libmpathpersist/mpath_updatepr.c	2012-01-12 11:53:01.000000000 -0500
@@ -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;
+}

--




More information about the dm-devel mailing list