FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > Redhat > Device-mapper Development

 
 
LinkBack Thread Tools
 
Old 12-19-2011, 03:34 PM
"Chauhan, Vijay"
 
Default persistent management feature for multipath-tools

PERSISTENT RESERVE OUT/IN commands are currently not supported on mpath device. Any command sent to mpath device is routed to only one of the physical path (selected by path selector) from the active path group. PR OUT registration service action is one of the such use-case which fails as it expects all the physical path for the given mpath device to be registered. Due to these limitations, most of the cluster applications needs to manage persistent reservation through underlying physical path.


This feature enables mpath device to be used with cluster application.

Following are the detailed description for Persistent Reservation management feature:
================================================== ================================================== =======
CONTENT
================================================== ================================================== =======
1. Feature Introduction
2. Steps to configure for persistent reservation management
3. mpathpersist Command Usage
4. PR IN/OUT service action and use-case handling
4.1 Persistent Reserve Out service action
4.1.1 [Register]
4.1.2 [Reserve]
4.1.3 [Release]
4.1.4 [CLEAR]
4.1.5 [PREEMPT] & [PREEMPT AND ABORT]
4.2 Persistent Reserve In service action
4.2.1 [READ KEY]
4.2.2 [READ RESERVATION]
4.2.3 [READ STATUS]
4.2.4 [REPORT CAPABILITIES]
4.3 Usage case handled by multipath tools for PR management
5. mpathpersist library and header
5.1 mpathpersist Library APIs.
5.1.1 int mpath_lib_init (void )
5.1.2 int mpath_lib_exit (void )
5.1.3 int mpath_persistent_reserve_in (int fd, int rq_servact,
struct prin_resp *resp, int noisy, int verbose)
5.1.4 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)
6. Limitation and restriction.



1. Feature Introduction
==========================

Persistent reservation management feature allows cluster management software to manage persistent reservation through mpath device. It processes management requests from callers and hides the management task details. It also handles persistent reservation management of data path life cycle and state changes.

All the patch for this feature are applicable to multipath-tools only. It adds new utility 'mpathpersist' and libmpathpersist library in multipath-tools to support this feature. 'mpathpersist' is similar to sg_persist utility with respect to cli usage but it is only applicable to dm multipath devices.


2. Steps to configure for persistent reservation management
================================================== ===========
This feature adds new parameter 'reservation_key' in default section and multipath section of multipath.conf.

'reservation_key' here represents RESERVATION KEY field of PERSISTENT RESERVE OUT parameter list which contains an 8-byte value provided by the application client to the device server to identify the I_T nexus.

STEP 1: Set reservation_key parameter in multipath.conf for mpath device. 'reservation_key' parameter needs to be set for all the mpath device applicable for persistent management.
STEP 2: restart multipathd daemon

Note: reservation key in multipath.com must be same as service action reservation key used/to be used for mpath device registration reservation.


3. mpathpersist Command Usage
===============================

mpathpersist CLI usage is kept close to sg_persist usage except it takes mpath device as device name.

Usage: mpathpersist [OPTIONS] [DEVICE]
Options:
--verbose|-v level verbosity level
0 Critical messages
1 Error messages
2 Warning messages
3 Informational messages
4 Informational messages with trace enabled
--clear|-C PR Out: Clear
--device=DEVICE|-d DEVICE query or change DEVICE
--help|-h output this usage message
--hex|-H output response in hex
--in|-i request PR In command
--out|-o request PR Out command
--param-aptpl|-Z PR Out parameter 'APTPL'
--read-keys|-k PR In: Read Keys
--param-sark=SARK|-S SARK PR Out parameter service action
reservation key (SARK is in hex)
--param-rk=RK|-K RK PR Out parameter reservation key
(RK is in hex)
--preempt|-P PR Out: Preempt
--preempt-abort|-A PR Out: Preempt and Abort
--prout-type=TYPE|-T TYPE PR Out command type
--read-status|-s PR In: Read Full Status
--read-keys|-k PR In: Read Keys
--read-reservation|-r PR In: Read Reservation
--register|-G PR Out: Register
--register-ignore|-I PR Out: Register and Ignore
--release|-L PR Out: Release
--report-capabilities|-c PR In: Report Capabilities
--reserve|-R PR Out: Reserve
--transport-id=TIDS|-X TIDS TransportIDs can be mentioned
in several forms


4. PR IN/OUT service action and use-case handling
================================================== =

4.1 Persistent Reserve Out service action:
----------------------------------
4.1.1 [Register]
The caller provides multipath device name, reservation key, and service action reservation key and optionally APTPL bit value. The persistent reservation management command issues PROUT Register service action to all active data paths of the multipath device. If reservation key or service action reservation key is not provided, fill with all 0s. For each path, a thread is created to process PROUT register service action. Consolidated results of all the paths are returned to caller. In case if this PROUT command fails with reservation conflict, all the successful registration by other threads will be rolled back.
Example: mpathpersist --out --register --param-sark=123abc --prout-type=8 /dev/mapper/mpath9
/*Unregister*/
mpathpersist --out --register --param-rk=123abc --prout-type=8 /dev/mapper/mpath9


4.1.2 [Reserve]
The caller provides multipath device name, reservation type and reservation key. The reservation SCOPE value is not required since persistent reservation supports only LU_SCOPE. The persistent reservation management command issues PROUT Reserve service action to any active data paths of the multipath
device. PROUT command is send to one of the active path of multipath device. Result is returned to the caller of this module.
Example: mpathpersist --out --reserve --param-rk=123abc --prout-type=8 /dev/mapper/mpath9


4.1.3 [Release]
The caller provides multipath device name, reservation type and reservation key. The persistent reservation management command issues PROUT Release service action to all active data paths of the multipath device. The reason why issuing PROUT Release service action is because it is unclear which
data path is the reservation holder. If RESERVATION CONFLICT SCSI status is received, it indicates that either the reservation key or
reservation type is invalid. Return error status back to the caller. After PROUT Release service action command is issued to all active data paths, a PRIN Read Reservation service action should be issued to an active data path. If the Read Reservation parameter
data indicates that the logical unit is still reserved and the registration key matches the reservation key
caller provided, this indicates that the reservation holder belongs to a data path in failed state or removed
data path of the multipath device. The following operations should be taken for this error case.
1. Issue a PRIN Report Full Status service action to any active data path
2. Remember the full status descriptors returned from the step 1.
3. Issue a PROUT clear reservation service action, via any active data path, to clear the reservation and registrants and
4. Restore all registrants by issuing PROUT register service action with transport IDs from the full status descriptors saved in the step 2.
Example: mpathpersist --out --release --param-rk=123abc --prout-type=8 /dev/mapper/mpath9


4.1.4 [CLEAR]
The caller provides multipath device name and reservation key. The persistent reservation management
command issues PROUT Preempt service action to any active data paths of the multipath device.
If RESERVATION CONFLICT SCSI status is received, it indicates that the reservation key is invalid or the
data path is not a registrant. Return error status back to the caller.
Example: mpathpersist --out --clear --param-rk=123abc --prout-type=8 /dev/mapper/mpath9


4.1.5 [PREEMPT] & [PREEMPT AND ABORT]
The caller provides multipath device name, reservation type, reservation key and service action reservation key. The persistent reservation management command issues PROUT Preempt service action to any active data paths of the multipath device. If RESERVATION CONFLICT SCSI status is received, it indicates that either the reservation key or service action reservation key is invalid. Return error status back to the caller. PROUT command is send to one of the active path of multipath device. Result is returned to the caller of this module.
Example: mpathpersist --out --preempt-abort --param-rk=0 --paramsark=789def --prout-type=8 /dev/mapper/mpath9


PS: This feature does not support ALL_TG_PT bit on. With a storage array having 8 or 16 target ports, the total number of registrants will be equal to total-number-of-initiator-ports X total-number-of target-ports. If ALL_TG_PT is on, too much storage array resources will be wasted and it also creates implementation challenge of managing registration rollback. In a use case where one initiator port (such as a FC port) connects to multiple target ports on the same storage array via a switch, ALL_TG_PT=1 will cause registration failed with RESERVATION CONFLICT status when issuing PROUT registration to the second data path which shares the same initiator port.

PS: This RFC version does not support REGISTER AND MOVE service action.

4.2 Persistent Reserve In service action:
--------------------------------------------
4.2.1 [READ KEY]
The caller provides multipath device. The persistent reservation management command selects any active data path and issues a PRIN Read Keys service action to the selected data path of the multipath device. Parameter data is sent to the caller with appropriate formatted. The persistent reservation
management command will not filter registration keys returned from the storage array. In other words, multiple registration keys is reported in general.
Example: mpathpersist -i -k /dev/mapper/mpath9


4.2.2 [READ RESERVATION]
The caller provides multipath device. The persistent reservation management command selects any active data path and issues a PRIN Read Reservation service action to the selected data path of the multipath device. Parameter data is sent to the caller with appropriate formatted.
Example: mpathpersist -i -r /dev/mapper/mpath9


4.2.3 [READ STATUS]
The caller provides multipath device. The persistent reservation management command selects any active data path and issues a PRIN Read Full Status service action to the selected data path of the multipath device. Parameter data is sent to the caller with appropriate formatted. The persistent reservation management command will not filter full status descriptor entries returned from the storage array. In other words, full statuses for multiple registrants is reported in general.
Example: mpathpersist -i -s /dev/mapper/mpath9


4.2.4 [REPORT CAPABILITIES]
The caller provides multipath device. The persistent reservation management command selects any active data path and issues a PRIN Report Capabilities service action to the selected data path of the multipath device. Parameter data is sent to the caller with appropriate formatted.
Example: mpathpersist -i -c /dev/mapper/mpath9


4.3 Use-case handled by multipath tools for PR management
- For any reinstated path, multipath daemon checks for persistent reservation on the path and registers the path with reservation_key (from multipath.conf) if required.
- For any new path discovery, multipath daemon checks for persistent reservation on the path and registers the path if required.
- In case of device all path failure condition, command is returns with failed status.
- PR command is retried by pr management for any Unit Attention.
- While performing persistent reservation registration on mpath device, if any of the path receives reservation conflict then successful registration on the other paths will be rolled back.

5. mpathpersist Library and Header
======================================


mpathpersist library provides four APIs for managing persistent reservation on device mapper multipath device.

5.1 mpathpersist Library APIs.
---------------------------------
5.1.1 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).


5.1.2 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.


5.1.3 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)


5.1.4 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

6. Limitation and restriction
-This feature doesn't support persistent reservation types of Write-Exclusive (1h)
and Exclusive-Access(3h).
- This feature will not support ALL_TG_PT bit on.
- Current implementation is limited to FC SAS and ISCSI transport protocol. Other protocol support could be added in future.


Regards,
Vijay Chauhan

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 
Old 12-19-2011, 03:34 PM
"Chauhan, Vijay"
 
Default persistent management feature for multipath-tools

This patch adds new cli utility 'mpathpersist' in multipath-tools for mpath persistent management.

Signed-off-by: Vijay Chauhan <Vijay.chauhan@netapp.com>
Reviewed-by: Bob Stankey <Robert.stankey@netapp.com>
Reviewed-by: Babu Moger <Babu.moger@netapp.com>
Reviewed-by: Yanling Q <Yanling.Q@netapp.com>
---
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_leng th / 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_descripto r;
+ 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_descripto r)
+ {
+ return ;
+ }
+
+
+ if (pr_buff->prin_descriptor.prin_readfd.number_of_descripto r == 0)
+ {
+ condlog(2, "No registration or resrvation found.");
+ return;
+ }
+
+ additional_length = pr_buff->prin_descriptor.prin_readfd.number_of_descripto r;
+
+ 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_descripto r = 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
" : "%.56s
";
+ memset(buff, ' ', 80);
+ buff[80] = '';
+ 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] = '';
+ if (log)
+ condlog(0, "%s", buff);
+ else
+ printf("%s
" , 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. m
 
Old 12-19-2011, 03:34 PM
"Chauhan, Vijay"
 
Default persistent management feature for multipath-tools

This patch includes changes in multipath tools files for supporting persistent management feature.

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

---
diff -uprN multipath-tools-orig/libmultipath/config.h multipath-tools/libmultipath/config.h
--- multipath-tools-orig/libmultipath/config.h 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/libmultipath/config.h 2011-12-19 23:12:10.000000000 +0530
@@ -49,6 +49,7 @@ struct mpentry {

char * prio_name;
char * prio_args;
+ unsigned char * reservation_key;
int pgpolicy;
int pgfailback;
int rr_weight;
@@ -111,6 +112,7 @@ struct config {
char * prio_args;
char * checker_name;
char * alias_prefix;
+ unsigned char * reservation_key;

vector keywords;
vector mptable;
diff -uprN multipath-tools-orig/libmultipath/configure.c multipath-tools/libmultipath/configure.c
--- multipath-tools-orig/libmultipath/configure.c 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/libmultipath/configure.c 2011-12-19 23:12:10.000000000 +0530
@@ -72,6 +72,7 @@ setup_map (struct multipath * mpp, char
select_gid(mpp);
select_fast_io_fail(mpp);
select_dev_loss(mpp);
+ select_reservation_key(mpp);

sysfs_set_scsi_tmo(mpp);
/*
diff -uprN multipath-tools-orig/libmultipath/dict.c multipath-tools/libmultipath/dict.c
--- multipath-tools-orig/libmultipath/dict.c 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/libmultipath/dict.c 2011-12-19 23:12:10.000000000 +0530
@@ -20,6 +20,7 @@
#include "defaults.h"
#include "prio.h"
#include "errno.h"
+#include <inttypes.h>

/*
* default block handlers
@@ -525,6 +526,53 @@ def_flush_on_last_del_handler(vector str
}

static int
+def_reservation_key_handler(vector strvec)
+{
+ char *buff;
+ char *tbuff;
+ int j, k;
+ int len;
+ uint64_t prkey;
+
+ buff = set_value(strvec);
+ if (!buff)
+ return 1;
+
+ tbuff = buff;
+
+ if (!memcmp("0x",buff, 2))
+ buff = buff + 2;
+
+ len = strlen(buff);
+
+ k = strspn(buff, "0123456789aAbBcCdDeEfF");
+
+ if (len != k) {
+ FREE(tbuff);
+ return 1;
+ }
+
+ if (1 != sscanf (buff, "%" SCNx64 "", &prkey))
+ {
+ FREE(tbuff);
+ return 1;
+ }
+
+ if (!conf->reservation_key)
+ conf->reservation_key = (unsigned char *) malloc(8);
+
+ memset(conf->reservation_key, 0, 8);
+
+ for (j = 7; j >= 0; --j) {
+ conf->reservation_key[j] = (prkey & 0xff);
+ prkey >>= 8;
+ }
+
+ FREE(tbuff);
+ return 0;
+}
+
+static int
names_handler(vector strvec)
{
char * buff;
@@ -1545,6 +1593,55 @@ mp_prio_args_handler (vector strvec)
return 0;
}

+static int
+mp_reservation_key_handler (vector strvec)
+{
+ char *buff;
+ char *tbuff;
+ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
+
+ int j, k, len;
+ uint64_t prkey;
+
+ if (!mpe)
+ return 1;
+
+ buff = set_value(strvec);
+ if (!buff)
+ return 1;
+
+ tbuff = buff;
+ if (!memcmp(buff, "0x", 2))
+ buff = buff + 2;
+
+ len = strlen(buff);
+
+ k = strspn(buff, "0123456789aAbBcCdDeEfF");
+ if (len != k) {
+ FREE(tbuff);
+ return 1;
+ }
+
+ if (1 != sscanf (buff, "%" SCNx64 "", &prkey))
+ {
+ FREE(tbuff);
+ return 1;
+ }
+
+ if (!mpe->reservation_key)
+ mpe->reservation_key = (unsigned char *) malloc(8);
+
+ memset(mpe->reservation_key, 0, 8);
+
+ for (j = 7; j >= 0; --j) {
+ mpe->reservation_key[j] = (prkey & 0xff);
+ prkey >>= 8;
+ }
+
+ FREE(tbuff);
+ return 0;
+}
+
/*
* config file keywords printing
*/
@@ -1768,6 +1865,25 @@ snprint_mp_prio_args(char * buff, int le
}

static int
+snprint_mp_reservation_key (char * buff, int len, void * data)
+{
+ int j;
+ uint64_t prkey;
+ unsigned char *keyp;
+
+ struct mpentry * mpe = (struct mpentry *)data;
+
+ for (j = 0; j < 8; ++j) {
+ if (j > 0)
+ prkey <<= 8;
+ prkey |= *keyp;
+ ++keyp;
+ }
+ return snprintf(buff, len, "%s" , mpe->reservation_key);
+}
+
+
+static int
snprint_hw_fast_io_fail(char * buff, int len, void * data)
{
struct hwentry * hwe = (struct hwentry *)data;
@@ -2367,6 +2483,12 @@ snprint_def_bindings_file (char * buff,
}

static int
+snprint_def_reservation_key(char * buff, int len, void * data)
+{
+ return snprintf(buff, len, "%s", conf->reservation_key);
+}
+
+static int
snprint_ble_simple (char * buff, int len, void * data)
{
struct blentry * ble = (struct blentry *)data;
@@ -2428,6 +2550,7 @@ init_keywords(void)
install_keyword("fast_io_fail_tmo", &def_fast_io_fail_handler, &snprint_def_fast_io_fail);
install_keyword("dev_loss_tmo", &def_dev_loss_handler, &snprint_def_dev_loss);
install_keyword("bindings_file", &bindings_file_handler, &snprint_def_bindings_file);
+ install_keyword("reservation_key", &def_reservation_key_handler, &snprint_def_reservation_key);
__deprecated install_keyword("default_selector", &def_selector_handler, NULL);
__deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
__deprecated install_keyword("default_getuid_callout", &def_getuid_callout_handler, NULL);
@@ -2510,5 +2633,6 @@ init_keywords(void)
install_keyword("mode", &mp_mode_handler, &snprint_mp_mode);
install_keyword("uid", &mp_uid_handler, &snprint_mp_uid);
install_keyword("gid", &mp_gid_handler, &snprint_mp_gid);
+ install_keyword("reservation_key", &mp_reservation_key_handler, &snprint_mp_reservation_key);
install_sublevel_end();
}
diff -uprN multipath-tools-orig/libmultipath/discovery.c multipath-tools/libmultipath/discovery.c
--- multipath-tools-orig/libmultipath/discovery.c 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/libmultipath/discovery.c 2011-12-19 23:12:10.000000000 +0530
@@ -902,7 +902,7 @@ pathinfo (struct path *pp, vector hwtabl
* fetch info not available through sysfs
*/
if (pp->fd < 0)
- pp->fd = opennode(pp->dev, O_RDONLY);
+ pp->fd = opennode(pp->dev, O_RDWR);

if (pp->fd < 0) {
condlog(4, "Couldn't open node for %s: %s",
diff -uprN multipath-tools-orig/libmultipath/propsel.c multipath-tools/libmultipath/propsel.c
--- multipath-tools-orig/libmultipath/propsel.c 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/libmultipath/propsel.c 2011-12-19 23:12:10.000000000 +0530
@@ -4,6 +4,7 @@
* Copyright (c) 2005 Kiyoshi Ueda, NEC
*/
#include <stdio.h>
+#include <inttypes.h>

#include "checkers.h"
#include "memory.h"
@@ -613,3 +614,46 @@ select_flush_on_last_del(struct multipat
condlog(3, "flush_on_last_del = DISABLED (internal default)");
return 0;
}
+
+extern int
+select_reservation_key (struct multipath * mp)
+{
+ int j;
+ unsigned char *keyp;
+ uint64_t prkey = 0;
+
+ if (mp->mpe && mp->mpe->reservation_key) {
+ keyp = mp->mpe->reservation_key;
+ for (j = 0; j < 8; ++j) {
+ if (j > 0)
+ prkey <<= 8;
+ prkey |= *keyp;
+ ++keyp;
+ }
+
+ condlog(3, "%s: reservation_key = 0x%" PRIx64 " (multipath setting)",
+ mp->alias, prkey);
+
+ mp->reservation_key = mp->mpe->reservation_key;
+ return 0;
+ }
+
+ if (conf->reservation_key) {
+ keyp = conf->reservation_key;
+ for (j = 0; j < 8; ++j) {
+ if (j > 0)
+ prkey <<= 8;
+ prkey |= *keyp;
+ ++keyp;
+ }
+
+ condlog(3, "%s: reservation_key = 0x%" PRIx64 " (config file default)",
+ mp->alias, prkey);
+
+ mp->reservation_key = conf->reservation_key;
+ return 0;
+ }
+
+ return 0;
+}
+
diff -uprN multipath-tools-orig/libmultipath/propsel.h multipath-tools/libmultipath/propsel.h
--- multipath-tools-orig/libmultipath/propsel.h 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/libmultipath/propsel.h 2011-12-19 23:12:09.000000000 +0530
@@ -17,3 +17,5 @@ int select_uid(struct multipath *mp);
int select_gid(struct multipath *mp);
int select_fast_io_fail(struct multipath *mp);
int select_dev_loss(struct multipath *mp);
+int select_reservation_key(struct multipath *mp);
+
diff -uprN multipath-tools-orig/libmultipath/structs.h multipath-tools/libmultipath/structs.h
--- multipath-tools-orig/libmultipath/structs.h 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/libmultipath/structs.h 2011-12-19 23:12:10.000000000 +0530
@@ -211,6 +211,10 @@ struct multipath {

/* checkers shared data */
void * mpcontext;
+ /* persistent management data*/
+ unsigned char * reservation_key;
+ unsigned char prflag;
+
};

struct pathgroup {
diff -uprN multipath-tools-orig/Makefile multipath-tools/Makefile
--- multipath-tools-orig/Makefile 2011-12-19 23:59:55.000000000 +0530
+++ multipath-tools/Makefile 2011-12-19 23:12:06.000000000 +0530
@@ -23,8 +23,10 @@ BUILDDIRS =
libmultipath
libmultipath/prioritizers
libmultipath/checkers
+ libmpathpersist
multipath
multipathd
+ mpathpersist
kpartx

ifeq ($(MULTIPATH_VERSION),)
diff -uprN multipath-tools-orig/Makefile.inc multipath-tools/Makefile.inc
--- multipath-tools-orig/Makefile.inc 2011-12-19 23:59:55.000000000 +0530
+++ multipath-tools/Makefile.inc 2011-12-19 23:12:06.000000000 +0530
@@ -27,10 +27,12 @@ bindir = $(exec_prefix)/sbin
libudevdir = ${prefix}/lib/udev
multipathdir = $(TOPDIR)/libmultipath
mandir = $(prefix)/usr/share/man/man8
+man3dir = $(prefix)/usr/share/man/man3
man5dir = $(prefix)/usr/share/man/man5
rcdir = $(prefix)/etc/init.d
syslibdir = $(prefix)/$(LIB)
libdir = $(prefix)/$(LIB)/multipath
+mpathpersistdir = $(TOPDIR)/libmpathpersist

GZIP = /bin/gzip -9 -c
INSTALL_PROGRAM = install
diff -uprN multipath-tools-orig/multipathd/cli.c multipath-tools/multipathd/cli.c
--- multipath-tools-orig/multipathd/cli.c 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/multipathd/cli.c 2011-12-19 23:12:09.000000000 +0530
@@ -184,6 +184,9 @@ load_keys (void)
r += add_key(keys, "quit", QUIT, 0);
r += add_key(keys, "exit", QUIT, 0);
r += add_key(keys, "shutdown", SHUTDOWN, 0);
+ r += add_key(keys, "getprstatus", GETPRSTATUS, 0);
+ r += add_key(keys, "setprstatus", SETPRSTATUS, 0);
+ r += add_key(keys, "unsetprstatus", UNSETPRSTATUS, 0);

if (r) {
free_keys(keys);
@@ -453,6 +456,9 @@ cli_init (void) {
add_handler(FAIL+PATH, NULL);
add_handler(QUIT, NULL);
add_handler(SHUTDOWN, NULL);
+ add_handler(GETPRSTATUS+MAP, NULL);
+ add_handler(SETPRSTATUS+MAP, NULL);
+ add_handler(UNSETPRSTATUS+MAP, NULL);

return 0;
}
diff -uprN multipath-tools-orig/multipathd/cli.h multipath-tools/multipathd/cli.h
--- multipath-tools-orig/multipathd/cli.h 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/multipathd/cli.h 2011-12-19 23:12:09.000000000 +0530
@@ -29,6 +29,9 @@ enum {
__WILDCARDS,
__QUIT,
__SHUTDOWN,
+ __GETPRSTATUS,
+ __SETPRSTATUS,
+ __UNSETPRSTATUS,
};

#define LIST (1 << __LIST)
@@ -62,6 +65,9 @@ enum {
#define WILDCARDS (1 << __WILDCARDS)
#define QUIT (1 << __QUIT)
#define SHUTDOWN (1 << __SHUTDOWN)
+#define GETPRSTATUS (1 << __GETPRSTATUS)
+#define SETPRSTATUS (1 << __SETPRSTATUS)
+#define UNSETPRSTATUS (1 << __UNSETPRSTATUS)

#define INITIAL_REPLY_LEN 1000

diff -uprN multipath-tools-orig/multipathd/cli_handlers.c multipath-tools/multipathd/cli_handlers.c
--- multipath-tools-orig/multipathd/cli_handlers.c 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/multipathd/cli_handlers.c 2011-12-20 00:11:45.000000000 +0530
@@ -883,3 +883,76 @@ cli_shutdown (void * v, char ** reply, i

return exit_daemon(0);
}
+
+int
+cli_getprstatus (void * v, char ** reply, int * len, void * data)
+{
+ struct multipath * mpp;
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, MAP);
+
+ get_path_layout(vecs->pathvec, 0);
+ mpp = find_mp_by_str(vecs->mpvec, param);
+
+ if (!mpp)
+ return 1;
+
+ condlog(3, "%s: prflag = %u", param, (unsigned int)mpp->prflag);
+
+ *reply =(char *)malloc(2);
+ *len = 2;
+ memset(*reply,0,2);
+
+
+ sprintf(*reply,"%d",mpp->prflag);
+ *reply[1]='';
+
+
+ condlog(3, "%s: reply = %s", param, *reply);
+
+ return 0;
+}
+
+int
+cli_setprstatus(void * v, char ** reply, int * len, void * data)
+{
+ struct multipath * mpp;
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, MAP);
+
+ get_path_layout(vecs->pathvec, 0);
+ mpp = find_mp_by_str(vecs->mpvec, param);
+
+ if (!mpp)
+ return 1;
+
+ if (!mpp->prflag) {
+ mpp->prflag = 1;
+ condlog(2, "%s: prflag is set", param);
+ }
+
+
+ return 0;
+}
+
+int
+cli_unsetprstatus(void * v, char ** reply, int * len, void * data)
+{
+ struct multipath * mpp;
+ struct vectors * vecs = (struct vectors *)data;
+ char * param = get_keyparam(v, MAP);
+
+ get_path_layout(vecs->pathvec, 0);
+ mpp = find_mp_by_str(vecs->mpvec, param);
+
+ if (!mpp)
+ return 1;
+
+ if (mpp->prflag) {
+ mpp->prflag = 0;
+ condlog(2, "%s: prflag is unset", param);
+ }
+
+ return 0;
+}
+
diff -uprN multipath-tools-orig/multipathd/cli_handlers.h multipath-tools/multipathd/cli_handlers.h
--- multipath-tools-orig/multipathd/cli_handlers.h 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/multipathd/cli_handlers.h 2011-12-20 00:11:45.000000000 +0530
@@ -31,3 +31,7 @@ int cli_fail(void * v, char ** reply, in
int cli_quit(void * v, char ** reply, int * len, void * data);
int cli_shutdown(void * v, char ** reply, int * len, void * data);
int cli_reassign (void * v, char ** reply, int * len, void * data);
+int cli_getprstatus(void * v, char ** reply, int * len, void * data);
+int cli_setprstatus(void * v, char ** reply, int * len, void * data);
+int cli_unsetprstatus(void * v, char ** reply, int * len, void * data);
+
diff -uprN multipath-tools-orig/multipathd/main.c multipath-tools/multipathd/main.c
--- multipath-tools-orig/multipathd/main.c 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/multipathd/main.c 2011-12-20 00:11:45.000000000 +0530
@@ -15,6 +15,7 @@
#include <sys/time.h>
#include <sys/resource.h>
#include <limits.h>
+#include <mpath_persist.h>

/*
* libcheckers
@@ -65,6 +66,12 @@
#define LOG_MSG(a,b)
if (strlen(b)) condlog(a, "%s: %s - %s", pp->mpp->alias, pp->dev, b);

+struct mpath_event_param
+{
+ char * devname;
+ struct multipath *mpp;
+};
+
pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER;

@@ -460,6 +467,9 @@ rescan:
goto fail; /* leave path added to pathvec */
}

+ /* persistent reseravtion check*/
+ mpath_pr_event_handle(pp);
+
/*
* push the map to the device-mapper
*/
@@ -861,6 +871,9 @@ uxlsnrloop (void * ap)
set_handler_callback(RESTOREQ+MAPS, cli_restore_all_queueing);
set_handler_callback(QUIT, cli_quit);
set_handler_callback(SHUTDOWN, cli_shutdown);
+ set_handler_callback(GETPRSTATUS+MAP, cli_getprstatus);
+ set_handler_callback(SETPRSTATUS+MAP, cli_setprstatus);
+ set_handler_callback(UNSETPRSTATUS+MAP, cli_unsetprstatus);

umask(077);
uxsock_listen(&uxsock_trigger, ap);
@@ -1139,6 +1152,16 @@ check_path (struct vectors * vecs, struc
return;
}

+ if(newstate == PATH_UP || newstate == PATH_GHOST){
+ if ( pp->mpp && pp->mpp->prflag ){
+ /*
+ * Check Persistent Reservation.
+ */
+ condlog(2, "%s: checking persistent reservation registration", pp->dev);
+ mpath_pr_event_handle(pp);
+ }
+ }
+
/*
* reinstate this path
*/
@@ -1303,6 +1326,10 @@ configure (struct vectors * vecs, int st

sync_maps_state(mpvec);

+ vector_foreach_slot(mpvec, mpp, i){
+ update_map_pr(mpp);
+ }
+
/*
* purge dm of old maps
*/
@@ -1789,3 +1816,127 @@ main (int argc, char *argv[])
return (child(NULL));
}

+void * mpath_pr_event_handler_fn (void * pathp )
+{
+ struct multipath * mpp;
+ int i,j, ret, isFound;
+ char dev[FILE_NAME_SIZE];
+ int fd;
+ struct path * pp = (struct path *)pathp;
+ unsigned char *keyp;
+ uint64_t prkey;
+ struct prout_param_descriptor *param;
+ struct prin_resp *resp;
+
+ mpp = pp->mpp;
+ resp = mpath_alloc_prin_response(MPATH_PRIN_RKEY_SA);
+ if (!resp){
+ condlog(0,"%s Alloc failed for prin response
", pp->dev);
+ return NULL;
+ }
+
+ condlog(3, "device %s:%s
", pp->dev, pp->mpp->wwid);
+ snprintf(dev, FILE_NAME_SIZE, "/dev/%s", pp->dev);
+
+ fd = open(dev, O_RDWR);
+ if(fd < 0){
+ condlog(0, "Unable to open device %s:%s
", pp->mpp->wwid, dev);
+ free(resp);
+ return NULL;
+ }
+
+ ret = prin_do_scsi_ioctl(fd, MPATH_PRIN_RKEY_SA, resp, 0);
+ if (ret != MPATH_PR_SUCCESS )
+ {
+ condlog(0,"%s : PR IN Read keys Service Action Failed Error=%d
", pp->dev, ret);
+ goto out;
+ }
+
+ condlog(3, " event pr=%d addlen=%d
",resp->prin_descriptor.prin_readkeys.prgeneration,
+ resp->prin_descriptor.prin_readkeys.additional_length );
+
+ if (resp->prin_descriptor.prin_readkeys.additional_length == 0 )
+ {
+ condlog(1, "%s: No key found. Device may not be registered.", pp->dev);
+ ret = MPATH_PR_SUCCESS;
+ goto out;
+ }
+ if ( mpp->reservation_key )
+ {
+ prkey = 0;
+ keyp = (unsigned char *)mpp->reservation_key;
+ for (j = 0; j < 8; ++j) {
+ if (j > 0)
+ prkey <<= 8;
+ prkey |= *keyp;
+ ++keyp;
+ }
+ condlog(2, "Multipath reservation_key: 0x%" PRIx64 " ", prkey);
+ }
+ else
+ {
+ condlog(0, " reservation_key not set in multiapth.conf");
+ ret = MPATH_PR_DMMP_ERROR;
+ goto out;
+ }
+ isFound =0;
+ for (i = 0; i < resp->prin_descriptor.prin_readkeys.additional_length/8; i++ )
+ {
+ condlog(2, "PR IN READKEYS[%d] reservation key:
",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: pr key found in prin readkeys response", mpp->alias);
+ isFound =1;
+ break;
+ }
+ }
+ if (!isFound)
+ {
+ condlog(0, "%s: Either device not registered or ", pp->dev);
+ condlog(0, "host is not authorised for registration. Skip path
");
+ ret = MPATH_PR_OTHER;
+ goto out;
+ }
+
+ param= malloc(sizeof(struct prout_param_descriptor));
+ memset(param, 0 , sizeof(struct prout_param_descriptor));
+
+ for (j = 7; j >= 0; --j) {
+ param->sa_key[j] = (prkey & 0xff);
+ prkey >>= 8;
+ }
+ param->num_transportid = 0;
+
+ ret = prout_do_scsi_ioctl(fd, MPATH_PROUT_REG_IGN_SA, 0, 0, param, 0);
+ if (ret != MPATH_PR_SUCCESS )
+ {
+ condlog(0,"%s: Reservation registration failed. Error: %d
", pp->dev, ret);
+ }
+ mpp->prflag = 1;
+
+ free(param);
+out:
+ free(resp);
+ close(fd);
+ return NULL;
+}
+int mpath_pr_event_handle(struct path *pp)
+{
+ pthread_t thread;
+ int rc;
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ rc = pthread_create(&thread, NULL , mpath_pr_event_handler_fn, pp);
+ if (rc) {
+ condlog(0, "%s: ERROR; return code from pthread_create() is %d
", pp->dev, rc);
+ return 0;
+ }
+ pthread_attr_destroy(&attr);
+ rc = pthread_join(thread, NULL);
+ return 0;
+}
+
diff -uprN multipath-tools-orig/multipathd/main.h multipath-tools/multipathd/main.h
--- multipath-tools-orig/multipathd/main.h 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/multipathd/main.h 2011-12-19 23:12:09.000000000 +0530
@@ -12,6 +12,8 @@ enum daemon_status {
};

extern pid_t daemon_pid;
+struct prout_param_descriptor;
+struct prin_resp;

int exit_daemon(int);
const char * daemon_status(void);
@@ -22,4 +24,16 @@ int ev_add_map (char *, char *, struct v
int ev_remove_map (char *, char *, int, struct vectors *);
void sync_map_state (struct multipath *);

+void * mpath_alloc_prin_response(int prin_sa);
+int prin_do_scsi_ioctl(int fd, int rq_servact, struct prin_resp * resp,
+ int noisy);
+void dumpHex(const char* , int len, int no_ascii);
+int prout_do_scsi_ioctl( int fd, int rq_servact, int rq_scope,
+ unsigned int rq_type, struct prout_param_descriptor *param,
+ int noisy);
+int mpath_pr_event_handle(struct path *pp);
+void * mpath_pr_event_handler_fn (void * );
+int update_map_pr(struct multipath *mpp);
+void * mpath_pr_event_handler_fn (void * pathp );
+
#endif /* MAIN_H */
diff -uprN multipath-tools-orig/multipathd/Makefile multipath-tools/multipathd/Makefile
--- multipath-tools-orig/multipathd/Makefile 2011-12-19 23:59:58.000000000 +0530
+++ multipath-tools/multipathd/Makefile 2011-12-19 23:12:09.000000000 +0530
@@ -5,9 +5,9 @@ include ../Makefile.inc
#
# basic flags setting
#
-CFLAGS += -I$(multipathdir)
+CFLAGS += -I$(multipathdir) -I$(mpathpersistdir)
LDFLAGS += -lpthread -ldevmapper -lreadline -lncurses -ldl
- -L$(multipathdir) -lmultipath
+ -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist

#
# debuging stuff


--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 
Old 12-19-2011, 03:35 PM
"Chauhan, Vijay"
 
Default persistent management feature for multipath-tools

This patch fixes the 32 fingerprint limit for multipathd cli.

Signed-off-by: Vijay Chauhan <Vijay.chauhan@netapp.com>

---
diff -uprN multipath-tools-patched2/multipathd/cli.c multipath-tools/multipathd/cli.c
--- multipath-tools-patched2/multipathd/cli.c 2011-12-18 02:25:43.000000000 -0500
+++ multipath-tools/multipathd/cli.c 2011-12-18 02:26:09.000000000 -0500
@@ -26,7 +26,7 @@ alloc_handler (void)
}

static int
-add_key (vector vec, char * str, int code, int has_param)
+add_key (vector vec, char * str, unsigned long code, int has_param)
{
struct key * kw;

@@ -57,7 +57,7 @@ out:
}

int
-add_handler (int fp, int (*fn)(void *, char **, int *, void *))
+add_handler (unsigned long fp, int (*fn)(void *, char **, int *, void *))
{
struct handler * h;

@@ -92,7 +92,7 @@ find_handler (int fp)
}

int
-set_handler_callback (int fp, int (*fn)(void *, char **, int *, void *))
+set_handler_callback (unsigned long fp, int (*fn)(void *, char **, int *, void *))
{
struct handler * h = find_handler(fp);

diff -uprN multipath-tools-patched2/multipathd/cli.h multipath-tools/multipathd/cli.h
--- multipath-tools-patched2/multipathd/cli.h 2011-12-18 02:25:43.000000000 -0500
+++ multipath-tools/multipathd/cli.h 2011-12-18 02:26:09.000000000 -0500
@@ -65,9 +65,9 @@ enum {
#define WILDCARDS (1 << __WILDCARDS)
#define QUIT (1 << __QUIT)
#define SHUTDOWN (1 << __SHUTDOWN)
-#define GETPRSTATUS (1 << __GETPRSTATUS)
-#define SETPRSTATUS (1 << __SETPRSTATUS)
-#define UNSETPRSTATUS (1 << __UNSETPRSTATUS)
+#define GETPRSTATUS (1 << __GETPRSTATUS)
+#define SETPRSTATUS (1 << __SETPRSTATUS)
+#define UNSETPRSTATUS (1UL << __UNSETPRSTATUS)

#define INITIAL_REPLY_LEN 1000

@@ -84,8 +84,8 @@ struct handler {
};

int alloc_handlers (void);
-int add_handler (int fp, int (*fn)(void *, char **, int *, void *));
-int set_handler_callback (int fp, int (*fn)(void *, char **, int *, void *));
+int add_handler (unsigned long fp, int (*fn)(void *, char **, int *, void *));
+int set_handler_callback (unsigned long fp, int (*fn)(void *, char **, int *, void *));
int parse_cmd (char * cmd, char ** reply, int * len, void *);
int load_keys (void);
char * get_keyparam (vector v, int code);

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 
Old 12-19-2011, 05:28 PM
"Chauhan, Vijay"
 
Default persistent management feature for multipath-tools

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@netapp.com>
Reviewed-by: Bob Stankey <Robert.stankey@netapp.com>
Reviewed-by: Babu Moger <Babu.moger@netapp.com>
Reviewed-by: Yanling Q <Yanling.Q@netapp.com>

---
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_leng th / 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_descripto r;
+ 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_descripto r)
+ {
+ return ;
+ }
+
+
+ if (pr_buff->prin_descriptor.prin_readfd.number_of_descripto r == 0)
+ {
+ condlog(2, "No registration or resrvation found.");
+ return;
+ }
+
+ additional_length = pr_buff->prin_descriptor.prin_readfd.number_of_descripto r;
+
+ 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_descripto r = 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
" : "%.56s
";
+ memset(buff, ' ', 80);
+ buff[80] = '';
+ 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] = '';
+ if (log)
+ condlog(0, "%s", buff);
+ else
+ printf("%s
" , 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.
 
Old 12-20-2011, 12:30 PM
"Chauhan, Vijay"
 
Default persistent management feature for multipath-tools

Mike,

Thanks for your comment. I will take care of it from next post.

Regards,
Vijay

On Tue, Dec 20, 2011 at 1:08 AM, Mike Snitzer <snitzer@redhat.com> wrote:
>Why don't your patches have distinct subjects?
>
>Also wrapping the 0th patch summary and patch headers of your messages
>to ~80-100 characters would be helpful.
>
>And providing stats in your patches would be ideal (allows high-level
>view of which files are touched by a patch), e.g. 'git format-patch' or
>'git diff -p --stat'.
>
>Anyway, thanks for working on this.
>
>Mike

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 
Old 12-20-2011, 12:35 PM
"Chauhan, Vijay"
 
Default persistent management feature for multipath-tools

On Tue, Dec 20, 2011 at 3:46 AM, Christophe Varoqui <christophe.varoqui@gmail.com> wrote:
>On lun., 2011-12-19 at 22:04 +0530, Chauhan, Vijay wrote:
>>
>Persistent reservation is a path-centric command set. I don't see
>clearly the benefit of folding (obfuscating?) it into the multipath
>layer.

Christophe, Thanks for your comments.
Yes, I agree. The persistent reservation model specified by T10 SPC defines that volume reservation should be identified by I_T nexuses. And also multipath layer well knows about the mapping between physical path and mpath device.

In addition, dynamic addition/deletion and path state change of physical paths are other complexities that could be handled in multipath layer effectively.

>
>Saving a few command lines ? I don't think there are wild admins playing
>with PR without a clustering toolkit out there, so the tricky command
>lines don't really matter.

I did not mean that this feature replaces clustering toolkit rather this feature supports clustering toolkit (which usages mpath device) by hiding complexities in multipath layer as mentioned above. Can you please be more specific if you are referring to any drawback using this feature?

>
>I do maintain a clustering toolkit that handles PR, and I know this
>feature would add code (multipath specific), not remove the current more
>generic code.
>
While implementing this feature, we have tried be generic which could work with other cluster solutions as well. If you still feel there is any scope of improvement then I can work on it. Your feedback with use-cases would be helpful.

>I also realize some other multipath implementations (PowerPath for one)
>propose that feature. I'm curious to know the motivation.
>
We are successfully using feature with one of the cluster solution and thought of posting it to this forum if it could benefit others as well as being a generic implementation.

>Am I the only one on the list thinking along this line ? Anyway, I have
>no hard feelings against this work.
>
>Best regards,
>Christophe Varoqui
>
>>
>> This feature enables mpath device to be used with cluster application.

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
 
Old 12-23-2011, 11:53 AM
"Chauhan, Vijay"
 
Default persistent management feature for multipath-tools

On Tue, Dec 20, 2011 at 9:03 PM, Hannes Reinecke <hare@suse.de> wrote:
>On 12/19/2011 11:16 PM, Christophe Varoqui wrote:
>> On lun., 2011-12-19 at 22:04 +0530, Chauhan, Vijay wrote:
>>> PERSISTENT RESERVE OUT/IN commands are currently not supported on
>mpath device. Any command sent to mpath device is routed to only one of
>the physical path (selected by path selector) from the active path
>group. PR OUT registration service action is one of the such use-case
>which fails as it expects all the physical path for the given mpath
>device to be registered. Due to these limitations, most of the cluster
>applications needs to manage persistent reservation through underlying
>physical path.
>>>
>> Persistent reservation is a path-centric command set. I don't see
>> clearly the benefit of folding (obfuscating?) it into the multipath
>> layer.
>>
>Agree. Persistent reservations is not something multipath should be
>handling internally. It'll just add functionality without any
>immediate gain.
>Plus we'd be incurring a support nightmare here.
>
>However, adding a _separate_ program for handling persistent
>reservations definitely would be a bonus, as this program could
>access multipath internals not otherwise accessible.
>And the integration into multipath doesn't gain us anything here;
>it's just used to figure out onto which paths PR should be updated.
>
>> Saving a few command lines ? I don't think there are wild admins
>playing
>> with PR without a clustering toolkit out there, so the tricky command
>> lines don't really matter.
>>
>Beg to disagree. 'Tricky command lines' are not the problem;
>figuring out multipath details (with the ever-changing output)
>definitely _is_.
>
>> I do maintain a clustering toolkit that handles PR, and I know this
>> feature would add code (multipath specific), not remove the current
>more
>> generic code.
>>
>> I also realize some other multipath implementations (PowerPath for
>one)
>> propose that feature. I'm curious to know the motivation.
>>
>> Am I the only one on the list thinking along this line ? Anyway, I
>have
>> no hard feelings against this work.
>>
>As did we, trying to implement a HA agent with persistent
>reservations :-)
>
>And hence I would definitely be glad having a tool setting
>persistent reservations on a multipathed device.
>Only I don't thing it should be built-into multipath itself.

Hannes, Thanks for your comment. Yes, I agree.

>
>Much like kpartx: you definitely need the functionality, but this
>functionality doesn't need to be part of multipath proper.

A new cli utility 'mpathpersist' and library 'libmpathpersist.so'
is introduced with this feature.

To elaborate on each component functionality:

mpathpersist cli is responsible for validating user inputs
& configuration and finally calls libmpathpersist.so library
APIs to perform pr management.

libmpathpersist.so library has all the intelligence for
retrieving multipath information and performing persistent
reservation on multipath device.

multipathd also uses libmpathpersist.so API's for handling
persistent reservation on new path discovery and path reinstated.

Also to be noted that this feature can be disabled in multipathd if
reservation_key keyword is not mentioned multipath.conf.

mpathpersist cli multipathd
| |
|- calls lib API |- Calls lib API for
| for PR management | new path discovery
! | or path reinstated
V |
libmpathpersist.so <------------!
Library --------------------------> libmultipath.so
- uses libmultipath library
for finding multipath details

Is this something similar you are proposing? If not then can
you please give more insight for my understanding.


Currently I am working on the fix for Mike Snitzer's review
comments and will resend these patches.

Diff stat below indicates the newly added and modified files
in multipath tools package:
Makefile | 2 +
Makefile.inc | 2 +
libmpathpersist/Makefile | 51 ++
libmpathpersist/mpath_persist.c | 897 ++++++++++++++++++++++++
libmpathpersist/mpath_persist.h | 241 +++++++
libmpathpersist/mpath_persistent_reserve_in.3 | 80 +++
libmpathpersist/mpath_persistent_reserve_out.3 | 92 +++
libmpathpersist/mpath_pr_ioctl.c | 572 +++++++++++++++
libmpathpersist/mpath_pr_ioctl.h | 111 +++
libmpathpersist/mpath_updatepr.c | 50 ++
libmpathpersist/mpathpr.h | 55 ++
libmultipath/config.h | 2 +
libmultipath/configure.c | 1 +
libmultipath/dict.c | 124 ++++
libmultipath/discovery.c | 2 +-
libmultipath/propsel.c | 44 ++
libmultipath/propsel.h | 2 +
libmultipath/structs.h | 4 +
mpathpersist/Makefile | 30 +
mpathpersist/main.c | 808 +++++++++++++++++++++
mpathpersist/main.h | 28 +
mpathpersist/mpathpersist.8 | 96 +++
multipathd/Makefile | 4 +-
multipathd/cli.c | 12 +-
multipathd/cli.h | 10 +-
multipathd/cli_handlers.c | 73 ++
multipathd/cli_handlers.h | 4 +
multipathd/main.c | 151 ++++
multipathd/main.h | 14 +
29 files changed, 3554 insertions(+), 8 deletions(-)

Thanks,
Vijay

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

Thread Tools




All times are GMT. The time now is 04:59 PM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright 2007 - 2008, www.linux-archive.org