File multipath-tools-git-update of Package multipath-tools

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5ef5aec
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+*.o
+.dotest
+*~
+*.so
+*.a
+*.gz
+kpartx
+multipath
+multipathd
diff --git a/Makefile b/Makefile
index ee554e7..54be0a5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,7 @@
 # Makefile
 #
 # Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
-
-BUILD = glibc
+#
 
 #
 # Try to supply the linux kernel headers.
@@ -20,7 +19,13 @@ endif
 export KRNLSRC
 export KRNLOBJ
 
-BUILDDIRS = $(shell find . -mindepth 2 -name Makefile -exec dirname {} \; | grep -vE '^lib|/\.')
+BUILDDIRS = \
+	libmultipath \
+	libmultipath/prioritizers \
+	libmultipath/checkers \
+	multipath \
+	multipathd \
+	kpartx
 
 ifeq   ($(MULTIPATH_VERSION),)
 VERSION = $(shell basename ${PWD} | cut -d'-' -f3)
diff --git a/Makefile.inc b/Makefile.inc
index 7e2d4e6..3e5bca0 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -13,31 +13,22 @@ ifeq ($(TOPDIR),)
 	TOPDIR	= ..
 endif
 
-ifeq ($(strip $(BUILD)),klibc)
-	CC = klcc
-	klibcdir = /usr/lib/klibc
-	libdm    = $(klibcdir)/lib/libdevmapper.a
-endif
-
 prefix      = 
 exec_prefix = $(prefix)
 bindir      = $(exec_prefix)/sbin
 libudevdir  = ${prefix}/lib/udev
-checkersdir = $(TOPDIR)/libcheckers
 multipathdir = $(TOPDIR)/libmultipath
 mandir      = $(prefix)/usr/share/man/man8
 man5dir     = $(prefix)/usr/share/man/man5
 rcdir	    = $(prefix)/etc/init.d
+libdir	    = $(prefix)/lib/multipath
 
 GZIP        = /bin/gzip -9 -c
-
-CHECKERSLIB = $(checkersdir)/libcheckers
-MULTIPATHLIB = $(multipathdir)/libmultipath
-
-INSTALL_PROGRAM = install -s
+INSTALL_PROGRAM = install
 
 OPTFLAGS     = -pipe -g -Wall -Wunused -Wstrict-prototypes
-CFLAGS	     = $(OPTFLAGS)
+CFLAGS	     = $(OPTFLAGS) -fPIC
+SHARED_FLAGS = -shared
 
 %.o:	%.c
 	$(CC) $(CFLAGS) -c -o $@ $<
diff --git a/devmap_name/Makefile b/devmap_name/Makefile
deleted file mode 100644
index d8d8b09..0000000
--- a/devmap_name/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-# Makefile
-#
-# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
-BUILD = glibc
-
-include ../Makefile.inc
-
-OBJS = devmap_name.o
-
-ifeq ($(strip $(BUILD)),klibc)
-	OBJS += $(libdm)
-else
-	LDFLAGS = -ldevmapper
-endif
-
-EXEC = devmap_name
-
-all: $(BUILD)
-
-prepare:
-	rm -f core *.o *.gz
-
-glibc: prepare $(OBJS)
-	$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
-	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
-
-klibc: prepare $(OBJS)
-	$(CC) -static -o $(EXEC) $(OBJS)
-	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
-
-install: $(EXEC) $(EXEC).8
-	install -d $(DESTDIR)$(bindir)
-	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/
-	install -d $(DESTDIR)$(mandir)
-	install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
-
-uninstall:
-	rm $(DESTDIR)$(bindir)/$(EXEC)
-	rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
-
-clean:
-	rm -f core *.o $(EXEC) *.gz
diff --git a/devmap_name/devmap_name.8 b/devmap_name/devmap_name.8
deleted file mode 100644
index 86d0931..0000000
--- a/devmap_name/devmap_name.8
+++ /dev/null
@@ -1,30 +0,0 @@
-.TH DEVMAP_NAME 8 "July 2006" "" "Linux Administrator's Manual"
-.SH NAME
-devmap_name \- Query device-mapper name
-.SH SYNOPSIS
-.BI devmap_name " major minor"
-.SH DESCRIPTION
-.B devmap_name
-queries the device-mapper for the name for the device
-specified by
-.I major
-and
-.I minor
-number.
-.br
-.B devmap_name
-can be called from
-.B udev
-by the following rule in
-.IR /etc/udev/udev.rules :
-.sp
-.nf
-KERNEL="dm-[0-9]*", PROGRAM="/sbin/devmap_name %M %m", \\
-	NAME="%k", SYMLINK="%c"
-.fi
-.SH "SEE ALSO"
-.BR udev (8),
-.BR dmsetup (8)
-.SH AUTHORS
-.B devmap_name
-was developed by Christophe Varoqui, <christophe.varoqui@free.fr> and others.
diff --git a/devmap_name/devmap_name.c b/devmap_name/devmap_name.c
deleted file mode 100644
index 525c348..0000000
--- a/devmap_name/devmap_name.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2004, 2005 Christophe Varoqui
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <linux/kdev_t.h>
-#include <libdevmapper.h>
-
-static void usage(char * progname) {
-	fprintf(stderr, "usage : %s [-t target type] dev_t\n", progname);
-	fprintf(stderr, "where dev_t is either 'major minor' or 'major:minor'\n");
-	exit(1);
-}
-
-int dm_target_type(int major, int minor, char *type)
-{
-	struct dm_task *dmt;
-	void *next = NULL;
-	uint64_t start, length;
-	char *target_type = NULL;
-	char *params;
-	int r = 1;
-
-	if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
-		return 1;
-
-	if (!dm_task_set_major(dmt, major) ||
-	    !dm_task_set_minor(dmt, minor))
-		goto bad;
-
-	dm_task_no_open_count(dmt);
-
-	if (!dm_task_run(dmt))
-		goto bad;
-
-	if (!type)
-		goto good;
-
-	do {
-		next = dm_get_next_target(dmt, next, &start, &length,
-					  &target_type, &params);
-		if (target_type && strcmp(target_type, type))
-			goto bad;
-	} while (next);
-
-good:
-	printf("%s\n", dm_task_get_name(dmt));
-	r = 0;
-bad:
-	dm_task_destroy(dmt);
-	return r;
-}
-
-int main(int argc, char **argv)
-{
-	int c;
-	int major, minor;
-	char *target_type = NULL;
-
-	while ((c = getopt(argc, argv, "t:")) != -1) {
-		switch (c) {
-		case 't':
-			target_type = optarg;
-			break;
-		default:
-			usage(argv[0]);
-			return 1;
-			break;
-		}
-	}
-
-	/* sanity check */
-	if (optind == argc - 2) {
-		major = atoi(argv[argc - 2]);
-		minor = atoi(argv[argc - 1]);
-	} else if (optind != argc - 1 ||
-		   2 != sscanf(argv[argc - 1], "%i:%i", &major, &minor))
-		usage(argv[0]);
-
-	if (dm_target_type(major, minor, target_type))
-		return 1;
-                                                                                
-	return 0;
-}
-
diff --git a/kpartx/Makefile b/kpartx/Makefile
index b4cca6c..21e4ad4 100644
--- a/kpartx/Makefile
+++ b/kpartx/Makefile
@@ -2,49 +2,30 @@
 #
 # Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
 #
-BUILD=glibc
-
 include ../Makefile.inc
 
 CFLAGS += -I. -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
 
-ifeq ($(strip $(BUILD)),klibc)
-	OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o gpt.o crc32.o \
-	       lopart.o xstrncpy.o devmapper.o dasd.o mac.o sun.o \
-	       $(MULTIPATHLIB)-$(BUILD).a $(libdm)
-else
-	LDFLAGS = -ldevmapper
-	OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o dasd.o sun.o \
-	       gpt.o mac.o crc32.o lopart.o xstrncpy.o devmapper.o
-endif
-
+LDFLAGS = -ldevmapper
+OBJS = bsd.o dos.o kpartx.o solaris.o unixware.o dasd.o sun.o \
+       gpt.o mac.o crc32.o lopart.o xstrncpy.o devmapper.o
 EXEC = kpartx
 
-all: $(BUILD)
-
-prepare:
-	rm -f core *.o *.gz
+all: $(EXEC)
 
-glibc: prepare $(OBJS)
+$(EXEC): $(OBJS)
 	$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
 	
-klibc: prepare $(OBJS)
-	$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
-	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
-
-$(MULTIPATHLIB)-$(BUILD).a:
-	make -C $(multipathdir) BUILD=$(BUILD)
-
 install: $(EXEC) $(EXEC).8
-	install -d $(DESTDIR)$(bindir)
+	$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
 	$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)
-	install -d $(DESTDIR)$(libudevdir)
-	install -m 755 kpartx_id $(DESTDIR)$(libudevdir)
-	install -d $(DESTDIR)/etc/udev/rules.d
-	install -m 644 kpartx.rules $(DESTDIR)/etc/udev/rules.d/
-	install -d $(DESTDIR)$(mandir)
-	install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
+	$(INSTALL_PROGRAM) -d $(DESTDIR)$(libudevdir)
+	$(INSTALL_PROGRAM) -m 755 kpartx_id $(DESTDIR)$(libudevdir)
+	$(INSTALL_PROGRAM) -d $(DESTDIR)/etc/udev/rules.d
+	$(INSTALL_PROGRAM) -m 644 kpartx.rules $(DESTDIR)/etc/udev/rules.d/
+	$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)
+	$(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
 
 uninstall:
 	rm -f $(DESTDIR)$(bindir)/$(EXEC)
diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c
index 6e3e198..893d6dd 100644
--- a/kpartx/devmapper.c
+++ b/kpartx/devmapper.c
@@ -4,10 +4,12 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdint.h>
 #include <libdevmapper.h>
 #include <ctype.h>
 #include <linux/kdev_t.h>
 #include <errno.h>
+#include "devmapper.h"
 
 #define UUID_PREFIX "part%d-"
 #define MAX_PREFIX_LEN 8
@@ -72,10 +74,10 @@ dm_simplecmd (int task, const char *name) {
 
 extern int
 dm_addmap (int task, const char *name, const char *target,
-	   const char *params, unsigned long size, const char *uuid, int part) {
+	   const char *params, uint64_t size, const char *uuid, int part) {
 	int r = 0;
 	struct dm_task *dmt;
-	char *prefixed_uuid;
+	char *prefixed_uuid = NULL;
 
 	if (!(dmt = dm_task_create (task)))
 		return 0;
diff --git a/kpartx/devmapper.h b/kpartx/devmapper.h
index ccdbead..2bd27d2 100644
--- a/kpartx/devmapper.h
+++ b/kpartx/devmapper.h
@@ -1,7 +1,7 @@
 int dm_prereq (char *, int, int, int);
 int dm_simplecmd (int, const char *);
-int dm_addmap (int, const char *, const char *, const char *, unsigned long,
-	       char *, int);
+int dm_addmap (int, const char *, const char *, const char *, uint64_t,
+	       const char *, int);
 int dm_map_present (char *);
 char * dm_mapname(int major, int minor);
 dev_t dm_get_first_dep(char *devname);
diff --git a/kpartx/gpt.c b/kpartx/gpt.c
index dc846ca..047a829 100644
--- a/kpartx/gpt.c
+++ b/kpartx/gpt.c
@@ -36,6 +36,7 @@
 #include <errno.h>
 #include <endian.h>
 #include <byteswap.h>
+#include <linux/fs.h>
 #include "crc32.h"
 
 #if BYTE_ORDER == LITTLE_ENDIAN
@@ -50,10 +51,18 @@
 #  define __cpu_to_le32(x) bswap_32(x)
 #endif
 
+#ifndef BLKGETLASTSECT
 #define BLKGETLASTSECT  _IO(0x12,108)   /* get last sector of block device */
+#endif
+#ifndef BLKGETSIZE
 #define BLKGETSIZE _IO(0x12,96)	        /* return device size */
+#endif
+#ifndef BLKSSZGET
 #define BLKSSZGET  _IO(0x12,104)	/* get block device sector size */
+#endif
+#ifndef BLKGETSIZE64
 #define BLKGETSIZE64 _IOR(0x12,114,sizeof(uint64_t))	/* return device size in bytes (u64 *arg) */
+#endif
 
 struct blkdev_ioctl_param {
         unsigned int block;
@@ -143,20 +152,14 @@ get_sector_size(int filedes)
 static uint64_t
 _get_num_sectors(int filedes)
 {
-	unsigned long sectors=0;
 	int rc;
-#if 0
-        uint64_t bytes=0;
+	uint64_t bytes=0;
 
- 	rc = ioctl(filedes, BLKGETSIZE64, &bytes);
+	rc = ioctl(filedes, BLKGETSIZE64, &bytes);
 	if (!rc)
 		return bytes / get_sector_size(filedes);
-#endif
-        rc = ioctl(filedes, BLKGETSIZE, &sectors);
-        if (rc)
-                return 0;
-        
-	return sectors;
+
+	return 0;
 }
 
 /************************************************************
@@ -193,7 +196,7 @@ last_lba(int filedes)
 		sectors = 1;
 	}
 
-	return sectors - 1;
+	return sectors ? sectors - 1 : 0;
 }
 
 
@@ -220,17 +223,22 @@ read_lba(int fd, uint64_t lba, void *buffer, size_t bytes)
 {
 	int sector_size = get_sector_size(fd);
 	off_t offset = lba * sector_size;
+	uint64_t lastlba;
         ssize_t bytesread;
 
 	lseek(fd, offset, SEEK_SET);
 	bytesread = read(fd, buffer, bytes);
 
+	lastlba = last_lba(fd);
+	if (!lastlba)
+		return bytesread;
+
         /* Kludge.  This is necessary to read/write the last
            block of an odd-sized disk, until Linux 2.5.x kernel fixes.
            This is only used by gpt.c, and only to read
            one sector, so we don't have to be fancy.
         */
-        if (!bytesread && !(last_lba(fd) & 1) && lba == last_lba(fd)) {
+        if (!bytesread && !(lastlba & 1) && lba == lastlba) {
                 bytesread = read_lastoddsector(fd, lba, buffer, bytes);
         }
         return bytesread;
@@ -505,7 +513,8 @@ find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
 	if (!gpt || !ptes)
 		return 0;
 
-	lastlba = last_lba(fd);
+	if (!(lastlba = last_lba(fd)))
+		return 0;
 	good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA,
 				 &pgpt, &pptes);
         if (good_pgpt) {
diff --git a/kpartx/kpartx.8 b/kpartx/kpartx.8
index 87b07ce..c61f312 100644
--- a/kpartx/kpartx.8
+++ b/kpartx/kpartx.8
@@ -26,6 +26,9 @@ List partition mappings that would be added -a
 .B \-p
 set device name-partition number delimiter
 .TP
+.B \-g
+force GUID partition table (GPT)
+.TP
 .B \-v
 Operate verbosely
 .SH "SEE ALSO"
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
index dbe2ee2..8658731 100644
--- a/kpartx/kpartx.c
+++ b/kpartx/kpartx.c
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <stdint.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <ctype.h>
@@ -82,7 +83,7 @@ initpts(void)
 	addpts("sun", read_sun_pt);
 }
 
-static char short_opts[] = "ladgvnp:t:";
+static char short_opts[] = "ladgvp:t:";
 
 /* Used in gpt.c */
 int force_gpt=0;
@@ -94,6 +95,7 @@ usage(void) {
 	printf("\t-d del partition devmappings\n");
 	printf("\t-l list partitions devmappings that would be added by -a\n");
 	printf("\t-p set device name-partition number delimiter\n");
+	printf("\t-g force GUID partition table (GPT)\n");
 	printf("\t-v verbose\n");
 	return 1;
 }
@@ -187,8 +189,7 @@ main(int argc, char **argv){
 	struct slice all;
 	struct pt *ptp;
 	enum action what = LIST;
-	char *p, *type, *diskdevice, *device, *progname;
-	int lower, upper;
+	char *type, *diskdevice, *device, *progname;
 	int verbose = 0;
 	char partname[PARTNAME_SIZE], params[PARTNAME_SIZE + 16];
 	char * loopdev = NULL;
@@ -202,7 +203,6 @@ main(int argc, char **argv){
 	initpts();
 	init_crc32();
 
-	lower = upper = 0;
 	type = device = diskdevice = NULL;
 	memset(&all, 0, sizeof(all));
 	memset(&partname, 0, sizeof(partname));
@@ -239,14 +239,6 @@ main(int argc, char **argv){
 		case 'v':
 			verbose = 1;
 			break;
-		case 'n':
-			p = optarg;
-			lower = atoi(p);
-			if ((p[1] == '-') && p[2])
-				upper = atoi(p+2);
-			else
-				upper = lower;
-			break;
 		case 'p':
 			delim = optarg;
 			break;
@@ -331,10 +323,9 @@ main(int argc, char **argv){
 		perror(device);
 		exit(1);
 	}
-	if (!lower)
-		lower = 1;
 
 	/* add/remove partitions to the kernel devmapper tables */
+	int r = 0;
 	for (i = 0; i < ptct; i++) {
 		ptp = &pts[i];
 
@@ -366,16 +357,16 @@ main(int argc, char **argv){
 
 				slices[j].minor = m++;
 
-				printf("%s%s%d : 0 %lu %s %lu\n",
+				printf("%s%s%d : 0 %" PRIu64 " %s %" PRIu64"\n",
 				       mapname, delim, j+1,
-				       (unsigned long) slices[j].size, device,
-				       (unsigned long) slices[j].start);
+				       slices[j].size, device,
+				       slices[j].start);
 			}
 			/* Loop to resolve contained slices */
 			d = c;
 			while (c) {
 				for (j = 0; j < n; j++) {
-					unsigned long start;
+					uint64_t start;
 					int k = slices[j].container - 1;
 
 					if (slices[j].size == 0)
@@ -387,9 +378,9 @@ main(int argc, char **argv){
 					slices[j].minor = m++;
 
 					start = slices[j].start - slices[k].start;
-					printf("%s%s%d : 0 %lu /dev/dm-%d %lu\n",
+					printf("%s%s%d : 0 %" PRIu64 " /dev/dm-%d %" PRIu64 "\n",
 					       mapname, delim, j+1,
-					       (unsigned long) slices[j].size,
+					       slices[j].size,
 					       slices[k].minor, start);
 					c--;
 				}
@@ -401,7 +392,7 @@ main(int argc, char **argv){
 			break;
 
 		case DELETE:
-			for (j = 0; j < n; j++) {
+			for (j = n-1; j >= 0; j--) {
 				if (safe_sprintf(partname, "%s%s%d",
 					     mapname, delim, j+1)) {
 					fprintf(stderr, "partname too small\n");
@@ -412,9 +403,10 @@ main(int argc, char **argv){
 				if (!slices[j].size || !dm_map_present(partname))
 					continue;
 
-				if (!dm_simplecmd(DM_DEVICE_REMOVE, partname))
+				if (!dm_simplecmd(DM_DEVICE_REMOVE, partname)) {
+					r++;
 					continue;
-
+				}
 				if (verbose)
 					printf("del devmap : %s\n", partname);
 			}
@@ -448,8 +440,8 @@ main(int argc, char **argv){
 				}
 				strip_slash(partname);
 
-				if (safe_sprintf(params, "%s %lu", device,
-					     (unsigned long)slices[j].start)) {
+				if (safe_sprintf(params, "%s %" PRIu64 ,
+						 device, slices[j].start)) {
 					fprintf(stderr, "params too small\n");
 					exit(1);
 				}
@@ -457,18 +449,23 @@ main(int argc, char **argv){
 				op = (dm_map_present(partname) ?
 					DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
 
-				dm_addmap(op, partname, DM_TARGET, params,
-					  slices[j].size, uuid, j+1);
-
-				if (op == DM_DEVICE_RELOAD)
-					dm_simplecmd(DM_DEVICE_RESUME,
-							partname);
-
+				if (!dm_addmap(op, partname, DM_TARGET, params,
+					  slices[j].size, uuid, j+1)) {
+					fprintf(stderr, "create/reload failed on %s\n",
+						partname);
+					r++;
+				}
+				if (op == DM_DEVICE_RELOAD &&
+				    !dm_simplecmd(DM_DEVICE_RESUME, partname)) {
+					fprintf(stderr, "resume failed on %s\n",
+						partname);
+					r++;
+				}
 				dm_devn(partname, &slices[j].major,
 					&slices[j].minor);
 
 				if (verbose)
-					printf("add map %s (%d:%d): 0 %lu %s %s\n",
+					printf("add map %s (%d:%d): 0 %" PRIu64 " %s %s\n",
 					       partname, slices[j].major,
 					       slices[j].minor, slices[j].size,
 					       DM_TARGET, params);
@@ -502,10 +499,10 @@ main(int argc, char **argv){
 					}
 					strip_slash(partname);
 
-					if (safe_sprintf(params, "%d:%d %lu",
+					if (safe_sprintf(params, "%d:%d %" PRIu64,
 							 slices[k].major,
 							 slices[k].minor,
-							 (unsigned long)slices[j].start)) {
+							 slices[j].start)) {
 						fprintf(stderr, "params too small\n");
 						exit(1);
 					}
@@ -524,7 +521,7 @@ main(int argc, char **argv){
 						&slices[j].minor);
 
 					if (verbose)
-						printf("add map %s : 0 %lu %s %s\n",
+						printf("add map %s : 0 %" PRIu64 " %s %s\n",
 						       partname, slices[j].size,
 						       DM_TARGET, params);
 					c--;
@@ -545,7 +542,7 @@ main(int argc, char **argv){
 	dm_lib_release();
 	dm_lib_exit();
 
-	return 0;
+	return r;
 }
 
 void *
diff --git a/kpartx/kpartx.h b/kpartx/kpartx.h
index 9b3aeca..43ae3f8 100644
--- a/kpartx/kpartx.h
+++ b/kpartx/kpartx.h
@@ -1,6 +1,8 @@
 #ifndef _KPARTX_H
 #define _KPARTX_H
 
+#include <stdint.h>
+
 /*
  * For each partition type there is a routine that takes
  * a block device and a range, and returns the list of
@@ -20,8 +22,8 @@
  * units: 512 byte sectors
  */
 struct slice {
-	unsigned long start;
-	unsigned long size;
+	uint64_t start;
+	uint64_t size;
 	int container;
 	int major;
 	int minor;
diff --git a/libcheckers/Makefile b/libcheckers/Makefile
deleted file mode 100644
index 6340a68..0000000
--- a/libcheckers/Makefile
+++ /dev/null
@@ -1,27 +0,0 @@
-# Makefile
-#
-# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
-#
-BUILD = glibc
-
-include ../Makefile.inc
-
-OBJS = libsg.o checkers.o readsector0.o tur.o directio.o emc_clariion.o hp_sw.o rdac.o
-
-all: $(BUILD)
-
-prepare:
-	@file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o *.gz
-
-klibc: prepare $(OBJS)
-	ar rs libcheckers-klibc.a *.o
-
-glibc: prepare $(OBJS)
-	ar rs libcheckers-glibc.a *.o
-
-install:
-
-uninstall:
-
-clean:
-	rm -f core *.a *.o *.gz
diff --git a/libcheckers/checkers.c b/libcheckers/checkers.c
deleted file mode 100644
index d7728a5..0000000
--- a/libcheckers/checkers.c
+++ /dev/null
@@ -1,159 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-
-#include "checkers.h"
-
-#include "directio.h"
-#include "tur.h"
-#include "hp_sw.h"
-#include "emc_clariion.h"
-#include "rdac.h"
-#include "readsector0.h"
-
-static struct checker checkers[] = {
-	{
-		.fd         = 0,
-		.sync       = 1,
-		.name       = DIRECTIO,
-		.message    = "",
-		.context    = NULL,
-		.check      = directio,
-		.init       = directio_init,
-		.free       = directio_free
-	},
-	{
-		.fd         = 0,
-		.sync       = 1,
-		.name       = TUR,
-		.message    = "",
-		.context    = NULL,
-		.check      = tur,
-		.init       = tur_init,
-		.free       = tur_free
-	},
-	{
-		.fd         = 0,
-		.sync       = 1,
-		.name       = HP_SW,
-		.message    = "",
-		.context    = NULL,
-		.check      = hp_sw,
-		.init       = hp_sw_init,
-		.free       = hp_sw_free
-	},
-	{
-		.fd         = 0,
-		.sync       = 1,
-		.name       = EMC_CLARIION,
-		.message    = "",
-		.context    = NULL,
-		.check      = emc_clariion,
-		.init       = emc_clariion_init,
-		.free       = emc_clariion_free
-	},
-	{
-		.fd         = 0,
-		.sync       = 1,
-		.name       = RDAC,
-		.message    = "",
-		.context    = NULL,
-		.check      = rdac,
-		.init       = rdac_init,
-		.free       = rdac_free
-	},
-	{
-		.fd         = 0,
-		.sync       = 1,
-		.name       = READSECTOR0,
-		.message    = "",
-		.context    = NULL,
-		.check      = readsector0,
-		.init       = readsector0_init,
-		.free       = readsector0_free
-	},
-	{0, 1, "", "", NULL, NULL, NULL, NULL},
-};
-
-void checker_set_fd (struct checker * c, int fd)
-{
-	c->fd = fd;
-}
-
-void checker_set_sync (struct checker * c)
-{
-	c->sync = 1;
-}
-
-void checker_set_async (struct checker * c)
-{
-	c->sync = 0;
-}
-
-struct checker * checker_lookup (char * name)
-{
-	struct checker * c = &checkers[0];
-	
-	while (c->check) {
-		if (!strncmp(name, c->name, CHECKER_NAME_LEN))
-			return c;
-		c++;
-	}
-	return NULL;
-}
-
-int checker_init (struct checker * c, void ** mpctxt_addr)
-{
-	c->mpcontext = mpctxt_addr;
-	return c->init(c);
-}
-
-void checker_put (struct checker * c)
-{
-	if (c->free)
-		c->free(c);
-	memset(c, 0x0, sizeof(struct checker));
-}
-
-int checker_check (struct checker * c)
-{
-	int r;
-
-	if (c->fd <= 0) {
-		MSG(c, "no usable fd");
-		return PATH_WILD;
-	}
-	r = c->check(c);
-
-	return r;
-}
-
-int checker_selected (struct checker * c)
-{
-	return (c->check) ? 1 : 0;
-}
-
-char * checker_name (struct checker * c)
-{
-	return c->name;
-}
-
-char * checker_message (struct checker * c)
-{
-	return c->message;
-}
-
-struct checker * checker_default (void)
-{
-	return checker_lookup(DEFAULT_CHECKER);
-}
-
-void checker_get (struct checker * dst, struct checker * src)
-{
-	dst->fd = src->fd;
-	dst->sync = src->sync;
-	strncpy(dst->name, src->name, CHECKER_NAME_LEN);
-	strncpy(dst->message, src->message, CHECKER_MSG_LEN);
-	dst->check = src->check;
-	dst->init = src->init;
-	dst->free = src->free;
-}
diff --git a/libcheckers/checkers.h b/libcheckers/checkers.h
deleted file mode 100644
index 9b270eb..0000000
--- a/libcheckers/checkers.h
+++ /dev/null
@@ -1,116 +0,0 @@
-#ifndef _CHECKERS_H
-#define _CHECKERS_H
-
-/*
- *
- * Userspace (multipath/multipathd) path states
- *
- * PATH_WILD:
- * - Use: None of the checkers (returned if we don't have an fd)
- * - Description: Corner case where "fd <= 0" for path fd (see checker_check())
- *
- * PATH_UNCHECKED:
- * - Use: Only in directio checker
- * - Description: set when fcntl(F_GETFL) fails to return flags or O_DIRECT
- *   not include in flags, or O_DIRECT read fails
- * - Notes:
- *   - multipathd: uses it to skip over paths in sync_map_state()
- *   - multipath: used in update_paths(); if state==PATH_UNCHECKED, call
- *     pathinfo()
- *
- * PATH_DOWN:
- * - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur)
- * - Description: Either a) SG_IO ioctl failed, or b) check condition on some
- *   SG_IO ioctls that succeed (tur, readsector0 checkers); path is down and
- *   you shouldn't try to send commands to it
- *
- * PATH_UP:
- * - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur)
- * - Description: Path is up and I/O can be sent to it
- *
- * PATH_SHAKY:
- * - Use: Only emc_clariion
- * - Description: Indicates path not available for "normal" operations
- *
- * PATH_GHOST:
- * - Use: Only hp_sw
- * - Description: Indicates a "passive/standby" path on active/passive HP
- *   arrays.  These paths will return valid answers to certain SCSI commands
- *   (tur, read_capacity, inquiry, start_stop), but will fail I/O commands.
- *   The path needs an initialization command to be sent to it in order for
- *   I/Os to succeed.
- *
- * PATH_PENDING:
- * - Use: All async checkers
- * - Description: Indicates a check IO is in flight.
- */
-#define PATH_WILD	-1
-#define PATH_UNCHECKED	0
-#define PATH_DOWN	1
-#define PATH_UP		2
-#define PATH_SHAKY	3
-#define PATH_GHOST	4
-#define PATH_PENDING	5
-
-#define DIRECTIO     "directio"
-#define TUR          "tur"
-#define HP_SW        "hp_sw"
-#define RDAC         "rdac"
-#define EMC_CLARIION "emc_clariion"
-#define READSECTOR0  "readsector0"
-
-#define DEFAULT_CHECKER DIRECTIO
-
-/*
- * Overloaded storage response time can be very long.
- * SG_IO timouts after DEF_TIMEOUT milliseconds, and checkers interprets this
- * as a path failure. multipathd then proactively evicts the path from the DM
- * multipath table in this case.
- *
- * This generaly snow balls and ends up in full eviction and IO errors for end
- * users. Bad. This may also cause SCSI bus resets, causing disruption for all
- * local and external storage hardware users.
- * 
- * Provision a long timeout. Longer than any real-world application would cope
- * with.
- */
-#define DEF_TIMEOUT		300000
-#define ASYNC_TIMEOUT_SEC	30
-
-/*
- * strings lengths
- */
-#define CHECKER_NAME_LEN 16
-#define CHECKER_MSG_LEN 256
-#define CHECKER_DEV_LEN 256
-
-struct checker {
-	int fd;
-	int sync;
-	char name[CHECKER_NAME_LEN];
-	char message[CHECKER_MSG_LEN];       /* comm with callers */
-	void * context;                      /* store for persistent data */
-	void ** mpcontext;                   /* store for persistent data
-						shared multipath-wide */
-	int (*check)(struct checker *);
-	int (*init)(struct checker *);       /* to allocate the context */
-	void (*free)(struct checker *);      /* to free the context */
-};
-
-#define MSG(c, fmt, args...) snprintf((c)->message, CHECKER_MSG_LEN, fmt, ##args);
-
-int checker_init (struct checker *, void **);
-void checker_put (struct checker *);
-void checker_reset (struct checker * c);
-void checker_set_sync (struct checker * c);
-void checker_set_async (struct checker * c);
-void checker_set_fd (struct checker *, int);
-struct checker * checker_lookup (char *);
-int checker_check (struct checker *);
-int checker_selected (struct checker *);
-char * checker_name (struct checker *);
-char * checker_message (struct checker *);
-struct checker * checker_default (void);
-void checker_get (struct checker *, struct checker *);
-
-#endif /* _CHECKERS_H */
diff --git a/libcheckers/directio.c b/libcheckers/directio.c
deleted file mode 100644
index ee09af7..0000000
--- a/libcheckers/directio.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (c) 2005 Hannes Reinecke, Suse
- */
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/fs.h>
-#include <errno.h>
-#include <linux/kdev_t.h>
-#include <asm/unistd.h>
-#include <libaio.h>
-
-#include "checkers.h"
-#include "../libmultipath/debug.h"
-
-#define MSG_DIRECTIO_UNKNOWN	"directio checker is not available"
-#define MSG_DIRECTIO_UP		"directio checker reports path is up"
-#define MSG_DIRECTIO_DOWN	"directio checker reports path is down"
-#define MSG_DIRECTIO_PENDING	"directio checker is waiting on aio"
-
-#define LOG(prio, fmt, args...) condlog(prio, "directio: " fmt, ##args)
-
-struct directio_context {
-	int		running;
-	int		reset_flags;
-	int		blksize;
-	unsigned char *	buf;
-	unsigned char * ptr;
-	io_context_t	ioctx;
-	struct iocb	io;
-};
-
-
-int directio_init (struct checker * c)
-{
-	unsigned long pgsize = getpagesize();
-	struct directio_context * ct;
-	long flags;
-
-	ct = malloc(sizeof(struct directio_context));
-	if (!ct)
-		return 1;
-	memset(ct, 0, sizeof(struct directio_context));
-
-	if (io_setup(1, &ct->ioctx) != 0) {
-		condlog(1, "io_setup failed");
-		free(ct);
-		return 1;
-	}
-
-	if (ioctl(c->fd, BLKBSZGET, &ct->blksize) < 0) {
-		MSG(c, "cannot get blocksize, set default");
-		ct->blksize = 512;
-	}
-	if (ct->blksize > 4096) {
-		/*
-		 * Sanity check for DASD; BSZGET is broken
-		 */
-		ct->blksize = 4096;
-	}
-	if (!ct->blksize)
-		goto out;
-	ct->buf = (unsigned char *)malloc(ct->blksize + pgsize);
-	if (!ct->buf)
-		goto out;
-
-	flags = fcntl(c->fd, F_GETFL);
-	if (flags < 0)
-		goto out;
-	if (!(flags & O_DIRECT)) {
-		flags |= O_DIRECT;
-		if (fcntl(c->fd, F_SETFL, flags) < 0)
-			goto out;
-		ct->reset_flags = 1;
-	}
-
-	ct->ptr = (unsigned char *) (((unsigned long)ct->buf + pgsize - 1) &
-		  (~(pgsize - 1)));
-
-	/* Sucessfully initialized, return the context. */
-	c->context = (void *) ct;
-	return 0;
-
-out:
-	if (ct->buf)
-		free(ct->buf);
-	io_destroy(ct->ioctx);
-	free(ct);
-	return 1;
-}
-
-void directio_free (struct checker * c)
-{
-	struct directio_context * ct = (struct directio_context *)c->context;
-	long flags;
-
-	if (!ct)
-		return;
-
-	if (ct->reset_flags) {
-		if ((flags = fcntl(c->fd, F_GETFL)) >= 0) {
-			flags &= ~O_DIRECT;
-			/* No point in checking for errors */
-			fcntl(c->fd, F_SETFL, flags);
-		}
-	}
-
-	if (ct->buf)
-		free(ct->buf);
-	io_destroy(ct->ioctx);
-	free(ct);
-}
-
-static int
-check_state(int fd, struct directio_context *ct, int sync)
-{
-	struct timespec	timeout = { .tv_nsec = 5 };
-	struct io_event event;
-	struct stat	sb;
-	int		rc = PATH_UNCHECKED;
-	long		r;
-
-	if (fstat(fd, &sb) == 0) {
-		LOG(4, "called for %x", (unsigned) sb.st_rdev);
-	}
-	if (sync) {
-		LOG(4, "called in synchronous mode");
-		timeout.tv_sec  = ASYNC_TIMEOUT_SEC;
-		timeout.tv_nsec = 0;
-	}
-
-	if (!ct->running) {
-		struct iocb *ios[1] = { &ct->io };
-
-		LOG(3, "starting new request");
-		memset(&ct->io, 0, sizeof(struct iocb));
-		io_prep_pread(&ct->io, fd, ct->ptr, ct->blksize, 0);
-		if (io_submit(ct->ioctx, 1, ios) != 1) {
-			LOG(3, "io_submit error %i", errno);
-			return PATH_UNCHECKED;
-		}
-	}
-	ct->running++;
-
-	r = io_getevents(ct->ioctx, 1L, 1L, &event, &timeout);
-	LOG(3, "async io getevents returns %li (errno=%s)", r, strerror(errno));
-
-	if (r < 1L) {
-		if (ct->running > ASYNC_TIMEOUT_SEC || sync) {
-			LOG(3, "abort check on timeout");
-			rc = PATH_DOWN;
-		} else
-			rc = PATH_PENDING;
-	} else {
-		LOG(3, "io finished %lu/%lu", event.res, event.res2);
-		ct->running = 0;
-		rc = (event.res == ct->blksize) ? PATH_UP : PATH_DOWN;
-	}
-
-	return rc;
-}
-
-int directio (struct checker * c)
-{
-	int ret;
-	struct directio_context * ct = (struct directio_context *)c->context;
-
-	if (!ct)
-		return PATH_UNCHECKED;
-
-	ret = check_state(c->fd, ct, c->sync);
-
-	switch (ret)
-	{
-	case PATH_UNCHECKED:
-		MSG(c, MSG_DIRECTIO_UNKNOWN);
-		break;
-	case PATH_DOWN:
-		MSG(c, MSG_DIRECTIO_DOWN);
-		break;
-	case PATH_UP:
-		MSG(c, MSG_DIRECTIO_UP);
-		break;
-	case PATH_PENDING:
-		MSG(c, MSG_DIRECTIO_PENDING);
-		break;
-	default:
-		break;
-	}
-	return ret;
-}
diff --git a/libcheckers/directio.h b/libcheckers/directio.h
deleted file mode 100644
index 1865b1f..0000000
--- a/libcheckers/directio.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _DIRECTIO_H
-#define _DIRECTIO_H
-
-int directio (struct checker *);
-int directio_init (struct checker *);
-void directio_free (struct checker *);
-
-#endif /* _DIRECTIO_H */
diff --git a/libcheckers/emc_clariion.c b/libcheckers/emc_clariion.c
deleted file mode 100644
index 6c7167e..0000000
--- a/libcheckers/emc_clariion.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (c) 2004, 2005 Lars Marowsky-Bree
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-#include "../libmultipath/sg_include.h"
-#include "libsg.h"
-#include "checkers.h"
-
-#define INQUIRY_CMD     0x12
-#define INQUIRY_CMDLEN  6
-#define HEAVY_CHECK_COUNT       10
-
-/*
- * Mechanism to track CLARiiON inactive snapshot LUs.
- * This is done so that we can fail passive paths
- * to an inactive snapshot LU even though since a
- * simple read test would return 02/04/03 instead
- * of 05/25/01 sensekey/ASC/ASCQ data.
- */
-#define	IS_INACTIVE_SNAP(c)   (c->mpcontext ?				   \
-			       ((struct emc_clariion_checker_LU_context *) \
-					(*c->mpcontext))->inactive_snap	   \
-					    : 0)
-
-#define	SET_INACTIVE_SNAP(c)  if (c->mpcontext)				   \
-				((struct emc_clariion_checker_LU_context *)\
-					(*c->mpcontext))->inactive_snap = 1
-
-#define	CLR_INACTIVE_SNAP(c)  if (c->mpcontext)				   \
-				((struct emc_clariion_checker_LU_context *)\
-					(*c->mpcontext))->inactive_snap = 0
-
-struct emc_clariion_checker_path_context {
-	char wwn[16];
-	unsigned wwn_set;
-};
-
-struct emc_clariion_checker_LU_context {
-	int inactive_snap;
-};
-
-extern void
-hexadecimal_to_ascii(char * wwn, char *wwnstr)
-{
-	int i,j, nbl;
-
-	for (i=0,j=0;i<16;i++) {
-		wwnstr[j++] = ((nbl = ((wwn[i]&0xf0) >> 4)) <= 9) ?
-					'0' + nbl : 'a' + (nbl - 10);
-		wwnstr[j++] = ((nbl = (wwn[i]&0x0f)) <= 9) ?
-					'0' + nbl : 'a' + (nbl - 10);
-	}
-	wwnstr[32]=0;
-}
-
-int emc_clariion_init (struct checker * c)
-{
-	/*
-	 * Allocate and initialize the path specific context.
-	 */
-	c->context = malloc(sizeof(struct emc_clariion_checker_path_context));
-	if (!c->context)
-		return 1;
-	((struct emc_clariion_checker_path_context *)c->context)->wwn_set = 0;
-
-	/*
-	 * Allocate and initialize the multi-path global context.
-	 */
-	if (c->mpcontext) {
-		void * mpctxt = malloc(sizeof(int));
-		*c->mpcontext = mpctxt;
-		CLR_INACTIVE_SNAP(c);
-	}
-
-	return 0;
-}
-
-void emc_clariion_free (struct checker * c)
-{
-	free(c->context);
-}
-
-int emc_clariion(struct checker * c)
-{
-	unsigned char sense_buffer[128] = { 0, };
-	unsigned char sb[SENSE_BUFF_LEN] = { 0, }, *sbb;
-	unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
-						sizeof(sense_buffer), 0};
-	struct sg_io_hdr io_hdr;
-	struct emc_clariion_checker_path_context * ct =
-		(struct emc_clariion_checker_path_context *)c->context;
-	char wwnstr[33];
-	int ret;
-
-	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-	io_hdr.interface_id = 'S';
-	io_hdr.cmd_len = sizeof (inqCmdBlk);
-	io_hdr.mx_sb_len = sizeof (sb);
-	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-	io_hdr.dxfer_len = sizeof (sense_buffer);
-	io_hdr.dxferp = sense_buffer;
-	io_hdr.cmdp = inqCmdBlk;
-	io_hdr.sbp = sb;
-	io_hdr.timeout = DEF_TIMEOUT;
-	io_hdr.pack_id = 0;
-	if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
-		MSG(c, "emc_clariion_checker: sending query command failed");
-		return PATH_DOWN;
-	}
-	if (io_hdr.info & SG_INFO_OK_MASK) {
-		MSG(c, "emc_clariion_checker: query command indicates error");
-		return PATH_DOWN;
-	}
-	if (/* Verify the code page - right page & revision */
-	    sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) {
-		MSG(c, "emc_clariion_checker: Path unit report page in "
-		    "unknown format");
-		return PATH_DOWN;
-	}
-
-	if ( /* Effective initiator type */
-	    	sense_buffer[27] != 0x03
-		/*
-		 * Failover mode should be set to 1 (PNR failover mode)
-		 * or 4 (ALUA failover mode).
-		 */
-		|| (((sense_buffer[28] & 0x07) != 0x04) &&
-		    ((sense_buffer[28] & 0x07) != 0x06))
-		/* Arraycommpath should be set to 1 */
-		|| (sense_buffer[30] & 0x04) != 0x04) {
-		MSG(c, "emc_clariion_checker: Path not correctly configured "
-		    "for failover");
-		return PATH_DOWN;
-	}
-
-	if ( /* LUN operations should indicate normal operations */
-		sense_buffer[48] != 0x00) {
-		MSG(c, "emc_clariion_checker: Path not available for normal "
-		    "operations");
-		return PATH_SHAKY;
-	}
-
-	if ( /* LUN should at least be bound somewhere and not be LUNZ */
-		sense_buffer[4] == 0x00) {
-		MSG(c, "emc_clariion_checker: Logical Unit is unbound "
-		    "or LUNZ");
-		return PATH_DOWN;
-	}
-	
-	/*
-	 * store the LUN WWN there and compare that it indeed did not
-	 * change in between, to protect against the path suddenly
-	 * pointing somewhere else.
-	 */
-	if (ct->wwn_set) {
-		if (memcmp(ct->wwn, &sense_buffer[10], 16) != 0) {
-			MSG(c, "emc_clariion_checker: Logical Unit WWN "
-			    "has changed!");
-			return PATH_DOWN;
-		}
-	} else {
-		memcpy(ct->wwn, &sense_buffer[10], 16);
-		ct->wwn_set = 1;
-	}
-	
-	/*
-	 * Issue read on active path to determine if inactive snapshot.
-	 */
-	if (sense_buffer[4] == 2) {/* if active path */
-		unsigned char buf[4096];
-
-		ret = sg_read(c->fd, &buf[0], sbb = &sb[0]);
-		if (ret == PATH_DOWN) {
-			hexadecimal_to_ascii(ct->wwn, wwnstr);
-
-			/*
-		 	 * Check for inactive snapshot LU this way.  Must
-			 * fail these.
-	 	 	 */
-			if (((sbb[2]&0xf) == 5) && (sbb[12] == 0x25) &&
-			    (sbb[13]==1)) {
-				/*
-			 	 * Do this so that we can fail even the
-			 	 * passive paths which will return
-				 * 02/04/03 not 05/25/01 on read.
-			 	 */
-				SET_INACTIVE_SNAP(c);
-				MSG(c, "emc_clariion_checker: Active "
-					"path to inactive snapshot WWN %s.",
-					wwnstr);
-			} else
-				MSG(c, "emc_clariion_checker: Read "
-					"error for WWN %s.  Sense data are "
-					"0x%x/0x%x/0x%x.", wwnstr,
-					sbb[2]&0xf, sbb[12], sbb[13]);
-		} else {
-			MSG(c, "emc_clariion_checker: Active path is "
-			    "healthy.");
-			/*
-		 	 * Remove the path from the set of paths to inactive
-		 	 * snapshot LUs if it was in this list since the
-		 	 * snapshot is no longer inactive.
-		 	 */
-			CLR_INACTIVE_SNAP(c);
-		}
-	} else {
-		if (IS_INACTIVE_SNAP(c)) {
-			hexadecimal_to_ascii(ct->wwn, wwnstr);
-			MSG(c, "emc_clariion_checker: Passive "
-				"path to inactive snapshot WWN %s.",
-				wwnstr);
-			ret = PATH_DOWN;
-		} else {
-			MSG(c,
-		    	    "emc_clariion_checker: Passive path is healthy.");
-			ret = PATH_UP;	/* not ghost */
-		}
-	}
-
-	return ret;
-}
diff --git a/libcheckers/emc_clariion.h b/libcheckers/emc_clariion.h
deleted file mode 100644
index a1018a6..0000000
--- a/libcheckers/emc_clariion.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _EMC_CLARIION_H
-#define _EMC_CLARIION_H
-
-int emc_clariion (struct checker *);
-int emc_clariion_init (struct checker *);
-void emc_clariion_free (struct checker *);
-
-#endif /* _EMC_CLARIION_H */
diff --git a/libcheckers/hp_sw.c b/libcheckers/hp_sw.c
deleted file mode 100644
index b9731ff..0000000
--- a/libcheckers/hp_sw.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 2005 Christophe Varoqui
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-#include "checkers.h"
-
-#include "../libmultipath/sg_include.h"
-
-#define TUR_CMD_LEN		6
-#define INQUIRY_CMDLEN		6
-#define INQUIRY_CMD		0x12
-#define SENSE_BUFF_LEN		32
-#define SCSI_CHECK_CONDITION	0x2
-#define SCSI_COMMAND_TERMINATED	0x22
-#define SG_ERR_DRIVER_SENSE	0x08
-#define RECOVERED_ERROR		0x01
-#define MX_ALLOC_LEN		255
-#define HEAVY_CHECK_COUNT       10
-
-#define MSG_HP_SW_UP	"hp_sw checker reports path is up"
-#define MSG_HP_SW_DOWN	"hp_sw checker reports path is down"
-#define MSG_HP_SW_GHOST	"hp_sw checker reports path is ghost"
-
-struct sw_checker_context {
-	void * dummy;
-};
-
-int hp_sw_init (struct checker * c)
-{
-	return 0;
-}
-
-void hp_sw_free (struct checker * c)
-{
-	return;
-}
-
-static int
-do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
-       void *resp, int mx_resp_len, int noisy)
-{
-        unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
-            { INQUIRY_CMD, 0, 0, 0, 0, 0 };
-        unsigned char sense_b[SENSE_BUFF_LEN];
-        struct sg_io_hdr io_hdr;
-                                                                                                                 
-        if (cmddt)
-                inqCmdBlk[1] |= 2;
-        if (evpd)
-                inqCmdBlk[1] |= 1;
-        inqCmdBlk[2] = (unsigned char) pg_op;
-	inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
-	inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
-        memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-        io_hdr.interface_id = 'S';
-        io_hdr.cmd_len = sizeof (inqCmdBlk);
-        io_hdr.mx_sb_len = sizeof (sense_b);
-        io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-        io_hdr.dxfer_len = mx_resp_len;
-        io_hdr.dxferp = resp;
-        io_hdr.cmdp = inqCmdBlk;
-        io_hdr.sbp = sense_b;
-        io_hdr.timeout = DEF_TIMEOUT;
- 
-        if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
-                return 1;
- 
-        /* treat SG_ERR here to get rid of sg_err.[ch] */
-        io_hdr.status &= 0x7e;
-        if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
-            (0 == io_hdr.driver_status))
-                return 0;
-        if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
-            (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
-            (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
-                if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
-                        int sense_key;
-                        unsigned char * sense_buffer = io_hdr.sbp;
-                        if (sense_buffer[0] & 0x2)
-                                sense_key = sense_buffer[1] & 0xf;
-                        else
-                                sense_key = sense_buffer[2] & 0xf;
-                        if(RECOVERED_ERROR == sense_key)
-                                return 0;
-                }
-        }
-        return 1;
-}
-
-static int
-do_tur (int fd)
-{
-        unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
-        struct sg_io_hdr io_hdr;
-        unsigned char sense_buffer[32];
-
-        memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-        io_hdr.interface_id = 'S';
-        io_hdr.cmd_len = sizeof (turCmdBlk);
-        io_hdr.mx_sb_len = sizeof (sense_buffer);
-        io_hdr.dxfer_direction = SG_DXFER_NONE;
-        io_hdr.cmdp = turCmdBlk;
-        io_hdr.sbp = sense_buffer;
-        io_hdr.timeout = DEF_TIMEOUT;
-        io_hdr.pack_id = 0;
-
-        if (ioctl(fd, SG_IO, &io_hdr) < 0)
-		return 1;
-
-        if (io_hdr.info & SG_INFO_OK_MASK)
-		return 1;
-
-	return 0;
-}
-
-extern int
-hp_sw (struct checker * c)
-{
-	char buff[MX_ALLOC_LEN];
-
-	if (0 != do_inq(c->fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
-		MSG(c, MSG_HP_SW_DOWN);
-		return PATH_DOWN;
-	}
-
-	if (do_tur(c->fd)) {
-		MSG(c, MSG_HP_SW_GHOST);
-                return PATH_GHOST;
-        }
-	MSG(c, MSG_HP_SW_UP);
-	return PATH_UP;
-}
diff --git a/libcheckers/hp_sw.h b/libcheckers/hp_sw.h
deleted file mode 100644
index 3be0d8e..0000000
--- a/libcheckers/hp_sw.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _HP_SW_H
-#define _HP_SW_H
-
-int hp_sw (struct checker *);
-int hp_sw_init (struct checker *);
-void hp_sw_free (struct checker *);
-
-#endif /* _HP_SW_H */
diff --git a/libcheckers/libsg.c b/libcheckers/libsg.c
deleted file mode 100644
index 9171b10..0000000
--- a/libcheckers/libsg.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2004, 2005 Christophe Varoqui
- */
-#include <string.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <sys/stat.h>
-
-#include "checkers.h"
-#include "libsg.h"
-#include "../libmultipath/sg_include.h"
-
-int
-sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff)
-{
-	/* defaults */
-	int blocks = 1;
-	long long start_block = 0;
-	int bs = 512;
-	int cdbsz = 10;
-	int * diop = NULL;
-
-	unsigned char rdCmd[cdbsz];
-	unsigned char *sbb = senseBuff;
-	struct sg_io_hdr io_hdr;
-	int res;
-	int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88};
-	int sz_ind;
-	struct stat filestatus;
-	int retry_count = 3;
-
-	if (fstat(sg_fd, &filestatus) != 0)
-		return PATH_DOWN;
-	bs = (filestatus.st_blksize > 4096)? 4096: filestatus.st_blksize;
-	memset(rdCmd, 0, cdbsz);
-	sz_ind = 1;
-	rdCmd[0] = rd_opcode[sz_ind];
-	rdCmd[2] = (unsigned char)((start_block >> 24) & 0xff);
-	rdCmd[3] = (unsigned char)((start_block >> 16) & 0xff);
-	rdCmd[4] = (unsigned char)((start_block >> 8) & 0xff);
-	rdCmd[5] = (unsigned char)(start_block & 0xff);
-	rdCmd[7] = (unsigned char)((blocks >> 8) & 0xff);
-	rdCmd[8] = (unsigned char)(blocks & 0xff);
-
-	memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
-	io_hdr.interface_id = 'S';
-	io_hdr.cmd_len = cdbsz;
-	io_hdr.cmdp = rdCmd;
-	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-	io_hdr.dxfer_len = bs * blocks;
-	io_hdr.dxferp = buff;
-	io_hdr.mx_sb_len = SENSE_BUFF_LEN;
-	io_hdr.sbp = senseBuff;
-	io_hdr.timeout = DEF_TIMEOUT;
-	io_hdr.pack_id = (int)start_block;
-	if (diop && *diop)
-	io_hdr.flags |= SG_FLAG_DIRECT_IO;
-
-retry: 
-	memset(senseBuff, 0, SENSE_BUFF_LEN);
-	while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno));
-
-	if (res < 0) {
-		if (ENOMEM == errno) {
-			return PATH_UP;
-		}
-		return PATH_DOWN;
-	}
-
-	if ((0 == io_hdr.status) &&
-	    (0 == io_hdr.host_status) &&
-	    (0 == io_hdr.driver_status)) {
-		return PATH_UP;
-	} else {
-		/*
-		 * Retry if UNIT_ATTENTION check condition.
-		 */
-		if ((sbb[2]&0xf) == 6) {
-			if (--retry_count)
-				goto retry;
-		}
-		return PATH_DOWN;
-	}
-}
diff --git a/libcheckers/libsg.h b/libcheckers/libsg.h
deleted file mode 100644
index 97c4491..0000000
--- a/libcheckers/libsg.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _LIBSG_H
-#define _LIBSG_H
-
-#define SENSE_BUFF_LEN 32
-
-int sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff);
-
-#endif /* _LIBSG_H */
diff --git a/libcheckers/rdac.c b/libcheckers/rdac.c
deleted file mode 100644
index f430488..0000000
--- a/libcheckers/rdac.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2005 Christophe Varoqui
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-#include "checkers.h"
-
-#include "../libmultipath/sg_include.h"
-
-#define INQUIRY_CMDLEN		6
-#define INQUIRY_CMD		0x12
-#define SENSE_BUFF_LEN		32
-#define RDAC_DEF_TIMEOUT	60000
-#define SCSI_CHECK_CONDITION	0x2
-#define SCSI_COMMAND_TERMINATED	0x22
-#define SG_ERR_DRIVER_SENSE	0x08
-#define RECOVERED_ERROR		0x01
-
-#define MSG_RDAC_UP    "rdac checker reports path is up"
-#define MSG_RDAC_DOWN  "rdac checker reports path is down"
-#define MSG_RDAC_GHOST "rdac checker reports path is ghost"
-
-struct rdac_checker_context {
-	void * dummy;
-};
-
-int rdac_init (struct checker * c)
-{
-	return 0;
-}
-
-void rdac_free (struct checker * c)
-{
-	return;
-}
-
-static int
-do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len)
-{
-	unsigned char inqCmdBlk[INQUIRY_CMDLEN] = { INQUIRY_CMD, 1, 0, 0, 0, 0 };
-	unsigned char sense_b[SENSE_BUFF_LEN];
-	struct sg_io_hdr io_hdr;
-
-	inqCmdBlk[2] = (unsigned char) pg_op;
-	inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
-	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-
-	io_hdr.interface_id = 'S';
-	io_hdr.cmd_len = sizeof (inqCmdBlk);
-	io_hdr.mx_sb_len = sizeof (sense_b);
-	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-	io_hdr.dxfer_len = mx_resp_len;
-	io_hdr.dxferp = resp;
-	io_hdr.cmdp = inqCmdBlk;
-	io_hdr.sbp = sense_b;
-	io_hdr.timeout = RDAC_DEF_TIMEOUT;
-
-	if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
-		return 1;
-
-	/* treat SG_ERR here to get rid of sg_err.[ch] */
-	io_hdr.status &= 0x7e;
-	if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
-	    (0 == io_hdr.driver_status))
-		return 0;
-	if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
-	    (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
-	    (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
-		if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
-			int sense_key;
-			unsigned char * sense_buffer = io_hdr.sbp;
-			if (sense_buffer[0] & 0x2)
-				sense_key = sense_buffer[1] & 0xf;
-			else
-				sense_key = sense_buffer[2] & 0xf;
-			if (RECOVERED_ERROR == sense_key)
-				return 0;
-		}
-	}
-	return 1;
-}
-
-struct volume_access_inq
-{
-	char dontcare0[8];
-	char avtcvp;
-	char dontcare1[39];
-};
-
-extern int
-rdac(struct checker * c)
-{
-	struct volume_access_inq inq;
-
-	if (0 != do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq))) {
-		MSG(c, MSG_RDAC_DOWN);
-		return PATH_DOWN;
-	}
-
-	return ((inq.avtcvp & 0x1) ? PATH_UP : PATH_GHOST);
-}
diff --git a/libcheckers/rdac.h b/libcheckers/rdac.h
deleted file mode 100644
index d7bf812..0000000
--- a/libcheckers/rdac.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _RDAC_H
-#define _RDAC_H
-
-int rdac(struct checker *);
-int rdac_init(struct checker *);
-void rdac_free(struct checker *);
-
-#endif /* _RDAC_H */
diff --git a/libcheckers/readsector0.c b/libcheckers/readsector0.c
deleted file mode 100644
index bef0eb6..0000000
--- a/libcheckers/readsector0.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2004, 2005 Christophe Varoqui
- */
-#include <stdio.h>
-
-#include "checkers.h"
-#include "libsg.h"
-
-#define MSG_READSECTOR0_UP	"readsector0 checker reports path is up"
-#define MSG_READSECTOR0_DOWN	"readsector0 checker reports path is down"
-
-struct readsector0_checker_context {
-	void * dummy;
-};
-
-int readsector0_init (struct checker * c)
-{
-	return 0;
-}
-
-void readsector0_free (struct checker * c)
-{
-	return;
-}
-
-extern int
-readsector0 (struct checker * c)
-{
-	unsigned char buf[4096];
-	unsigned char sbuf[SENSE_BUFF_LEN];
-	int ret;
-
-	ret = sg_read(c->fd, &buf[0], &sbuf[0]);
-
-	switch (ret)
-	{
-	case PATH_DOWN:
-		MSG(c, MSG_READSECTOR0_DOWN);
-		break;
-	case PATH_UP:
-		MSG(c, MSG_READSECTOR0_UP);
-		break;
-	default:
-		break;
-	}
-	return ret;
-}
diff --git a/libcheckers/readsector0.h b/libcheckers/readsector0.h
deleted file mode 100644
index 0f5d654..0000000
--- a/libcheckers/readsector0.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _READSECTOR0_H
-#define _READSECTOR0_H
-
-int readsector0 (struct checker *);
-int readsector0_init (struct checker *);
-void readsector0_free (struct checker *);
-
-#endif /* _READSECTOR0_H */
diff --git a/libcheckers/tur.c b/libcheckers/tur.c
deleted file mode 100644
index e79bc0a..0000000
--- a/libcheckers/tur.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Some code borrowed from sg-utils.
- *
- * Copyright (c) 2004 Christophe Varoqui
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-#include "checkers.h"
-
-#include "../libmultipath/sg_include.h"
-
-#define TUR_CMD_LEN 6
-#define HEAVY_CHECK_COUNT       10
-
-#define MSG_TUR_UP	"tur checker reports path is up"
-#define MSG_TUR_DOWN	"tur checker reports path is down"
-
-struct tur_checker_context {
-	void * dummy;
-};
-
-int tur_init (struct checker * c)
-{
-	return 0;
-}
-
-void tur_free (struct checker * c)
-{
-	return;
-}
-
-extern int
-tur (struct checker * c)
-{
-	struct sg_io_hdr io_hdr;
-        unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
-        unsigned char sense_buffer[32];
-
-        memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-        io_hdr.interface_id = 'S';
-        io_hdr.cmd_len = sizeof (turCmdBlk);
-        io_hdr.mx_sb_len = sizeof (sense_buffer);
-        io_hdr.dxfer_direction = SG_DXFER_NONE;
-        io_hdr.cmdp = turCmdBlk;
-        io_hdr.sbp = sense_buffer;
-        io_hdr.timeout = DEF_TIMEOUT;
-        io_hdr.pack_id = 0;
-        if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
-		MSG(c, MSG_TUR_DOWN);
-                return PATH_DOWN;
-        }
-        if (io_hdr.info & SG_INFO_OK_MASK) {
-		MSG(c, MSG_TUR_DOWN);
-                return PATH_DOWN;
-        }
-	MSG(c, MSG_TUR_UP);
-        return PATH_UP;
-}
diff --git a/libcheckers/tur.h b/libcheckers/tur.h
deleted file mode 100644
index a2e8c88..0000000
--- a/libcheckers/tur.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _TUR_H
-#define _TUR_H
-
-int tur (struct checker *);
-int tur_init (struct checker *);
-void tur_free (struct checker *);
-
-#endif /* _TUR_H */
diff --git a/libmultipath/Makefile b/libmultipath/Makefile
index 511f5ad..21fcd74 100644
--- a/libmultipath/Makefile
+++ b/libmultipath/Makefile
@@ -2,50 +2,35 @@
 #
 # Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
 #
-BUILD = glibc
-
 include ../Makefile.inc
 
-CFLAGS += -I$(checkersdir)
+LIBS = libmultipath.so
 
 OBJS = memory.o parser.o vector.o devmapper.o callout.o \
        hwtable.o blacklist.o util.o dmparser.o config.o \
        structs.o discovery.o propsel.o dict.o \
        pgpolicies.o debug.o regex.o defaults.o uevent.o \
        switchgroup.o uxsock.o print.o alias.o log_pthread.o \
-       log.o configure.o structs_vec.o sysfs.o
-
-PREVBUILD = $(shell nm debug.o 2> /dev/null|grep log_safe)
-
-ifeq ($(strip $(DAEMON)),1)
-	OBJS += lock.o waiter.o
-	CFLAGS += -DDAEMON
-	CLEAN = $(shell if [ "x$(PREVBUILD)" = "x" ]; then echo clean; fi)
-else
-	CLEAN = $(shell if [ ! "x$(PREVBUILD)" = "x" ]; then echo clean; fi)
-endif
+       log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \
+       lock.o waiter.o
 
-LIBDM_API_FLUSH = $(shell objdump -T /lib/libdevmapper.so.* | grep -c dm_task_no_flush)
+LIBDM_API_FLUSH = $(shell if test -d /lib64 ; then objdump -T /lib64/libdevmapper.so* ; else objdump -T /lib/libdevmapper.so.* ; fi | grep -c dm_task_no_flush)
 
 ifeq ($(strip $(LIBDM_API_FLUSH)),1)
 	CFLAGS += -DLIBDM_API_FLUSH
 endif
 
-all: $(BUILD)
-
-prepare: $(CLEAN)
-	@file *-$(BUILD).a >/dev/null 2>&1 || rm -f core *.o *.gz
-	@rm -f *-$(BUILD).a
-
-klibc: $(OBJS)
-	ar rs libmultipath-klibc.a *.o
+all: $(LIBS)
 
-glibc: $(OBJS)
-	ar rs libmultipath-glibc.a *.o
+$(LIBS): $(OBJS)
+	$(CC) $(SHARED_FLAGS) $(CFLAGS) -o $@ $(OBJS)
 
 install:
+	$(INSTALL_PROGRAM) -m 755 -d $(DESTDIR)$(libdir)
+	$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir)/$(LIBS)
 
 uninstall:
+	rm -f $(DESTDIR)$(libdir)/$(LIBS)
 
 clean:
-	rm -f core *.a *.o *.gz
+	rm -f core *.a *.o *.gz *.so
diff --git a/libmultipath/alias.c b/libmultipath/alias.c
index ca434fe..517b055 100644
--- a/libmultipath/alias.c
+++ b/libmultipath/alias.c
@@ -179,6 +179,46 @@ fail:
 	return -1;
 }
 
+static int
+format_devname(char *name, int id, int len)
+{
+	int pos;
+
+	memset(name,0, len);
+	strcpy(name,"mpath");
+	for (pos = len - 1; pos >= 5; pos--) {
+		name[pos] = 'a' + id % 26;
+		if (id < 26)
+			break;
+		id /= 26;
+		id--;
+	}
+	memmove(name + 5, name + pos, len - pos);
+	name[5 + len - pos] = '\0';
+	return (5 + len - pos);
+}
+
+static int
+scan_devname(char *alias)
+{
+	char *c;
+	int i, n = 0;
+
+	if (strncmp(alias, "mpath", 5))
+		return -1;
+
+	c = alias + 5;
+	while (*c != '\0' && *c != ' ' && *c != '\t') {
+		i = *c - 'a';
+		n = ( n * 26 ) + i;
+		c++;
+		if (*c < 'a' || *c > 'z')
+			break;
+		n++;
+	}
+
+	return n;
+}
 
 static int
 lookup_binding(FILE *f, char *map_wwid, char **map_alias)
@@ -200,7 +240,8 @@ lookup_binding(FILE *f, char *map_wwid, char **map_alias)
 		alias = strtok(buf, " \t");
 		if (!alias) /* blank line */
 			continue;
-		if (sscanf(alias, "mpath%d", &curr_id) == 1 && curr_id >= id)
+		curr_id = scan_devname(alias);
+		if (curr_id >= id)
 			id = curr_id + 1;
 		wwid = strtok(NULL, " \t");
 		if (!wwid){
@@ -221,7 +262,7 @@ lookup_binding(FILE *f, char *map_wwid, char **map_alias)
 	}
 	condlog(3, "No matching wwid [%s] in bindings file.", map_wwid);
 	return id;
-}	
+}
 
 static int
 rlookup_binding(FILE *f, char **map_wwid, char *map_alias)
@@ -243,7 +284,8 @@ rlookup_binding(FILE *f, char **map_wwid, char *map_alias)
 		alias = strtok(buf, " \t");
 		if (!alias) /* blank line */
 			continue;
-		if (sscanf(alias, "mpath%d", &curr_id) == 1 && curr_id >= id)
+		curr_id = scan_devname(alias);
+		if (curr_id >= id)
 			id = curr_id + 1;
 		wwid = strtok(NULL, " \t");
 		if (!wwid){
@@ -264,7 +306,7 @@ rlookup_binding(FILE *f, char **map_wwid, char *map_alias)
 	}
 	condlog(3, "No matching alias [%s] in bindings file.", map_alias);
 	return id;
-}	
+}
 
 static char *
 allocate_binding(int fd, char *wwid, int id)
@@ -272,13 +314,16 @@ allocate_binding(int fd, char *wwid, int id)
 	char buf[LINE_MAX];
 	off_t offset;
 	char *alias, *c;
-	
+	int i;
+
 	if (id < 0) {
 		condlog(0, "Bindings file full. Cannot allocate new binding");
 		return NULL;
 	}
-	
-	snprintf(buf, LINE_MAX, "mpath%d %s\n", id, wwid);
+
+	i = format_devname(buf, id, LINE_MAX);
+	c = buf + i;
+	snprintf(c,LINE_MAX - i, " %s\n", wwid);
 	buf[LINE_MAX - 1] = '\0';
 
 	offset = lseek(fd, 0, SEEK_END);
@@ -304,7 +349,7 @@ allocate_binding(int fd, char *wwid, int id)
 		condlog(3, "Created new binding [%s] for WWID [%s]", alias,
 			wwid);
 	return alias;
-}		
+}
 
 char *
 get_user_friendly_alias(char *wwid, char *file)
diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c
index 0c277cb..d85b385 100644
--- a/libmultipath/blacklist.c
+++ b/libmultipath/blacklist.c
@@ -2,8 +2,8 @@
  * Copyright (c) 2004, 2005 Christophe Varoqui
  */
 #include <stdio.h>
-#include <checkers.h>
 
+#include "checkers.h"
 #include "memory.h"
 #include "vector.h"
 #include "util.h"
@@ -297,16 +297,14 @@ _filter_path (struct config * conf, struct path * pp)
 	int r;
 
 	r = _filter_devnode(conf->blist_devnode, conf->elist_devnode,pp->dev);
-	if (r)
-		return r;
-	r = _filter_wwid(conf->blist_wwid, conf->elist_devnode, pp->wwid);
-	if (r)
+	if (r > 0)
 		return r;
 	r = _filter_device(conf->blist_device, conf->elist_device,
 		 	   pp->vendor_id, pp->product_id);
-	if (r)
+	if (r > 0)
 		return r;
-	return 0;
+	r = _filter_wwid(conf->blist_wwid, conf->elist_wwid, pp->wwid);
+	return r;
 }
 
 int
diff --git a/libmultipath/callout.c b/libmultipath/callout.c
index 46b89e6..4dd33c5 100644
--- a/libmultipath/callout.c
+++ b/libmultipath/callout.c
@@ -10,11 +10,11 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <stdlib.h>
+#include <fcntl.h>
 #include <sys/wait.h>
 #include <errno.h>
 
-#include <checkers.h>
-
+#include "checkers.h"
 #include "vector.h"
 #include "structs.h"
 #include "debug.h"
@@ -33,7 +33,7 @@ int execute_program(char *path, char *value, int len)
 	int retval;
 	int count;
 	int status;
-	int fds[2];
+	int fds[2], null_fd;
 	pid_t pid;
 	char *pos;
 	char arg[PROGRAM_SIZE];
@@ -76,7 +76,16 @@ int execute_program(char *path, char *value, int len)
 		close(STDOUT_FILENO);
 
 		/* dup write side of pipe to STDOUT */
-		dup(fds[1]);
+		if (dup(fds[1]) < 0)
+			return -1;
+
+		/* Ignore writes to stderr */
+		null_fd = open("/dev/null", O_WRONLY);
+		if (null_fd > 0) {
+			close(STDERR_FILENO);
+			dup(null_fd);
+			close(null_fd);
+		}
 
 		retval = execv(argv[0], argv);
 
diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c
new file mode 100644
index 0000000..5889ad7
--- /dev/null
+++ b/libmultipath/checkers.c
@@ -0,0 +1,187 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <dlfcn.h>
+
+#include "debug.h"
+#include "checkers.h"
+#include "vector.h"
+#include "config.h"
+
+static LIST_HEAD(checkers);
+
+int init_checkers (void)
+{
+	INIT_LIST_HEAD(&checkers);
+	if (!add_checker(DEFAULT_CHECKER))
+		return 1;
+	return 0;
+}
+
+struct checker * alloc_checker (void)
+{
+	return zalloc(sizeof(struct checker));
+}
+
+void free_checker (struct checker * c)
+{
+	free(c);
+}
+
+void cleanup_checkers (void)
+{
+	struct checker * checker_loop;
+	struct checker * checker_temp;
+
+	list_for_each_entry_safe(checker_loop, checker_temp, &checkers, node) {
+		list_del(&checker_loop->node);
+		free(checker_loop);
+	}
+}
+
+struct checker * checker_lookup (char * name)
+{
+	struct checker * c;
+
+	list_for_each_entry(c, &checkers, node) {
+		if (!strncmp(name, c->name, CHECKER_NAME_LEN))
+			return c;
+	}
+	return add_checker(name);
+}
+
+struct checker * add_checker (char * name)
+{
+	char libname[LIB_CHECKER_NAMELEN];
+	void * handle;
+	struct checker * c;
+	char *errstr;
+
+	c = alloc_checker();
+	if (!c)
+		return NULL;
+	snprintf(libname, LIB_CHECKER_NAMELEN, "%s/libcheck%s.so",
+		 conf->multipath_dir, name);
+	condlog(3, "loading %s checker", libname);
+	handle = dlopen(libname, RTLD_NOW);
+	errstr = dlerror();
+	if (errstr != NULL)
+	condlog(0, "A dynamic linking error occurred: (%s)", errstr);
+	if (!handle)
+		goto out;
+
+	c->check = (int (*)(struct checker *)) dlsym(handle, "libcheck_check");
+	errstr = dlerror();
+	if (errstr != NULL)
+	condlog(0, "A dynamic linking error occurred: (%s)", errstr);
+	if (!c->check)
+		goto out;
+
+	c->init = (int (*)(struct checker *)) dlsym(handle, "libcheck_init");
+	errstr = dlerror();
+	if (errstr != NULL)
+	condlog(0, "A dynamic linking error occurred: (%s)", errstr);
+	if (!c->init)
+		goto out;
+
+	c->free = (void (*)(struct checker *)) dlsym(handle, "libcheck_free");
+	errstr = dlerror();
+	if (errstr != NULL)
+	condlog(0, "A dynamic linking error occurred: (%s)", errstr);
+	if (!c->free)
+		goto out;
+
+	snprintf(c->name, CHECKER_NAME_LEN, "%s", name);
+	c->fd = 0;
+	c->sync = 1;
+	list_add(&c->node, &checkers);
+	return c;
+out:
+	free_checker(c);
+	return NULL;
+}
+
+void checker_set_fd (struct checker * c, int fd)
+{
+	c->fd = fd;
+}
+
+void checker_set_sync (struct checker * c)
+{
+	c->sync = 1;
+}
+
+void checker_set_async (struct checker * c)
+{
+	c->sync = 0;
+}
+
+void checker_enable (struct checker * c)
+{
+	c->disable = 0;
+}
+
+void checker_disable (struct checker * c)
+{
+	c->disable = 1;
+}
+
+int checker_init (struct checker * c, void ** mpctxt_addr)
+{
+	c->mpcontext = mpctxt_addr;
+	return c->init(c);
+}
+
+void checker_put (struct checker * c)
+{
+	if (c->free)
+		c->free(c);
+	memset(c, 0x0, sizeof(struct checker));
+}
+
+int checker_check (struct checker * c)
+{
+	int r;
+
+	if (c->disable)
+		return PATH_UNCHECKED;
+	if (c->fd <= 0) {
+		MSG(c, "no usable fd");
+		return PATH_WILD;
+	}
+	r = c->check(c);
+
+	return r;
+}
+
+int checker_selected (struct checker * c)
+{
+	return (c->check) ? 1 : 0;
+}
+
+char * checker_name (struct checker * c)
+{
+	return c->name;
+}
+
+char * checker_message (struct checker * c)
+{
+	return c->message;
+}
+
+void checker_get (struct checker * dst, char * name)
+{
+	struct checker * src = checker_lookup(name);
+
+	if (!src) {
+		dst->check = NULL;
+		return;
+	}
+	dst->fd = src->fd;
+	dst->sync = src->sync;
+	strncpy(dst->name, src->name, CHECKER_NAME_LEN);
+	strncpy(dst->message, src->message, CHECKER_MSG_LEN);
+	dst->check = src->check;
+	dst->init = src->init;
+	dst->free = src->free;
+}
diff --git a/libmultipath/checkers.h b/libmultipath/checkers.h
new file mode 100644
index 0000000..a65aaf9
--- /dev/null
+++ b/libmultipath/checkers.h
@@ -0,0 +1,126 @@
+#ifndef _CHECKERS_H
+#define _CHECKERS_H
+
+#include "list.h"
+#include "memory.h"
+
+/*
+ *
+ * Userspace (multipath/multipathd) path states
+ *
+ * PATH_WILD:
+ * - Use: None of the checkers (returned if we don't have an fd)
+ * - Description: Corner case where "fd <= 0" for path fd (see checker_check())
+ *
+ * PATH_UNCHECKED:
+ * - Use: Only in directio checker
+ * - Description: set when fcntl(F_GETFL) fails to return flags or O_DIRECT
+ *   not include in flags, or O_DIRECT read fails
+ * - Notes:
+ *   - multipathd: uses it to skip over paths in sync_map_state()
+ *   - multipath: used in update_paths(); if state==PATH_UNCHECKED, call
+ *     pathinfo()
+ *
+ * PATH_DOWN:
+ * - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur)
+ * - Description: Either a) SG_IO ioctl failed, or b) check condition on some
+ *   SG_IO ioctls that succeed (tur, readsector0 checkers); path is down and
+ *   you shouldn't try to send commands to it
+ *
+ * PATH_UP:
+ * - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur)
+ * - Description: Path is up and I/O can be sent to it
+ *
+ * PATH_SHAKY:
+ * - Use: Only emc_clariion
+ * - Description: Indicates path not available for "normal" operations
+ *
+ * PATH_GHOST:
+ * - Use: Only hp_sw
+ * - Description: Indicates a "passive/standby" path on active/passive HP
+ *   arrays.  These paths will return valid answers to certain SCSI commands
+ *   (tur, read_capacity, inquiry, start_stop), but will fail I/O commands.
+ *   The path needs an initialization command to be sent to it in order for
+ *   I/Os to succeed.
+ *
+ * PATH_PENDING:
+ * - Use: All async checkers
+ * - Description: Indicates a check IO is in flight.
+ */
+#define PATH_WILD	-1
+#define PATH_UNCHECKED	0
+#define PATH_DOWN	1
+#define PATH_UP		2
+#define PATH_SHAKY	3
+#define PATH_GHOST	4
+#define PATH_PENDING	5
+
+#define DIRECTIO     "directio"
+#define TUR          "tur"
+#define HP_SW        "hp_sw"
+#define RDAC         "rdac"
+#define EMC_CLARIION "emc_clariion"
+#define READSECTOR0  "readsector0"
+#define CCISS_TUR    "cciss_tur"
+
+#define DEFAULT_CHECKER DIRECTIO
+
+/*
+ * Overloaded storage response time can be very long.
+ * SG_IO timouts after DEF_TIMEOUT milliseconds, and checkers interprets this
+ * as a path failure. multipathd then proactively evicts the path from the DM
+ * multipath table in this case.
+ *
+ * This generaly snow balls and ends up in full eviction and IO errors for end
+ * users. Bad. This may also cause SCSI bus resets, causing disruption for all
+ * local and external storage hardware users.
+ * 
+ * Provision a long timeout. Longer than any real-world application would cope
+ * with.
+ */
+#define DEF_TIMEOUT		300000
+#define ASYNC_TIMEOUT_SEC	30
+
+/*
+ * strings lengths
+ */
+#define CHECKER_NAME_LEN 16
+#define CHECKER_MSG_LEN 256
+#define CHECKER_DEV_LEN 256
+#define LIB_CHECKER_NAMELEN 256
+
+struct checker {
+	struct list_head node;
+	int fd;
+	int sync;
+	int disable;
+	char name[CHECKER_NAME_LEN];
+	char message[CHECKER_MSG_LEN];       /* comm with callers */
+	void * context;                      /* store for persistent data */
+	void ** mpcontext;                   /* store for persistent data
+						shared multipath-wide */
+	int (*check)(struct checker *);
+	int (*init)(struct checker *);       /* to allocate the context */
+	void (*free)(struct checker *);      /* to free the context */
+};
+
+#define MSG(c, fmt, args...) snprintf((c)->message, CHECKER_MSG_LEN, fmt, ##args);
+
+int init_checkers (void);
+struct checker * add_checker (char *);
+struct checker * checker_lookup (char *);
+int checker_init (struct checker *, void **);
+void checker_put (struct checker *);
+void checker_reset (struct checker *);
+void checker_set_sync (struct checker *);
+void checker_set_async (struct checker *);
+void checker_set_fd (struct checker *, int);
+void checker_enable (struct checker *);
+void checker_disable (struct checker *);
+int checker_check (struct checker *);
+int checker_selected (struct checker *);
+char * checker_name (struct checker *);
+char * checker_message (struct checker *);
+void checker_get (struct checker *, char *);
+
+#endif /* _CHECKERS_H */
diff --git a/libmultipath/checkers/Makefile b/libmultipath/checkers/Makefile
new file mode 100644
index 0000000..a20dfac
--- /dev/null
+++ b/libmultipath/checkers/Makefile
@@ -0,0 +1,30 @@
+# Makefile
+#
+# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
+#
+include ../../Makefile.inc
+
+LIBS= \
+	libcheckcciss_tur.so \
+	libcheckreadsector0.so \
+	libchecktur.so \
+	libcheckdirectio.so \
+	libcheckemc_clariion.so \
+	libcheckhp_sw.so \
+	libcheckrdac.so
+
+CFLAGS += -I..
+
+all: $(LIBS)
+
+libcheck%.so: libsg.o %.o
+	$(CC) $(SHARED_FLAGS) -o $@ $^
+
+install:
+	$(INSTALL_PROGRAM) -m 755 $(LIBS) $(DESTDIR)$(libdir)
+
+uninstall:
+	rm -f $(DESTDIR)$(libdir)/$(LIBS)
+
+clean:
+	rm -f core *.a *.o *.gz *.so
diff --git a/libmultipath/checkers/cciss.h b/libmultipath/checkers/cciss.h
new file mode 100644
index 0000000..ebdff06
--- /dev/null
+++ b/libmultipath/checkers/cciss.h
@@ -0,0 +1,142 @@
+#ifndef CCISS_H
+#define CCISS_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define CCISS_IOC_MAGIC 'B'
+
+/*
+ * transfer direction
+ */
+#define XFER_NONE		0x00
+#define XFER_WRITE		0x01
+#define XFER_READ		0x02
+#define XFER_RSVD		0x03
+
+/*
+ * task attribute
+ */
+#define ATTR_UNTAGGED		0x00
+#define ATTR_SIMPLE		0x04
+#define ATTR_HEADOFQUEUE	0x05
+#define ATTR_ORDERED		0x06
+#define ATTR_ACA		0x07
+
+/*
+ * cdb type
+ */
+#define TYPE_CMD		0x00
+#define TYPE_MSG		0x01
+
+#define SENSEINFOBYTES		32
+
+/*
+ * Type defs used in the following structs
+ */
+#define BYTE __u8
+#define WORD __u16
+#define HWORD __u16
+#define DWORD __u32
+
+#pragma pack(1)
+
+//Command List Structure
+typedef union _SCSI3Addr_struct {
+   struct {
+    BYTE Dev;
+    BYTE Bus:6;
+    BYTE Mode:2;        // b00
+  } PeripDev;
+   struct {
+    BYTE DevLSB;
+    BYTE DevMSB:6;
+    BYTE Mode:2;        // b01
+  } LogDev;
+   struct {
+    BYTE Dev:5;
+    BYTE Bus:3;
+    BYTE Targ:6;
+    BYTE Mode:2;        // b10
+  } LogUnit;
+} SCSI3Addr_struct;
+
+typedef struct _PhysDevAddr_struct {
+  DWORD             TargetId:24;
+  DWORD             Bus:6;
+  DWORD             Mode:2;
+  SCSI3Addr_struct  Target[2]; //2 level target device addr
+} PhysDevAddr_struct;
+
+typedef struct _LogDevAddr_struct {
+  DWORD            VolId:30;
+  DWORD            Mode:2;
+  BYTE             reserved[4];
+} LogDevAddr_struct;
+
+typedef union _LUNAddr_struct {
+  BYTE               LunAddrBytes[8];
+  SCSI3Addr_struct   SCSI3Lun[4];
+  PhysDevAddr_struct PhysDev;
+  LogDevAddr_struct  LogDev;
+} LUNAddr_struct;
+
+typedef struct _RequestBlock_struct {
+  BYTE   CDBLen;
+  struct {
+    BYTE Type:3;
+    BYTE Attribute:3;
+    BYTE Direction:2;
+  } Type;
+  HWORD  Timeout;
+  BYTE   CDB[16];
+} RequestBlock_struct;
+
+typedef union _MoreErrInfo_struct{
+  struct {
+    BYTE  Reserved[3];
+    BYTE  Type;
+    DWORD ErrorInfo;
+  }Common_Info;
+  struct{
+    BYTE  Reserved[2];
+    BYTE  offense_size;//size of offending entry
+    BYTE  offense_num; //byte # of offense 0-base
+    DWORD offense_value;
+  }Invalid_Cmd;
+}MoreErrInfo_struct;
+
+typedef struct _ErrorInfo_struct {
+  BYTE               ScsiStatus;
+  BYTE               SenseLen;
+  HWORD              CommandStatus;
+  DWORD              ResidualCnt;
+  MoreErrInfo_struct MoreErrInfo;
+  BYTE               SenseInfo[SENSEINFOBYTES];
+} ErrorInfo_struct;
+
+#pragma pack()
+
+typedef struct _IOCTL_Command_struct {
+	LUNAddr_struct		LUN_info;
+	RequestBlock_struct	Request;
+	ErrorInfo_struct	error_info;
+	WORD			buf_size;  /* size in bytes of the buf */
+	BYTE			*buf;
+} IOCTL_Command_struct;
+
+typedef struct _LogvolInfo_struct{
+	__u32   LunID;
+	int     num_opens;  /* number of opens on the logical volume */
+	int     num_parts;  /* number of partitions configured on logvol */
+} LogvolInfo_struct;
+
+#define CCISS_PASSTHRU     _IOWR(CCISS_IOC_MAGIC, 11, IOCTL_Command_struct)
+#define CCISS_GETLUNINFO   _IOR(CCISS_IOC_MAGIC, 17, LogvolInfo_struct)
+
+int cciss_init( struct checker *);
+void cciss_free (struct checker * c);
+int cciss_tur( struct checker *);
+
+#endif
+
diff --git a/libmultipath/checkers/cciss_tur.c b/libmultipath/checkers/cciss_tur.c
new file mode 100644
index 0000000..4c26901
--- /dev/null
+++ b/libmultipath/checkers/cciss_tur.c
@@ -0,0 +1,137 @@
+/*
+ *****************************************************************************
+ *                                                                           *
+ *     (C)  Copyright 2007 Hewlett-Packard Development Company, L.P          *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify it   *
+ * under the terms of the GNU General Public License as published by the Free*
+ * Software  Foundation; either version 2 of the License, or (at your option)*
+ * any later version.                                                        *
+ *                                                                           *
+ * This program is distributed in the hope that it will be useful, but       *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY*
+ * or FITNESS FOR  A PARTICULAR PURPOSE. See the GNU General Public License  *
+ * for more details.                                                         *
+ *                                                                           *
+ * You should have received a copy of the GNU General Public License along   *
+ * with this program; if not, write to the Free Software Foundation, Inc.,   *
+ * 675 Mass Ave, Cambridge, MA 02139, USA.                                   *
+ *                                                                           *
+ * The copy of the GNU General Public License is available at                *
+ * /opt/hp/HPDMmultipath-tool directoy                                       *
+ *                                                                           *
+ *****************************************************************************
+*/
+
+/*
+ *  This program originally derived from and inspired by
+ *  Christophe Varoqui's tur.c, part of libchecker.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "checkers.h"
+
+#include "cciss.h"
+
+#define TUR_CMD_LEN 6
+#define HEAVY_CHECK_COUNT       10
+
+#define MSG_CCISS_TUR_UP	"cciss_tur checker reports path is up"
+#define MSG_CCISS_TUR_DOWN	"cciss_tur checker reports path is down"
+
+struct cciss_tur_checker_context {
+	void * dummy;
+};
+
+int libcheck_init (struct checker * c)
+{
+	return 0;
+}
+
+void libcheck_free (struct checker * c)
+{
+	return;
+}
+
+extern int
+libcheck_check (struct checker * c)
+{
+	int rc;
+	int ret;
+	unsigned int lun = 0;
+	struct cciss_tur_checker_context * ctxt = NULL;
+	LogvolInfo_struct    lvi;       // logical "volume" info
+	IOCTL_Command_struct cic;       // cciss ioctl command
+
+	if ((c->fd) <= 0) {
+		MSG(c,"no usable fd");
+		ret = -1;
+		goto out;
+	}
+
+	rc = ioctl(c->fd, CCISS_GETLUNINFO, &lvi);
+	if ( rc != 0) {
+		perror("Error: ");
+		fprintf(stderr, "cciss TUR  failed in CCISS_GETLUNINFO: %s\n",
+			strerror(errno));
+		MSG(c,MSG_CCISS_TUR_DOWN);
+		ret = PATH_DOWN;
+		goto out;
+	} else {
+		lun = lvi.LunID;
+	}
+
+	memset(&cic, 0, sizeof(cic));
+	cic.LUN_info.LogDev.VolId = lun & 0x3FFFFFFF;
+	cic.LUN_info.LogDev.Mode = 0x01; /* logical volume addressing */
+	cic.Request.CDBLen = 6;  /* need to try just 2 bytes here */
+	cic.Request.Type.Type =  TYPE_CMD; // It is a command.
+	cic.Request.Type.Attribute = ATTR_SIMPLE;
+	cic.Request.Type.Direction = XFER_NONE;
+	cic.Request.Timeout = 0;
+
+	cic.Request.CDB[0] = 0;
+	cic.Request.CDB[1] = 0;
+	cic.Request.CDB[2] = 0;
+	cic.Request.CDB[3] = 0;
+	cic.Request.CDB[4] = 0;
+	cic.Request.CDB[5] = 0;
+
+	rc = ioctl(c->fd, CCISS_PASSTHRU, &cic);
+	if (rc < 0) {
+		fprintf(stderr, "cciss TUR  failed: %s\n",
+			strerror(errno));
+		MSG(c,MSG_CCISS_TUR_DOWN);
+		ret = PATH_DOWN;
+		goto out;
+	}
+
+	if ((cic.error_info.CommandStatus | cic.error_info.ScsiStatus )) {
+		MSG(c,MSG_CCISS_TUR_DOWN);
+		ret = PATH_DOWN;
+		goto out;
+	}
+
+	MSG(c,MSG_CCISS_TUR_UP);
+
+	ret = PATH_UP;
+out:
+	/*
+	 * caller told us he doesn't want to keep the context :
+	 * free it
+	 */
+	if (!c->context)
+		free(ctxt);
+
+	return(ret);
+}
diff --git a/libmultipath/checkers/directio.c b/libmultipath/checkers/directio.c
new file mode 100644
index 0000000..5c92dac
--- /dev/null
+++ b/libmultipath/checkers/directio.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2005 Hannes Reinecke, Suse
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <errno.h>
+#include <linux/kdev_t.h>
+#include <asm/unistd.h>
+#include <libaio.h>
+
+#include "checkers.h"
+#include "../libmultipath/debug.h"
+
+#define MSG_DIRECTIO_UNKNOWN	"directio checker is not available"
+#define MSG_DIRECTIO_UP		"directio checker reports path is up"
+#define MSG_DIRECTIO_DOWN	"directio checker reports path is down"
+#define MSG_DIRECTIO_PENDING	"directio checker is waiting on aio"
+
+#define LOG(prio, fmt, args...) condlog(prio, "directio: " fmt, ##args)
+
+struct directio_context {
+	int		running;
+	int		reset_flags;
+	int		blksize;
+	unsigned char *	buf;
+	unsigned char * ptr;
+	io_context_t	ioctx;
+	struct iocb	io;
+};
+
+
+int libcheck_init (struct checker * c)
+{
+	unsigned long pgsize = getpagesize();
+	struct directio_context * ct;
+	long flags;
+
+	ct = malloc(sizeof(struct directio_context));
+	if (!ct)
+		return 1;
+	memset(ct, 0, sizeof(struct directio_context));
+
+	if (io_setup(1, &ct->ioctx) != 0) {
+		condlog(1, "io_setup failed");
+		free(ct);
+		return 1;
+	}
+
+	if (ioctl(c->fd, BLKBSZGET, &ct->blksize) < 0) {
+		MSG(c, "cannot get blocksize, set default");
+		ct->blksize = 512;
+	}
+	if (ct->blksize > 4096) {
+		/*
+		 * Sanity check for DASD; BSZGET is broken
+		 */
+		ct->blksize = 4096;
+	}
+	if (!ct->blksize)
+		goto out;
+	ct->buf = (unsigned char *)malloc(ct->blksize + pgsize);
+	if (!ct->buf)
+		goto out;
+
+	flags = fcntl(c->fd, F_GETFL);
+	if (flags < 0)
+		goto out;
+	if (!(flags & O_DIRECT)) {
+		flags |= O_DIRECT;
+		if (fcntl(c->fd, F_SETFL, flags) < 0)
+			goto out;
+		ct->reset_flags = 1;
+	}
+
+	ct->ptr = (unsigned char *) (((unsigned long)ct->buf + pgsize - 1) &
+		  (~(pgsize - 1)));
+
+	/* Sucessfully initialized, return the context. */
+	c->context = (void *) ct;
+	return 0;
+
+out:
+	if (ct->buf)
+		free(ct->buf);
+	io_destroy(ct->ioctx);
+	free(ct);
+	return 1;
+}
+
+void libcheck_free (struct checker * c)
+{
+	struct directio_context * ct = (struct directio_context *)c->context;
+	long flags;
+
+	if (!ct)
+		return;
+
+	if (ct->reset_flags) {
+		if ((flags = fcntl(c->fd, F_GETFL)) >= 0) {
+			flags &= ~O_DIRECT;
+			/* No point in checking for errors */
+			fcntl(c->fd, F_SETFL, flags);
+		}
+	}
+
+	if (ct->buf)
+		free(ct->buf);
+	io_destroy(ct->ioctx);
+	free(ct);
+}
+
+static int
+check_state(int fd, struct directio_context *ct, int sync)
+{
+	struct timespec	timeout = { .tv_nsec = 5 };
+	struct io_event event;
+	struct stat	sb;
+	int		rc = PATH_UNCHECKED;
+	long		r;
+
+	if (fstat(fd, &sb) == 0) {
+		LOG(4, "called for %x", (unsigned) sb.st_rdev);
+	}
+	if (sync) {
+		LOG(4, "called in synchronous mode");
+		timeout.tv_sec  = ASYNC_TIMEOUT_SEC;
+		timeout.tv_nsec = 0;
+	}
+
+	if (!ct->running) {
+		struct iocb *ios[1] = { &ct->io };
+
+		LOG(3, "starting new request");
+		memset(&ct->io, 0, sizeof(struct iocb));
+		io_prep_pread(&ct->io, fd, ct->ptr, ct->blksize, 0);
+		if (io_submit(ct->ioctx, 1, ios) != 1) {
+			LOG(3, "io_submit error %i", errno);
+			return PATH_UNCHECKED;
+		}
+	}
+	ct->running++;
+
+	r = io_getevents(ct->ioctx, 1L, 1L, &event, &timeout);
+	LOG(3, "async io getevents returns %li (errno=%s)", r, strerror(errno));
+
+	if (r < 1L) {
+		if (ct->running > ASYNC_TIMEOUT_SEC || sync) {
+			LOG(3, "abort check on timeout");
+			rc = PATH_DOWN;
+		} else
+			rc = PATH_PENDING;
+	} else {
+		LOG(3, "io finished %lu/%lu", event.res, event.res2);
+		ct->running = 0;
+		rc = (event.res == ct->blksize) ? PATH_UP : PATH_DOWN;
+	}
+
+	return rc;
+}
+
+int libcheck_check (struct checker * c)
+{
+	int ret;
+	struct directio_context * ct = (struct directio_context *)c->context;
+
+	if (!ct)
+		return PATH_UNCHECKED;
+
+	ret = check_state(c->fd, ct, c->sync);
+
+	switch (ret)
+	{
+	case PATH_UNCHECKED:
+		MSG(c, MSG_DIRECTIO_UNKNOWN);
+		break;
+	case PATH_DOWN:
+		MSG(c, MSG_DIRECTIO_DOWN);
+		break;
+	case PATH_UP:
+		MSG(c, MSG_DIRECTIO_UP);
+		break;
+	case PATH_PENDING:
+		MSG(c, MSG_DIRECTIO_PENDING);
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
diff --git a/libmultipath/checkers/directio.h b/libmultipath/checkers/directio.h
new file mode 100644
index 0000000..1865b1f
--- /dev/null
+++ b/libmultipath/checkers/directio.h
@@ -0,0 +1,8 @@
+#ifndef _DIRECTIO_H
+#define _DIRECTIO_H
+
+int directio (struct checker *);
+int directio_init (struct checker *);
+void directio_free (struct checker *);
+
+#endif /* _DIRECTIO_H */
diff --git a/libmultipath/checkers/emc_clariion.c b/libmultipath/checkers/emc_clariion.c
new file mode 100644
index 0000000..9eac31d
--- /dev/null
+++ b/libmultipath/checkers/emc_clariion.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2004, 2005 Lars Marowsky-Bree
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "../libmultipath/sg_include.h"
+#include "libsg.h"
+#include "checkers.h"
+
+#define INQUIRY_CMD     0x12
+#define INQUIRY_CMDLEN  6
+#define HEAVY_CHECK_COUNT       10
+
+/*
+ * Mechanism to track CLARiiON inactive snapshot LUs.
+ * This is done so that we can fail passive paths
+ * to an inactive snapshot LU even though since a
+ * simple read test would return 02/04/03 instead
+ * of 05/25/01 sensekey/ASC/ASCQ data.
+ */
+#define	IS_INACTIVE_SNAP(c)   (c->mpcontext ?				   \
+			       ((struct emc_clariion_checker_LU_context *) \
+					(*c->mpcontext))->inactive_snap	   \
+					    : 0)
+
+#define	SET_INACTIVE_SNAP(c)  if (c->mpcontext)				   \
+				((struct emc_clariion_checker_LU_context *)\
+					(*c->mpcontext))->inactive_snap = 1
+
+#define	CLR_INACTIVE_SNAP(c)  if (c->mpcontext)				   \
+				((struct emc_clariion_checker_LU_context *)\
+					(*c->mpcontext))->inactive_snap = 0
+
+struct emc_clariion_checker_path_context {
+	char wwn[16];
+	unsigned wwn_set;
+};
+
+struct emc_clariion_checker_LU_context {
+	int inactive_snap;
+};
+
+extern void
+hexadecimal_to_ascii(char * wwn, char *wwnstr)
+{
+	int i,j, nbl;
+
+	for (i=0,j=0;i<16;i++) {
+		wwnstr[j++] = ((nbl = ((wwn[i]&0xf0) >> 4)) <= 9) ?
+					'0' + nbl : 'a' + (nbl - 10);
+		wwnstr[j++] = ((nbl = (wwn[i]&0x0f)) <= 9) ?
+					'0' + nbl : 'a' + (nbl - 10);
+	}
+	wwnstr[32]=0;
+}
+
+int libcheck_init (struct checker * c)
+{
+	/*
+	 * Allocate and initialize the path specific context.
+	 */
+	c->context = malloc(sizeof(struct emc_clariion_checker_path_context));
+	if (!c->context)
+		return 1;
+	((struct emc_clariion_checker_path_context *)c->context)->wwn_set = 0;
+
+	/*
+	 * Allocate and initialize the multi-path global context.
+	 */
+	if (c->mpcontext) {
+		void * mpctxt = malloc(sizeof(int));
+		*c->mpcontext = mpctxt;
+		CLR_INACTIVE_SNAP(c);
+	}
+
+	return 0;
+}
+
+void libcheck_free (struct checker * c)
+{
+	free(c->context);
+}
+
+int libcheck_check (struct checker * c)
+{
+	unsigned char sense_buffer[128] = { 0, };
+	unsigned char sb[SENSE_BUFF_LEN] = { 0, }, *sbb;
+	unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
+						sizeof(sense_buffer), 0};
+	struct sg_io_hdr io_hdr;
+	struct emc_clariion_checker_path_context * ct =
+		(struct emc_clariion_checker_path_context *)c->context;
+	char wwnstr[33];
+	int ret;
+
+	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = sizeof (inqCmdBlk);
+	io_hdr.mx_sb_len = sizeof (sb);
+	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+	io_hdr.dxfer_len = sizeof (sense_buffer);
+	io_hdr.dxferp = sense_buffer;
+	io_hdr.cmdp = inqCmdBlk;
+	io_hdr.sbp = sb;
+	io_hdr.timeout = DEF_TIMEOUT;
+	io_hdr.pack_id = 0;
+	if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
+		MSG(c, "emc_clariion_checker: sending query command failed");
+		return PATH_DOWN;
+	}
+	if (io_hdr.info & SG_INFO_OK_MASK) {
+		MSG(c, "emc_clariion_checker: query command indicates error");
+		return PATH_DOWN;
+	}
+	if (/* Verify the code page - right page & revision */
+	    sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) {
+		MSG(c, "emc_clariion_checker: Path unit report page in "
+		    "unknown format");
+		return PATH_DOWN;
+	}
+
+	if ( /* Effective initiator type */
+	    	sense_buffer[27] != 0x03
+		/*
+		 * Failover mode should be set to 1 (PNR failover mode)
+		 * or 4 (ALUA failover mode).
+		 */
+		|| (((sense_buffer[28] & 0x07) != 0x04) &&
+		    ((sense_buffer[28] & 0x07) != 0x06))
+		/* Arraycommpath should be set to 1 */
+		|| (sense_buffer[30] & 0x04) != 0x04) {
+		MSG(c, "emc_clariion_checker: Path not correctly configured "
+		    "for failover");
+		return PATH_DOWN;
+	}
+
+	if ( /* LUN operations should indicate normal operations */
+		sense_buffer[48] != 0x00) {
+		MSG(c, "emc_clariion_checker: Path not available for normal "
+		    "operations");
+		return PATH_SHAKY;
+	}
+
+	if ( /* LUN should at least be bound somewhere and not be LUNZ */
+		sense_buffer[4] == 0x00) {
+		MSG(c, "emc_clariion_checker: Logical Unit is unbound "
+		    "or LUNZ");
+		return PATH_DOWN;
+	}
+	
+	/*
+	 * store the LUN WWN there and compare that it indeed did not
+	 * change in between, to protect against the path suddenly
+	 * pointing somewhere else.
+	 */
+	if (ct->wwn_set) {
+		if (memcmp(ct->wwn, &sense_buffer[10], 16) != 0) {
+			MSG(c, "emc_clariion_checker: Logical Unit WWN "
+			    "has changed!");
+			return PATH_DOWN;
+		}
+	} else {
+		memcpy(ct->wwn, &sense_buffer[10], 16);
+		ct->wwn_set = 1;
+	}
+	
+	/*
+	 * Issue read on active path to determine if inactive snapshot.
+	 */
+	if (sense_buffer[4] == 2) {/* if active path */
+		unsigned char buf[4096];
+
+		ret = sg_read(c->fd, &buf[0], sbb = &sb[0]);
+		if (ret == PATH_DOWN) {
+			hexadecimal_to_ascii(ct->wwn, wwnstr);
+
+			/*
+		 	 * Check for inactive snapshot LU this way.  Must
+			 * fail these.
+	 	 	 */
+			if (((sbb[2]&0xf) == 5) && (sbb[12] == 0x25) &&
+			    (sbb[13]==1)) {
+				/*
+			 	 * Do this so that we can fail even the
+			 	 * passive paths which will return
+				 * 02/04/03 not 05/25/01 on read.
+			 	 */
+				SET_INACTIVE_SNAP(c);
+				MSG(c, "emc_clariion_checker: Active "
+					"path to inactive snapshot WWN %s.",
+					wwnstr);
+			} else
+				MSG(c, "emc_clariion_checker: Read "
+					"error for WWN %s.  Sense data are "
+					"0x%x/0x%x/0x%x.", wwnstr,
+					sbb[2]&0xf, sbb[12], sbb[13]);
+		} else {
+			MSG(c, "emc_clariion_checker: Active path is "
+			    "healthy.");
+			/*
+		 	 * Remove the path from the set of paths to inactive
+		 	 * snapshot LUs if it was in this list since the
+		 	 * snapshot is no longer inactive.
+		 	 */
+			CLR_INACTIVE_SNAP(c);
+		}
+	} else {
+		if (IS_INACTIVE_SNAP(c)) {
+			hexadecimal_to_ascii(ct->wwn, wwnstr);
+			MSG(c, "emc_clariion_checker: Passive "
+				"path to inactive snapshot WWN %s.",
+				wwnstr);
+			ret = PATH_DOWN;
+		} else {
+			MSG(c,
+		    	    "emc_clariion_checker: Passive path is healthy.");
+			ret = PATH_UP;	/* not ghost */
+		}
+	}
+
+	return ret;
+}
diff --git a/libmultipath/checkers/emc_clariion.h b/libmultipath/checkers/emc_clariion.h
new file mode 100644
index 0000000..a1018a6
--- /dev/null
+++ b/libmultipath/checkers/emc_clariion.h
@@ -0,0 +1,8 @@
+#ifndef _EMC_CLARIION_H
+#define _EMC_CLARIION_H
+
+int emc_clariion (struct checker *);
+int emc_clariion_init (struct checker *);
+void emc_clariion_free (struct checker *);
+
+#endif /* _EMC_CLARIION_H */
diff --git a/libmultipath/checkers/hp_sw.c b/libmultipath/checkers/hp_sw.c
new file mode 100644
index 0000000..7509307
--- /dev/null
+++ b/libmultipath/checkers/hp_sw.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "checkers.h"
+
+#include "../libmultipath/sg_include.h"
+
+#define TUR_CMD_LEN		6
+#define INQUIRY_CMDLEN		6
+#define INQUIRY_CMD		0x12
+#define SENSE_BUFF_LEN		32
+#define SCSI_CHECK_CONDITION	0x2
+#define SCSI_COMMAND_TERMINATED	0x22
+#define SG_ERR_DRIVER_SENSE	0x08
+#define RECOVERED_ERROR		0x01
+#define MX_ALLOC_LEN		255
+#define HEAVY_CHECK_COUNT       10
+
+#define MSG_HP_SW_UP	"hp_sw checker reports path is up"
+#define MSG_HP_SW_DOWN	"hp_sw checker reports path is down"
+#define MSG_HP_SW_GHOST	"hp_sw checker reports path is ghost"
+
+struct sw_checker_context {
+	void * dummy;
+};
+
+int libcheck_init (struct checker * c)
+{
+	return 0;
+}
+
+void libcheck_free (struct checker * c)
+{
+	return;
+}
+
+static int
+do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
+       void *resp, int mx_resp_len, int noisy)
+{
+        unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
+            { INQUIRY_CMD, 0, 0, 0, 0, 0 };
+        unsigned char sense_b[SENSE_BUFF_LEN];
+        struct sg_io_hdr io_hdr;
+                                                                                                                 
+        if (cmddt)
+                inqCmdBlk[1] |= 2;
+        if (evpd)
+                inqCmdBlk[1] |= 1;
+        inqCmdBlk[2] = (unsigned char) pg_op;
+	inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+	inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
+        memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+        io_hdr.interface_id = 'S';
+        io_hdr.cmd_len = sizeof (inqCmdBlk);
+        io_hdr.mx_sb_len = sizeof (sense_b);
+        io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+        io_hdr.dxfer_len = mx_resp_len;
+        io_hdr.dxferp = resp;
+        io_hdr.cmdp = inqCmdBlk;
+        io_hdr.sbp = sense_b;
+        io_hdr.timeout = DEF_TIMEOUT;
+ 
+        if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
+                return 1;
+ 
+        /* treat SG_ERR here to get rid of sg_err.[ch] */
+        io_hdr.status &= 0x7e;
+        if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
+            (0 == io_hdr.driver_status))
+                return 0;
+        if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
+            (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
+            (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
+                if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
+                        int sense_key;
+                        unsigned char * sense_buffer = io_hdr.sbp;
+                        if (sense_buffer[0] & 0x2)
+                                sense_key = sense_buffer[1] & 0xf;
+                        else
+                                sense_key = sense_buffer[2] & 0xf;
+                        if(RECOVERED_ERROR == sense_key)
+                                return 0;
+                }
+        }
+        return 1;
+}
+
+static int
+do_tur (int fd)
+{
+        unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
+        struct sg_io_hdr io_hdr;
+        unsigned char sense_buffer[32];
+
+        memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+        io_hdr.interface_id = 'S';
+        io_hdr.cmd_len = sizeof (turCmdBlk);
+        io_hdr.mx_sb_len = sizeof (sense_buffer);
+        io_hdr.dxfer_direction = SG_DXFER_NONE;
+        io_hdr.cmdp = turCmdBlk;
+        io_hdr.sbp = sense_buffer;
+        io_hdr.timeout = DEF_TIMEOUT;
+        io_hdr.pack_id = 0;
+
+        if (ioctl(fd, SG_IO, &io_hdr) < 0)
+		return 1;
+
+        if (io_hdr.info & SG_INFO_OK_MASK)
+		return 1;
+
+	return 0;
+}
+
+extern int
+libcheck_check (struct checker * c)
+{
+	char buff[MX_ALLOC_LEN];
+
+	if (0 != do_inq(c->fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
+		MSG(c, MSG_HP_SW_DOWN);
+		return PATH_DOWN;
+	}
+
+	if (do_tur(c->fd)) {
+		MSG(c, MSG_HP_SW_GHOST);
+                return PATH_GHOST;
+        }
+	MSG(c, MSG_HP_SW_UP);
+	return PATH_UP;
+}
diff --git a/libmultipath/checkers/hp_sw.h b/libmultipath/checkers/hp_sw.h
new file mode 100644
index 0000000..3be0d8e
--- /dev/null
+++ b/libmultipath/checkers/hp_sw.h
@@ -0,0 +1,8 @@
+#ifndef _HP_SW_H
+#define _HP_SW_H
+
+int hp_sw (struct checker *);
+int hp_sw_init (struct checker *);
+void hp_sw_free (struct checker *);
+
+#endif /* _HP_SW_H */
diff --git a/libmultipath/checkers/libsg.c b/libmultipath/checkers/libsg.c
new file mode 100644
index 0000000..4cb7ecc
--- /dev/null
+++ b/libmultipath/checkers/libsg.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
+#include <string.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "checkers.h"
+#include "libsg.h"
+#include "../libmultipath/sg_include.h"
+
+int
+sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff)
+{
+	/* defaults */
+	int blocks = 1;
+	long long start_block = 0;
+	int bs = 512;
+	int cdbsz = 10;
+	int * diop = NULL;
+
+	unsigned char rdCmd[cdbsz];
+	unsigned char *sbb = senseBuff;
+	struct sg_io_hdr io_hdr;
+	int res;
+	int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88};
+	int sz_ind;
+	struct stat filestatus;
+	int retry_count = 3;
+
+	if (fstat(sg_fd, &filestatus) != 0)
+		return PATH_DOWN;
+	bs = (filestatus.st_blksize > 4096)? 4096: filestatus.st_blksize;
+	memset(rdCmd, 0, cdbsz);
+	sz_ind = 1;
+	rdCmd[0] = rd_opcode[sz_ind];
+	rdCmd[2] = (unsigned char)((start_block >> 24) & 0xff);
+	rdCmd[3] = (unsigned char)((start_block >> 16) & 0xff);
+	rdCmd[4] = (unsigned char)((start_block >> 8) & 0xff);
+	rdCmd[5] = (unsigned char)(start_block & 0xff);
+	rdCmd[7] = (unsigned char)((blocks >> 8) & 0xff);
+	rdCmd[8] = (unsigned char)(blocks & 0xff);
+
+	memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = cdbsz;
+	io_hdr.cmdp = rdCmd;
+	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+	io_hdr.dxfer_len = bs * blocks;
+	io_hdr.dxferp = buff;
+	io_hdr.mx_sb_len = SENSE_BUFF_LEN;
+	io_hdr.sbp = senseBuff;
+	io_hdr.timeout = DEF_TIMEOUT;
+	io_hdr.pack_id = (int)start_block;
+	if (diop && *diop)
+	io_hdr.flags |= SG_FLAG_DIRECT_IO;
+
+retry: 
+	memset(senseBuff, 0, SENSE_BUFF_LEN);
+	while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno));
+
+	if (res < 0) {
+		if (ENOMEM == errno) {
+			return PATH_UP;
+		}
+		return PATH_DOWN;
+	}
+
+	if ((0 == io_hdr.status) &&
+	    (0 == io_hdr.host_status) &&
+	    (0 == io_hdr.driver_status)) {
+		return PATH_UP;
+	} else {
+		int key = 0;
+
+		if (io_hdr.sb_len_wr > 3) {
+			if (sbb[0] == 0x72 || sbb[0] == 0x73)
+				key = sbb[1] & 0x0f;
+			else if (io_hdr.sb_len_wr > 13 &&
+				 ((sbb[0] & 0x7f) == 0x70 ||
+				  (sbb[0] & 0x7f) == 0x71))
+				key = sbb[2] & 0x0f;
+		}
+
+		/*
+		 * Retry if UNIT_ATTENTION check condition.
+		 */
+		if (key == 0x6) {
+			if (--retry_count)
+				goto retry;
+		}
+		return PATH_DOWN;
+	}
+}
diff --git a/libmultipath/checkers/libsg.h b/libmultipath/checkers/libsg.h
new file mode 100644
index 0000000..97c4491
--- /dev/null
+++ b/libmultipath/checkers/libsg.h
@@ -0,0 +1,8 @@
+#ifndef _LIBSG_H
+#define _LIBSG_H
+
+#define SENSE_BUFF_LEN 32
+
+int sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff);
+
+#endif /* _LIBSG_H */
diff --git a/libmultipath/checkers/rdac.c b/libmultipath/checkers/rdac.c
new file mode 100644
index 0000000..0086125
--- /dev/null
+++ b/libmultipath/checkers/rdac.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "checkers.h"
+
+#include "../libmultipath/sg_include.h"
+
+#define INQUIRY_CMDLEN		6
+#define INQUIRY_CMD		0x12
+#define SENSE_BUFF_LEN		32
+#define RDAC_DEF_TIMEOUT	60000
+#define SCSI_CHECK_CONDITION	0x2
+#define SCSI_COMMAND_TERMINATED	0x22
+#define SG_ERR_DRIVER_SENSE	0x08
+#define RECOVERED_ERROR		0x01
+
+#define MSG_RDAC_UP    "rdac checker reports path is up"
+#define MSG_RDAC_DOWN  "rdac checker reports path is down"
+#define MSG_RDAC_GHOST "rdac checker reports path is ghost"
+
+struct rdac_checker_context {
+	void * dummy;
+};
+
+int libcheck_init (struct checker * c)
+{
+	return 0;
+}
+
+void libcheck_free (struct checker * c)
+{
+	return;
+}
+
+static int
+do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len)
+{
+	unsigned char inqCmdBlk[INQUIRY_CMDLEN] = { INQUIRY_CMD, 1, 0, 0, 0, 0 };
+	unsigned char sense_b[SENSE_BUFF_LEN];
+	struct sg_io_hdr io_hdr;
+
+	inqCmdBlk[2] = (unsigned char) pg_op;
+	inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
+	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = sizeof (inqCmdBlk);
+	io_hdr.mx_sb_len = sizeof (sense_b);
+	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+	io_hdr.dxfer_len = mx_resp_len;
+	io_hdr.dxferp = resp;
+	io_hdr.cmdp = inqCmdBlk;
+	io_hdr.sbp = sense_b;
+	io_hdr.timeout = RDAC_DEF_TIMEOUT;
+
+	if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
+		return 1;
+
+	/* treat SG_ERR here to get rid of sg_err.[ch] */
+	io_hdr.status &= 0x7e;
+	if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
+	    (0 == io_hdr.driver_status))
+		return 0;
+	if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
+	    (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
+	    (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
+		if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
+			int sense_key;
+			unsigned char * sense_buffer = io_hdr.sbp;
+			if (sense_buffer[0] & 0x2)
+				sense_key = sense_buffer[1] & 0xf;
+			else
+				sense_key = sense_buffer[2] & 0xf;
+			if (RECOVERED_ERROR == sense_key)
+				return 0;
+		}
+	}
+	return 1;
+}
+
+struct volume_access_inq
+{
+	char dontcare0[8];
+	char avtcvp;
+	char dontcare1[39];
+};
+
+extern int
+libcheck_check (struct checker * c)
+{
+	struct volume_access_inq inq;
+
+	if (0 != do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq))) {
+		MSG(c, MSG_RDAC_DOWN);
+		return PATH_DOWN;
+	}
+
+	return ((inq.avtcvp & 0x1) ? PATH_UP : PATH_GHOST);
+}
diff --git a/libmultipath/checkers/rdac.h b/libmultipath/checkers/rdac.h
new file mode 100644
index 0000000..d7bf812
--- /dev/null
+++ b/libmultipath/checkers/rdac.h
@@ -0,0 +1,8 @@
+#ifndef _RDAC_H
+#define _RDAC_H
+
+int rdac(struct checker *);
+int rdac_init(struct checker *);
+void rdac_free(struct checker *);
+
+#endif /* _RDAC_H */
diff --git a/libmultipath/checkers/readsector0.c b/libmultipath/checkers/readsector0.c
new file mode 100644
index 0000000..24182e6
--- /dev/null
+++ b/libmultipath/checkers/readsector0.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
+#include <stdio.h>
+
+#include "checkers.h"
+#include "libsg.h"
+
+#define MSG_READSECTOR0_UP	"readsector0 checker reports path is up"
+#define MSG_READSECTOR0_DOWN	"readsector0 checker reports path is down"
+
+struct readsector0_checker_context {
+	void * dummy;
+};
+
+int libcheck_init (struct checker * c)
+{
+	return 0;
+}
+
+void libcheck_free (struct checker * c)
+{
+	return;
+}
+
+int libcheck_check (struct checker * c)
+{
+	unsigned char buf[4096];
+	unsigned char sbuf[SENSE_BUFF_LEN];
+	int ret;
+
+	ret = sg_read(c->fd, &buf[0], &sbuf[0]);
+
+	switch (ret)
+	{
+	case PATH_DOWN:
+		MSG(c, MSG_READSECTOR0_DOWN);
+		break;
+	case PATH_UP:
+		MSG(c, MSG_READSECTOR0_UP);
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
diff --git a/libmultipath/checkers/readsector0.h b/libmultipath/checkers/readsector0.h
new file mode 100644
index 0000000..0f5d654
--- /dev/null
+++ b/libmultipath/checkers/readsector0.h
@@ -0,0 +1,8 @@
+#ifndef _READSECTOR0_H
+#define _READSECTOR0_H
+
+int readsector0 (struct checker *);
+int readsector0_init (struct checker *);
+void readsector0_free (struct checker *);
+
+#endif /* _READSECTOR0_H */
diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c
new file mode 100644
index 0000000..43b846d
--- /dev/null
+++ b/libmultipath/checkers/tur.c
@@ -0,0 +1,88 @@
+/*
+ * Some code borrowed from sg-utils.
+ *
+ * Copyright (c) 2004 Christophe Varoqui
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "checkers.h"
+
+#include "../libmultipath/sg_include.h"
+
+#define TUR_CMD_LEN 6
+#define HEAVY_CHECK_COUNT       10
+
+#define MSG_TUR_UP	"tur checker reports path is up"
+#define MSG_TUR_DOWN	"tur checker reports path is down"
+
+struct tur_checker_context {
+	void * dummy;
+};
+
+int libcheck_init (struct checker * c)
+{
+	return 0;
+}
+
+void libcheck_free (struct checker * c)
+{
+	return;
+}
+
+extern int
+libcheck_check (struct checker * c)
+{
+	struct sg_io_hdr io_hdr;
+	unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
+	unsigned char sense_buffer[32];
+	int retry_tur = 5;
+
+ retry:
+	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = sizeof (turCmdBlk);
+	io_hdr.mx_sb_len = sizeof (sense_buffer);
+	io_hdr.dxfer_direction = SG_DXFER_NONE;
+	io_hdr.cmdp = turCmdBlk;
+	io_hdr.sbp = sense_buffer;
+	io_hdr.timeout = DEF_TIMEOUT;
+	io_hdr.pack_id = 0;
+	if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
+		MSG(c, MSG_TUR_DOWN);
+		return PATH_DOWN;
+	}
+	if (io_hdr.info & SG_INFO_OK_MASK) {
+		int key = 0, asc, ascq;
+
+		if (io_hdr.sb_len_wr > 3) {
+			if (io_hdr.sbp[0] == 0x72 || io_hdr.sbp[0] == 0x73) {
+				key = io_hdr.sbp[1] & 0x0f;
+				asc = io_hdr.sbp[2];
+				ascq = io_hdr.sbp[3];
+			} else if (io_hdr.sb_len_wr > 13 &&
+				   ((io_hdr.sbp[0] & 0x7f) == 0x70 ||
+				    (io_hdr.sbp[0] & 0x7f) == 0x71)) {
+				key = io_hdr.sbp[2] & 0x0f;
+				asc = io_hdr.sbp[12];
+				ascq = io_hdr.sbp[13];
+			}
+		}
+		if (key == 0x6) {
+			/* Unit Attention, retry */
+			if (--retry_tur)
+				goto retry;
+		}
+		MSG(c, MSG_TUR_DOWN);
+		return PATH_DOWN;
+	}
+	MSG(c, MSG_TUR_UP);
+	return PATH_UP;
+}
diff --git a/libmultipath/checkers/tur.h b/libmultipath/checkers/tur.h
new file mode 100644
index 0000000..a2e8c88
--- /dev/null
+++ b/libmultipath/checkers/tur.h
@@ -0,0 +1,8 @@
+#ifndef _TUR_H
+#define _TUR_H
+
+int tur (struct checker *);
+int tur_init (struct checker *);
+void tur_free (struct checker *);
+
+#endif /* _TUR_H */
diff --git a/libmultipath/config.c b/libmultipath/config.c
index a39af8a..a109cd9 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -6,8 +6,7 @@
 #include <stdio.h>
 #include <string.h>
 
-#include <checkers.h>
-
+#include "checkers.h"
 #include "memory.h"
 #include "util.h"
 #include "debug.h"
@@ -19,24 +18,33 @@
 #include "config.h"
 #include "blacklist.h"
 #include "defaults.h"
+#include "prio.h"
 
-static struct hwentry *
-find_hwe_strmatch (vector hwtable, char * vendor, char * product, char * revision)
+static int
+hwe_strmatch (struct hwentry *hwe1, struct hwentry *hwe2)
 {
-	int i;
-	struct hwentry *hwe, *ret = NULL;
+	if (hwe1->vendor && hwe2->vendor && strcmp(hwe1->vendor, hwe2->vendor))
+		return 1;
 
-	vector_foreach_slot (hwtable, hwe, i) {
-		if (hwe->vendor && vendor && strcmp(hwe->vendor, vendor))
-			continue;
+	if (hwe1->product && hwe2->product && strcmp(hwe1->product, hwe2->product))
+		return 1;
 
-		if (hwe->product && product && strcmp(hwe->product, product))
-			continue;
+	if (hwe1->revision && hwe2->revision && strcmp(hwe1->revision, hwe2->revision))
+		return 1;
 
-		if (hwe->revision && revision && strcmp(hwe->revision, revision))
-			continue;
+	return 0;
+}
 
-		ret = hwe;
+static struct hwentry *
+find_hwe_strmatch (vector hwtable, struct hwentry *hwe)
+{
+	int i;
+	struct hwentry *tmp, *ret = NULL;
+
+	vector_foreach_slot (hwtable, tmp, i) {
+		if (hwe_strmatch(tmp, hwe))
+			continue;
+		ret = tmp;
 		break;
 	}
 	return ret;
@@ -135,9 +143,6 @@ free_hwe (struct hwentry * hwe)
 	if (hwe->getuid)
 		FREE(hwe->getuid);
 
-	if (hwe->getprio)
-		FREE(hwe->getprio);
-
 	if (hwe->features)
 		FREE(hwe->features);
 
@@ -242,12 +247,47 @@ set_param_str(char * str)
 	return dst;
 }
 
+#define merge_str(s) \
+	if (hwe2->s) { \
+		if (hwe1->s) \
+			free(hwe1->s); \
+		if (!(hwe1->s = set_param_str(hwe2->s))) \
+			return 1; \
+	}
+
+#define merge_num(s) \
+	if (hwe2->s) \
+		hwe1->s = hwe2->s
+
+
+static int
+merge_hwe (struct hwentry * hwe1, struct hwentry * hwe2)
+{
+	merge_str(vendor);
+	merge_str(product);
+	merge_str(revision);
+	merge_str(getuid);
+	merge_str(features);
+	merge_str(hwhandler);
+	merge_str(selector);
+	merge_str(checker_name);
+	merge_str(prio_name);
+	merge_str(bl_product);
+	merge_num(pgpolicy);
+	merge_num(pgfailback);
+	merge_num(rr_weight);
+	merge_num(no_path_retry);
+	merge_num(minio);
+
+	return 0;
+}
+
 int
 store_hwe (vector hwtable, struct hwentry * dhwe)
 {
 	struct hwentry * hwe;
 
-	if (find_hwe_strmatch(hwtable, dhwe->vendor, dhwe->product, dhwe->revision))
+	if (find_hwe_strmatch(hwtable, dhwe))
 		return 0;
 	
 	if (!(hwe = alloc_hwe()))
@@ -265,9 +305,6 @@ store_hwe (vector hwtable, struct hwentry * dhwe)
 	if (dhwe->getuid && !(hwe->getuid = set_param_str(dhwe->getuid)))
 		goto out;
 
-	if (dhwe->getprio && !(hwe->getprio = set_param_str(dhwe->getprio)))
-		goto out;
-				
 	if (dhwe->features && !(hwe->features = set_param_str(dhwe->features)))
 		goto out;
 	
@@ -276,13 +313,18 @@ store_hwe (vector hwtable, struct hwentry * dhwe)
 
 	if (dhwe->selector && !(hwe->selector = set_param_str(dhwe->selector)))
 		goto out;
+
+	if (dhwe->checker_name && !(hwe->checker_name = set_param_str(dhwe->checker_name)))
+		goto out;
+				
+	if (dhwe->prio_name && !(hwe->prio_name = set_param_str(dhwe->prio_name)))
+		goto out;
 				
 	hwe->pgpolicy = dhwe->pgpolicy;
 	hwe->pgfailback = dhwe->pgfailback;
 	hwe->rr_weight = dhwe->rr_weight;
 	hwe->no_path_retry = dhwe->no_path_retry;
 	hwe->minio = dhwe->minio;
-	hwe->checker = dhwe->checker;
 
 	if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product)))
 		goto out;
@@ -297,6 +339,27 @@ out:
 	return 1;
 }
 
+static int
+factorize_hwtable (vector hw)
+{
+	struct hwentry *hwe1, *hwe2;
+	int i, j;
+
+	vector_foreach_slot(hw, hwe1, i) {
+		j = i+1;
+		vector_foreach_slot_after(hw, hwe2, j) {
+			if (hwe_strmatch(hwe1, hwe2))
+				continue;
+			/* dup */
+			merge_hwe(hwe1, hwe2);
+			free_hwe(hwe2);
+			vector_del_slot(hw, j);
+			j--;
+		}
+	}
+	return 0;
+}
+
 struct config *
 alloc_config (void)
 {
@@ -315,15 +378,15 @@ free_config (struct config * conf)
 	if (conf->udev_dir)
 		FREE(conf->udev_dir);
 
+	if (conf->multipath_dir)
+		FREE(conf->multipath_dir);
+
 	if (conf->selector)
 		FREE(conf->selector);
 
 	if (conf->getuid)
 		FREE(conf->getuid);
 
-	if (conf->getprio)
-		FREE(conf->getprio);
-
 	if (conf->features)
 		FREE(conf->features);
 
@@ -361,7 +424,21 @@ load_config (char * file)
 
 	conf->dev_type = DEV_NONE;
 	conf->minio = 1000;
+	conf->max_fds = 0;
 	conf->bindings_file = DEFAULT_BINDINGS_FILE;
+	conf->multipath_dir = set_default(DEFAULT_MULTIPATHDIR);
+
+	/*
+	 * preload default hwtable
+	 */
+	if (conf->hwtable == NULL) {
+		conf->hwtable = vector_alloc();
+
+		if (!conf->hwtable)
+			goto out;
+	}
+	if (setup_default_hwtable(conf->hwtable))
+		goto out;
 
 	/*
 	 * read the config file
@@ -373,35 +450,31 @@ load_config (char * file)
 			goto out;
 		}
 	}
-	
+
 	/*
-	 * fill the voids left in the config file
+	 * remove duplica in hwtable. config file takes precedence
+	 * over build-in hwtable
 	 */
-	if (conf->hwtable == NULL) {
-		conf->hwtable = vector_alloc();
-		
-		if (!conf->hwtable)
-			goto out;
-		
-	}
-	if (setup_default_hwtable(conf->hwtable))
-		goto out;
+	factorize_hwtable(conf->hwtable);
 
+	/*
+	 * fill the voids left in the config file
+	 */
 	if (conf->blist_devnode == NULL) {
 		conf->blist_devnode = vector_alloc();
-		
+
 		if (!conf->blist_devnode)
 			goto out;
 	}
 	if (conf->blist_wwid == NULL) {
 		conf->blist_wwid = vector_alloc();
-		
+
 		if (!conf->blist_wwid)
 			goto out;
 	}
 	if (conf->blist_device == NULL) {
 		conf->blist_device = vector_alloc();
-		
+
 		if (!conf->blist_device)
 			goto out;
 	}
@@ -409,21 +482,21 @@ load_config (char * file)
 		goto out;
 
 	if (conf->elist_devnode == NULL) {
-                conf->elist_devnode = vector_alloc();
+		conf->elist_devnode = vector_alloc();
 
-                if (!conf->elist_devnode)
+		if (!conf->elist_devnode)
 			goto out;
 	}
 	if (conf->elist_wwid == NULL) {
 		conf->elist_wwid = vector_alloc();
 
-                if (!conf->elist_wwid)
+		if (!conf->elist_wwid)
 			goto out;
 	}
 
 	if (conf->elist_device == NULL) {
 		conf->elist_device = vector_alloc();
-		
+
 		if (!conf->elist_device)
 			goto out;
 	}
@@ -449,13 +522,16 @@ load_config (char * file)
 	if (conf->hwhandler == NULL)
 		conf->hwhandler = set_default(DEFAULT_HWHANDLER);
 
-	if (!conf->selector  || !conf->udev_dir         ||
+	if (!conf->selector  || !conf->udev_dir || !conf->multipath_dir ||
 	    !conf->getuid    || !conf->features ||
 	    !conf->hwhandler)
 		goto out;
 
-	if (!conf->checker)
-		conf->checker = checker_lookup(DEFAULT_CHECKER);
+	if (!conf->prio_name)
+		conf->prio_name = set_default(DEFAULT_PRIO);
+
+	if (!conf->checker_name)
+		conf->checker_name = set_default(DEFAULT_CHECKER);
 
 	return 0;
 out:
diff --git a/libmultipath/config.h b/libmultipath/config.h
index a25b3ad..fb917f4 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -16,11 +16,11 @@ struct hwentry {
 	char * product;
 	char * revision;
 	char * getuid;
-	char * getprio;
 	char * features;
 	char * hwhandler;
 	char * selector;
 	char * checker_name;
+	char * prio_name;
 
 	int pgpolicy;
 	int pgfailback;
@@ -28,7 +28,6 @@ struct hwentry {
 	int no_path_retry;
 	int minio;
 	int pg_timeout;
-	struct checker * checker;
 	char * bl_product;
 };
 
@@ -53,7 +52,6 @@ struct config {
 	int pgpolicy_flag;
 	int with_sysfs;
 	int pgpolicy;
-	struct checker * checker;
 	enum devtypes dev_type;
 	int minio;
 	int checkint;
@@ -64,16 +62,20 @@ struct config {
 	int no_path_retry;
 	int user_friendly_names;
 	int pg_timeout;
+	int max_fds;
+	int force_reload;
 
 	char * dev;
 	char * sysfs_dir;
 	char * udev_dir;
+	char * multipath_dir;
 	char * selector;
 	char * getuid;
-	char * getprio;
 	char * features;
 	char * hwhandler;
 	char * bindings_file;
+	char * prio_name;
+	char * checker_name;
 
 	vector keywords;
 	vector mptable;
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index 3cd6041..285a8a2 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -14,8 +14,7 @@
 #include <errno.h>
 #include <libdevmapper.h>
 
-#include <checkers.h>
-
+#include "checkers.h"
 #include "vector.h"
 #include "memory.h"
 #include "devmapper.h"
@@ -34,6 +33,7 @@
 #include "pgpolicies.h"
 #include "dict.h"
 #include "alias.h"
+#include "prio.h"
 
 extern int
 setup_map (struct multipath * mpp)
@@ -130,7 +130,7 @@ pgcmp (struct multipath * mpp, struct multipath * cmpp)
 }
 
 static void
-select_action (struct multipath * mpp, vector curmp)
+select_action (struct multipath * mpp, vector curmp, int force_reload)
 {
 	struct multipath * cmpp;
 
@@ -154,7 +154,7 @@ select_action (struct multipath * mpp, vector curmp)
 
 	if (!find_mp_by_wwid(curmp, mpp->wwid)) {
 		condlog(2, "%s: remove (wwid changed)", cmpp->alias);
-		dm_flush_map(mpp->alias, DEFAULT_TARGET);
+		dm_flush_map(mpp->alias);
 		strncat(cmpp->wwid, mpp->wwid, WWID_SIZE);
 		drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
 		mpp->action = ACT_CREATE;
@@ -169,6 +169,12 @@ select_action (struct multipath * mpp, vector curmp)
 			mpp->alias);
 		return;
 	}
+	if (force_reload) {
+		mpp->action = ACT_RELOAD;
+		condlog(3, "%s: set ACT_RELOAD (forced by user)",
+			mpp->alias);
+		return;
+	}
 	if (cmpp->size != mpp->size) {
 		mpp->action = ACT_RELOAD;
 		condlog(3, "%s: set ACT_RELOAD (size change)",
@@ -183,14 +189,14 @@ select_action (struct multipath * mpp, vector curmp)
 			mpp->alias);
 		return;
 	}
-	if (strncmp(cmpp->hwhandler, mpp->hwhandler,
+	if (!cmpp->selector || strncmp(cmpp->hwhandler, mpp->hwhandler,
 		    strlen(mpp->hwhandler))) {
 		mpp->action = ACT_RELOAD;
 		condlog(3, "%s: set ACT_RELOAD (hwhandler change)",
 			mpp->alias);
 		return;
 	}
-	if (strncmp(cmpp->selector, mpp->selector,
+	if (!cmpp->selector || strncmp(cmpp->selector, mpp->selector,
 		    strlen(mpp->selector))) {
 		mpp->action = ACT_RELOAD;
 		condlog(3, "%s: set ACT_RELOAD (selector change)",
@@ -203,7 +209,7 @@ select_action (struct multipath * mpp, vector curmp)
 			mpp->alias, cmpp->minio, mpp->minio);
 		return;
 	}
-	if (VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
+	if (!cmpp->pg || VECTOR_SIZE(cmpp->pg) != VECTOR_SIZE(mpp->pg)) {
 		mpp->action = ACT_RELOAD;
 		condlog(3, "%s: set ACT_RELOAD (path group number change)",
 			mpp->alias);
@@ -330,28 +336,19 @@ domap (struct multipath * mpp)
 			break;
 		}
 
-		r = dm_addmap(DM_DEVICE_CREATE, mpp->alias, DEFAULT_TARGET,
-			      mpp->params, mpp->size, mpp->wwid);
+		r = dm_addmap_create(mpp->alias, mpp->params, mpp->size,
+				     mpp->wwid);
 
-		/*
-		 * DM_DEVICE_CREATE is actually DM_DEV_CREATE plus
-		 * DM_TABLE_LOAD. Failing the second part leaves an
-		 * empty map. Clean it up.
-		 */
-		if (!r && dm_map_present(mpp->alias)) {
-			condlog(3, "%s: failed to load map "
-				   "(a path might be in use)",
-				   mpp->alias);
-			dm_flush_map(mpp->alias, DEFAULT_TARGET);
-		}
+		if (!r)
+			 r = dm_addmap_create_ro(mpp->alias, mpp->params,
+						 mpp->size, mpp->wwid);
 
 		lock_multipath(mpp, 0);
 		break;
 
 	case ACT_RELOAD:
-		r = (dm_addmap(DM_DEVICE_RELOAD, mpp->alias, DEFAULT_TARGET,
-			      mpp->params, mpp->size, NULL) &&
-		     dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
+		r = (dm_addmap_reload(mpp->alias, mpp->params, mpp->size, NULL)
+		     && dm_simplecmd(DM_DEVICE_RESUME, mpp->alias));
 		break;
 
 	case ACT_RENAME:
@@ -364,18 +361,24 @@ domap (struct multipath * mpp)
 
 	if (r) {
 		/*
-		 * DM_DEVICE_CREATE, DM_DEIVCE_RENAME, or DM_DEVICE_RELOAD
+		 * DM_DEVICE_CREATE, DM_DEVICE_RENAME, or DM_DEVICE_RELOAD
 		 * succeeded
 		 */
-#ifndef DAEMON
-		dm_switchgroup(mpp->alias, mpp->bestpg);
-		if (mpp->action != ACT_NOTHING)
-			print_multipath_topology(mpp, conf->verbosity);
-#else
-		mpp->stat_map_loads++;
-		condlog(2, "%s: load table [0 %llu %s %s]", mpp->alias,
-                        mpp->size, DEFAULT_TARGET, mpp->params);
-#endif
+		if (!mpp->waiter) {
+			/* multipath client mode */
+			dm_switchgroup(mpp->alias, mpp->bestpg);
+			if (mpp->action != ACT_NOTHING)
+				print_multipath_topology(mpp, conf->verbosity);
+		} else  {
+			/* multipath daemon mode */
+			mpp->stat_map_loads++;
+			condlog(2, "%s: load table [0 %llu %s %s]", mpp->alias,
+				mpp->size, TGT_MPATH, mpp->params);
+			/*
+			 * Required action is over, reset for the stateful daemon
+			 */
+			mpp->action = ACT_NOTHING;
+		}
 		return DOMAP_OK;
 	}
 	return DOMAP_FAIL;
@@ -404,7 +407,7 @@ deadmap (struct multipath * mpp)
 }
 
 extern int
-coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
+coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_reload)
 {
 	int r = 1;
 	int k, i;
@@ -417,6 +420,11 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
 
 	memset(empty_buff, 0, WWID_SIZE);
 
+	if (force_reload) {
+		vector_foreach_slot (pathvec, pp1, k) {
+			pp1->mpp = NULL;
+		}
+	}
 	vector_foreach_slot (pathvec, pp1, k) {
 		/* skip this path for some reason */
 
@@ -440,7 +448,8 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
 		/*
 		 * at this point, we know we really got a new mp
 		 */
-		if ((mpp = add_map_with_path(vecs, pp1, 0)) == NULL)
+		mpp = add_map_with_path(vecs, pp1, 0);
+		if (!mpp)
 			return 1;
 
 		if (pp1->priority == PRIO_UNDEF)
@@ -448,7 +457,7 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
 
 		if (!mpp->paths) {
 			condlog(0, "%s: skip coalesce (no paths)", mpp->alias);
-			remove_map(mpp, vecs, NULL, 0);
+			remove_map(mpp, vecs, 0);
 			continue;
 		}
 		
@@ -476,12 +485,12 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
 		verify_paths(mpp, vecs, NULL);
 		
 		if (setup_map(mpp)) {
-			remove_map(mpp, vecs, NULL, 0);
+			remove_map(mpp, vecs, 0);
 			continue;
 		}
 
 		if (mpp->action == ACT_UNDEF)
-			select_action(mpp, curmp);
+			select_action(mpp, curmp, force_reload);
 
 		r = domap(mpp);
 
@@ -490,7 +499,7 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
 				   "for create/reload map",
 				mpp->alias, r);
 			if (r == DOMAP_FAIL) {
-				remove_map(mpp, vecs, NULL, 0);
+				remove_map(mpp, vecs, 0);
 				continue;
 			} else /* if (r == DOMAP_RETRY) */
 				return r;
@@ -518,7 +527,7 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
 				vector_set_slot(newmp, mpp);
 			}
 			else
-				remove_map(mpp, vecs, NULL, 0);
+				remove_map(mpp, vecs, 0);
 		}
 	}
 	/*
@@ -538,9 +547,9 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid)
 			if ((j = find_slot(newmp, (void *)mpp)) != -1)
 				vector_del_slot(newmp, j);
 
-			remove_map(mpp, vecs, NULL, 0);
+			remove_map(mpp, vecs, 0);
 
-			if (dm_flush_map(mpp->alias, DEFAULT_TARGET))
+			if (dm_flush_map(mpp->alias))
 				condlog(2, "%s: remove failed (dead)",
 					mpp->alias);
 			else
diff --git a/libmultipath/configure.h b/libmultipath/configure.h
index 1cbbe82..75d5057 100644
--- a/libmultipath/configure.h
+++ b/libmultipath/configure.h
@@ -24,6 +24,6 @@ enum actions {
 int setup_map (struct multipath * mpp);
 int domap (struct multipath * mpp);
 int reinstate_paths (struct multipath *mpp);
-int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid);
+int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload);
 char * get_refwwid (char * dev, enum devtypes dev_type, vector pathvec);
 
diff --git a/libmultipath/debug.c b/libmultipath/debug.c
index 05dfb06..d30517d 100644
--- a/libmultipath/debug.c
+++ b/libmultipath/debug.c
@@ -5,11 +5,9 @@
 #include <stdlib.h>
 #include <stdarg.h>
 
-#if DAEMON
 #include "log_pthread.h"
 #include <sys/types.h>
 #include <time.h>
-#endif
 
 #include "vector.h"
 #include "config.h"
@@ -23,12 +21,11 @@ void dlog (int sink, int prio, const char * fmt, ...)
 	thres = (conf) ? conf->verbosity : 0;
 
 	if (prio <= thres) {
-#if DAEMON
 		if (!sink) {
 			time_t t = time(NULL);
 			struct tm *tb = localtime(&t);
 			char buff[16];
-			
+
 			strftime(buff, sizeof(buff), "%b %d %H:%M:%S", tb);
 			buff[sizeof(buff)-1] = '\0';
 
@@ -37,9 +34,6 @@ void dlog (int sink, int prio, const char * fmt, ...)
 		}
 		else
 			log_safe(prio + 3, fmt, ap);
-#else
-		vfprintf(stdout, fmt, ap);
-#endif
 	}
 	va_end(ap);
 }
diff --git a/libmultipath/debug.h b/libmultipath/debug.h
index 082fff1..c6120c1 100644
--- a/libmultipath/debug.h
+++ b/libmultipath/debug.h
@@ -1,21 +1,13 @@
 void dlog (int sink, int prio, const char * fmt, ...)
 	__attribute__((format(printf, 3, 4)));
 
-#if DAEMON
 
 #include <pthread.h>
 #include <stdarg.h>
 
 #include "log_pthread.h"
 
-int logsink;
+extern int logsink;
 
 #define condlog(prio, fmt, args...) \
 	dlog(logsink, prio, fmt "\n", ##args)
-
-#else /* DAEMON */
-
-#define condlog(prio, fmt, args...) \
-	dlog(0, prio, fmt "\n", ##args)
-
-#endif /* DAEMON */
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
index df7d971..826f360 100644
--- a/libmultipath/defaults.h
+++ b/libmultipath/defaults.h
@@ -1,10 +1,10 @@
 #define DEFAULT_GETUID		"/lib/udev/scsi_id -g -u -s /block/%n"
 #define DEFAULT_UDEVDIR		"/dev"
+#define DEFAULT_MULTIPATHDIR	"/lib/multipath"
 #define DEFAULT_SELECTOR	"round-robin 0"
 #define DEFAULT_FEATURES	"0"
 #define DEFAULT_HWHANDLER	"0"
 #define DEFAULT_MINIO		1000
-#define DEFAULT_GETPRIO		NULL
 #define DEFAULT_PGPOLICY       FAILOVER
 #define DEFAULT_FAILBACK       -FAILBACK_MANUAL
 #define DEFAULT_RR_WEIGHT      RR_WEIGHT_NONE
@@ -15,7 +15,6 @@
 #define DEFAULT_CHECKINT	5
 #define MAX_CHECKINT(a)		(a << 2)
 
-#define DEFAULT_TARGET		"multipath"
 #define DEFAULT_PIDFILE		"/var/run/multipathd.pid"
 #define DEFAULT_SOCKET		"/var/run/multipathd.sock"
 #define DEFAULT_CONFIGFILE	"/etc/multipath.conf"
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index d6991ba..d329781 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -14,8 +14,7 @@
 #include <unistd.h>
 #include <errno.h>
 
-#include <checkers.h>
-
+#include "checkers.h"
 #include "vector.h"
 #include "structs.h"
 #include "debug.h"
@@ -23,11 +22,9 @@
 #include "devmapper.h"
 #include "config.h"
 
-#if DAEMON
 #include "log_pthread.h"
 #include <sys/types.h>
 #include <time.h>
-#endif
 
 #define MAX_WAIT 5
 #define LOOPS_PER_SEC 5
@@ -48,8 +45,7 @@ dm_write_log (int level, const char *file, int line, const char *f, ...)
 	if (thres <= 3 || level > thres)
 		return;
 
-        va_start(ap, f);
-#if DAEMON
+	va_start(ap, f);
 	if (!logsink) {
 		time_t t = time(NULL);
 		struct tm *tb = localtime(&t);
@@ -66,12 +62,7 @@ dm_write_log (int level, const char *file, int line, const char *f, ...)
 		condlog(level, "libdevmapper: %s(%i): ", file, line);
 		log_safe(level + 3, f, ap);
 	}
-#else
-	fprintf(stdout, "libdevmapper: %s(%i): ", file, line);
-	vfprintf(stdout, f, ap);
-	fprintf(stdout, "\n");
-#endif
-        va_end(ap);
+	va_end(ap);
 
 	return;
 }
@@ -151,11 +142,11 @@ out:
 }
 
 extern int
-dm_prereq (char * str)
+dm_prereq (void)
 {
 	if (dm_libprereq())
 		return 1;
-	return dm_drvprereq(str);
+	return dm_drvprereq(TGT_MPATH);
 }
 
 extern int
@@ -184,7 +175,8 @@ dm_simplecmd (int task, const char *name) {
 
 extern int
 dm_addmap (int task, const char *name, const char *target,
-	   const char *params, unsigned long long size, const char *uuid) {
+	   const char *params, unsigned long long size, const char *uuid,
+	   int ro) {
 	int r = 0;
 	struct dm_task *dmt;
 	char *prefixed_uuid = NULL;
@@ -198,6 +190,9 @@ dm_addmap (int task, const char *name, const char *target,
 	if (!dm_task_add_target (dmt, 0, size, target, params))
 		goto addout;
 
+	if (ro)
+		dm_task_set_ro(dmt);
+
 	if (uuid){
 		prefixed_uuid = MALLOC(UUID_PREFIX_LEN + strlen(uuid) + 1);
 		if (!prefixed_uuid) {
@@ -220,11 +215,59 @@ dm_addmap (int task, const char *name, const char *target,
 
 	addout:
 	dm_task_destroy (dmt);
+
+	return r;
+}
+
+static int
+_dm_addmap_create (const char *name, const char *params,
+		  unsigned long long size, const char *uuid, int ro) {
+	int r;
+	r = dm_addmap(DM_DEVICE_CREATE, name, TGT_MPATH, params, size, uuid,
+		      ro);
+	/*
+	 * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD.
+	 * Failing the second part leaves an empty map. Clean it up.
+	 */
+	if (!r && dm_map_present(name)) {
+		condlog(3, "%s: failed to load map (a path might be in use)",
+			name);
+		dm_flush_map(name);
+	}
 	return r;
 }
 
+#define ADDMAP_RW 0
+#define ADDMAP_RO 1
+
+extern int
+dm_addmap_create (const char *name, const char *params,
+		  unsigned long long size, const char *uuid) {
+	return _dm_addmap_create(name, params, size, uuid, ADDMAP_RW);
+}
+
+extern int
+dm_addmap_create_ro (const char *name, const char *params,
+		  unsigned long long size, const char *uuid) {
+	return _dm_addmap_create(name, params, size, uuid, ADDMAP_RO);
+}
+
+extern int
+dm_addmap_reload (const char *name, const char *params,
+		  unsigned long long size, const char *uuid) {
+	return dm_addmap(DM_DEVICE_RELOAD, name, TGT_MPATH, params, size, uuid,
+			 ADDMAP_RW);
+}
+
+extern int
+dm_addmap_reload_ro (const char *name, const char *params,
+		     unsigned long long size, const char *uuid) {
+	return dm_addmap(DM_DEVICE_RELOAD, name, TGT_MPATH, params, size, uuid,
+			 ADDMAP_RO);
+}
+
 extern int
-dm_map_present (char * str)
+dm_map_present (const char * str)
 {
 	int r = 0;
 	struct dm_task *dmt;
@@ -361,7 +404,7 @@ out:
  *   -1 : empty map
  */
 extern int
-dm_type(char * name, char * type)
+dm_type(const char * name, char * type)
 {
 	int r = 0;
 	struct dm_task *dmt;
@@ -396,7 +439,7 @@ out:
 }
 
 static int
-dm_dev_t (char * mapname, char * dev_t, int len)
+dm_dev_t (const char * mapname, char * dev_t, int len)
 {
 	int r = 1;
 	struct dm_task *dmt;
@@ -425,7 +468,7 @@ out:
 }
 	
 int
-dm_get_opencount (char * mapname)
+dm_get_opencount (const char * mapname)
 {
 	int r = -1;
 	struct dm_task *dmt;
@@ -475,14 +518,14 @@ out:
 }
 	
 extern int
-dm_flush_map (char * mapname, char * type)
+dm_flush_map (const char * mapname)
 {
 	int r;
 
 	if (!dm_map_present(mapname))
 		return 0;
 
-	if (dm_type(mapname, type) <= 0)
+	if (dm_type(mapname, TGT_MPATH) <= 0)
 		return 1;
 
 	if (dm_remove_partmaps(mapname))
@@ -503,7 +546,7 @@ dm_flush_map (char * mapname, char * type)
 }
 
 extern int
-dm_flush_maps (char * type)
+dm_flush_maps (void)
 {
 	int r = 0;
 	struct dm_task *dmt;
@@ -525,7 +568,7 @@ dm_flush_maps (char * type)
 		goto out;
 
 	do {
-		r += dm_flush_map(names->name, type);
+		r += dm_flush_map(names->name);
 		next = names->next;
 		names = (void *) names + next;
 	} while (next);
@@ -642,7 +685,7 @@ dm_disablegroup(char * mapname, int index)
 }
 
 int
-dm_get_maps (vector mp, char * type)
+dm_get_maps (vector mp)
 {
 	struct multipath * mpp;
 	int r = 1;
@@ -651,7 +694,7 @@ dm_get_maps (vector mp, char * type)
 	struct dm_names *names;
 	unsigned next = 0;
 
-	if (!type || !mp)
+	if (!mp)
 		return 1;
 
 	if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
@@ -671,7 +714,7 @@ dm_get_maps (vector mp, char * type)
 	}
 
 	do {
-		info = dm_type(names->name, type);
+		info = dm_type(names->name, TGT_MPATH);
 
 		if (info <= 0)
 			goto next;
@@ -717,7 +760,7 @@ out:
 }
 
 extern int
-dm_get_name(char *uuid, char *type, char *name)
+dm_get_name(char *uuid, char *name)
 {
 	vector vec;
 	struct multipath *mpp;
@@ -728,7 +771,7 @@ dm_get_name(char *uuid, char *type, char *name)
 	if (!vec)
 		return 0;
 
-	if (dm_get_maps(vec, type)) {
+	if (dm_get_maps(vec)) {
 		vector_free(vec);
 		return 0;
 	}
@@ -827,7 +870,7 @@ bad:
 }
 
 int
-dm_remove_partmaps (char * mapname)
+dm_remove_partmaps (const char * mapname)
 {
 	struct dm_task *dmt;
 	struct dm_names *names;
@@ -861,7 +904,7 @@ dm_remove_partmaps (char * mapname)
 		    /*
 		     * if devmap target is "linear"
 		     */
-		    (dm_type(names->name, "linear") > 0) &&
+		    (dm_type(names->name, TGT_PART) > 0) &&
 
 		    /*
 		     * and the multipath mapname and the part mapname start
@@ -984,7 +1027,7 @@ dm_rename_partmaps (char * old, char * new)
 		    /*
 		     * if devmap target is "linear"
 		     */
-		    (dm_type(names->name, "linear") > 0) &&
+		    (dm_type(names->name, TGT_PART) > 0) &&
 
 		    /*
 		     * and the multipath mapname and the part mapname start
diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h
index 8438034..a340c00 100644
--- a/libmultipath/devmapper.h
+++ b/libmultipath/devmapper.h
@@ -1,14 +1,23 @@
+#define TGT_MPATH	"multipath"
+#define TGT_PART	"linear"
+
 void dm_init(void);
-int dm_prereq (char *);
+int dm_prereq (void);
 int dm_simplecmd (int, const char *);
-int dm_addmap (int, const char *, const char *, const char *,
-	       unsigned long long, const char *uuid);
-int dm_map_present (char *);
+int dm_addmap_create (const char *, const char *,
+                      unsigned long long size, const char *uuid);
+int dm_addmap_create_ro (const char *, const char *,
+			 unsigned long long size, const char *uuid);
+int dm_addmap_reload (const char *, const char *,
+                      unsigned long long size, const char *uuid);
+int dm_addmap_reload_ro (const char *, const char *,
+			 unsigned long long size, const char *uuid);
+int dm_map_present (const char *);
 int dm_get_map(char *, unsigned long long *, char *);
 int dm_get_status(char *, char *);
-int dm_type(char *, char *);
-int dm_flush_map (char *, char *);
-int dm_flush_maps (char *);
+int dm_type(const char *, char *);
+int dm_flush_map (const char *);
+int dm_flush_maps (void);
 int dm_fail_path(char * mapname, char * path);
 int dm_reinstate_path(char * mapname, char * path);
 int dm_queue_if_no_path(char *mapname, int enable);
@@ -16,12 +25,12 @@ int dm_set_pg_timeout(char *mapname, int timeout_val);
 int dm_switchgroup(char * mapname, int index);
 int dm_enablegroup(char * mapname, int index);
 int dm_disablegroup(char * mapname, int index);
-int dm_get_maps (vector mp, char * type);
+int dm_get_maps (vector mp);
 int dm_geteventnr (char *name);
 int dm_get_minor (char *name);
 char * dm_mapname(int major, int minor);
-int dm_remove_partmaps (char * mapname);
+int dm_remove_partmaps (const char * mapname);
 int dm_get_uuid(char *name, char *uuid);
 int dm_get_info (char * mapname, struct dm_info ** dmi);
 int dm_rename (char * old, char * new);
-int dm_get_name(char * uuid, char * type, char * name);
+int dm_get_name(char * uuid, char * name);
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 4572a7d..f5bca30 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -4,8 +4,7 @@
  * Copyright (c) 2005 Benjamin Marzinski, Redhat
  * Copyright (c) 2005 Kiyoshi Ueda, NEC
  */
-#include <checkers.h>
-
+#include "checkers.h"
 #include "vector.h"
 #include "hwtable.h"
 #include "structs.h"
@@ -16,6 +15,7 @@
 #include "pgpolicies.h"
 #include "blacklist.h"
 #include "defaults.h"
+#include "prio.h"
 
 /*
  * default block handlers
@@ -44,6 +44,17 @@ udev_dir_handler(vector strvec)
 }
 
 static int
+multipath_dir_handler(vector strvec)
+{
+	conf->multipath_dir = set_value(strvec);
+
+	if (!conf->multipath_dir)
+		return 1;
+
+	return 0;
+}
+
+static int
 def_selector_handler(vector strvec)
 {
 	conf->selector = set_value(strvec);
@@ -82,19 +93,13 @@ def_getuid_callout_handler(vector strvec)
 }
 
 static int
-def_prio_callout_handler(vector strvec)
+def_prio_handler(vector strvec)
 {
-	conf->getprio = set_value(strvec);
+	conf->prio_name = set_value(strvec);
 
-	if (!conf->getprio)
+	if (!conf->prio_name)
 		return 1;
-	
-	if (strlen(conf->getprio) == 4 &&
-	    !strcmp(conf->getprio, "none")) {
-		FREE(conf->getprio);
-		conf->getprio = NULL;
-	}
-		
+
 	return 0;
 }
 
@@ -112,21 +117,32 @@ def_features_handler(vector strvec)
 static int
 def_path_checker_handler(vector strvec)
 {
+	conf->checker_name = set_value(strvec);
+
+	if (!conf->checker_name)
+		return 1;
+	
+	return 0;
+}
+
+static int
+def_minio_handler(vector strvec)
+{
 	char * buff;
 
 	buff = set_value(strvec);
 
 	if (!buff)
 		return 1;
-	
-	conf->checker = checker_lookup(buff);
+
+	conf->minio = atoi(buff);
 	FREE(buff);
 
 	return 0;
 }
 
 static int
-def_minio_handler(vector strvec)
+max_fds_handler(vector strvec)
 {
 	char * buff;
 
@@ -135,7 +151,11 @@ def_minio_handler(vector strvec)
 	if (!buff)
 		return 1;
 
-	conf->minio = atoi(buff);
+	if (strlen(buff) == 9 &&
+	    !strcmp(buff, "unlimited"))
+		conf->max_fds = MAX_FDS_UNLIMITED;
+	else
+		conf->max_fds = atoi(buff);
 	FREE(buff);
 
 	return 0;
@@ -398,7 +418,8 @@ ble_except_product_handler(vector strvec)
 static int
 devices_handler(vector strvec)
 {
-	conf->hwtable = vector_alloc();
+	if (!conf->hwtable)
+		conf->hwtable = vector_alloc();
 
 	if (!conf->hwtable)
 		return 1;
@@ -521,20 +542,16 @@ hw_selector_handler(vector strvec)
 static int
 hw_path_checker_handler(vector strvec)
 {
-	char * buff;
 	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
 
 	if (!hwe)
 		return 1;
 
-	buff = set_value(strvec);
+	hwe->checker_name = set_value(strvec);
 
-	if (!buff)
+	if (!hwe->checker_name)
 		return 1;
 	
-	hwe->checker = checker_lookup(buff);
-	FREE(buff);
-
 	return 0;
 }
 
@@ -571,23 +588,18 @@ hw_handler_handler(vector strvec)
 }
 
 static int
-prio_callout_handler(vector strvec)
+hw_prio_handler(vector strvec)
 {
 	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-	
+
 	if (!hwe)
 		return 1;
 
-	hwe->getprio = set_value(strvec);
+	hwe->prio_name = set_value(strvec);
 
-	if (!hwe->getprio)
+	if (!hwe->prio_name)
 		return 1;
 
-	if (strlen(hwe->getprio) == 4 && !strcmp(hwe->getprio, "none")) {
-		FREE(hwe->getprio);
-		hwe->getprio = NULL;
-	}
-
 	return 0;
 }
 
@@ -1075,7 +1087,7 @@ snprint_hw_vendor (char * buff, int len, void * data)
 	if (!hwe->vendor)
 		return 0;
 
-	return snprintf(buff, len, "%s", hwe->vendor);
+	return snprintf(buff, len, "\"%s\"", hwe->vendor);
 }
 
 static int
@@ -1086,7 +1098,7 @@ snprint_hw_product (char * buff, int len, void * data)
 	if (!hwe->product)
 		return 0;
 
-	return snprintf(buff, len, "%s", hwe->product);
+	return snprintf(buff, len, "\"%s\"", hwe->product);
 }
 
 static int
@@ -1097,7 +1109,7 @@ snprint_hw_bl_product (char * buff, int len, void * data)
 	if (!hwe->bl_product)
 		return 0;
 
-	return snprintf(buff, len, "%s", hwe->bl_product);
+	return snprintf(buff, len, "\"%s\"", hwe->bl_product);
 }
 
 static int
@@ -1111,27 +1123,20 @@ snprint_hw_getuid_callout (char * buff, int len, void * data)
 	    !strcmp(hwe->getuid, conf->getuid))
 		return 0;
 
-	return snprintf(buff, len, "%s", hwe->getuid);
+	return snprintf(buff, len, "\"%s\"", hwe->getuid);
 }
 
 static int
-snprint_hw_prio_callout (char * buff, int len, void * data)
+snprint_hw_prio (char * buff, int len, void * data)
 {
 	struct hwentry * hwe = (struct hwentry *)data;
 
-	if (!conf->getprio && !hwe->getprio)
+	if (!hwe->prio_name)
 		return 0;
-	if (!conf->getprio && hwe->getprio)
-		return snprintf(buff, len, "%s", hwe->getprio);
-	if (conf->getprio && !hwe->getprio)
-		return snprintf(buff, len, "none");
-
-	/* conf->getprio && hwe->getprio */
-	if (strlen(hwe->getprio) == strlen(conf->getprio) &&
-	    !strcmp(hwe->getprio, conf->getprio))
+	if (!strcmp(hwe->prio_name, conf->prio_name))
 		return 0;
-
-	return snprintf(buff, len, "%s", hwe->getprio);
+	
+	return snprintf(buff, len, "%s", hwe->prio_name);
 }
 
 static int
@@ -1145,7 +1150,7 @@ snprint_hw_features (char * buff, int len, void * data)
 	    !strcmp(hwe->features, conf->features))
 		return 0;
 
-	return snprintf(buff, len, "%s", hwe->features);
+	return snprintf(buff, len, "\"%s\"", hwe->features);
 }
 
 static int
@@ -1159,7 +1164,7 @@ snprint_hw_hardware_handler (char * buff, int len, void * data)
 	    !strcmp(hwe->hwhandler, conf->hwhandler))
 		return 0;
 
-	return snprintf(buff, len, "%s", hwe->hwhandler);
+	return snprintf(buff, len, "\"%s\"", hwe->hwhandler);
 }
 
 static int
@@ -1294,14 +1299,12 @@ snprint_hw_path_checker (char * buff, int len, void * data)
 {
 	struct hwentry * hwe = (struct hwentry *)data;
 
-	if (!hwe->checker)
+	if (!hwe->checker_name)
 		return 0;
-	if (!checker_selected(hwe->checker))
-		return 0;
-	if (hwe->checker == conf->checker)
+	if (!strcmp(hwe->checker_name, conf->checker_name))
 		return 0;
 	
-	return snprintf(buff, len, "%s", checker_name(hwe->checker));
+	return snprintf(buff, len, "%s", hwe->checker_name);
 }
 
 static int
@@ -1321,7 +1324,19 @@ snprint_def_udev_dir (char * buff, int len, void * data)
 	    !strcmp(conf->udev_dir, DEFAULT_UDEVDIR))
 		return 0;
 
-	return snprintf(buff, len, "%s", conf->udev_dir);
+	return snprintf(buff, len, "\"%s\"", conf->udev_dir);
+}
+
+static int
+snprint_def_multipath_dir (char * buff, int len, void * data)
+{
+	if (!conf->udev_dir)
+		return 0;
+	if (strlen(DEFAULT_MULTIPATHDIR) == strlen(conf->multipath_dir) &&
+	    !strcmp(conf->multipath_dir, DEFAULT_MULTIPATHDIR))
+		return 0;
+
+	return snprintf(buff, len, "\"%s\"", conf->multipath_dir);
 }
 
 static int
@@ -1360,16 +1375,20 @@ snprint_def_getuid_callout (char * buff, int len, void * data)
 	    !strcmp(conf->getuid, DEFAULT_GETUID))
 		return 0;
 
-	return snprintf(buff, len, "%s", conf->getuid);
+	return snprintf(buff, len, "\"%s\"", conf->getuid);
 }
 
 static int
-snprint_def_getprio_callout (char * buff, int len, void * data)
+snprint_def_prio (char * buff, int len, void * data)
 {
-	if (!conf->getprio)
+	if (!conf->prio_name)
 		return 0;
 
-	return snprintf(buff, len, "%s", conf->getprio);
+	if (strlen(conf->prio_name) == strlen(DEFAULT_PRIO) &&
+	    !strcmp(conf->prio_name, DEFAULT_PRIO))
+		return 0;
+	
+	return snprintf(buff, len, "%s", conf->prio_name);
 }
 
 static int
@@ -1381,18 +1400,19 @@ snprint_def_features (char * buff, int len, void * data)
 	    !strcmp(conf->features, DEFAULT_FEATURES))
 		return 0;
 
-	return snprintf(buff, len, "%s", conf->features);
+	return snprintf(buff, len, "\"%s\"", conf->features);
 }
 
 static int
 snprint_def_path_checker (char * buff, int len, void * data)
 {
-	if (!conf->checker)
+	if (!conf->checker_name)
 		return 0;
-	if (conf->checker == checker_default())
+	if (strlen(conf->checker_name) == strlen(DEFAULT_CHECKER) &&
+	    !strcmp(conf->checker_name, DEFAULT_CHECKER))
 		return 0;
 	
-	return snprintf(buff, len, "%s", checker_name(conf->checker));
+	return snprintf(buff, len, "%s", conf->checker_name);
 }
 
 static int
@@ -1428,6 +1448,17 @@ snprint_def_rr_min_io (char * buff, int len, void * data)
 }
 
 static int
+snprint_max_fds (char * buff, int len, void * data)
+{
+	if (!conf->max_fds)
+		return 0;
+
+	if (conf->max_fds < 0)
+		return snprintf(buff, len, "unlimited");	
+	return snprintf(buff, len, "%d", conf->max_fds);
+}
+
+static int
 snprint_def_rr_weight (char * buff, int len, void * data)
 {
 	if (!conf->rr_weight)
@@ -1493,7 +1524,7 @@ snprint_ble_simple (char * buff, int len, void * data)
 {
 	struct blentry * ble = (struct blentry *)data;
 
-	return snprintf(buff, len, "%s", ble->str);
+	return snprintf(buff, len, "\"%s\"", ble->str);
 }
 
 static int
@@ -1501,7 +1532,7 @@ snprint_bled_vendor (char * buff, int len, void * data)
 {
 	struct blentry_device * bled = (struct blentry_device *)data;
 
-	return snprintf(buff, len, "%s", bled->vendor);
+	return snprintf(buff, len, "\"%s\"", bled->vendor);
 }
 	
 static int
@@ -1509,7 +1540,7 @@ snprint_bled_product (char * buff, int len, void * data)
 {
 	struct blentry_device * bled = (struct blentry_device *)data;
 
-	return snprintf(buff, len, "%s", bled->product);
+	return snprintf(buff, len, "\"%s\"", bled->product);
 }
 	
 #define __deprecated
@@ -1520,14 +1551,17 @@ init_keywords(void)
 	install_keyword_root("defaults", NULL);
 	install_keyword("polling_interval", &polling_interval_handler, &snprint_def_polling_interval);
 	install_keyword("udev_dir", &udev_dir_handler, &snprint_def_udev_dir);
+	install_keyword("multipath_dir", &multipath_dir_handler, &snprint_def_multipath_dir);
 	install_keyword("selector", &def_selector_handler, &snprint_def_selector);
 	install_keyword("path_grouping_policy", &def_pgpolicy_handler, &snprint_def_path_grouping_policy);
 	install_keyword("getuid_callout", &def_getuid_callout_handler, &snprint_def_getuid_callout);
-	install_keyword("prio_callout", &def_prio_callout_handler, &snprint_def_getprio_callout);
+	install_keyword("prio", &def_prio_handler, &snprint_def_prio);
 	install_keyword("features", &def_features_handler, &snprint_def_features);
 	install_keyword("path_checker", &def_path_checker_handler, &snprint_def_path_checker);
+	install_keyword("checker", &def_path_checker_handler, &snprint_def_path_checker);
 	install_keyword("failback", &default_failback_handler, &snprint_def_failback);
 	install_keyword("rr_min_io", &def_minio_handler, &snprint_def_rr_min_io);
+	install_keyword("max_fds", &max_fds_handler, &snprint_max_fds);
 	install_keyword("rr_weight", &def_weight_handler, &snprint_def_rr_weight);
 	install_keyword("no_path_retry", &def_no_path_retry_handler, &snprint_def_no_path_retry);
 	install_keyword("pg_timeout", &def_pg_timeout_handler, &snprint_def_pg_timeout);
@@ -1535,7 +1569,6 @@ init_keywords(void)
 	__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);
-	__deprecated install_keyword("default_prio_callout", &def_prio_callout_handler, NULL);
 	__deprecated install_keyword("default_features", &def_features_handler, NULL);
 	__deprecated install_keyword("default_path_checker", &def_path_checker_handler, NULL);
 
@@ -1577,9 +1610,10 @@ init_keywords(void)
 	install_keyword("getuid_callout", &hw_getuid_callout_handler, &snprint_hw_getuid_callout);
 	install_keyword("path_selector", &hw_selector_handler, &snprint_hw_selector);
 	install_keyword("path_checker", &hw_path_checker_handler, &snprint_hw_path_checker);
+	install_keyword("checker", &hw_path_checker_handler, &snprint_hw_path_checker);
 	install_keyword("features", &hw_features_handler, &snprint_hw_features);
 	install_keyword("hardware_handler", &hw_handler_handler, &snprint_hw_hardware_handler);
-	install_keyword("prio_callout", &prio_callout_handler, &snprint_hw_prio_callout);
+	install_keyword("prio", &hw_prio_handler, &snprint_hw_prio);
 	install_keyword("failback", &hw_failback_handler, &snprint_hw_failback);
 	install_keyword("rr_weight", &hw_weight_handler, &snprint_hw_rr_weight);
 	install_keyword("no_path_retry", &hw_no_path_retry_handler, &snprint_hw_no_path_retry);
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index c842eb0..7baa9e7 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -11,8 +11,7 @@
 #include <dirent.h>
 #include <errno.h>
 
-#include <checkers.h>
-
+#include "checkers.h"
 #include "vector.h"
 #include "memory.h"
 #include "util.h"
@@ -25,6 +24,7 @@
 #include "sg_include.h"
 #include "sysfs.h"
 #include "discovery.h"
+#include "prio.h"
 
 struct path *
 store_pathinfo (vector pathvec, vector hwtable, char * devname, int flag)
@@ -133,9 +133,9 @@ sysfs_get_##fname (struct sysfs_device * dev, char * buff, size_t len) \
 	attr = sysfs_attr_get_value(dev->devpath, #fname); \
 	if (!attr) \
 		return 1; \
-\
 	if (strlcpy(buff, attr, len) != strlen(attr)) \
 		return 2; \
+	strchop(buff); \
 	return 0; \
 }
 
@@ -361,10 +361,13 @@ get_inq (char * vendor, char * product, char * rev, int fd)
 	if (0 == do_inq(fd, 0, 0, 0, buff, MX_ALLOC_LEN, 0)) {
 		memcpy(vendor, buff + 8, 8);
 		vendor[8] = '\0';
+		strchop(vendor);
 		memcpy(product, buff + 16, 16);
 		product[16] = '\0';
+		strchop(product);
 		memcpy(rev, buff + 32, 4);
 		rev[4] = '\0';
+		strchop(rev);
 		return 0;
 	}
 	return 1;
@@ -546,6 +549,9 @@ sysfs_pathinfo(struct path * pp)
 	if (!parent)
 		parent = pp->sysdev;
 
+	if (!strncmp(parent->kernel, "block",5))
+		parent = sysfs_device_get_parent(parent);
+
 	condlog(3, "%s: subsystem = %s", pp->dev, parent->subsystem);
 
 	if (!strncmp(parent->subsystem, "scsi",4))
@@ -617,8 +623,8 @@ get_state (struct path * pp)
 	}
 	pp->state = checker_check(c);
 	condlog(3, "%s: state = %i", pp->dev, pp->state);
-	if (pp->state == PATH_DOWN)
-		condlog(2, "%s: checker msg is \"%s\"",
+	if (pp->state == PATH_DOWN && strlen(checker_message(c)))
+		condlog(3, "%s: checker msg is \"%s\"",
 			pp->dev, checker_message(c));
 	return 0;
 }
@@ -626,27 +632,22 @@ get_state (struct path * pp)
 static int
 get_prio (struct path * pp)
 {
-	char buff[CALLOUT_MAX_SIZE];
-	char prio[16];
+	if (!pp)
+		return 0;
 
-	if (!pp->getprio_selected) {
-		select_getprio(pp);
-		pp->getprio_selected = 1;
+	if (!pp->prio) {
+		select_prio(pp);
+		if (!pp->prio)
+			return 1;
 	}
-	if (!pp->getprio) {
-		pp->priority = PRIO_DEFAULT;
-	} else if (apply_format(pp->getprio, &buff[0], pp)) {
-		condlog(0, "error formatting prio callout command");
-		pp->priority = PRIO_UNDEF;
-		return 1;
-	} else if (execute_program(buff, prio, 16)) {
-		condlog(0, "error calling out %s", buff);
+	pp->priority = prio_getprio(pp->prio, pp);
+	if (pp->priority < 0) {
+		condlog(3, "%s: %s prio error", pp->dev, prio_name(pp->prio));
 		pp->priority = PRIO_UNDEF;
 		return 1;
-	} else
-		pp->priority = atoi(prio);
-
-	condlog(3, "%s: prio = %u", pp->dev, pp->priority);
+	}
+	condlog(3, "%s: %s prio = %u",
+		pp->dev, prio_name(pp->prio), pp->priority);
 	return 0;
 }
 
@@ -662,7 +663,7 @@ get_uid (struct path * pp)
 		condlog(0, "error formatting uid callout command");
 		memset(pp->wwid, 0, WWID_SIZE);
 	} else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
-		condlog(0, "error calling out %s", buff);
+		condlog(3, "error calling out %s", buff);
 		memset(pp->wwid, 0, WWID_SIZE);
 		return 1;
 	}
@@ -723,5 +724,6 @@ blank:
 	 */
 	memset(pp->wwid, 0, WWID_SIZE);
 	pp->state = PATH_DOWN;
+
 	return 0;
 }
diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c
index 631933d..bc3f231 100644
--- a/libmultipath/dmparser.c
+++ b/libmultipath/dmparser.c
@@ -7,8 +7,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <checkers.h>
-
+#include "checkers.h"
 #include "vector.h"
 #include "memory.h"
 #include "structs.h"
@@ -146,6 +145,8 @@ disassemble_map (vector pathvec, char * params, struct multipath * mpp)
 			FREE(word);
 			return 1;
 		}
+		setup_feature(mpp, word);
+
 		FREE(word);
 	}
 
@@ -183,11 +184,12 @@ disassemble_map (vector pathvec, char * params, struct multipath * mpp)
 	num_pg = atoi(word);
 	FREE(word);
 
-	if (num_pg > 0 && !mpp->pg)
+	if (num_pg > 0 && !mpp->pg) {
 		mpp->pg = vector_alloc();
-	
-	if (!mpp->pg)
-		return 1;
+		if (!mpp->pg)
+			return 1;
+	}
+
 	/*
 	 * first pg to try
 	 */
@@ -278,10 +280,9 @@ disassemble_map (vector pathvec, char * params, struct multipath * mpp)
 
 				strncpy(pp->dev_t, word, BLK_DEV_SIZE);
 
-#ifndef DAEMON
-				if (store_path(pathvec, pp))
+				/* Only call this in multipath client mode */
+				if (!mpp->waiter && store_path(pathvec, pp))
 					goto out;
-#endif
 			}
 			FREE(word);
 
@@ -329,6 +330,7 @@ out1:
 	FREE(word);
 out:
 	free_pgvec(mpp->pg, KEEP_PATHS);
+	mpp->pg = NULL;
 	return 1;
 }
 
@@ -398,6 +400,9 @@ disassemble_status (char * params, struct multipath * mpp)
 	num_pg = atoi(word);
 	FREE(word);
 
+	if (num_pg == 0)
+		return 0;
+
 	/*
 	 * next pg to try
 	 */
diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c
index ef761d7..0a94f10 100644
--- a/libmultipath/hwtable.c
+++ b/libmultipath/hwtable.c
@@ -1,12 +1,12 @@
 #include <stdio.h>
 
-#include <checkers.h>
-
+#include "checkers.h"
 #include "vector.h"
 #include "defaults.h"
 #include "structs.h"
 #include "config.h"
 #include "pgpolicies.h"
+#include "prio.h"
 
 /*
  * Tuning suggestions on these parameters should go to
@@ -27,7 +27,6 @@ static struct hwentry default_hw[] = {
 		.vendor        = "APPLE*",
 		.product       = "Xserve RAID ",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = NULL,
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -37,6 +36,7 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = DEFAULT_CHECKER,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	/*
 	 * StorageWorks controller family
@@ -48,7 +48,6 @@ static struct hwentry default_hw[] = {
 		.vendor        = "3PARdata",
 		.product       = "VV",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = NULL,
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -58,14 +57,14 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = DEFAULT_CHECKER,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	{
 		.vendor        = "DEC",
 		.product       = "HSG80",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_hp_sw /dev/%n",
 		.features      = "1 queue_if_no_path",
-		.hwhandler     = "1 hp_sw",
+		.hwhandler     = "1 hp-sw",
 		.selector      = DEFAULT_SELECTOR,
 		.pgpolicy      = GROUP_BY_PRIO,
 		.pgfailback    = FAILBACK_UNDEF,
@@ -73,101 +72,117 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = HP_SW,
+		.prio_name     = PRIO_HP_SW,
 	},
 	{
 		.vendor        = "HP",
 		.product       = "A6189A",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = NULL,
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
 		.pgpolicy      = MULTIBUS,
 		.pgfailback    = FAILBACK_UNDEF,
 		.rr_weight     = RR_WEIGHT_NONE,
-		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.no_path_retry = 12,
 		.minio         = DEFAULT_MINIO,
-		.checker_name  = READSECTOR0,
+		.checker_name  = DIRECTIO,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	{
 		/* MSA 1000/MSA1500 EVA 3000/5000 with old firmware */
 		.vendor        = "(COMPAQ|HP)",
 		.product       = "(MSA|HSV)1.0.*",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_hp_sw /dev/%n",
 		.features      = "1 queue_if_no_path",
-		.hwhandler     = "1 hp_sw",
+		.hwhandler     = "1 hp-sw",
 		.selector      = DEFAULT_SELECTOR,
 		.pgpolicy      = GROUP_BY_PRIO,
 		.pgfailback    = FAILBACK_UNDEF,
 		.rr_weight     = RR_WEIGHT_NONE,
-		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.no_path_retry = 12,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = HP_SW,
+		.prio_name     = PRIO_HP_SW,
 	},
 	{
 		/* MSA 1000/1500 with new firmware */
 		.vendor        = "HP",
 		.product       = "MSA VOLUME",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_alua /dev/%n",
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
 		.pgpolicy      = GROUP_BY_PRIO,
 		.pgfailback    = -FAILBACK_IMMEDIATE,
 		.rr_weight     = RR_WEIGHT_NONE,
-		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.no_path_retry = 12,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = TUR,
+		.prio_name     = PRIO_ALUA,
 	},
 	{
-		/* EVA 3000/5000 with new firmware */
+		.vendor        = "HP",
+		.product       = "MSA2000s*",
+		.getuid        = "/sbin/cciss_id %n",
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_PRIO,
+		.pgfailback    = -FAILBACK_IMMEDIATE,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = 12,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = TUR,
+		.prio_name     = DEFAULT_PRIO,
+	},
+	{
+		/* EVA 3000/5000 with new firmware, EVA 4000/6000/8000 */
 		.vendor        = "(COMPAQ|HP)",
-		.product       = "(MSA|HSV)1.1.*",
+		.product       = "HSV1[01]1|HSV2[01]0|HSV300",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_alua /dev/%n",
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
 		.pgpolicy      = GROUP_BY_PRIO,
 		.pgfailback    = -FAILBACK_IMMEDIATE,
 		.rr_weight     = RR_WEIGHT_NONE,
-		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.no_path_retry = 12,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = TUR,
+		.prio_name     = PRIO_ALUA,
 	},
 	{
-		/* EVA 4000/6000/8000 */
+		/* HP MSA2000 product family */
 		.vendor        = "HP",
-		.product       = "HSV2.*",
+		.product       = "MSA2[02]12*",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_alua /dev/%n",
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
-		.pgpolicy      = GROUP_BY_PRIO,
+		.pgpolicy      = MULTIBUS,
 		.pgfailback    = -FAILBACK_IMMEDIATE,
 		.rr_weight     = RR_WEIGHT_NONE,
-		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.no_path_retry = 12,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = TUR,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	{
 		/* HP Smart Array */
 		.vendor        = "HP",
 		.product       = "LOGICAL VOLUME.*",
 		.getuid        = "/lib/udev/scsi_id -n -g -u -s /block/%n",
-		.getprio       = NULL,
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
 		.pgpolicy      = MULTIBUS,
 		.pgfailback    = FAILBACK_UNDEF,
 		.rr_weight     = RR_WEIGHT_NONE,
-		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.no_path_retry = 12,
 		.minio         = DEFAULT_MINIO,
-		.checker_name  = TUR,
+		.checker_name  = CCISS_TUR,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	/*
 	 * DDN controller family
@@ -179,7 +194,6 @@ static struct hwentry default_hw[] = {
 		.vendor        = "DDN",
 		.product       = "SAN DataDirector",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = NULL,
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -189,6 +203,7 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = DIRECTIO,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	/*
 	 * EMC / Clariion controller family
@@ -200,7 +215,6 @@ static struct hwentry default_hw[] = {
 		.vendor        = "EMC",
 		.product       = "SYMMETRIX",
 		.getuid        = "/lib/udev/scsi_id -g -u -ppre-spc3-83 -s /block/%n",
-		.getprio       = NULL,
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -209,14 +223,14 @@ static struct hwentry default_hw[] = {
 		.rr_weight     = RR_WEIGHT_NONE,
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
-		.checker_name  = READSECTOR0,
+		.checker_name  = DIRECTIO,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	{
 		.vendor        = "DGC",
 		.product       = ".*",
 		.bl_product    = "LUNZ",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_emc /dev/%n",
 		.features      = "1 queue_if_no_path",
 		.hwhandler     = "1 emc",
 		.selector      = DEFAULT_SELECTOR,
@@ -226,6 +240,7 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = (300 / DEFAULT_CHECKINT),
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = EMC_CLARIION,
+		.prio_name     = PRIO_EMC,
 	},
 	/*
 	 * Fujitsu controller family
@@ -237,7 +252,6 @@ static struct hwentry default_hw[] = {
 		.vendor        = "FSC",
 		.product       = "CentricStor",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = NULL,
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -246,7 +260,8 @@ static struct hwentry default_hw[] = {
 		.rr_weight     = RR_WEIGHT_NONE,
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
-		.checker_name  = READSECTOR0,
+		.checker_name  = DIRECTIO,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	/*
 	 * Hitachi controller family
@@ -258,7 +273,6 @@ static struct hwentry default_hw[] = {
 		.vendor        = "(HITACHI|HP)",
 		.product       = "OPEN-.*",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = NULL,
 		.features      = "1 queue_if_no_path",
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -268,12 +282,12 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = TUR,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	{
 		.vendor        = "HITACHI",
 		.product       = "DF.*",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_hds_modular /dev/%n",
 		.features      = "1 queue_if_no_path",
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -283,6 +297,7 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = TUR,
+		.prio_name     = PRIO_HDS,
 	},
 	/*
 	 * IBM controller family
@@ -294,7 +309,6 @@ static struct hwentry default_hw[] = {
 		.vendor        = "IBM",
 		.product       = "ProFibre 4000R",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = NULL,
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -303,46 +317,94 @@ static struct hwentry default_hw[] = {
 		.rr_weight     = RR_WEIGHT_NONE,
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
-		.checker_name  = READSECTOR0,
+		.checker_name  = DIRECTIO,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	{
-		/* IBM DS4100 / FAStT100 */
+		/* IBM FAStT 1722-600 */
+		.vendor        = "IBM",
+		.product       = "1722-600",
+		.getuid        = DEFAULT_GETUID,
+		.features      = "1 queue_if_no_path",
+		.hwhandler     = "1 rdac",
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_PRIO,
+		.pgfailback    = -FAILBACK_IMMEDIATE,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = 300,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = RDAC,
+		.prio_name     = PRIO_RDAC,
+	},
+	{
+		/* IBM DS4400 / FAStT700 */
 		.vendor        = "IBM",
 		.product       = "1742",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_rdac /dev/%n",
 		.features      = DEFAULT_FEATURES,
-		.hwhandler     = DEFAULT_HWHANDLER,
+		.hwhandler     = "1 rdac",
 		.selector      = DEFAULT_SELECTOR,
 		.pgpolicy      = GROUP_BY_PRIO,
 		.pgfailback    = -FAILBACK_IMMEDIATE,
 		.rr_weight     = RR_WEIGHT_NONE,
-		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.no_path_retry = NO_PATH_RETRY_QUEUE,
 		.minio         = DEFAULT_MINIO,
-		.checker_name  = TUR,
+		.checker_name  = RDAC,
+		.prio_name     = PRIO_RDAC,
+	},
+	{
+	    /* IBM DS4700 */
+		.vendor        = "IBM",
+		.product       = "1814",
+		.getuid        = DEFAULT_GETUID,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = "1 rdac",
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_PRIO,
+		.pgfailback    = -FAILBACK_IMMEDIATE,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_QUEUE,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = RDAC,
+		.prio_name     = PRIO_RDAC,
+	},
+	{
+	    /* IBM DS4800 */
+		.vendor        = "IBM",
+		.product       = "1815",
+		.getuid        = DEFAULT_GETUID,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = "1 rdac",
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_PRIO,
+		.pgfailback    = -FAILBACK_IMMEDIATE,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_QUEUE,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = RDAC,
+		.prio_name     = PRIO_RDAC,
 	},
 	{
 		/* IBM Netfinity Fibre Channel RAID Controller Unit */
 		.vendor        = "IBM",
 		.product       = "3526",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_rdac /dev/%n",
 		.features      = DEFAULT_FEATURES,
-		.hwhandler     = DEFAULT_HWHANDLER,
+		.hwhandler     = "1 rdac",
 		.selector      = DEFAULT_SELECTOR,
 		.pgpolicy      = GROUP_BY_PRIO,
 		.pgfailback    = -FAILBACK_IMMEDIATE,
 		.rr_weight     = RR_WEIGHT_NONE,
-		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.no_path_retry = NO_PATH_RETRY_QUEUE,
 		.minio         = DEFAULT_MINIO,
-		.checker_name  = TUR,
+		.checker_name  = RDAC,
+		.prio_name     = PRIO_RDAC,
 	},
 	{
 		/* IBM DS4200 / FAStT200 */
 		.vendor        = "IBM",
 		.product       = "3542",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = NULL,
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -352,13 +414,13 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = TUR,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	{
 		/* IBM ESS F20 aka Shark */
 		.vendor        = "IBM",
 		.product       = "2105(800|F20)",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = NULL,
 		.features      = "1 queue_if_no_path",
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -368,13 +430,13 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = TUR,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	{
 		/* IBM DS6000 */
 		.vendor        = "IBM",
 		.product       = "1750500",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_alua /dev/%n",
 		.features      = "1 queue_if_no_path",
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -384,13 +446,13 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = TUR,
+		.prio_name     = PRIO_ALUA,
 	},
 	{
 		/* IBM DS8000 */
 		.vendor        = "IBM",
 		.product       = "2107900",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = NULL,
 		.features      = "1 queue_if_no_path",
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -400,13 +462,13 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = TUR,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	{
 		/* IBM SAN Volume Controller */
 		.vendor        = "IBM",
 		.product       = "2145",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_alua /dev/%n",
 		.features      = "1 queue_if_no_path",
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -416,6 +478,7 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = TUR,
+		.prio_name     = PRIO_ALUA,
 	},
 	{
 		/* IBM S/390 ECKD DASD */
@@ -423,7 +486,6 @@ static struct hwentry default_hw[] = {
 		.product       = "S/390 DASD ECKD",
 		.bl_product       = "S/390.*",
 		.getuid        = "/sbin/dasdinfo -u -b %n",
-		.getprio       = NULL,
 		.features      = "1 queue_if_no_path",
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -433,8 +495,26 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = DIRECTIO,
+		.prio_name     = DEFAULT_PRIO,
 	},
- 	/*
+	{
+		/* IBM S/390 FBA DASD */
+		.vendor        = "IBM",
+		.product       = "S/390 DASD FBA",
+		.bl_product       = "S/390.*",
+		.getuid        = "/sbin/dasdinfo -u -b %n",
+		.features      = "1 queue_if_no_path",
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = MULTIBUS,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = DIRECTIO,
+		.prio_name     = DEFAULT_PRIO,
+	},
+	/*
 	 * NETAPP controller family
 	 *
 	 * Maintainer : Dave Wysochanski
@@ -444,7 +524,6 @@ static struct hwentry default_hw[] = {
 		.vendor        = "NETAPP",
 		.product       = "LUN.*",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_netapp /dev/%n",
 		.features      = "1 queue_if_no_path",
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -453,9 +532,10 @@ static struct hwentry default_hw[] = {
 		.rr_weight     = RR_WEIGHT_NONE,
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = 128,
-		.checker_name  = READSECTOR0,
+		.checker_name  = DIRECTIO,
+		.prio_name     = PRIO_NETAPP,
 	},
- 	/*
+	/*
 	 * IBM NSeries (NETAPP) controller family
 	 *
 	 * Maintainer : Dave Wysochanski
@@ -465,7 +545,6 @@ static struct hwentry default_hw[] = {
 		.vendor        = "IBM",
 		.product       = "Nseries.*",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_netapp /dev/%n",
 		.features      = "1 queue_if_no_path",
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -474,7 +553,8 @@ static struct hwentry default_hw[] = {
 		.rr_weight     = RR_WEIGHT_NONE,
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = 128,
-		.checker_name  = READSECTOR0,
+		.checker_name  = DIRECTIO,
+		.prio_name     = PRIO_NETAPP,
 	},
 	/*
 	 * Pillar Data controller family
@@ -486,7 +566,6 @@ static struct hwentry default_hw[] = {
 		.vendor        = "Pillar",
 		.product       = "Axiom.*",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_alua %n",
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -496,6 +575,7 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = TUR,
+		.prio_name     = PRIO_ALUA,
 	},
 	/*
 	 * SGI arrays
@@ -507,7 +587,6 @@ static struct hwentry default_hw[] = {
 		.vendor        = "SGI",
 		.product       = "TP9[13]00",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = NULL,
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -516,15 +595,15 @@ static struct hwentry default_hw[] = {
 		.rr_weight     = RR_WEIGHT_NONE,
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
-		.checker_name  = READSECTOR0,
+		.checker_name  = DIRECTIO,
+		.prio_name     = DEFAULT_PRIO,
 	},
 	{
 		.vendor        = "SGI",
 		.product       = "TP9[45]00",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_rdac /dev/%n",
 		.features      = DEFAULT_FEATURES,
-		.hwhandler     = DEFAULT_HWHANDLER,
+		.hwhandler     = "1 rdac",
 		.selector      = DEFAULT_SELECTOR,
 		.pgpolicy      = GROUP_BY_PRIO,
 		.pgfailback    = -FAILBACK_IMMEDIATE,
@@ -532,14 +611,14 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_QUEUE,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = RDAC,
+		.prio_name     = PRIO_RDAC,
 	},
 	{
 		.vendor        = "SGI",
 		.product       = "IS.*",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_rdac /dev/%n",
 		.features      = DEFAULT_FEATURES,
-		.hwhandler     = DEFAULT_HWHANDLER,
+		.hwhandler     = "1 rdac",
 		.selector      = DEFAULT_SELECTOR,
 		.pgpolicy      = GROUP_BY_PRIO,
 		.pgfailback    = -FAILBACK_IMMEDIATE,
@@ -547,6 +626,7 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_QUEUE,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = RDAC,
+		.prio_name     = PRIO_RDAC,
 	},
 	/*
 	 * STK arrays
@@ -558,9 +638,8 @@ static struct hwentry default_hw[] = {
 		.vendor        = "STK",
 		.product       = "OPENstorage D280",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = "/sbin/mpath_prio_rdac /dev/%n",
 		.features      = DEFAULT_FEATURES,
-		.hwhandler     = DEFAULT_HWHANDLER,
+		.hwhandler     = "1 rdac",
 		.selector      = DEFAULT_SELECTOR,
 		.pgpolicy      = GROUP_BY_PRIO,
 		.pgfailback    = -FAILBACK_IMMEDIATE,
@@ -568,6 +647,7 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
 		.checker_name  = TUR,
+		.prio_name     = PRIO_RDAC,
 	},
 	/*
 	 * SUN arrays
@@ -579,7 +659,6 @@ static struct hwentry default_hw[] = {
 		.vendor        = "SUN",
 		.product       = "(StorEdge 3510|T4)",
 		.getuid        = DEFAULT_GETUID,
-		.getprio       = NULL,
 		.features      = DEFAULT_FEATURES,
 		.hwhandler     = DEFAULT_HWHANDLER,
 		.selector      = DEFAULT_SELECTOR,
@@ -588,7 +667,60 @@ static struct hwentry default_hw[] = {
 		.rr_weight     = RR_WEIGHT_NONE,
 		.no_path_retry = NO_PATH_RETRY_UNDEF,
 		.minio         = DEFAULT_MINIO,
-		.checker_name  = READSECTOR0,
+		.checker_name  = DIRECTIO,
+		.prio_name     = DEFAULT_PRIO,
+	},
+	/*
+	 * Pivot3 RAIGE
+	 *
+	 * Maintainer : Bart Brooks, Pivot3
+	 * Mail : bartb@pivot3.com
+	 */
+	{
+		.vendor        = "PIVOT3",
+		.product       = "RAIGE VOLUME",
+		.getuid        = "/sbin/scsi_id -p 0x80 -g -u -s /block/%n",
+		.features      = "1 queue_if_no_path",
+		.hwhandler     = DEFAULT_HWHANDLER,
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = MULTIBUS,
+		.pgfailback    = FAILBACK_UNDEF,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_UNDEF,
+		.minio         = 100,
+		.checker_name  = TUR,
+		.prio_name     = DEFAULT_PRIO,
+	},
+	{
+		.vendor        = "SUN",
+		.product       = "CSM200_R",
+		.getuid        = DEFAULT_GETUID,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = "1 rdac",
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_PRIO,
+		.pgfailback    = -FAILBACK_IMMEDIATE,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_QUEUE,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = RDAC,
+		.prio_name     = PRIO_RDAC,
+	},
+	/* SUN/LSI 2540 */
+	{
+		.vendor        = "SUN",
+		.product       = "LCSM100_F",
+		.getuid        = DEFAULT_GETUID,
+		.features      = DEFAULT_FEATURES,
+		.hwhandler     = "1 rdac",
+		.selector      = DEFAULT_SELECTOR,
+		.pgpolicy      = GROUP_BY_PRIO,
+		.pgfailback    = -FAILBACK_IMMEDIATE,
+		.rr_weight     = RR_WEIGHT_NONE,
+		.no_path_retry = NO_PATH_RETRY_QUEUE,
+		.minio         = DEFAULT_MINIO,
+		.checker_name  = RDAC,
+		.prio_name     = PRIO_RDAC,
 	},
 	/*
 	 * EOL
@@ -597,7 +729,6 @@ static struct hwentry default_hw[] = {
 		.vendor        = NULL,
 		.product       = NULL,
 		.getuid        = NULL,
-		.getprio       = NULL,
 		.features      = NULL,
 		.hwhandler     = NULL,
 		.selector      = NULL,
@@ -607,6 +738,7 @@ static struct hwentry default_hw[] = {
 		.no_path_retry = 0,
 		.minio         = 0,
 		.checker_name  = NULL,
+		.prio_name     = NULL,
 	},
 };
 
@@ -617,7 +749,6 @@ setup_default_hwtable (vector hw)
 	struct hwentry * hwe = default_hw;
 
 	while (hwe->vendor) {
-		hwe->checker = checker_lookup(hwe->checker_name);
 		r += store_hwe(hw, hwe);
 		hwe++;
 	}
diff --git a/libmultipath/log_pthread.c b/libmultipath/log_pthread.c
index 5a82b6a..8909440 100644
--- a/libmultipath/log_pthread.c
+++ b/libmultipath/log_pthread.c
@@ -15,9 +15,7 @@
 void log_safe (int prio, const char * fmt, va_list ap)
 {
 	pthread_mutex_lock(logq_lock);
-	//va_start(ap, fmt);
 	log_enqueue(prio, fmt, ap);
-	va_end(ap);
 	pthread_mutex_unlock(logq_lock);
 
 	pthread_mutex_lock(logev_lock);
@@ -33,7 +31,8 @@ static void flush_logqueue (void)
 		pthread_mutex_lock(logq_lock);
 		empty = log_dequeue(la->buff);
 		pthread_mutex_unlock(logq_lock);
-		log_syslog(la->buff);
+		if (!empty)
+			log_syslog(la->buff);
 	} while (empty == 0);
 }
 
diff --git a/libmultipath/parser.c b/libmultipath/parser.c
index f9c555e..ad2bb4f 100644
--- a/libmultipath/parser.c
+++ b/libmultipath/parser.c
@@ -203,7 +203,7 @@ alloc_strvec(char *string)
 	cp = string;
 
 	/* Skip white spaces */
-	while (isspace((int) *cp) && *cp != '\0')
+	while ((isspace((int) *cp) || !isascii((int) *cp)) && *cp != '\0')
 		cp++;
 
 	/* Return if there is only white spaces */
@@ -241,8 +241,10 @@ alloc_strvec(char *string)
 				in_string = 1;
 
 		} else {
-			while ((in_string || !isspace((int) *cp)) && *cp
-				!= '\0' && *cp != '"')
+			while ((in_string ||
+				(!isspace((int) *cp) && isascii((int) *cp) &&
+				 *cp != '!' && *cp != '#')) &&
+			       *cp != '\0' && *cp != '"')
 				cp++;
 			strlen = cp - start;
 			token = MALLOC(strlen + 1);
@@ -255,7 +257,8 @@ alloc_strvec(char *string)
 		}
 		vector_set_slot(strvec, token);
 
-		while (isspace((int) *cp) && *cp != '\0')
+		while ((isspace((int) *cp) || !isascii((int) *cp))
+		       && *cp != '\0')
 			cp++;
 		if (*cp == '\0' || *cp == '!' || *cp == '#')
 			return strvec;
diff --git a/libmultipath/pgpolicies.c b/libmultipath/pgpolicies.c
index 0ac7448..2a9671a 100644
--- a/libmultipath/pgpolicies.c
+++ b/libmultipath/pgpolicies.c
@@ -5,8 +5,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <checkers.h>
-
+#include "checkers.h"
 #include "util.h"
 #include "memory.h"
 #include "vector.h"
@@ -127,6 +126,7 @@ out1:
 	FREE(bitmap);
 out:
 	free_pgvec(mp->pg, KEEP_PATHS);
+	mp->pg = NULL;
 	return 1;
 }
 
@@ -198,6 +198,7 @@ out1:
 	FREE(bitmap);
 out:
 	free_pgvec(mp->pg, KEEP_PATHS);
+	mp->pg = NULL;
 	return 1;
 }
 
@@ -232,6 +233,7 @@ one_path_per_group (struct multipath * mp)
 	return 0;
 out:
 	free_pgvec(mp->pg, KEEP_PATHS);
+	mp->pg = NULL;
 	return 1;
 }
 
@@ -264,6 +266,7 @@ one_group (struct multipath * mp)	/* aka multibus */
 	return 0;
 out:
 	free_pgvec(mp->pg, KEEP_PATHS);
+	mp->pg = NULL;
 	return 1;
 }
 
@@ -338,6 +341,7 @@ group_by_prio (struct multipath * mp)
 	return 0;
 out:
 	free_pgvec(mp->pg, KEEP_PATHS);
+	mp->pg = NULL;
 	return 1;
 
 }
diff --git a/libmultipath/print.c b/libmultipath/print.c
index 01a157a..3be1c9d 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -8,8 +8,7 @@
 #include <sys/stat.h>
 #include <dirent.h>
 
-#include <checkers.h>
-
+#include "checkers.h"
 #include "vector.h"
 #include "structs.h"
 #include "structs_vec.h"
@@ -21,6 +20,8 @@
 #include "defaults.h"
 #include "parser.h"
 #include "blacklist.h"
+#include "switchgroup.h"
+#include "devmapper.h"
 
 #define MAX(x,y) (x > y) ? x : y
 #define TAIL     (line + len - 1 - c)
@@ -89,8 +90,19 @@ snprint_sysfs (char * buff, size_t len, struct multipath * mpp)
 {
 	if (mpp->dmi)
 		return snprintf(buff, len, "dm-%i", mpp->dmi->minor);
+	else
+		return snprintf(buff, len, "n/a");
+}
 
-	return 0;
+static int
+snprint_ro (char * buff, size_t len, struct multipath * mpp)
+{
+	if (!mpp->dmi)
+		return snprintf(buff, len, "n/a");
+	if (mpp->dmi->read_only)
+		return snprintf(buff, len, "ro");
+	else
+		return snprintf(buff, len, "rw");
 }
 
 static int
@@ -221,6 +233,16 @@ snprint_multipath_uuid (char * buff, size_t len, struct multipath * mpp)
 }
 
 static int
+snprint_multipath_vpr (char * buff, size_t len, struct multipath * mpp)
+{
+	struct path * pp = first_path(mpp);
+	if (!pp)
+		return 0;
+	return snprintf(buff, len, "%s,%s",
+		        pp->vendor_id, pp->product_id);
+}
+
+static int
 snprint_action (char * buff, size_t len, struct multipath * mpp)
 {
 	switch (mpp->action) {
@@ -340,6 +362,13 @@ snprint_pg_selector (char * buff, size_t len, struct pathgroup * pgp)
 static int
 snprint_pg_pri (char * buff, size_t len, struct pathgroup * pgp)
 {
+	/*
+	 * path group priority is not updated for every path prio change,
+	 * but only on switch group code path.
+	 *
+	 * Printing is another reason to update.
+	 */
+	path_group_prio_update(pgp);
 	return snprint_int(buff, len, pgp->priority);
 }
 
@@ -371,6 +400,7 @@ struct multipath_data mpd[] = {
 	{'F', "failback",      0, snprint_failback},
 	{'Q', "queueing",      0, snprint_queueing},
 	{'N', "paths",         0, snprint_nb_paths},
+	{'r', "write_prot",    0, snprint_ro},
 	{'t', "dm-st",         0, snprint_dm_map_state},
 	{'S', "size",          0, snprint_multipath_size},
 	{'f', "features",      0, snprint_features},
@@ -381,6 +411,7 @@ struct multipath_data mpd[] = {
 	{'2', "map_loads",     0, snprint_map_loads},
 	{'3', "total_q_time",  0, snprint_total_q_time},
 	{'4', "q_timeouts",    0, snprint_q_timeouts},
+	{'s', "vend/prod/rev", 0, snprint_multipath_vpr},
 	{0, NULL, 0 , NULL}
 };
 
@@ -405,14 +436,17 @@ struct pathgroup_data pgd[] = {
 };
 
 void
-get_path_layout (vector pathvec)
+get_path_layout (vector pathvec, int header)
 {
 	int i, j;
 	char buff[MAX_FIELD_LEN];
 	struct path * pp;
 
 	for (j = 0; pd[j].header; j++) {
-		pd[j].width = strlen(pd[j].header);
+		if (header)
+			pd[j].width = strlen(pd[j].header);
+		else
+			pd[j].width = 0;
 
 		vector_foreach_slot (pathvec, pp, i) {
 			pd[j].snprint(buff, MAX_FIELD_LEN, pp);
@@ -422,14 +456,17 @@ get_path_layout (vector pathvec)
 }
 
 void
-get_multipath_layout (vector mpvec)
+get_multipath_layout (vector mpvec, int header)
 {
 	int i, j;
 	char buff[MAX_FIELD_LEN];
 	struct multipath * mpp;
 
 	for (j = 0; mpd[j].header; j++) {
-		mpd[j].width = strlen(mpd[j].header);
+		if (header)
+			mpd[j].width = strlen(mpd[j].header);
+		else
+			mpd[j].width = 0;
 
 		vector_foreach_slot (mpvec, mpp, i) {
 			mpd[j].snprint(buff, MAX_FIELD_LEN, mpp);
@@ -683,16 +720,15 @@ snprint_multipath_topology (char * buff, int len, struct multipath * mpp,
 	c += sprintf(c, "%%n");
 	
 	if (strncmp(mpp->alias, mpp->wwid, WWID_SIZE))
-		c += sprintf(c, " (%%w) ");
+		c += sprintf(c, " (%%w)");
 
-	c += sprintf(c, "%%d ");
-	c += snprint_vpr(c, 24, first_path(mpp));
+	c += sprintf(c, " %%d %%s");
 
 	fwd += snprint_multipath(buff + fwd, len - fwd, style, mpp);
 	if (fwd > len)
 		return len;
 	fwd += snprint_multipath(buff + fwd, len - fwd,
-				 "[size=%S][features=%f][hwhandler=%h]", mpp);
+				 "[size=%S][features=%f][hwhandler=%h][%r]", mpp);
 	if (fwd > len)
 		return len;
 
@@ -1118,15 +1154,16 @@ snprint_devices (char * buff, int len, struct vectors *vecs)
 		return len;
 	fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n");
 
-	strcpy(devpath,"/sys/block");
-	devptr = devpath + 10;
+	strcpy(devpath,"/sys/block/");
 	while ((blkdev = readdir(blkdir)) != NULL) {
 		if ((strcmp(blkdev->d_name,".") == 0) ||
 		    (strcmp(blkdev->d_name,"..") == 0))
 			continue;
 
-		strcat(devptr,blkdev->d_name);
-		if (stat(devptr, &statbuf) < 0)
+		devptr = devpath + 11;
+		*devptr = '\0';
+		strncat(devptr, blkdev->d_name, PATH_MAX-12);
+		if (stat(devpath, &statbuf) < 0)
 			continue;
 
 		if (S_ISDIR(statbuf.st_mode) == 0)
@@ -1135,18 +1172,20 @@ snprint_devices (char * buff, int len, struct vectors *vecs)
 		if ((len - fwd - threshold)  <= 0)
 			return len;
 
-		fwd += snprintf(buff + fwd, len - fwd, "    %s", devpath);
-		pp = find_path_by_dev(vecs->pathvec, devpath);
+		fwd += snprintf(buff + fwd, len - fwd, "    %s", devptr);
+		pp = find_path_by_dev(vecs->pathvec, devptr);
 		if (!pp) {
 			r = filter_devnode(conf->blist_devnode,
-					   conf->elist_devnode, devpath);
+					   conf->elist_devnode, devptr);
 			if (r > 0)
 				fwd += snprintf(buff + fwd, len - fwd,
-						" (blacklisted)");
+						" devnode blacklisted, unmonitored");
 			else if (r < 0)
 				fwd += snprintf(buff + fwd, len - fwd,
-						" (whitelisted)");
-		}
+						" devnode whitelisted, unmonitored");
+		} else
+			fwd += snprintf(buff + fwd, len - fwd,
+					" devnode whitelisted, monitored");
 		fwd += snprintf(buff + fwd, len - fwd, "\n");
 	}
 	closedir(blkdir);
@@ -1197,13 +1236,19 @@ print_map (struct multipath * mpp)
 {
 	if (mpp->size && mpp->params)
 		printf("0 %llu %s %s\n",
-			 mpp->size, DEFAULT_TARGET, mpp->params);
+			 mpp->size, TGT_MPATH, mpp->params);
 	return;
 }
 
 extern void
 print_all_paths (vector pathvec, int banner)
 {
+	print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);
+}
+
+extern void
+print_all_paths_custo (vector pathvec, int banner, char *fmt)
+{
 	int i;
 	struct path * pp;
 	char line[MAX_LINE_LEN];
@@ -1217,11 +1262,11 @@ print_all_paths (vector pathvec, int banner)
 	if (banner)
 		fprintf(stdout, "===== paths list =====\n");
 
-	get_path_layout(pathvec);
-	snprint_path_header(line, MAX_LINE_LEN, PRINT_PATH_LONG);
+	get_path_layout(pathvec, 1);
+	snprint_path_header(line, MAX_LINE_LEN, fmt);
 	fprintf(stdout, "%s", line);
 
 	vector_foreach_slot (pathvec, pp, i)
-		print_path(pp, PRINT_PATH_LONG);
+		print_path(pp, fmt);
 }
 
diff --git a/libmultipath/print.h b/libmultipath/print.h
index 73c2f63..5c7023c 100644
--- a/libmultipath/print.h
+++ b/libmultipath/print.h
@@ -1,7 +1,7 @@
 #define PRINT_PATH_LONG      "%w %i %d %D %p %t%T %s"
 #define PRINT_PATH_INDENT    " \\_ %i %d %D %t%T"
 #define PRINT_PATH_CHECKER   "%i %d %D %p %t%T %C"
-#define PRINT_MAP_STATUS     "%n %F %Q %N %t"
+#define PRINT_MAP_STATUS     "%n %F %Q %N %t %r"
 #define PRINT_MAP_STATS      "%n %0 %1 %2 %3 %4"
 #define PRINT_MAP_NAMES      "%n %d %w"
 #define PRINT_PG_INDENT      "\\_ %s [prio=%p]%t"
@@ -32,8 +32,8 @@ struct pathgroup_data {
 	int (*snprint)(char * buff, size_t len, struct pathgroup * pgp);
 };
 
-void get_path_layout (vector pathvec);
-void get_multipath_layout (vector mpvec);
+void get_path_layout (vector pathvec, int header);
+void get_multipath_layout (vector mpvec, int header);
 int snprint_path_header (char *, int, char *);
 int snprint_multipath_header (char *, int, char *);
 int snprint_path (char *, int, char *, struct path *);
@@ -54,5 +54,6 @@ void print_multipath (struct multipath * mpp, char * style);
 void print_pathgroup (struct pathgroup * pgp, char * style);
 void print_map (struct multipath * mpp);
 void print_all_paths (vector pathvec, int banner);
+void print_all_paths_custo (vector pathvec, int banner, char *fmt);
 void print_hwtable (vector hwtable);
 
diff --git a/libmultipath/prio.c b/libmultipath/prio.c
new file mode 100644
index 0000000..c9d2873
--- /dev/null
+++ b/libmultipath/prio.c
@@ -0,0 +1,93 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <dlfcn.h>
+
+#include "debug.h"
+#include "prio.h"
+#include "config.h"
+
+static LIST_HEAD(prioritizers);
+
+int init_prio (void)
+{
+	INIT_LIST_HEAD(&prioritizers);
+	if (!add_prio(DEFAULT_PRIO))
+		return 1;
+	return 0;
+}
+
+struct prio * alloc_prio (void)
+{
+	return zalloc(sizeof(struct prio));
+}
+
+void free_prio (struct prio * p)
+{
+	free(p);
+}
+
+void cleanup_prio(void)
+{
+	struct prio * prio_loop;
+	struct prio * prio_temp;
+
+	list_for_each_entry_safe(prio_loop, prio_temp, &prioritizers, node) {
+		list_del(&prio_loop->node);
+		free(prio_loop);
+	}
+}
+
+struct prio * prio_lookup (char * name)
+{
+	struct prio * p;
+
+	list_for_each_entry(p, &prioritizers, node) {
+		if (!strncmp(name, p->name, PRIO_NAME_LEN))
+			return p;
+	}
+	return add_prio(name);
+}
+
+struct prio * add_prio (char * name)
+{
+	char libname[LIB_PRIO_NAMELEN];
+	void * handle;
+	struct prio * p;
+	char *errstr;
+
+	p = alloc_prio();
+	if (!p)
+		return NULL;
+	snprintf(libname, LIB_PRIO_NAMELEN, "%s/libprio%s.so",
+		 conf->multipath_dir, name);
+	condlog(3, "loading %s prioritizer", libname);
+	handle = dlopen(libname, RTLD_NOW);
+	errstr = dlerror();
+	if (errstr != NULL)
+	condlog(0, "A dynamic linking error occurred: (%s)", errstr);
+	if (!handle)
+		goto out;
+	p->getprio = (int (*)(struct path *)) dlsym(handle, "getprio");
+	errstr = dlerror();
+	if (errstr != NULL)
+	condlog(0, "A dynamic linking error occurred: (%s)", errstr);
+	if (!p->getprio)
+		goto out;
+	snprintf(p->name, PRIO_NAME_LEN, "%s", name);
+	list_add(&p->node, &prioritizers);
+	return p;
+out:
+	free_prio(p);
+	return NULL;
+}
+
+int prio_getprio (struct prio * p, struct path * pp)
+{
+	return p->getprio(pp);
+}
+
+char * prio_name (struct prio * p)
+{
+	return p->name;
+}
diff --git a/libmultipath/prio.h b/libmultipath/prio.h
new file mode 100644
index 0000000..491e6fc
--- /dev/null
+++ b/libmultipath/prio.h
@@ -0,0 +1,50 @@
+#ifndef _PRIO_H
+#define _PRIO_H
+
+/*
+ * knowing about path struct gives flexibility to prioritizers
+ */
+#include "checkers.h"
+#include "vector.h"
+#include "structs.h"
+#include "list.h"
+#include "memory.h"
+
+#define DEFAULT_PRIO "const"
+
+/*
+ * Known prioritizers for use in hwtable.c
+ */
+#define PRIO_ALUA "alua"
+#define PRIO_CONST "const"
+#define PRIO_EMC "emc"
+#define PRIO_HDS "hds"
+#define PRIO_HP_SW "hp_sw"
+#define PRIO_NETAPP "netapp"
+#define PRIO_RANDOM "random"
+#define PRIO_RDAC "rdac"
+
+/*
+ * Value used to mark the fact prio was not defined
+ */
+#define PRIO_UNDEF -1
+
+/*
+ * strings lengths
+ */
+#define LIB_PRIO_NAMELEN 255
+#define PRIO_NAME_LEN 16
+
+struct prio {
+	struct list_head node;
+	char name[PRIO_NAME_LEN];
+	int (*getprio)(struct path *);
+};
+
+int init_prio (void);
+struct prio * add_prio (char *);
+struct prio * prio_lookup (char *);
+int prio_getprio (struct prio *, struct path *);
+char * prio_name (struct prio *);
+
+#endif /* _PRIO_H */
diff --git a/libmultipath/prioritizers/Makefile b/libmultipath/prioritizers/Makefile
new file mode 100644
index 0000000..1f70ef1
--- /dev/null
+++ b/libmultipath/prioritizers/Makefile
@@ -0,0 +1,34 @@
+# Makefile
+#
+# Copyright (C) 2007 Christophe Varoqui, <christophe.varoqui@free.fr>
+#
+include ../../Makefile.inc
+
+LIBS = \
+	libpriorandom.so \
+	libprioconst.so \
+	libpriohp_sw.so \
+	libprioemc.so \
+	libpriordac.so \
+	libprioalua.so \
+	libprionetapp.so \
+	libpriohds.so
+
+CFLAGS += -I..
+
+all: $(LIBS)
+
+libprioalua.so: alua.o alua_rtpg.o
+	$(CC) $(SHARED_FLAGS) -o $@ $^
+
+libprio%.so: %.o
+	$(CC) $(SHARED_FLAGS) -o $@ $^
+
+install: $(LIBS)
+	$(INSTALL_PROGRAM) -m 755 libprio*.so $(DESTDIR)$(libdir)
+
+uninstall:
+	rm -f $(DESTDIR)$(libdir)/libprio*.so
+
+clean:
+	rm -f core *.a *.o *.gz *.so
diff --git a/libmultipath/prioritizers/alua.c b/libmultipath/prioritizers/alua.c
new file mode 100644
index 0000000..1b52b8e
--- /dev/null
+++ b/libmultipath/prioritizers/alua.c
@@ -0,0 +1,95 @@
+/*
+ * (C) Copyright IBM Corp. 2004, 2005   All Rights Reserved.
+ *
+ * main.c
+ *
+ * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
+ * It determines the ALUA state of a device and prints a priority value to
+ * stdout.
+ *
+ * Author(s): Jan Kunigk
+ *            S. Bader <shbader@de.ibm.com>
+ * 
+ * This file is released under the GPL.
+ */
+#include <stdio.h>
+
+#include <debug.h>
+#include <prio.h>
+
+#include "alua.h"
+
+#define ALUA_PRIO_NOT_SUPPORTED			1
+#define ALUA_PRIO_RTPG_FAILED			2
+#define ALUA_PRIO_GETAAS_FAILED			3
+#define ALUA_PRIO_TPGS_FAILED			4
+
+int
+get_alua_info(int fd)
+{
+	char *	aas_string[] = {
+		[AAS_OPTIMIZED]		= "active/optimized",
+		[AAS_NON_OPTIMIZED]	= "active/non-optimized",
+		[AAS_STANDBY]		= "standby",
+		[AAS_UNAVAILABLE]	= "unavailable",
+		[AAS_TRANSITIONING]	= "transitioning between states",
+	};
+	int	rc;
+	int	tpg;
+
+	rc = get_target_port_group_support(fd);
+	if (rc < 0)
+		return -ALUA_PRIO_TPGS_FAILED;
+
+	if (rc == TPGS_NONE)
+		return -ALUA_PRIO_NOT_SUPPORTED;
+
+	tpg = get_target_port_group(fd);
+	if (tpg < 0)
+		return -ALUA_PRIO_RTPG_FAILED;
+
+	condlog(3, "reported target port group is %i", tpg);
+	rc = get_asymmetric_access_state(fd, tpg);
+	if (rc < 0)
+		return -ALUA_PRIO_GETAAS_FAILED;
+
+	condlog(3, "aas = [%s]",
+		(aas_string[rc]) ? aas_string[rc] : "invalid/reserved");
+	return rc;
+}
+
+int getprio (struct path * pp)
+{
+	int rc = get_alua_info(pp->fd);
+	if (rc >= 0) {
+		switch(rc) {
+			case AAS_OPTIMIZED:
+				rc = 50;
+				break;
+			case AAS_NON_OPTIMIZED:
+				rc = 10;
+				break;
+			case AAS_STANDBY:
+				rc = 1;
+				break;
+			default:
+				rc = 0;
+		}
+	} else {
+		switch(-rc) {
+			case ALUA_PRIO_NOT_SUPPORTED:
+				condlog(0, "%s: alua not supported", pp->dev);
+				break;
+			case ALUA_PRIO_RTPG_FAILED:
+				condlog(0, "%s: couldn't get target port group", pp->dev);
+				break;
+			case ALUA_PRIO_GETAAS_FAILED:
+				condlog(0, "%s: couln't get asymmetric access state", pp->dev);
+				break;
+			case ALUA_PRIO_TPGS_FAILED:
+				condlog(3, "%s: couln't get supported alua states", pp->dev);
+				break;
+		}
+	}
+	return rc;
+}
diff --git a/libmultipath/prioritizers/alua.h b/libmultipath/prioritizers/alua.h
new file mode 100644
index 0000000..78a3d15
--- /dev/null
+++ b/libmultipath/prioritizers/alua.h
@@ -0,0 +1,9 @@
+#ifndef _ALUA_H
+#define _ALUA_H
+
+#include "alua_rtpg.h"
+
+#define PRIO_ALUA "alua"
+int prio_alua(struct path * pp);
+
+#endif
diff --git a/libmultipath/prioritizers/alua_rtpg.c b/libmultipath/prioritizers/alua_rtpg.c
new file mode 100644
index 0000000..c5528c5
--- /dev/null
+++ b/libmultipath/prioritizers/alua_rtpg.c
@@ -0,0 +1,301 @@
+/*
+ * (C) Copyright IBM Corp. 2004, 2005   All Rights Reserved.
+ *
+ * rtpg.c
+ *
+ * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
+ * It determines the ALUA state of a device and prints a priority value to
+ * stdout.
+ *
+ * Author(s): Jan Kunigk
+ *            S. Bader <shbader@de.ibm.com>
+ * 
+ * This file is released under the GPL.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <inttypes.h>
+
+#define __user
+#include <scsi/sg.h>
+
+#include "alua_rtpg.h"
+
+#define SENSE_BUFF_LEN  32
+#define DEF_TIMEOUT     300000
+
+/*
+ * Macro used to print debug messaged.
+ */
+#if DEBUG > 0
+#define PRINT_DEBUG(f, a...) \
+		fprintf(stderr, "DEBUG: " f, ##a)
+#else
+#define PRINT_DEBUG(f, a...)
+#endif
+
+/*
+ * Optionally print the commands sent and the data received a hex dump.
+ */
+#if DEBUG > 0
+#if DEBUG_DUMPHEX > 0
+#define PRINT_HEX(p, l)	print_hex(p, l)
+void
+print_hex(unsigned char *p, unsigned long len)
+{
+	int	i;
+
+	for(i = 0; i < len; i++) {
+		if (i % 16 == 0)
+			printf("%04x: ", i);
+		printf("%02x%s", p[i], (((i + 1) % 16) == 0) ? "\n" : " ");
+	}
+	printf("\n");
+}
+#else
+#define PRINT_HEX(p, l)
+#endif
+#else
+#define PRINT_HEX(p, l)
+#endif
+
+/*
+ * Returns 0 if the SCSI command either was successful or if the an error was
+ * recovered, otherwise 1. (definitions taken from sg_err.h)
+ */
+#define SCSI_CHECK_CONDITION    0x2
+#define SCSI_COMMAND_TERMINATED 0x22
+#define SG_ERR_DRIVER_SENSE     0x08
+#define RECOVERED_ERROR 0x01
+
+static int
+scsi_error(struct sg_io_hdr *hdr)
+{
+	/* Treat SG_ERR here to get rid of sg_err.[ch] */
+        hdr->status &= 0x7e;
+
+	if (
+		(hdr->status == 0)        &&
+		(hdr->host_status == 0)   &&
+		(hdr->driver_status == 0)
+	) {
+		return 0;
+	}
+
+	if (
+		(hdr->status == SCSI_CHECK_CONDITION)    ||
+		(hdr->status == SCSI_COMMAND_TERMINATED) ||
+		((hdr->driver_status & 0xf) == SG_ERR_DRIVER_SENSE)
+	) {
+		if (hdr->sbp && (hdr->sb_len_wr > 2)) {
+			int		sense_key;
+			unsigned char *	sense_buffer = hdr->sbp;
+
+			if (sense_buffer[0] & 0x2)
+				sense_key = sense_buffer[1] & 0xf;
+			else
+				sense_key = sense_buffer[2] & 0xf;
+
+			if (sense_key == RECOVERED_ERROR)
+				return 0;
+		}
+	}
+
+	return 1;
+}
+
+/*
+ * Helper function to setup and run a SCSI inquiry command.
+ */
+int
+do_inquiry(int fd, int evpd, unsigned int codepage, void *resp, int resplen)
+{
+	struct inquiry_command	cmd;
+	struct sg_io_hdr	hdr;
+	unsigned char		sense[SENSE_BUFF_LEN];
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op = OPERATION_CODE_INQUIRY;
+	if (evpd) {
+		inquiry_command_set_evpd(&cmd);
+		cmd.page = codepage;
+	}
+	set_uint16(cmd.length, resplen);
+	PRINT_HEX((unsigned char *) &cmd, sizeof(cmd));
+
+        memset(&hdr, 0, sizeof(hdr));
+        hdr.interface_id	= 'S';
+        hdr.cmdp		= (unsigned char *) &cmd;
+        hdr.cmd_len		= sizeof(cmd);
+        hdr.dxfer_direction	= SG_DXFER_FROM_DEV;
+        hdr.dxferp		= resp;
+        hdr.dxfer_len		= resplen;
+        hdr.sbp			= sense;
+        hdr.mx_sb_len		= sizeof(sense);
+        hdr.timeout		= DEF_TIMEOUT;
+ 
+        if (ioctl(fd, SG_IO, &hdr) < 0) {
+		PRINT_DEBUG("do_inquiry: IOCTL failed!\n");
+		return -RTPG_INQUIRY_FAILED;
+	}
+
+	if (scsi_error(&hdr)) {
+		PRINT_DEBUG("do_inquiry: SCSI error!\n");
+		return -RTPG_INQUIRY_FAILED;
+	}
+	PRINT_HEX((unsigned char *) resp, resplen);
+ 
+        return 0;
+}
+
+/*
+ * This function returns the support for target port groups by evaluating the
+ * data returned by the standard inquiry command.
+ */
+int
+get_target_port_group_support(int fd)
+{
+	struct inquiry_data	inq;
+	int			rc;
+
+	rc = do_inquiry(fd, 0, 0x00, &inq, sizeof(inq));
+	if (!rc) {
+		rc = inquiry_data_get_tpgs(&inq);
+	}
+
+	return rc;
+}
+
+int
+get_target_port_group(int fd)
+{
+	unsigned char		buf[128];
+	struct vpd83_data *	vpd83;
+	struct vpd83_dscr *	dscr;
+	int			rc;
+
+	rc = do_inquiry(fd, 1, 0x83, buf, sizeof(buf));
+	if (!rc) {
+		vpd83 = (struct vpd83_data *) buf;
+
+		rc = -RTPG_NO_TPG_IDENTIFIER;
+		FOR_EACH_VPD83_DSCR(vpd83, dscr) {
+			if ((((char *) dscr) - ((char *) vpd83)) > sizeof(buf))
+				break;
+
+			if (vpd83_dscr_istype(dscr, IDTYPE_TARGET_PORT_GROUP)) {
+				struct vpd83_tpg_dscr *	p;
+
+				if (rc != -RTPG_NO_TPG_IDENTIFIER) {
+					PRINT_DEBUG("get_target_port_group: "
+						"more than one TPG identifier "
+						"found!\n");
+					continue;
+				}
+
+				p  = (struct vpd83_tpg_dscr *) dscr->data;
+				rc = get_uint16(p->tpg);
+			}
+		}
+		if (rc == -RTPG_NO_TPG_IDENTIFIER) {
+			PRINT_DEBUG("get_target_port_group: "
+				"no TPG identifier found!\n");
+		}
+	}
+
+	return rc;
+}
+
+int
+do_rtpg(int fd, void* resp, long resplen)
+{
+	struct rtpg_command	cmd;
+	struct sg_io_hdr	hdr;
+	unsigned char		sense[SENSE_BUFF_LEN];
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.op			= OPERATION_CODE_RTPG;
+	rtpg_command_set_service_action(&cmd);
+	set_uint32(cmd.length, resplen);
+	PRINT_HEX((unsigned char *) &cmd, sizeof(cmd));
+
+        memset(&hdr, 0, sizeof(hdr));
+	hdr.interface_id	= 'S';
+        hdr.cmdp		= (unsigned char *) &cmd;
+        hdr.cmd_len		= sizeof(cmd);
+        hdr.dxfer_direction	= SG_DXFER_FROM_DEV;
+        hdr.dxferp		= resp;
+        hdr.dxfer_len		= resplen;
+        hdr.mx_sb_len		= sizeof(sense);
+        hdr.sbp			= sense;
+        hdr.timeout		= DEF_TIMEOUT;
+ 
+	if (ioctl(fd, SG_IO, &hdr) < 0)
+                return -RTPG_RTPG_FAILED;
+
+	if (scsi_error(&hdr)) {
+		PRINT_DEBUG("do_rtpg: SCSI error!\n");
+		return -RTPG_RTPG_FAILED;
+	}
+	PRINT_HEX(resp, resplen);
+
+        return 0;
+} 
+
+int
+get_asymmetric_access_state(int fd, unsigned int tpg)
+{
+	unsigned char		*buf;
+	struct rtpg_data *	tpgd;
+	struct rtpg_tpg_dscr *	dscr;
+	int			rc;
+	int			buflen;
+	uint32_t		scsi_buflen;
+
+	buflen = 128; /* Initial value from old code */
+	buf = (unsigned char *)malloc(buflen);
+	if (!buf) {
+		PRINT_DEBUG ("malloc failed: could not allocate"
+			"%u bytes\n", buflen);
+		return -RTPG_RTPG_FAILED;
+	}
+	rc = do_rtpg(fd, buf, buflen);
+	if (rc < 0)
+		return rc;
+	scsi_buflen = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
+	if (buflen < (scsi_buflen + 4)) {
+		free(buf);
+		buf = (unsigned char *)malloc(scsi_buflen);
+		if (!buf) {
+			PRINT_DEBUG ("malloc failed: could not allocate"
+				"%u bytes\n", scsi_buflen);
+			return -RTPG_RTPG_FAILED;
+		}
+		buflen = scsi_buflen;
+		rc = do_rtpg(fd, buf, buflen);
+		if (rc < 0)
+			goto out;
+	}
+		
+
+	tpgd = (struct rtpg_data *) buf;
+	rc   = -RTPG_TPG_NOT_FOUND;
+	RTPG_FOR_EACH_PORT_GROUP(tpgd, dscr) {
+		if (get_uint16(dscr->tpg) == tpg) {
+			if (rc != -RTPG_TPG_NOT_FOUND) {
+				PRINT_DEBUG("get_asymmetric_access_state: "
+					"more than one entry with same port "
+					"group.\n");
+			} else {
+				PRINT_DEBUG("pref=%i\n", dscr->pref);
+				rc = rtpg_tpg_dscr_get_aas(dscr);
+			}
+		}
+	}
+out:
+	free(buf);
+	return rc;
+}
+
diff --git a/libmultipath/prioritizers/alua_rtpg.h b/libmultipath/prioritizers/alua_rtpg.h
new file mode 100644
index 0000000..c43e0a9
--- /dev/null
+++ b/libmultipath/prioritizers/alua_rtpg.h
@@ -0,0 +1,30 @@
+/*
+ * (C) Copyright IBM Corp. 2004, 2005   All Rights Reserved.
+ *
+ * rtpg.h
+ *
+ * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
+ * It determines the ALUA state of a device and prints a priority value to
+ * stdout.
+ *
+ * Author(s): Jan Kunigk
+ *            S. Bader <shbader@de.ibm.com>
+ * 
+ * This file is released under the GPL.
+ */
+#ifndef __RTPG_H__
+#define __RTPG_H__
+#include "alua_spc3.h"
+
+#define RTPG_SUCCESS				0
+#define RTPG_INQUIRY_FAILED			1
+#define RTPG_NO_TPG_IDENTIFIER			2
+#define RTPG_RTPG_FAILED			3
+#define RTPG_TPG_NOT_FOUND			4
+
+int get_target_port_group_support(int fd);
+int get_target_port_group(int fd);
+int get_asymmetric_access_state(int fd, unsigned int tpg);
+
+#endif /* __RTPG_H__ */
+
diff --git a/libmultipath/prioritizers/alua_spc3.h b/libmultipath/prioritizers/alua_spc3.h
new file mode 100644
index 0000000..bddbbdd
--- /dev/null
+++ b/libmultipath/prioritizers/alua_spc3.h
@@ -0,0 +1,322 @@
+/*
+ * (C) Copyright IBM Corp. 2004, 2005   All Rights Reserved.
+ *
+ * spc3.h
+ *
+ * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
+ * It determines the ALUA state of a device and prints a priority value to
+ * stdout.
+ *
+ * Author(s): Jan Kunigk
+ *            S. Bader <shbader@de.ibm.com>
+ * 
+ * This file is released under the GPL.
+ */
+#ifndef __SPC3_H__
+#define __SPC3_H__
+/*=============================================================================
+ * Some helper functions for getting and setting 16 and 32 bit values.
+ *=============================================================================
+ */
+static inline unsigned short
+get_uint16(unsigned char *p)
+{
+	return (p[0] << 8) + p[1];
+}
+
+static inline void
+set_uint16(unsigned char *p, unsigned short v)
+{
+	p[0] = (v >> 8) & 0xff;
+	p[1] = v & 0xff;
+}
+
+static inline unsigned int
+get_uint32(unsigned char *p)
+{
+	return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
+}
+
+static inline void
+set_uint32(unsigned char *p, unsigned int v)
+{
+	p[0] = (v >> 24) & 0xff;
+	p[1] = (v >> 16) & 0xff;
+	p[2] = (v >>  8) & 0xff;
+	p[3] = v & 0xff;
+}
+
+/*=============================================================================
+ * Definitions to support the standard inquiry command as defined in SPC-3.
+ * If the evpd (enable vital product data) bit is set the data that will be
+ * returned is selected by the page field. This field must be 0 if the evpd
+ * bit is not set.
+ *=============================================================================
+ */
+#define OPERATION_CODE_INQUIRY		0x12
+
+struct inquiry_command {
+	unsigned char	op;
+	unsigned char	b1;		/* xxxxxx.. = reserved               */
+					/* ......x. = obsolete               */
+					/* .......x = evpd                   */
+	unsigned char	page;
+	unsigned char	length[2];
+	unsigned char	control;
+} __attribute__((packed));
+
+static inline void
+inquiry_command_set_evpd(struct inquiry_command *ic)
+{
+	ic->b1 |= 1;
+}
+
+/*-----------------------------------------------------------------------------
+ * Data returned by the standard inquiry command.
+ *-----------------------------------------------------------------------------
+ *
+ * Peripheral qualifier codes.
+ */
+#define PQ_CONNECTED					0x0
+#define PQ_DISCONNECTED					0x1
+#define PQ_UNSUPPORTED					0x3
+
+/* Defined peripheral device types. */
+#define PDT_DIRECT_ACCESS				0x00
+#define PDT_SEQUENTIAL_ACCESS				0x01
+#define PDT_PRINTER					0x02
+#define PDT_PROCESSOR					0x03
+#define PDT_WRITE_ONCE					0x04
+#define PDT_CD_DVD					0x05
+#define PDT_SCANNER					0x06
+#define PDT_OPTICAL_MEMORY				0x07
+#define PDT_MEDIUM_CHANGER				0x08
+#define PDT_COMMUNICATIONS				0x09
+#define PDT_STORAGE_ARRAY_CONTROLLER			0x0c
+#define PDT_ENCLOSURE_SERVICES				0x0d
+#define PDT_SIMPLIFIED_DIRECT_ACCESS			0x0e
+#define PDT_OPTICAL_CARD_READER_WRITER			0x0f
+#define PDT_BRIDGE_CONTROLLER				0x10
+#define PDT_OBJECT_BASED				0x11
+#define PDT_AUTOMATION_INTERFACE			0x12
+#define PDT_LUN						0x1e
+#define PDT_UNKNOWN					0x1f
+
+/* Defined version codes. */
+#define VERSION_NONE					0x00
+#define VERSION_SPC					0x03
+#define VERSION_SPC2					0x04
+#define VERSION_SPC3					0x05
+
+/* Defined TPGS field values. */
+#define TPGS_NONE					0x0
+#define TPGS_IMPLICIT					0x1
+#define TPGS_EXPLICIT					0x2
+#define TPGS_BOTH					0x3
+
+struct inquiry_data {
+	unsigned char	b0;		/* xxx..... = peripheral_qualifier   */
+					/* ...xxxxx = peripheral_device_type */
+	unsigned char	b1;             /* x....... = removable medium       */
+					/* .xxxxxxx = reserverd              */
+	unsigned char	version;
+	unsigned char	b3;		/* xx...... = obsolete               */
+					/* ..x..... = normal aca supported   */
+					/* ...x.... = hirarchichal lun supp. */
+					/* ....xxxx = response format        */
+					/*            2 is spc-3 format      */
+	unsigned char	length;
+	unsigned char	b5;		/* x....... = storage controller     */
+					/*            component supported    */
+					/* .x...... = access controls coord. */
+					/* ..xx.... = target port group supp.*/
+					/* ....x... = third party copy supp. */
+					/* .....xx. = reserved               */
+					/* .......x = protection info supp.  */
+	unsigned char	b6;		/* x....... = bque                   */
+					/* .x...... = enclosure services sup.*/
+					/* ..x..... = vs1                    */
+					/* ...x.... = multiport support      */
+					/* ....x... = medium changer         */
+					/* .....xx. = obsolete               */
+					/* .......x = add16                  */
+	unsigned char	b7;		/* xx...... = obsolete               */
+					/* ..x..... = wbus16                 */
+					/* ...x.... = sync                   */
+					/* ....x... = linked commands supp.  */
+					/* .....x.. = obsolete               */
+					/* ......x. = command queue support  */
+					/* .......x = vs2                    */
+	unsigned char	vendor_identification[8];
+	unsigned char	product_identification[16];
+	unsigned char	product_revision[4];
+	unsigned char	vendor_specific[20];
+	unsigned char	b56;		/* xxxx.... = reserved               */
+					/* ....xx.. = clocking               */
+					/* ......x. = qas                    */
+					/* .......x = ius                    */
+	unsigned char	reserved4;
+	unsigned char	version_descriptor[8][2];
+	unsigned char	reserved5[22];
+	unsigned char	vendor_parameters[0];
+} __attribute__((packed));
+
+static inline int
+inquiry_data_get_tpgs(struct inquiry_data *id)
+{
+	return (id->b5 >> 4) & 3;
+}
+
+/*-----------------------------------------------------------------------------
+ * Inquiry data returned when requesting vital product data page 0x83.
+ *-----------------------------------------------------------------------------
+ */
+#define CODESET_BINARY			0x1
+#define CODESET_ACSII			0x2
+#define CODESET_UTF8			0x3
+
+#define ASSOCIATION_UNIT		0x0
+#define ASSOCIATION_PORT		0x1
+#define ASSOCIATION_DEVICE		0x2
+
+#define IDTYPE_VENDOR_SPECIFIC		0x0
+#define IDTYPE_T10_VENDOR_ID		0x1
+#define IDTYPE_EUI64			0x2
+#define IDTYPE_NAA			0x3
+#define IDTYPE_RELATIVE_TPG_ID		0x4
+#define IDTYPE_TARGET_PORT_GROUP	0x5
+#define IDTYPE_LUN_GROUP		0x6
+#define IDTYPE_MD5_LUN_ID		0x7
+#define IDTYPE_SCSI_NAME_STRING		0x8
+
+struct vpd83_tpg_dscr {
+	unsigned char		reserved1[2];
+	unsigned char		tpg[2];
+} __attribute__((packed));
+
+struct vpd83_dscr {
+	unsigned char		b0;	/* xxxx.... = protocol id            */
+					/* ....xxxx = codeset                */
+	unsigned char		b1;	/* x....... = protocol id valid      */
+					/* .x...... = reserved               */
+					/* ..xx.... = association            */
+					/* ....xxxx = id type                */
+	unsigned char		reserved2;
+	unsigned char		length;				/* size-4    */
+	unsigned char		data[0];
+} __attribute__((packed));
+
+static inline int
+vpd83_dscr_istype(struct vpd83_dscr *d, unsigned char type)
+{
+	return ((d->b1 & 7) == type);
+}
+
+struct vpd83_data {
+	unsigned char		b0;	/* xxx..... = peripheral_qualifier   */
+					/* ...xxxxx = peripheral_device_type */
+	unsigned char		page_code;			/* 0x83      */
+	unsigned char		length[2];			/* size-4    */
+	struct vpd83_dscr	data[0];
+} __attribute__((packed));
+
+/*-----------------------------------------------------------------------------
+ * This macro should be used to walk through all identification descriptors
+ * defined in the code page 0x83.
+ * The argument p is a pointer to the code page 0x83 data and d is used to
+ * point to the current descriptor.
+ *-----------------------------------------------------------------------------
+ */
+#define FOR_EACH_VPD83_DSCR(p, d) \
+		for( \
+			d = p->data; \
+			(((char *) d) - ((char *) p)) < \
+			get_uint16(p->length); \
+			d = (struct vpd83_dscr *) \
+				((char *) d + d->length + 4) \
+		)
+
+/*=============================================================================
+ * The following stuctures and macros are used to call the report target port
+ * groups command defined in SPC-3.
+ * This command is used to get information about the target port groups (which
+ * states are supported, which ports belong to this group, and so on) and the
+ * current state of each target port group.
+ *=============================================================================
+ */
+#define OPERATION_CODE_RTPG		0xa3
+#define SERVICE_ACTION_RTPG		0x0a
+
+struct rtpg_command {
+	unsigned char		op;	/* 0xa3                              */
+	unsigned char		b1;	/* xxx..... = reserved               */
+					/* ...xxxxx = service action (0x0a)  */
+	unsigned char			reserved2[4];
+	unsigned char			length[4];
+	unsigned char			reserved3;
+	unsigned char			control;
+} __attribute__((packed));
+
+static inline void
+rtpg_command_set_service_action(struct rtpg_command *cmd)
+{
+	cmd->b1 = (cmd->b1 & 0xe0) | SERVICE_ACTION_RTPG;
+}
+
+struct rtpg_tp_dscr {
+	unsigned char			obsolete1[2];
+	/* The Relative Target Port Identifier of a target port. */
+	unsigned char			rtpi[2];
+} __attribute__((packed));
+
+#define AAS_OPTIMIZED			0x0
+#define AAS_NON_OPTIMIZED		0x1
+#define AAS_STANDBY			0x2
+#define AAS_UNAVAILABLE			0x3
+#define AAS_TRANSITIONING		0xf
+
+#define TPG_STATUS_NONE			0x0
+#define TPG_STATUS_SET			0x1
+#define TPG_STATUS_IMPLICIT_CHANGE	0x2
+
+struct rtpg_tpg_dscr {
+	unsigned char	b0;		/* x....... = pref(ered) port        */
+					/* .xxx.... = reserved               */
+					/* ....xxxx = asymetric access state */
+	unsigned char	b1;		/* xxxx.... = reserved               */
+					/* ....x... = unavailable support    */
+					/* .....x.. = standby support        */
+					/* ......x. = non-optimized support  */
+					/* .......x = optimized support      */
+	unsigned char			tpg[2];
+	unsigned char			reserved3;
+	unsigned char			status;
+	unsigned char			vendor_unique;
+	unsigned char			port_count;
+	struct rtpg_tp_dscr		data[0];
+} __attribute__((packed));
+
+static inline int
+rtpg_tpg_dscr_get_aas(struct rtpg_tpg_dscr *d)
+{
+	return (d->b0 & 0x0f);
+}
+
+struct rtpg_data {
+	unsigned char			length[4];		/* size-4 */
+	struct rtpg_tpg_dscr		data[0];
+} __attribute__((packed));
+
+#define RTPG_FOR_EACH_PORT_GROUP(p, g) \
+		for( \
+			g = &(p->data[0]); \
+			(((char *) g) - ((char *) p)) < get_uint32(p->length); \
+			g = (struct rtpg_tpg_dscr *) ( \
+				((char *) g) + \
+				sizeof(struct rtpg_tpg_dscr) + \
+				g->port_count * sizeof(struct rtpg_tp_dscr) \
+			) \
+		)
+
+#endif /* __SPC3_H__ */
+
diff --git a/libmultipath/prioritizers/const.c b/libmultipath/prioritizers/const.c
new file mode 100644
index 0000000..529cf82
--- /dev/null
+++ b/libmultipath/prioritizers/const.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+#include <prio.h>
+
+int getprio (struct path * pp)
+{
+	return 1;
+}
diff --git a/libmultipath/prioritizers/const.h b/libmultipath/prioritizers/const.h
new file mode 100644
index 0000000..220db54
--- /dev/null
+++ b/libmultipath/prioritizers/const.h
@@ -0,0 +1,7 @@
+#ifndef _CONST_H
+#define _CONST_H
+
+#define PRIO_CONST "const"
+int prio_const(struct path * pp);
+
+#endif
diff --git a/libmultipath/prioritizers/emc.c b/libmultipath/prioritizers/emc.c
new file mode 100644
index 0000000..61d7a77
--- /dev/null
+++ b/libmultipath/prioritizers/emc.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include <sg_include.h>
+#include <debug.h>
+#include <prio.h>
+
+#define INQUIRY_CMD     0x12
+#define INQUIRY_CMDLEN  6
+
+#define pp_emc_log(prio, msg) condlog(prio, "%s: emc prio: " msg, dev)
+
+int emc_clariion_prio(const char *dev, int fd)
+{
+	unsigned char sense_buffer[256];
+	unsigned char sb[128];
+	unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
+						sizeof(sb), 0};
+	struct sg_io_hdr io_hdr;
+	int ret = 0;
+
+	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = sizeof (inqCmdBlk);
+	io_hdr.mx_sb_len = sizeof (sb);
+	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+	io_hdr.dxfer_len = sizeof (sense_buffer);
+	io_hdr.dxferp = sense_buffer;
+	io_hdr.cmdp = inqCmdBlk;
+	io_hdr.sbp = sb;
+	io_hdr.timeout = 60000;
+	io_hdr.pack_id = 0;
+	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+		pp_emc_log(0, "sending query command failed");
+		goto out;
+	}
+	if (io_hdr.info & SG_INFO_OK_MASK) {
+		pp_emc_log(0, "query command indicates error");
+		goto out;
+	}
+
+	if (/* Verify the code page - right page & revision */
+	    sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) {
+		pp_emc_log(0, "path unit report page in unknown format");
+		goto out;
+	}
+	
+	if ( /* Effective initiator type */
+	    	sense_buffer[27] != 0x03
+		/*
+		 * Failover mode should be set to 1 (PNR failover mode)
+		 * or 4 (ALUA failover mode).
+		 */
+		|| (((sense_buffer[28] & 0x07) != 0x04) &&
+		    ((sense_buffer[28] & 0x07) != 0x06))
+		/* Arraycommpath should be set to 1 */
+		|| (sense_buffer[30] & 0x04) != 0x04) {
+		pp_emc_log(0, "path not correctly configured for failover");
+	}
+
+	if ( /* LUN operations should indicate normal operations */
+		sense_buffer[48] != 0x00) {
+		pp_emc_log(0, "path not available for normal operations");
+	}
+
+	/* Is the default owner equal to this path? */
+	/* Note this will switch to the default priority group, even if
+	 * it is not the currently active one. */
+	ret = (sense_buffer[5] == sense_buffer[8]) ? 1 : 0;
+	
+out:
+	return(ret);
+}
+
+int getprio (struct path * pp)
+{
+	return emc_clariion_prio(pp->dev, pp->fd);
+}
diff --git a/libmultipath/prioritizers/emc.h b/libmultipath/prioritizers/emc.h
new file mode 100644
index 0000000..0ab0bc5
--- /dev/null
+++ b/libmultipath/prioritizers/emc.h
@@ -0,0 +1,7 @@
+#ifndef _EMC_H
+#define _EMC_H
+
+#define PRIO_EMC "emc"
+int prio_emc(struct path * pp);
+
+#endif
diff --git a/libmultipath/prioritizers/hds.c b/libmultipath/prioritizers/hds.c
new file mode 100644
index 0000000..6ebe4d8
--- /dev/null
+++ b/libmultipath/prioritizers/hds.c
@@ -0,0 +1,170 @@
+/*
+ * (C) Copyright HDS GmbH 2006. All Rights Reserved.
+ *
+ * pp_hds_modular.c
+ * Version 2.00
+ *
+ * Prioritizer for Device Mapper Multipath and HDS Storage
+ *
+ * Hitachis Modular Storage contains two controllers for redundancy. The 
+ * Storage internal LUN (LDEV) will normally allocated via two pathes to the 
+ * server (one path per controller). For performance reasons should the server 
+ * access to a LDEV only via one controller. The other path to the other
+ * controller is stand-by. It is also possible to allocate more as one path 
+ * for a LDEV per controller. Here is active/active access allowed. The other 
+ * pathes via the other controller are stand-by.
+ *
+ * This prioritizer checks with inquiry command the represented LDEV and 
+ * Controller number and gives back a priority followed by this scheme:
+ *
+ * CONTROLLER ODD  and LDEV  ODD: PRIORITY 1
+ * CONTROLLER ODD  and LDEV EVEN: PRIORITY 0
+ * CONTROLLER EVEN and LDEV  ODD: PRIORITY 0
+ * CONTROLLER EVEN and LDEV EVEN: PRIORITY 1
+ *
+ * In the storage you can define for each LDEV a owner controller. If the 
+ * server makes IOs via the other controller the storage will switch the 
+ * ownership automatically. In this case you can see in the storage that the 
+ * current controller is different from the default controller, but this is
+ * absolutely no problem.
+ *
+ * With this prioritizer it is possible to establish a static load balancing. 
+ * Half of the LUNs are accessed via one HBA/storage controller and the other 
+ * half via the other HBA/storage controller.
+ *
+ * In cluster environmemnts (RAC) it also guarantees that all cluster nodes have
+ * access to the LDEVs via the same controller.
+ * 
+ * You can run the prioritizer manually in verbose mode:
+ * # pp_hds_modular -v 8:224
+ * VENDOR:  HITACHI
+ * PRODUCT: DF600F-CM
+ * SERIAL:  0x0105
+ * LDEV:    0x00C6
+ * CTRL:    1
+ * PORT:    B
+ * CTRL ODD, LDEV EVEN, PRIO 0
+ *
+ * To compile this source please execute # cc pp_hds_modular.c -o /sbin/mpath_prio_hds_modular
+ *
+ * Changes 2006-07-16:
+ *         - Changed to forward declaration of functions
+ *         - The switch-statement was changed to a logical expression
+ *         - unlinking of the devpath now also occurs at the end of 
+ *           hds_modular_prio to avoid old /tmp/.pp_balance.%u.%u.devnode
+ *           entries in /tmp-Directory
+ *         - The for-statements for passing variables where changed to
+ *           snprintf-commands in verbose mode
+ * Changes 2006-08-10:
+ *         - Back to the old switch statements because the regular expression does
+ *           not work under RHEL4 U3 i386
+ * Changes 2007-06-27:
+ *	- switched from major:minor argument to device node argument
+ *
+ * This file is released under the GPL.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+
+#include <sg_include.h>
+#include <debug.h>
+#include <prio.h>
+
+#define INQ_REPLY_LEN 255
+#define INQ_CMD_CODE 0x12
+#define INQ_CMD_LEN 6
+
+#define pp_hds_log(prio, fmt, args...) \
+        condlog(prio, "%s: hds prio: " fmt, dev, ##args)
+
+int hds_modular_prio (const char *dev, int fd)
+{
+	int k;
+	char vendor[8];
+	char product[32];
+	char serial[32];
+	char ldev[32];
+	char ctrl[32];
+	char port[32];
+	unsigned char inqCmdBlk[INQ_CMD_LEN] = { INQ_CMD_CODE, 0, 0, 0, INQ_REPLY_LEN, 0 };
+	unsigned char inqBuff[INQ_REPLY_LEN];
+	unsigned char *inqBuffp = inqBuff;
+	unsigned char sense_buffer[32];
+	sg_io_hdr_t io_hdr;
+
+	if ((ioctl (fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
+		pp_hds_log(0, "can't use SG ioctl interface");
+		return -1;
+	}
+
+	memset (&io_hdr, 0, sizeof (sg_io_hdr_t));
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = sizeof (inqCmdBlk);
+	io_hdr.mx_sb_len = sizeof (sense_buffer);
+	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+	io_hdr.dxfer_len = INQ_REPLY_LEN;
+	io_hdr.dxferp = inqBuff;
+	io_hdr.cmdp = inqCmdBlk;
+	io_hdr.sbp = sense_buffer;
+	io_hdr.timeout = 2000;	/* TimeOut = 2 seconds */
+
+	if (ioctl (fd, SG_IO, &io_hdr) < 0) {
+		pp_hds_log(0, "SG_IO error");
+		return -1;
+	}
+	if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
+		pp_hds_log(0, "SCSI error");
+		return -1;
+	}
+
+	snprintf (vendor, 9, "%.8s", inqBuffp + 8);
+	snprintf (product, 17, "%.16s", inqBuffp + 16);
+	snprintf (serial, 5, "%.4s", inqBuffp + 40);
+	snprintf (ldev, 5, "%.4s", inqBuffp + 44);
+	snprintf (ctrl, 2, "%.1s", inqBuffp + 49);
+	snprintf (port, 2, "%.1s", inqBuffp + 50);
+
+	pp_hds_log(4, "VENDOR:  %s", vendor);
+	pp_hds_log(4, "PRODUCT: %s", product);
+	pp_hds_log(4, "SERIAL:  0x%s", serial);
+	pp_hds_log(4, "LDEV:    0x%s", ldev);
+	pp_hds_log(4, "CTRL:    %s", ctrl);
+	pp_hds_log(4, "PORT:    %s", port);
+
+	switch (ctrl[0]) {
+	case '0': case '2': case '4': case '6': case '8':
+		switch (ldev[3]) {
+		case '0': case '2': case '4': case '6': case '8': case 'A': case 'C': case 'E':
+			pp_hds_log(4, "CTRL EVEN, LDEV EVEN, PRIO 1");
+			return 1;
+			break;
+		case '1': case '3': case '5': case '7': case '9': case 'B': case 'D': case 'F':
+			pp_hds_log(4, "CTRL EVEN, LDEV ODD, PRIO 0");
+			return 0;
+			break;
+		}
+	case '1': case '3': case '5': case '7': case '9':
+		switch (ldev[3]) {
+		case '0': case '2': case '4': case '6': case '8': case 'A': case 'C': case 'E':
+			pp_hds_log(4, "CTRL ODD, LDEV EVEN, PRIO 0");
+			return 0;
+			break;
+		case '1': case '3': case '5': case '7': case '9': case 'B': case 'D': case 'F':
+			pp_hds_log(4, "CTRL ODD, LDEV ODD, PRIO 1");
+			return 1;
+			break;
+		}
+	}
+	return -1;
+}
+
+int getprio (struct path * pp)
+{
+	return hds_modular_prio(pp->dev, pp->fd);
+}
diff --git a/libmultipath/prioritizers/hds.h b/libmultipath/prioritizers/hds.h
new file mode 100644
index 0000000..084d77c
--- /dev/null
+++ b/libmultipath/prioritizers/hds.h
@@ -0,0 +1,7 @@
+#ifndef _HDS_H
+#define _HDS_H
+
+#define PRIO_HDS "hds"
+int prio_hds(struct path * pp);
+
+#endif
diff --git a/libmultipath/prioritizers/hp_sw.c b/libmultipath/prioritizers/hp_sw.c
new file mode 100644
index 0000000..ae0975f
--- /dev/null
+++ b/libmultipath/prioritizers/hp_sw.c
@@ -0,0 +1,100 @@
+/*
+ * Path priority checker for HP active/standby controller
+ *
+ * Check the path state and sort them into groups.
+ * There is actually a preferred path in the controller;
+ * we should ask HP on how to retrieve that information.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include <sg_include.h>
+#include <debug.h>
+#include <prio.h>
+
+#define TUR_CMD_LEN		6
+#define SCSI_CHECK_CONDITION	0x2
+#define SCSI_COMMAND_TERMINATED	0x22
+#define SG_ERR_DRIVER_SENSE	0x08
+#define RECOVERED_ERROR		0x01
+#define NOT_READY		0x02
+#define UNIT_ATTENTION		0x06
+
+#define HP_PATH_ACTIVE		0x04
+#define HP_PATH_STANDBY		0x02
+#define HP_PATH_FAILED		0x00
+
+#define pp_hp_sw_log(prio, fmt, args...) \
+        condlog(prio, "%s: hp_sw prio: " fmt, dev, ##args)
+
+int hp_sw_prio(const char *dev, int fd)
+{
+        unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
+	unsigned char sb[128];
+	struct sg_io_hdr io_hdr;
+	int ret = HP_PATH_FAILED;
+
+	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = sizeof (turCmdBlk);
+	io_hdr.mx_sb_len = sizeof (sb);
+	io_hdr.dxfer_direction = SG_DXFER_NONE;
+	io_hdr.cmdp = turCmdBlk;
+	io_hdr.sbp = sb;
+	io_hdr.timeout = 60000;
+	io_hdr.pack_id = 0;
+ retry:
+	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+		pp_hp_sw_log(0, "sending tur command failed");
+		goto out;
+	}
+        io_hdr.status &= 0x7e;
+        if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
+            (0 == io_hdr.driver_status)) {
+		/* Command completed normally, path is active */
+                ret = HP_PATH_ACTIVE;
+	}
+
+        if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
+            (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
+            (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
+                if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
+                        int sense_key, asc, asq;
+                        unsigned char * sense_buffer = io_hdr.sbp;
+                        if (sense_buffer[0] & 0x2) {
+                                sense_key = sense_buffer[1] & 0xf;
+				asc = sense_buffer[2];
+				asq = sense_buffer[3];
+			} else {
+                                sense_key = sense_buffer[2] & 0xf;
+				asc = sense_buffer[12];
+				asq = sense_buffer[13];
+			}
+                        if(RECOVERED_ERROR == sense_key)
+                                ret = HP_PATH_ACTIVE;
+			if(NOT_READY == sense_key) {
+				if (asc == 0x04 && asq == 0x02) {
+					/* This is a standby path */
+					ret = HP_PATH_STANDBY;
+				}
+			}
+			if(UNIT_ATTENTION == sense_key) {
+				if (asc == 0x29) {
+					/* Retry for device reset */
+					goto retry;
+				}
+			}
+                }
+        }
+out:
+	return(ret);
+}
+
+int getprio (struct path * pp)
+{
+	return hp_sw_prio(pp->dev, pp->fd);
+}
diff --git a/libmultipath/prioritizers/hp_sw.h b/libmultipath/prioritizers/hp_sw.h
new file mode 100644
index 0000000..2fea486
--- /dev/null
+++ b/libmultipath/prioritizers/hp_sw.h
@@ -0,0 +1,7 @@
+#ifndef _HP_SW_H
+#define _HP_SW_H
+
+#define PRIO_HP_SW "hp_sw"
+int prio_hp_sw(struct path * pp);
+
+#endif
diff --git a/libmultipath/prioritizers/netapp.c b/libmultipath/prioritizers/netapp.c
new file mode 100644
index 0000000..812ecf6
--- /dev/null
+++ b/libmultipath/prioritizers/netapp.c
@@ -0,0 +1,243 @@
+/* 
+ * Copyright 2005 Network Appliance, Inc., All Rights Reserved
+ * Author:  David Wysochanski available at davidw@netapp.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License v2 for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <sg_include.h>
+#include <debug.h>
+#include <prio.h>
+
+#define INQUIRY_CMD	0x12
+#define INQUIRY_CMDLEN	6
+#define DEFAULT_PRIOVAL	10
+#define RESULTS_MAX	256
+#define SG_TIMEOUT	30000
+
+#define pp_netapp_log(prio, fmt, args...) \
+        condlog(prio, "%s: netapp prio: " fmt, dev, ##args)
+
+static void dump_cdb(unsigned char *cdb, int size)
+{
+	int i;
+	char buf[10*5+1];
+	char * p = &buf[0];
+	
+	condlog(0, "- SCSI CDB: ");
+	for (i=0; i<size; i++) {
+		p += snprintf(p, 10*(size-i), "0x%02x ", cdb[i]);
+	}
+	condlog(0, "%s", buf);
+}
+
+static void process_sg_error(struct sg_io_hdr *io_hdr)
+{
+	int i;
+	char buf[128*5+1];
+	char * p = &buf[0];
+	
+	condlog(0, "- masked_status=0x%02x, host_status=0x%02x, "
+		"driver_status=0x%02x", io_hdr->masked_status,
+		io_hdr->host_status, io_hdr->driver_status);
+	if (io_hdr->sb_len_wr > 0) {
+		condlog(0, "- SCSI sense data: ");
+		for (i=0; i<io_hdr->sb_len_wr; i++) {
+			p += snprintf(p, 128*(io_hdr->sb_len_wr-i), "0x%02x ",
+				      io_hdr->sbp[i]);
+		}
+		condlog(0, "%s", buf);
+	}
+}
+
+/*
+ * Returns:
+ * -1: error, errno set
+ *  0: success
+ */
+static int send_gva(const char *dev, int fd, unsigned char pg,
+		    unsigned char *results, int *results_size)
+{
+	unsigned char sb[128];
+	unsigned char cdb[10] = {0xc0, 0, 0x1, 0xa, 0x98, 0xa,
+				 pg, sizeof(sb), 0, 0};
+	struct sg_io_hdr io_hdr;
+	int ret = -1;
+
+	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = sizeof (cdb);
+	io_hdr.mx_sb_len = sizeof (sb);
+	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+	io_hdr.dxfer_len = *results_size;
+	io_hdr.dxferp = results;
+	io_hdr.cmdp = cdb;
+	io_hdr.sbp = sb;
+	io_hdr.timeout = SG_TIMEOUT;
+	io_hdr.pack_id = 0;
+	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+		pp_netapp_log(0, "SG_IO ioctl failed, errno=%d", errno);
+		dump_cdb(cdb, sizeof(cdb));
+		goto out;
+	}
+	if (io_hdr.info & SG_INFO_OK_MASK) {
+		pp_netapp_log(0, "SCSI error");
+		dump_cdb(cdb, sizeof(cdb));
+		process_sg_error(&io_hdr);
+		goto out;
+	}
+
+	if (results[4] != 0x0a || results[5] != 0x98 ||
+	    results[6] != 0x0a ||results[7] != 0x01) {
+		dump_cdb(cdb, sizeof(cdb));
+		pp_netapp_log(0, "GVA return wrong format ");
+		pp_netapp_log(0, "results[4-7] = 0x%02x 0x%02x 0x%02x 0x%02x",
+			results[4], results[5], results[6], results[7]);
+		goto out;
+	}
+	ret = 0;
+ out:
+	return(ret);
+}
+
+/*
+ * Retuns:
+ * -1: Unable to obtain proxy info
+ *  0: Device _not_ proxy path
+ *  1: Device _is_ proxy path
+ */
+static int get_proxy(const char *dev, int fd)
+{
+	unsigned char results[256];
+	unsigned char sb[128];
+	unsigned char cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xc1, 0,
+						   sizeof(sb), 0};
+	struct sg_io_hdr io_hdr;
+	int ret = -1;
+
+	memset(&results, 0, sizeof (results));
+	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = sizeof (cdb);
+	io_hdr.mx_sb_len = sizeof (sb);
+	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+	io_hdr.dxfer_len = sizeof (results);
+	io_hdr.dxferp = results;
+	io_hdr.cmdp = cdb;
+	io_hdr.sbp = sb;
+	io_hdr.timeout = SG_TIMEOUT;
+	io_hdr.pack_id = 0;
+	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+		pp_netapp_log(0, "ioctl sending inquiry command failed, "
+			"errno=%d", errno);
+		dump_cdb(cdb, sizeof(cdb));
+		goto out;
+	}
+	if (io_hdr.info & SG_INFO_OK_MASK) {
+		pp_netapp_log(0, "SCSI error");
+		dump_cdb(cdb, sizeof(cdb));
+		process_sg_error(&io_hdr);
+		goto out;
+	}
+
+	if (results[1] != 0xc1 || results[8] != 0x0a ||
+	    results[9] != 0x98 || results[10] != 0x0a ||
+	    results[11] != 0x0 || results[12] != 0xc1 ||
+	    results[13] != 0x0) {
+		pp_netapp_log(0,"proxy info page in unknown format - ");
+		pp_netapp_log(0,"results[8-13]=0x%02x 0x%02x 0x%02x 0x%02x "
+			"0x%02x 0x%02x",
+			results[8], results[9], results[10],
+			results[11], results[12], results[13]);
+		dump_cdb(cdb, sizeof(cdb));
+		goto out;
+	}
+	ret = (results[19] & 0x02) >> 1;
+
+ out:
+	return(ret);
+}
+
+/*
+ * Returns priority of device based on device info.
+ *
+ * 4: FCP non-proxy, FCP proxy unknown, or unable to determine protocol
+ * 3: iSCSI HBA
+ * 2: iSCSI software
+ * 1: FCP proxy
+ */
+static int netapp_prio(const char *dev, int fd)
+{
+	unsigned char results[RESULTS_MAX];
+	int results_size=RESULTS_MAX;
+	int rc;
+	int is_proxy;
+	int is_iscsi_software;
+	int is_iscsi_hardware;
+	int tot_len;
+
+	is_iscsi_software = is_iscsi_hardware = is_proxy = 0;
+
+	memset(&results, 0, sizeof (results));
+	rc = send_gva(dev, fd, 0x41, results, &results_size);
+	if (rc == 0) {
+		tot_len = results[0] << 24 | results[1] << 16 |
+			  results[2] << 8 | results[3];
+		if (tot_len <= 8) {
+			goto try_fcp_proxy;
+		}
+		if (results[8] != 0x41) {
+			pp_netapp_log(0, "GVA page 0x41 error - "
+				"results[8] = 0x%x", results[8]);
+			goto try_fcp_proxy;
+		}
+		if ((strncmp((char *)&results[12], "ism_sw", 6) == 0) ||
+		    (strncmp((char *)&results[12], "iswt", 4) == 0)) {
+			is_iscsi_software = 1;
+			goto prio_select;
+		}
+		else if (strncmp((char *)&results[12], "ism_sn", 6) == 0) {
+			is_iscsi_hardware = 1;
+			goto prio_select;
+		}
+	}
+	
+ try_fcp_proxy:	
+	rc = get_proxy(dev, fd);
+	if (rc >= 0) {
+		is_proxy = rc;
+	}
+
+ prio_select:
+	if (is_iscsi_hardware) {
+		return 3;
+	} else if (is_iscsi_software) {
+		return 2;
+	} else {
+		if (is_proxy) {
+			return 1;
+		} else {
+			/* Either non-proxy, or couldn't get proxy info */
+			return 4;
+		}
+	}
+}
+
+int getprio (struct path * pp)
+{
+	return netapp_prio(pp->dev, pp->fd);
+}
diff --git a/libmultipath/prioritizers/netapp.h b/libmultipath/prioritizers/netapp.h
new file mode 100644
index 0000000..ec38821
--- /dev/null
+++ b/libmultipath/prioritizers/netapp.h
@@ -0,0 +1,7 @@
+#ifndef _NETAPP_H
+#define _NETAPP_H
+
+#define PRIO_NETAPP "netapp"
+int prio_netapp(struct path * pp);
+
+#endif
diff --git a/libmultipath/prioritizers/random.c b/libmultipath/prioritizers/random.c
new file mode 100644
index 0000000..e3852a7
--- /dev/null
+++ b/libmultipath/prioritizers/random.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <prio.h>
+
+int getprio (struct path * pp)
+{
+	struct timeval tv;
+	
+	gettimeofday(&tv, NULL);
+	srand((unsigned int)tv.tv_usec);
+	return 1+(int) (10.0*rand()/(RAND_MAX+1.0));
+}
diff --git a/libmultipath/prioritizers/random.h b/libmultipath/prioritizers/random.h
new file mode 100644
index 0000000..b9dae69
--- /dev/null
+++ b/libmultipath/prioritizers/random.h
@@ -0,0 +1,7 @@
+#ifndef _RANDOM_H
+#define _RANDOM_H
+
+#define PRIO_RANDOM "random"
+int prio_random(struct path * pp);
+
+#endif
diff --git a/libmultipath/prioritizers/rdac.c b/libmultipath/prioritizers/rdac.c
new file mode 100644
index 0000000..4dd8f44
--- /dev/null
+++ b/libmultipath/prioritizers/rdac.c
@@ -0,0 +1,90 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include <sg_include.h>
+#include <debug.h>
+#include <prio.h>
+
+#define INQUIRY_CMD     0x12
+#define INQUIRY_CMDLEN  6
+
+#define pp_rdac_log(prio, msg) condlog(prio, "%s: rdac prio: " msg, dev)
+
+int rdac_prio(const char *dev, int fd)
+{
+	unsigned char sense_buffer[256];
+	unsigned char sb[128];
+	unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC9, 0,
+						sizeof(sb), 0};
+	struct sg_io_hdr io_hdr;
+	int ret = 0;
+
+	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+	io_hdr.interface_id = 'S';
+	io_hdr.cmd_len = sizeof (inqCmdBlk);
+	io_hdr.mx_sb_len = sizeof (sb);
+	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+	io_hdr.dxfer_len = sizeof (sense_buffer);
+	io_hdr.dxferp = sense_buffer;
+	io_hdr.cmdp = inqCmdBlk;
+	io_hdr.sbp = sb;
+	io_hdr.timeout = 60000;
+	io_hdr.pack_id = 0;
+	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
+		pp_rdac_log(0, "sending inquiry command failed");
+		goto out;
+	}
+	if (io_hdr.info & SG_INFO_OK_MASK) {
+		pp_rdac_log(0, "inquiry command indicates error");
+		goto out;
+	}
+	
+	if (/* Verify the code page - right page & page identifier */
+	    sense_buffer[1] != 0xc9 || 
+	    sense_buffer[3] != 0x2c ||
+	    sense_buffer[4] != 'v' ||
+	    sense_buffer[5] != 'a' ||
+	    sense_buffer[6] != 'c' ) {
+		pp_rdac_log(0, "volume access control page in unknown format");
+		goto out;
+	}
+	
+	if ( /* Current Volume Path Bit */
+		( sense_buffer[8] & 0x01) == 0x01 ) {
+		/* 
+		 * This volume was owned by the controller receiving
+		 * the inquiry command.
+		 */
+		ret |= 0x01;
+	}
+
+	/* Volume Preferred Path Priority */
+	switch ( sense_buffer[9] & 0x0F ) {
+	case 0x01:
+		/* 
+		 * Access to this volume is most preferred through
+		 * this path and other paths with this value.
+		 */
+		ret |= 0x02;
+		break;
+	case 0x02:
+		/*
+		 * Access to this volume through this path is to be used
+		 * as a secondary path. Typically this path would be used
+		 * for fail-over situations.
+		 */
+		/* Fallthrough */
+	default:
+		/* Reserved values */
+		break;
+	}
+	
+out:
+	return(ret);
+}
+
+int getprio (struct path * pp)
+{
+	return rdac_prio(pp->dev, pp->fd);
+}
diff --git a/libmultipath/prioritizers/rdac.h b/libmultipath/prioritizers/rdac.h
new file mode 100644
index 0000000..a5b7f8e
--- /dev/null
+++ b/libmultipath/prioritizers/rdac.h
@@ -0,0 +1,7 @@
+#ifndef _RDAC_H
+#define _RDAC_H
+
+#define PRIO_RDAC "rdac"
+int prio_rdac(struct path * pp);
+
+#endif
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index 45a3728..43611ff 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -5,8 +5,7 @@
  */
 #include <stdio.h>
 
-#include <checkers.h>
-
+#include "checkers.h"
 #include "memory.h"
 #include "vector.h"
 #include "structs.h"
@@ -16,6 +15,7 @@
 #include "alias.h"
 #include "defaults.h"
 #include "devmapper.h"
+#include "prio.h"
 
 pgpolicyfn *pgpolicies[] = {
 	NULL,
@@ -168,8 +168,7 @@ select_alias (struct multipath * mp)
 		if (mp->alias == NULL){
 			char *alias;
 			if ((alias = MALLOC(WWID_SIZE)) != NULL){
-				if (dm_get_name(mp->wwid, DEFAULT_TARGET,
-						alias) == 1)
+				if (dm_get_name(mp->wwid, alias) == 1)
 					mp->alias = alias;
 				else
 					FREE(alias);
@@ -217,19 +216,19 @@ select_checker(struct path *pp)
 {
 	struct checker * c = &pp->checker;
 
-	if (pp->hwe && pp->hwe->checker) {
-		checker_get(c, pp->hwe->checker);
+	if (pp->hwe && pp->hwe->checker_name) {
+		checker_get(c, pp->hwe->checker_name);
 		condlog(3, "%s: path checker = %s (controller setting)",
 			pp->dev, checker_name(c));
 		return 0;
 	}
-	if (conf->checker) {
-		checker_get(c, conf->checker);
+	if (conf->checker_name) {
+		checker_get(c, conf->checker_name);
 		condlog(3, "%s: path checker = %s (config file default)",
 			pp->dev, checker_name(c));
 		return 0;
 	}
-	checker_get(c, checker_default());
+	checker_get(c, DEFAULT_CHECKER);
 	condlog(3, "%s: path checker = %s (internal default)",
 		pp->dev, checker_name(c));
 	return 0;
@@ -257,22 +256,23 @@ select_getuid (struct path * pp)
 }
 
 extern int
-select_getprio (struct path * pp)
+select_prio (struct path * pp)
 {
-	if (pp->hwe && pp->hwe->getprio) {
-		pp->getprio = pp->hwe->getprio;
-		condlog(3, "%s: getprio = %s (controller setting)",
-			pp->dev, pp->getprio);
+	if (pp->hwe && pp->hwe->prio_name) {
+		pp->prio = prio_lookup(pp->hwe->prio_name);
+		condlog(3, "%s: prio = %s (controller setting)",
+			pp->dev, pp->hwe->prio_name);
 		return 0;
 	}
-	if (conf->getprio) {
-		pp->getprio = conf->getprio;
-		condlog(3, "%s: getprio = %s (config file default)",
-			pp->dev, pp->getprio);
+	if (conf->prio_name) {
+		pp->prio = prio_lookup(conf->prio_name);
+		condlog(3, "%s: prio = %s (config file default)",
+			pp->dev, conf->prio_name);
 		return 0;
 	}
-	pp->getprio = DEFAULT_GETPRIO;
-	condlog(3, "%s: getprio = NULL (internal default)", pp->dev);
+	pp->prio = prio_lookup(DEFAULT_PRIO);
+	condlog(3, "%s: prio = %s (internal default)",
+		pp->dev, DEFAULT_PRIO);
 	return 0;
 }
 
diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h
index afd1f88..62802f8 100644
--- a/libmultipath/propsel.h
+++ b/libmultipath/propsel.h
@@ -7,7 +7,7 @@ int select_features (struct multipath * mp);
 int select_hwhandler (struct multipath * mp);
 int select_checker(struct path *pp);
 int select_getuid (struct path * pp);
-int select_getprio (struct path * pp);
+int select_prio (struct path * pp);
 int select_no_path_retry(struct multipath *mp);
 int select_pg_timeout(struct multipath *mp);
 int select_minio(struct multipath *mp);
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index d36eaef..852e6b3 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -6,8 +6,7 @@
 #include <unistd.h>
 #include <libdevmapper.h>
 
-#include <checkers.h>
-
+#include "checkers.h"
 #include "memory.h"
 #include "vector.h"
 #include "util.h"
@@ -17,6 +16,7 @@
 #include "structs_vec.h"
 #include "blacklist.h"
 #include "waiter.h"
+#include "prio.h"
 
 struct path *
 alloc_path (void)
@@ -170,14 +170,12 @@ free_multipath (struct multipath * mpp, int free_paths)
 
 	if (mpp->dmi)
 		FREE(mpp->dmi);
-	
-#if DAEMON
+
 	/*
 	 * better own vecs->lock here
 	 */
 	if (mpp->waiter)
 		((struct event_thread *)mpp->waiter)->mpp = NULL;
-#endif
 
 	free_pathvec(mpp->paths, free_paths);
 	free_pgvec(mpp->pg, free_paths);
@@ -364,15 +362,27 @@ pathcount (struct multipath * mpp, int state)
 	int count = 0;
 	int i;
 
-	vector_foreach_slot (mpp->pg, pgp, i)
-		count += pathcountgr(pgp, state);
-
+	if (mpp->pg) {
+		vector_foreach_slot (mpp->pg, pgp, i)
+			count += pathcountgr(pgp, state);
+	}
 	return count;
 }
 
 struct path *
 first_path (struct multipath * mpp)
 {
-	struct pathgroup * pgp = VECTOR_SLOT(mpp->pg, 0);
-	return VECTOR_SLOT(pgp->paths, 0);
+	struct pathgroup * pgp;
+	if (!mpp->pg)
+		return NULL;
+	pgp = VECTOR_SLOT(mpp->pg, 0);
+
+	return pgp?VECTOR_SLOT(pgp->paths, 0):NULL;
+}
+
+extern void
+setup_feature(struct multipath * mpp, char *feature)
+{
+	if (!strncmp(feature, "queue_if_no_path", 16))
+		mpp->no_path_retry = NO_PATH_RETRY_QUEUE;
 }
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index f821f87..85d5109 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -21,8 +21,7 @@
 #define NO_PATH_RETRY_FAIL	-1
 #define NO_PATH_RETRY_QUEUE	-2
 
-#define PRIO_UNDEF		-1
-#define PRIO_DEFAULT		1
+#define MAX_FDS_UNLIMITED	-1
 
 enum free_path_switch {
 	KEEP_PATHS,
@@ -121,8 +120,7 @@ struct path {
 	int priority;
 	int pgindex;
 	char * getuid;
-	char * getprio;
-	int getprio_selected;
+	struct prio * prio;
 	struct checker checker;
 	struct multipath * mpp;
 	int fd;
@@ -213,6 +211,7 @@ struct path * first_path (struct multipath * mpp);
 
 int pathcountgr (struct pathgroup *, int);
 int pathcount (struct multipath *, int);
+void setup_feature(struct multipath *, char *);
 
 extern char sysfs_path[PATH_SIZE];
 
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index 1cc6028..34b7669 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -2,20 +2,20 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <checkers.h>
-
+#include "checkers.h"
 #include "vector.h"
 #include "defaults.h"
 #include "debug.h"
 #include "structs.h"
 #include "structs_vec.h"
+#include "waiter.h"
 #include "devmapper.h"
 #include "dmparser.h"
 #include "config.h"
 #include "propsel.h"
 #include "sysfs.h"
 #include "discovery.h"
-#include "waiter.h"
+#include "prio.h"
 
 /*
  * creates or updates mpp->paths reading mpp->pg
@@ -62,7 +62,7 @@ adopt_paths (vector pathvec, struct multipath * mpp)
 			condlog(3, "%s: ownership set to %s",
 				pp->dev, mpp->alias);
 			pp->mpp = mpp;
-			
+
 			if (!mpp->paths && !(mpp->paths = vector_alloc()))
 				return 1;
 
@@ -81,8 +81,7 @@ orphan_path (struct path * pp)
 	pp->mpp = NULL;
 	pp->dmstate = PSTATE_UNDEF;
 	pp->getuid = NULL;
-	pp->getprio = NULL;
-	pp->getprio_selected = 0;
+	pp->prio = NULL;
 	checker_put(&pp->checker);
 	if (pp->fd >= 0)
 		close(pp->fd);
@@ -112,9 +111,13 @@ set_multipath_wwid (struct multipath * mpp)
 	dm_get_uuid(mpp->alias, mpp->wwid);
 }
 
-extern void
-remove_map (struct multipath * mpp, struct vectors * vecs,
-	    stop_waiter_thread_func *stop_waiter, int purge_vec)
+#define KEEP_WAITER 0
+#define STOP_WAITER 1
+#define PURGE_VEC 1
+
+static void
+_remove_map (struct multipath * mpp, struct vectors * vecs,
+	    int stop_waiter, int purge_vec)
 {
 	int i;
 
@@ -124,7 +127,7 @@ remove_map (struct multipath * mpp, struct vectors * vecs,
 	 * stop the DM event waiter thread
 	 */
 	if (stop_waiter)
-		stop_waiter(mpp, vecs);
+		stop_waiter_thread(mpp, vecs);
 
 	/*
 	 * clear references to this map
@@ -142,14 +145,26 @@ remove_map (struct multipath * mpp, struct vectors * vecs,
 }
 
 extern void
-remove_maps (struct vectors * vecs,
-	     stop_waiter_thread_func *stop_waiter)
+remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec)
+{
+	_remove_map(mpp, vecs, KEEP_WAITER, purge_vec);
+}
+
+extern void
+remove_map_and_stop_waiter (struct multipath * mpp, struct vectors * vecs,
+			    int purge_vec)
+{
+	_remove_map(mpp, vecs, STOP_WAITER, purge_vec);
+}
+
+static void
+_remove_maps (struct vectors * vecs, int stop_waiter)
 {
 	int i;
 	struct multipath * mpp;
 
 	vector_foreach_slot (vecs->mpvec, mpp, i) {
-		remove_map(mpp, vecs, stop_waiter, 1);
+		_remove_map(mpp, vecs, stop_waiter, 1);
 		i--;
 	}
 
@@ -157,16 +172,31 @@ remove_maps (struct vectors * vecs,
 	vecs->mpvec = NULL;
 }
 
+extern void
+remove_maps (struct vectors * vecs)
+{
+	_remove_maps(vecs, KEEP_WAITER);
+}
+
+extern void
+remove_maps_and_stop_waiters (struct vectors * vecs)
+{
+	_remove_maps(vecs, STOP_WAITER);
+}
+
 static struct hwentry *
 extract_hwe_from_path(struct multipath * mpp)
 {
-	struct path * pp;
-	struct pathgroup * pgp;
+	struct path * pp = NULL;
+	struct pathgroup * pgp = NULL;
 
-	pgp = VECTOR_SLOT(mpp->pg, 0);
-	pp = VECTOR_SLOT(pgp->paths, 0);
+	if (mpp && mpp->pg)
+		pgp = VECTOR_SLOT(mpp->pg, 0);
 
-	return pp->hwe;
+	if (pgp && pgp->paths)
+		pp = VECTOR_SLOT(pgp->paths, 0);
+
+	return pp?pp->hwe:NULL;
 }
 
 static int
@@ -220,7 +250,8 @@ set_no_path_retry(struct multipath *mpp)
 {
 	mpp->retry_tick = 0;
 	mpp->nr_active = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
-	select_no_path_retry(mpp);
+	if (mpp->nr_active > 0)
+		select_no_path_retry(mpp);
 
 	switch (mpp->no_path_retry) {
 	case NO_PATH_RETRY_UNDEF:
@@ -267,18 +298,17 @@ retry:
 		char new_alias[WWID_SIZE];
 
 		/*
-	 	 * detect an external rename of the multipath device
+		 * detect an external rename of the multipath device
 		 */
-		if (dm_get_name(mpp->wwid, DEFAULT_TARGET, new_alias)) {
+		if (dm_get_name(mpp->wwid, new_alias)) {
 			condlog(3, "%s multipath mapped device name has "
 				"changed from %s to %s", mpp->wwid,
 				mpp->alias, new_alias);
 			strcpy(mpp->alias, new_alias);
-#if DAEMON
-			if (mpp->waiter) 
+
+			if (mpp->waiter)
 				strncpy(((struct event_thread *)mpp->waiter)->mapname,
 					new_alias, WWID_SIZE);
-#endif
 			goto retry;
 		}
 		condlog(0, "%s: failed to setup multipath", mpp->alias);
@@ -294,14 +324,13 @@ retry:
 
 	return 0;
 out:
-	remove_map(mpp, vecs, NULL, 1);
+	remove_map(mpp, vecs, PURGE_VEC);
 	return 1;
 }
 
 extern struct multipath *
 add_map_without_path (struct vectors * vecs,
-		      int minor, char * alias,
-		      start_waiter_thread_func *start_waiter)
+		      int minor, char * alias)
 {
 	struct multipath * mpp = alloc_multipath();
 
@@ -315,18 +344,18 @@ add_map_without_path (struct vectors * vecs,
 
 	if (adopt_paths(vecs->pathvec, mpp))
 		goto out;
-	
+
 	if (!vector_alloc_slot(vecs->mpvec))
 		goto out;
 
 	vector_set_slot(vecs->mpvec, mpp);
 
-	if (start_waiter(mpp, vecs))
+	if (start_waiter_thread(mpp, vecs))
 		goto out;
 
 	return mpp;
 out:
-	remove_map(mpp, vecs, NULL, 1);
+	remove_map(mpp, vecs, PURGE_VEC);
 	return NULL;
 }
 
@@ -359,7 +388,7 @@ add_map_with_path (struct vectors * vecs,
 	return mpp;
 
 out:
-	remove_map(mpp, vecs, NULL, add_vec);
+	remove_map(mpp, vecs, PURGE_VEC);
 	return NULL;
 }
 
diff --git a/libmultipath/structs_vec.h b/libmultipath/structs_vec.h
index 81d9eaa..19a2387 100644
--- a/libmultipath/structs_vec.h
+++ b/libmultipath/structs_vec.h
@@ -2,16 +2,11 @@
 #define _STRUCTS_VEC_H
 
 struct vectors {
-#if DAEMON
 	pthread_mutex_t *lock;
-#endif
 	vector pathvec;
 	vector mpvec;
 };
 
-typedef void (stop_waiter_thread_func) (struct multipath *, struct vectors *);
-typedef int (start_waiter_thread_func) (struct multipath *, struct vectors *);
-
 void set_no_path_retry(struct multipath *mpp);
 
 int adopt_paths (vector pathvec, struct multipath * mpp);
@@ -23,14 +18,13 @@ int update_mpp_paths(struct multipath * mpp, vector pathvec);
 int setup_multipath (struct vectors * vecs, struct multipath * mpp);
 int update_multipath_strings (struct multipath *mpp, vector pathvec);
 	
-void remove_map (struct multipath * mpp, struct vectors * vecs,
-		 stop_waiter_thread_func *stop_waiter, int purge_vec);
-void remove_maps (struct vectors * vecs,
-		  stop_waiter_thread_func *stop_waiter);
+void remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec);
+void remove_map_and_stop_waiter (struct multipath * mpp, struct vectors * vecs, int purge_vec);
+void remove_maps (struct vectors * vecs);
+void remove_maps_and_stop_waiters (struct vectors * vecs);
 
 struct multipath * add_map_without_path (struct vectors * vecs,
-				int minor, char * alias,
-				start_waiter_thread_func *start_waiter);
+				int minor, char * alias);
 struct multipath * add_map_with_path (struct vectors * vecs,
 				struct path * pp, int add_vec);
 int update_multipath (struct vectors *vecs, char *mapname);
diff --git a/libmultipath/switchgroup.c b/libmultipath/switchgroup.c
index 757543f..58b08f6 100644
--- a/libmultipath/switchgroup.c
+++ b/libmultipath/switchgroup.c
@@ -2,21 +2,36 @@
  * Copyright (c) 2005 Christophe Varoqui
  * Copyright (c) 2005 Edward Goggin, EMC
  */
-#include <checkers.h>
-
+#include "checkers.h"
 #include "vector.h"
 #include "structs.h"
 #include "switchgroup.h"
 
+extern void
+path_group_prio_update (struct pathgroup * pgp)
+{
+	int i;
+	int priority = 0;
+	struct path * pp;
+
+	if (!pgp->paths) {
+		pgp->priority = 0;
+		return;
+	}
+	vector_foreach_slot (pgp->paths, pp, i) {
+		if (pp->state != PATH_DOWN)
+			priority += pp->priority;
+	}
+	pgp->priority = priority;
+}
+
 extern int
 select_path_group (struct multipath * mpp)
 {
-	int i, j;
+	int i;
 	int highest = 0;
 	int bestpg = 1;
 	struct pathgroup * pgp;
-	struct path * pp;
-	int priority;
 
 	if (!mpp->pg)
 		return 1;
@@ -25,14 +40,7 @@ select_path_group (struct multipath * mpp)
 		if (!pgp->paths)
 			continue;
 
-		priority = 0;
-
-		vector_foreach_slot (pgp->paths, pp, j) {
-			if (pp->state != PATH_DOWN)
-				priority += pp->priority;
-		}
-		pgp->priority = priority;
-
+		path_group_prio_update(pgp);
 		if (pgp->priority > highest) {
 			highest = pgp->priority;
 			bestpg = i + 1;
diff --git a/libmultipath/switchgroup.h b/libmultipath/switchgroup.h
index edf6f24..9365e2e 100644
--- a/libmultipath/switchgroup.h
+++ b/libmultipath/switchgroup.h
@@ -1 +1,2 @@
+void path_group_prio_update (struct pathgroup * pgp);
 int select_path_group (struct multipath * mpp);
diff --git a/libmultipath/sysfs.c b/libmultipath/sysfs.c
index b9621ac..9f11b95 100644
--- a/libmultipath/sysfs.c
+++ b/libmultipath/sysfs.c
@@ -4,12 +4,12 @@
  *	This program is free software; you can redistribute it and/or modify it
  *	under the terms of the GNU General Public License as published by the
  *	Free Software Foundation version 2 of the License.
- * 
+ *
  *	This program is distributed in the hope that it will be useful, but
  *	WITHOUT ANY WARRANTY; without even the implied warranty of
  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  *	General Public License for more details.
- * 
+ *
  *	You should have received a copy of the GNU General Public License along
  *	with this program; if not, write to the Free Software Foundation, Inc.,
  *	51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
@@ -58,7 +58,7 @@ int sysfs_init(char *path, size_t len)
 		strlcpy(sysfs_path, path, len);
 		remove_trailing_chars(sysfs_path, '/');
 	} else
-		strlcpy(sysfs_path, "/sys", len);
+		strlcpy(sysfs_path, "/sys", sizeof(sysfs_path));
 	dbg("sysfs_path='%s'", sysfs_path);
 
 	INIT_LIST_HEAD(&attr_list);
@@ -80,6 +80,7 @@ void sysfs_cleanup(void)
 	}
 
 	list_for_each_entry_safe(sysdev_loop, sysdev_temp, &sysfs_dev_list, node) {
+		list_del(&sysdev_loop->node);
 		free(sysdev_loop);
 	}
 }
@@ -162,9 +163,23 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
 	int len;
 	char *pos;
 
+	/* we handle only these devpathes */
+	if (devpath != NULL &&
+	    strncmp(devpath, "/devices/", 9) != 0 &&
+	    strncmp(devpath, "/subsystem/", 11) != 0 &&
+	    strncmp(devpath, "/module/", 8) != 0 &&
+	    strncmp(devpath, "/bus/", 5) != 0 &&
+	    strncmp(devpath, "/class/", 7) != 0 &&
+	    strncmp(devpath, "/block/", 7) != 0) {
+		dbg("invalid devpath '%s'", devpath);
+		return NULL;
+	}
+
 	dbg("open '%s'", devpath);
 	strlcpy(devpath_real, devpath, sizeof(devpath_real));
 	remove_trailing_chars(devpath_real, '/');
+	if (devpath[0] == '\0' )
+		return NULL;
 
 	/* if we got a link, resolve it to the real device */
 	strlcpy(path, sysfs_path, sizeof(path));
@@ -174,24 +189,26 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
 		dbg("stat '%s' failed: %s", path, strerror(errno));
 		list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) {
 			if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) {
-				dbg("found vanished dev in cache '%s'", sysdev_loop->dev.devpath);
+				dbg("found vanished dev in cache '%s'",
+				    sysdev_loop->dev.devpath);
 				return &sysdev_loop->dev;
 			}
 		}
 		return NULL;
 	}
+
 	if (S_ISLNK(statbuf.st_mode)) {
 		if (sysfs_resolve_link(devpath_real, sizeof(devpath_real)) != 0)
 			return NULL;
-
 	}
 
 	list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) {
 		if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) {
 			dbg("found dev in cache '%s'", sysdev_loop->dev.devpath);
-				dev = &sysdev_loop->dev;
+			dev = &sysdev_loop->dev;
 		}
 	}
+
 	if(!dev) {
 		/* it is a new device */
 		dbg("new device '%s'", devpath_real);
@@ -217,33 +234,25 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
 		pos = strrchr(link_target, '/');
 		if (pos != NULL)
 			strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem));
-	} else if (strncmp(dev->devpath, "/class/", 7) == 0) {
-		/* get subsystem from class dir */
-		strlcpy(dev->subsystem, &dev->devpath[7], sizeof(dev->subsystem));
-		pos = strchr(dev->subsystem, '/');
-		if (pos != NULL)
-			pos[0] = '\0';
-		else
-			dev->subsystem[0] = '\0';
-	} else if (strncmp(dev->devpath, "/block/", 7) == 0) {
-		strlcpy(dev->subsystem, "block", sizeof(dev->subsystem));
-	} else if (strncmp(dev->devpath, "/devices/", 9) == 0) {
-		/* get subsystem from "bus" link */
-		strlcpy(link_path, sysfs_path, sizeof(link_path));
-		strlcat(link_path, dev->devpath, sizeof(link_path));
-		strlcat(link_path, "/bus", sizeof(link_path));
-		len = readlink(link_path, link_target, sizeof(link_target));
-		if (len > 0) {
-			link_target[len] = '\0';
-			dbg("bus link '%s' points to '%s'", link_path, link_target);
-			pos = strrchr(link_target, '/');
-			if (pos != NULL)
-				strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem));
-		}
 	} else if (strstr(dev->devpath, "/drivers/") != NULL) {
 		strlcpy(dev->subsystem, "drivers", sizeof(dev->subsystem));
 	} else if (strncmp(dev->devpath, "/module/", 8) == 0) {
 		strlcpy(dev->subsystem, "module", sizeof(dev->subsystem));
+	} else if (strncmp(dev->devpath, "/subsystem/", 11) == 0) {
+		pos = strrchr(dev->devpath, '/');
+		if (pos == &dev->devpath[10])
+			strlcpy(dev->subsystem, "subsystem",
+				sizeof(dev->subsystem));
+	} else if (strncmp(dev->devpath, "/class/", 7) == 0) {
+		pos = strrchr(dev->devpath, '/');
+		if (pos == &dev->devpath[6])
+			strlcpy(dev->subsystem, "subsystem",
+				sizeof(dev->subsystem));
+	} else if (strncmp(dev->devpath, "/bus/", 5) == 0) {
+		pos = strrchr(dev->devpath, '/');
+		if (pos == &dev->devpath[4])
+			strlcpy(dev->subsystem, "subsystem",
+				sizeof(dev->subsystem));
 	}
 
 	/* get driver name */
@@ -258,6 +267,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
 		if (pos != NULL)
 			strlcpy(dev->driver, &pos[1], sizeof(dev->driver));
 	}
+
 	return dev;
 }
 
@@ -272,13 +282,6 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
 	if (dev->parent != NULL)
 		return dev->parent;
 
-	/* requesting a parent is only valid for devices */
-	if ((strncmp(dev->devpath, "/devices/", 9) != 0) &&
-	    (strncmp(dev->devpath, "/subsystem/", 11) != 0) &&
-	    (strncmp(dev->devpath, "/class/", 7) != 0) &&
-	    (strncmp(dev->devpath, "/block/", 7) != 0))
-		return NULL;
-
 	strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
 	dbg("'%s'", parent_devpath);
 
@@ -288,20 +291,6 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
 		return NULL;
 	pos[0] = '\0';
 
-	/* are we at the top level of /devices */
-	if (strcmp(parent_devpath, "/devices") == 0) {
-		dbg("/devices top level");
-		return NULL;
-	}
-
-	/* at the subsystems top level we want to follow the old-style "device" link */
-	if (strncmp(parent_devpath, "/subsystem", 10) == 0) {
-		pos = strrchr(parent_devpath, '/');
-		if (pos == &parent_devpath[10] || pos == parent_devpath || strcmp(pos, "/devices") == 0) {
-			dbg("/subsystem top level, look for device link");
-			goto device_link;
-		}
-	}
 	if (strncmp(parent_devpath, "/class", 6) == 0) {
 		pos = strrchr(parent_devpath, '/');
 		if (pos == &parent_devpath[6] || pos == parent_devpath) {
@@ -314,6 +303,11 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
 		goto device_link;
 	}
 
+	/* are we at the top level? */
+	pos = strrchr(parent_devpath, '/');
+	if (pos == NULL || pos == parent_devpath)
+		return NULL;
+
 	/* get parent and remember it */
 	dev->parent = sysfs_device_get(parent_devpath);
 	return dev->parent;
@@ -375,6 +369,8 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
 
 	dbg("open '%s'/'%s'", devpath, attr_name);
 	sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
+	if(sysfs_len >= sizeof(path_full))
+		sysfs_len = sizeof(path_full) - 1;
 	path = &path_full[sysfs_len];
 	strlcat(path_full, devpath, sizeof(path_full));
 	strlcat(path_full, "/", sizeof(path_full));
@@ -419,8 +415,10 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
 			link_target[len] = '\0';
 			pos = strrchr(link_target, '/');
 			if (pos != NULL) {
-				dbg("cache '%s' with link value '%s'", path_full, value);
-				strlcpy(attr->value_local, &pos[1], sizeof(attr->value_local));
+				dbg("cache '%s' with link value '%s'",
+				    path_full, value);
+				strlcpy(attr->value_local, &pos[1],
+					sizeof(attr->value_local));
 				attr->value = attr->value_local;
 			}
 		}
@@ -438,7 +436,8 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
 	/* read attribute value */
 	fd = open(path_full, O_RDONLY);
 	if (fd < 0) {
-		dbg("attribute '%s' does not exist", path_full);
+		dbg("attribute '%s' can not be opened: %s",
+		    path_full, strerror(errno));
 		goto out;
 	}
 	size = read(fd, value, sizeof(value));
@@ -458,3 +457,95 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
 out:
 	return attr->value;
 }
+
+int sysfs_lookup_devpath_by_subsys_id(char *devpath_full, size_t len,
+				      const char *subsystem, const char *id)
+{
+	size_t sysfs_len;
+	char path_full[PATH_SIZE];
+	char *path;
+	struct stat statbuf;
+
+	sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
+	path = &path_full[sysfs_len];
+
+	if (strcmp(subsystem, "subsystem") == 0) {
+		strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len);
+		strlcat(path, id, sizeof(path_full) - sysfs_len);
+		if (stat(path_full, &statbuf) == 0)
+			goto found;
+
+		strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len);
+		strlcat(path, id, sizeof(path_full) - sysfs_len);
+		if (stat(path_full, &statbuf) == 0)
+			goto found;
+		goto out;
+
+		strlcpy(path, "/class/", sizeof(path_full) - sysfs_len);
+		strlcat(path, id, sizeof(path_full) - sysfs_len);
+		if (stat(path_full, &statbuf) == 0)
+			goto found;
+	}
+
+	if (strcmp(subsystem, "module") == 0) {
+		strlcpy(path, "/module/", sizeof(path_full) - sysfs_len);
+		strlcat(path, id, sizeof(path_full) - sysfs_len);
+		if (stat(path_full, &statbuf) == 0)
+			goto found;
+		goto out;
+	}
+
+	if (strcmp(subsystem, "drivers") == 0) {
+		char subsys[NAME_SIZE];
+		char *driver;
+
+		strlcpy(subsys, id, sizeof(subsys));
+		driver = strchr(subsys, ':');
+		if (driver != NULL) {
+			driver[0] = '\0';
+			driver = &driver[1];
+			strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len);
+			strlcat(path, subsys, sizeof(path_full) - sysfs_len);
+			strlcat(path, "/drivers/", sizeof(path_full) - sysfs_len);
+			strlcat(path, driver, sizeof(path_full) - sysfs_len);
+			if (stat(path_full, &statbuf) == 0)
+				goto found;
+
+			strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len);
+			strlcat(path, subsys, sizeof(path_full) - sysfs_len);
+			strlcat(path, "/drivers/", sizeof(path_full) - sysfs_len);
+			strlcat(path, driver, sizeof(path_full) - sysfs_len);
+			if (stat(path_full, &statbuf) == 0)
+				goto found;
+		}
+		goto out;
+	}
+
+	strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len);
+	strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
+	strlcat(path, "/devices/", sizeof(path_full) - sysfs_len);
+	strlcat(path, id, sizeof(path_full) - sysfs_len);
+	if (stat(path_full, &statbuf) == 0)
+		goto found;
+
+	strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len);
+	strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
+	strlcat(path, "/devices/", sizeof(path_full) - sysfs_len);
+	strlcat(path, id, sizeof(path_full) - sysfs_len);
+	if (stat(path_full, &statbuf) == 0)
+		goto found;
+
+	strlcpy(path, "/class/", sizeof(path_full) - sysfs_len);
+	strlcat(path, subsystem, sizeof(path_full) - sysfs_len);
+	strlcat(path, "/", sizeof(path_full) - sysfs_len);
+	strlcat(path, id, sizeof(path_full) - sysfs_len);
+	if (stat(path_full, &statbuf) == 0)
+		goto found;
+out:
+	return 0;
+found:
+	if (S_ISLNK(statbuf.st_mode))
+		sysfs_resolve_link(path, sizeof(path_full) - sysfs_len);
+	strlcpy(devpath_full, path, len);
+	return 1;
+}
diff --git a/libmultipath/uxsock.c b/libmultipath/uxsock.c
index abb9f85..a070943 100644
--- a/libmultipath/uxsock.c
+++ b/libmultipath/uxsock.c
@@ -14,6 +14,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/poll.h>
+#include <signal.h>
 #include <errno.h>
 
 #include "memory.h"
@@ -127,9 +128,23 @@ size_t read_all(int fd, void *buf, size_t len)
  */
 int send_packet(int fd, const char *buf, size_t len)
 {
-	if (write_all(fd, &len, sizeof(len)) != sizeof(len)) return -1;
-	if (write_all(fd, buf, len) != len) return -1;	
-	return 0;
+	int ret = 0;
+	sigset_t set, old;
+
+	/* Block SIGPIPE */
+	sigemptyset(&set);
+	sigaddset(&set, SIGPIPE);
+	pthread_sigmask(SIG_BLOCK, &set, &old);
+
+	if (write_all(fd, &len, sizeof(len)) != sizeof(len))
+		ret = -1;
+	if (!ret && write_all(fd, buf, len) != len)
+		ret = -1;
+
+	/* And unblock it again */
+	pthread_sigmask(SIG_SETMASK, &old, NULL);
+
+	return ret;
 }
 
 /*
diff --git a/libmultipath/waiter.h b/libmultipath/waiter.h
index 0223924..468ce5f 100644
--- a/libmultipath/waiter.h
+++ b/libmultipath/waiter.h
@@ -1,8 +1,6 @@
 #ifndef _WAITER_H
 #define _WAITER_H
 
-#if DAEMON
-
 struct event_thread {
 	struct dm_task *dmt;
 	pthread_t thread;
@@ -19,5 +17,4 @@ int start_waiter_thread (struct multipath *mpp, struct vectors *vecs);
 int waiteventloop (struct event_thread *waiter);
 void *waitevent (void *et);
 
-#endif /* DAEMON */
 #endif /* _WAITER_H */
diff --git a/multipath-tools.spec.in b/multipath-tools.spec.in
index 3caede6..b224779 100644
--- a/multipath-tools.spec.in
+++ b/multipath-tools.spec.in
@@ -22,7 +22,6 @@ are :
 * multipath :   scan the system for multipathed devices, assembles them
                 and update the device-mapper's maps
 * multipathd :  wait for maps events, then execs multipath
-* devmap-name : provides a meaningful device name to udev for devmaps
 * kpartx :      maps linear devmaps upon device partitions, which makes
                 multipath maps partionable
 
@@ -41,20 +40,10 @@ rm -rf $RPM_BUILD_ROOT
 
 %files
 %defattr(-,root,root,-)
-%{prefix}/sbin/devmap_name
 %{prefix}/sbin/multipath
 %{prefix}/sbin/kpartx
-%{prefix}/sbin/mpath_prio_alua
-%{prefix}/sbin/mpath_prio_emc
-%{prefix}/sbin/mpath_prio_random
-%{prefix}/sbin/mpath_prio_balance_units
-%{prefix}/sbin/mpath_prio_netapp
-%{prefix}/sbin/mpath_prio_rdac
-%{prefix}/sbin/mpath_prio_hds_modular
-%{prefix}/usr/share/man/man8/devmap_name.8.gz
 %{prefix}/usr/share/man/man8/multipath.8.gz
 %{prefix}/usr/share/man/man8/kpartx.8.gz
-%{prefix}/usr/share/man/man8/mpath_prio_alua.8.gz
 %{prefix}/usr/share/man/man8/multipathd.8.gz
 %{prefix}/sbin/multipathd
 %{prefix}/etc/udev/rules.d/multipath.rules
diff --git a/multipath.conf.annotated b/multipath.conf.annotated
index e6cfe9a..49c9c5c 100644
--- a/multipath.conf.annotated
+++ b/multipath.conf.annotated
@@ -38,7 +38,7 @@
 #	# scope   : multipath
 #	# desc    : the default path grouping policy to apply to unspecified
 #	#           multipaths
-#	# default : multibus
+#	# default : failover
 #	#
 #	path_grouping_policy	multibus
 #
@@ -52,14 +52,14 @@
 #	getuid_callout	"/lib/udev/scsi_id -g -u -s /block/%n"
 #
 #	#
-#	# name    : prio_callout
+#	# name    : prio
 #	# scope   : multipath
-#	# desc    : the default program and args to callout to obtain a path 
+#	# desc    : the default function to call to obtain a path 
 #	#           priority value. The ALUA bits in SPC-3 provide an
-#	#           exploitable prio value for example. "none" is a valid value
+#	#           exploitable prio value for example.
 #	# default : (null)
 #	#
-#	#prio_callout	"/bin/true"
+#	#prio	"alua"
 #
 #	#
 #	# name    : path_checker
@@ -80,6 +80,16 @@
 #	rr_min_io	100
 #
 #	#
+#	# name    : max_fds
+#	# scope   : multipathd
+#	# desc    : Sets the maximum number of open file descriptors for the
+#	#           multipathd process.
+#	# values  : unlimited|n > 0
+#	# default : None
+#	#
+#	max_fds		8192
+#
+#	#
 #	# name    : rr_weight
 #	# scope   : multipath
 #	# desc    : if set to priorities the multipath configurator will assign
@@ -96,9 +106,9 @@
 #	#	    0 means immediate failback, values >0 means deffered failback
 #	#	    expressed in seconds.
 #	# values  : manual|immediate|n > 0
-#	# default : immediate
+#	# default : manual
 #	#
-#	failback	manual
+#	failback	immediate
 #
 #	#
 #	# name    : no_path_retry
@@ -219,9 +229,9 @@
 #		#	    0 means immediate failback, values >0 means deffered failback
 #		#	    expressed in seconds.
 #		# values  : manual|immediate|n > 0
-#		# default : immediate
+#		# default : manual
 #		#
-#		failback		manual
+#		failback		immediate
 #
 #		#
 #		# name    : no_path_retry
@@ -296,15 +306,14 @@
 #		getuid_callout          "/lib/udev/scsi_id -g -u -s /block/%n"
 #
 #		#
-#		# name    : prio_callout
+#		# name    : prio
 #		# scope   : multipath
-#		# desc    : the program and args to callout to obtain a path 
+#		# desc    : the function to call to obtain a path 
 #		#           weight. Weights are summed for each path group to
 #		#	    determine the next PG to use case of failure.
-#		#	    "none" is a valid value.
 #		# default : no callout, all paths equals
 #		#
-#		prio_callout          "/sbin/mpath_prio_balance_units %d"
+#		prio          "hp_sw"
 #
 #		#
 #		# name    : path_checker
@@ -331,7 +340,7 @@
 #		#	    0 means immediate failback, values >0 means deffered failback
 #		#	    expressed in seconds.
 #		# values  : manual|immediate|n > 0
-#		# default : immediate
+#		# default : manual
 #		#
 #		failback		30
 #
diff --git a/multipath.conf.synthetic b/multipath.conf.synthetic
index 633d625..33f820b 100644
--- a/multipath.conf.synthetic
+++ b/multipath.conf.synthetic
@@ -8,9 +8,10 @@
 #	selector		"round-robin 0"
 #	path_grouping_policy	multibus
 #	getuid_callout		"/lib/udev/scsi_id -g -u -s /block/%n"
-#	prio_callout		/bin/true
+#	prio			const
 #	path_checker		directio
 #	rr_min_io		100
+#	max_fds			8192
 #	rr_weight		priorities
 #	failback		immediate
 #	no_path_retry		fail
diff --git a/multipath/02_multipath b/multipath/02_multipath
index 067c582..467a7cb 100755
--- a/multipath/02_multipath
+++ b/multipath/02_multipath
@@ -5,7 +5,6 @@
 # this tool is statically linked against klibc : no additional libs
 #
 cp /sbin/multipath $INITRDDIR/sbin
-cp /sbin/devmap_name $INITRDDIR/sbin
 cp /sbin/kpartx $INITRDDIR/sbin
 
 #
diff --git a/multipath/Makefile b/multipath/Makefile
index 4923b2f..2d74ffe 100644
--- a/multipath/Makefile
+++ b/multipath/Makefile
@@ -1,52 +1,33 @@
 # Makefile
 #
 # Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
-BUILD = glibc
-
+#
 include ../Makefile.inc
 
-OBJS = main.o $(MULTIPATHLIB)-$(BUILD).a $(CHECKERSLIB)-$(BUILD).a
+OBJS = main.o
 
-CFLAGS += -I$(multipathdir) -I$(checkersdir)
-LDFLAGS += -laio
-
-ifeq ($(strip $(BUILD)),klibc)
-	OBJS += $(libdm)
-else
-	LDFLAGS += -ldevmapper
-endif
+CFLAGS += -I$(multipathdir) -Wl,-rpath,$(libdir)
+LDFLAGS += -lpthread -ldevmapper -laio -ldl \
+	   -lmultipath -L$(multipathdir)
 
 EXEC = multipath
 
-all: $(BUILD)
+all: $(EXEC)
 
-prepare:
-	make -C $(multipathdir) prepare
-	rm -f core *.o *.gz
+$(EXEC): $(OBJS)
+	$(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
 	$(GZIP) $(EXEC).conf.5 > $(EXEC).conf.5.gz
 
-glibc: prepare $(OBJS)
-	$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
-
-klibc: prepare $(OBJS)
-	$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
-
-$(CHECKERSLIB)-$(BUILD).a:
-	make -C $(checkersdir) BUILD=$(BUILD) $(BUILD)
-
-$(MULTIPATHLIB)-$(BUILD).a:
-	make -C $(multipathdir) BUILD=$(BUILD) $(BUILD)
-
 install:
-	install -d $(DESTDIR)$(bindir)
+	$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
 	$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
-	install -d $(DESTDIR)/etc/udev/rules.d
-	install -m 644 multipath.rules $(DESTDIR)/etc/udev/rules.d/
-	install -d $(DESTDIR)$(mandir)
-	install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
-	install -d $(DESTDIR)$(man5dir)
-	install -m 644 $(EXEC).conf.5.gz $(DESTDIR)$(man5dir)
+	$(INSTALL_PROGRAM) -d $(DESTDIR)/etc/udev/rules.d
+	$(INSTALL_PROGRAM) -m 644 multipath.rules $(DESTDIR)/etc/udev/rules.d/
+	$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)
+	$(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
+	$(INSTALL_PROGRAM) -d $(DESTDIR)$(man5dir)
+	$(INSTALL_PROGRAM) -m 644 $(EXEC).conf.5.gz $(DESTDIR)$(man5dir)
 
 uninstall:
 	rm $(DESTDIR)/etc/udev/rules.d/multipath.rules
diff --git a/multipath/main.c b/multipath/main.c
index 815c307..4c65808 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -27,6 +27,7 @@
 #include <ctype.h>
 
 #include <checkers.h>
+#include <prio.h>
 #include <vector.h>
 #include <memory.h>
 #include <libdevmapper.h>
@@ -48,6 +49,8 @@
 #include <pgpolicies.h>
 #include <version.h>
 
+int logsink;
+
 static int
 filter_pathvec (vector pathvec, char * refwwid)
 {
@@ -72,34 +75,39 @@ static void
 usage (char * progname)
 {
 	fprintf (stderr, VERSION_STRING);
-	fprintf (stderr, "Usage: %s\t[-v level] [-d] [-h|-l|-ll|-f|-F]\n",
-		progname);
+	fprintf (stderr, "Usage:\n");
+	fprintf (stderr, "  %s [-d] [-r] [-v lvl] [-p pol] [-b fil] [dev]\n", progname);
+	fprintf (stderr, "  %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname);
+	fprintf (stderr, "  %s -F [-v lvl]\n", progname);
+	fprintf (stderr, "  %s -h\n", progname);
 	fprintf (stderr,
-		"\t\t\t[-p failover|multibus|group_by_serial|group_by_prio]\n" \
-		"\t\t\t[device]\n" \
-		"\n" \
-		"\t-v level\tverbosity level\n" \
-		"\t   0\t\t\tno output\n" \
-		"\t   1\t\t\tprint created devmap names only\n" \
-		"\t   2\t\t\tdefault verbosity\n" \
-		"\t   3\t\t\tprint debug information\n" \
-		"\t-h\t\tprint this usage text\n" \
-		"\t-b file\t\tbindings file location\n" \
-		"\t-d\t\tdry run, do not create or update devmaps\n" \
-		"\t-l\t\tshow multipath topology (sysfs and DM info)\n" \
-		"\t-ll\t\tshow multipath topology (maximum info)\n" \
-		"\t-f\t\tflush a multipath device map\n" \
-		"\t-F\t\tflush all multipath device maps\n" \
-		"\t-p policy\tforce all maps to specified policy :\n" \
-		"\t   failover\t\t1 path per priority group\n" \
-		"\t   multibus\t\tall paths in 1 priority group\n" \
-		"\t   group_by_serial\t1 priority group per serial\n" \
-		"\t   group_by_prio\t1 priority group per priority lvl\n" \
-		"\t   group_by_node_name\t1 priority group per target node\n" \
-		"\n" \
-		"\tdevice\t\tlimit scope to the device's multipath\n" \
-		"\t\t\t(udev-style $DEVNAME reference, eg /dev/sdb\n" \
-		"\t\t\tor major:minor or a device map name)\n" \
+		"\n"
+		"Where:\n"
+		"  -h      print this usage text\n" \
+		"  -l      show multipath topology (sysfs and DM info)\n" \
+		"  -ll     show multipath topology (maximum info)\n" \
+		"  -f      flush a multipath device map\n" \
+		"  -F      flush all multipath device maps\n" \
+		"  -d      dry run, do not create or update devmaps\n" \
+		"  -r      force devmap reload\n" \
+		"  -p      policy failover|multibus|group_by_serial|group_by_prio\n" \
+		"  -b fil  bindings file location\n" \
+		"  -p pol  force all maps to specified path grouping policy :\n" \
+		"          . failover            one path per priority group\n" \
+		"          . multibus            all paths in one priority group\n" \
+		"          . group_by_serial     one priority group per serial\n" \
+		"          . group_by_prio       one priority group per priority lvl\n" \
+		"          . group_by_node_name  one priority group per target node\n" \
+		"  -v lvl  verbosity level\n" \
+		"          . 0 no output\n" \
+		"          . 1 print created devmap names only\n" \
+		"          . 2 default verbosity\n" \
+		"          . 3 print debug information\n" \
+		"  dev     action limited to:\n" \
+		"          . multipath named 'dev' (ex: mpath0) or\n" \
+		"          . multipath whose wwid is 'dev' (ex: 60051..)\n" \
+		"          . multipath including the path named 'dev' (ex: /dev/sda)\n" \
+		"          . multipath including the path with maj:min 'dev' (ex: 8:0)\n" \
 		);
 
 	exit(1);
@@ -149,7 +157,7 @@ get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
 	int i;
 	struct multipath * mpp;
 
-	if (dm_get_maps(curmp, DEFAULT_TARGET))
+	if (dm_get_maps(curmp))
 		return 1;
 
 	vector_foreach_slot (curmp, mpp, i) {
@@ -280,7 +288,7 @@ configure (void)
 	if (conf->verbosity > 2)
 		print_all_paths(pathvec, 1);
 
-	get_path_layout(pathvec);
+	get_path_layout(pathvec, 1);
 
 	if (get_dm_mpvec(curmp, pathvec, refwwid))
 		goto out;
@@ -295,7 +303,7 @@ configure (void)
 	/*
 	 * core logic entry point
 	 */
-	r = coalesce_paths(&vecs, NULL, NULL);
+	r = coalesce_paths(&vecs, NULL, NULL, conf->force_reload);
 
 out:
 	if (refwwid)
@@ -320,17 +328,25 @@ main (int argc, char *argv[])
 		exit(1);
 	}
 
-	if (dm_prereq(DEFAULT_TARGET))
+	if (dm_prereq())
 		exit(1);
 
 	if (load_config(DEFAULT_CONFIGFILE))
 		exit(1);
 
+	if (init_checkers()) {
+		condlog(0, "failed to initialize checkers");
+		exit(1);
+	}
+	if (init_prio()) {
+		condlog(0, "failed to initialize prioritizers");
+		exit(1);
+	}
 	if (sysfs_init(conf->sysfs_dir, FILE_NAME_SIZE)) {
 		condlog(0, "multipath tools need sysfs mounted");
 		exit(1);
 	}
-	while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:")) != EOF ) {
+	while ((arg = getopt(argc, argv, ":dhl::FfM:v:p:b:r")) != EOF ) {
 		switch(arg) {
 		case 1: printf("optarg : %s\n",optarg);
 			break;
@@ -373,6 +389,9 @@ main (int argc, char *argv[])
 				usage(argv[0]);
 			}                
 			break;
+		case 'r':
+			conf->force_reload = 1;
+			break;
 		case 'h':
 			usage(argv[0]);
 		case ':':
@@ -405,14 +424,14 @@ main (int argc, char *argv[])
 
 	if (conf->remove == FLUSH_ONE) {
 		if (conf->dev_type == DEV_DEVMAP)
-			dm_flush_map(conf->dev, DEFAULT_TARGET);
+			dm_flush_map(conf->dev);
 		else
 			condlog(0, "must provide a map name to remove");
 
 		goto out;
 	}
 	else if (conf->remove == FLUSH_ALL) {
-		dm_flush_maps(DEFAULT_TARGET);
+		dm_flush_maps();
 		goto out;
 	}
 	while ((r = configure()) < 0)
@@ -420,9 +439,17 @@ main (int argc, char *argv[])
 	
 out:
 	sysfs_cleanup();
-	free_config(conf);
 	dm_lib_release();
 	dm_lib_exit();
+
+	/*
+	 * Freeing config must be done after dm_lib_exit(), because
+	 * the logging function (dm_write_log()), which is called there,
+	 * references the config.
+	 */
+	free_config(conf);
+	conf = NULL;
+
 #ifdef _DEBUG_
 	dbg_free_final(NULL);
 #endif
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index c8ab6b0..c66d7fc 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -374,6 +374,15 @@ section:
 .RE
 .PD
 .LP
+.SH "KNOWN ISSUES"
+The usage of
+.B queue_if_no_path
+option can lead to
+.B D state
+processes being hung and not killable in situations where all the paths to the LUN go offline.
+It is advisable to use the
+.B no_path_retry
+option instead.
 .SH "SEE ALSO"
 .BR udev (8),
 .BR dmsetup (8)
diff --git a/multipathd/Makefile b/multipathd/Makefile
index b430b94..b1af76c 100644
--- a/multipathd/Makefile
+++ b/multipathd/Makefile
@@ -1,4 +1,3 @@
-BUILD = glibc
 EXEC = multipathd
 
 include ../Makefile.inc
@@ -6,8 +5,9 @@ include ../Makefile.inc
 #
 # basic flags setting
 #
-CFLAGS += -DDAEMON -I$(multipathdir) -I$(checkersdir)
-LDFLAGS = -lpthread -ldevmapper -lreadline -lncurses -laio
+CFLAGS += -I$(multipathdir) -Wl,-rpath,$(libdir)
+LDFLAGS += -lpthread -ldevmapper -lreadline -lncurses -laio -ldl \
+	   -lmultipath -L$(multipathdir)
 
 #
 # debuging stuff
@@ -19,36 +19,24 @@ LDFLAGS = -lpthread -ldevmapper -lreadline -lncurses -laio
 #
 # object files
 #
-OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o \
-       $(MULTIPATHLIB)-glibc.a $(CHECKERSLIB)-glibc.a \
+OBJS = main.o pidfile.o uxlsnr.o uxclnt.o cli.o cli_handlers.o
 
 
 #
 # directives
 #
-all : $(BUILD)
+all : $(EXEC)
 
-glibc: $(EXEC)
-
-klibc:
-	$(MAKE) BUILD=glibc glibc
-
-$(EXEC): clean $(OBJS)
-	$(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
+$(EXEC): $(OBJS)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $(EXEC) $(OBJS)
 	$(GZIP) $(EXEC).8 > $(EXEC).8.gz
 
-$(CHECKERSLIB)-glibc.a:
-	$(MAKE) -C $(checkersdir) BUILD=glibc glibc
-
-$(MULTIPATHLIB)-glibc.a:
-	$(MAKE) -C $(multipathdir) DAEMON=1 BUILD=glibc glibc
-
 install:
-	install -d $(DESTDIR)$(bindir)
+	$(INSTALL_PROGRAM) -d $(DESTDIR)$(bindir)
 	$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)
-	install -d $(DESTDIR)$(rcdir)
-	install -d $(DESTDIR)$(mandir)
-	install -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
+	$(INSTALL_PROGRAM) -d $(DESTDIR)$(rcdir)
+	$(INSTALL_PROGRAM) -d $(DESTDIR)$(mandir)
+	$(INSTALL_PROGRAM) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)
 
 uninstall:
 	rm -f $(DESTDIR)$(bindir)/$(EXEC)
@@ -56,6 +44,5 @@ uninstall:
 	rm -f $(DESTDIR)$(mandir)/$(EXEC).8.gz
 
 clean:
-	$(MAKE) -C $(multipathdir) prepare DAEMON=1
 	rm -f core *.o $(EXEC) *.gz
 
diff --git a/multipathd/cli.c b/multipathd/cli.c
index d786eef..7eaac73 100644
--- a/multipathd/cli.c
+++ b/multipathd/cli.c
@@ -3,6 +3,7 @@
  */
 #include <memory.h>
 #include <vector.h>
+#include <parser.h>
 #include <util.h>
 #include <version.h>
 #include <readline/readline.h>
@@ -168,6 +169,7 @@ load_keys (void)
 	r += add_key(keys, "config", CONFIG, 0);
 	r += add_key(keys, "blacklist", BLACKLIST, 0);
 	r += add_key(keys, "devices", DEVICES, 0);
+	r += add_key(keys, "format", FMT, 1);
 
 	if (r) {
 		free_keys(keys);
@@ -210,13 +212,17 @@ find_key (const char * str)
 static int
 get_cmdvec (char * cmd, vector *v)
 {
-	int fwd = 1;
+	int i;
 	int r = 0;
-	char * p = cmd;
+	int get_param = 0;
 	char * buff;
 	struct key * kw = NULL;
 	struct key * cmdkw = NULL;
-	vector cmdvec;
+	vector cmdvec, strvec;
+
+	strvec = alloc_strvec(cmd);
+	if (!strvec)
+		return 0;
 
 	cmdvec = vector_alloc();
 	*v = cmdvec;
@@ -224,21 +230,20 @@ get_cmdvec (char * cmd, vector *v)
 	if (!cmdvec)
 		return E_NOMEM;
 
-	while (fwd) {
-		fwd = get_word(p, &buff);
-
-		if (!buff)
-			break;
-
-		p += fwd;
+	vector_foreach_slot(strvec, buff, i) {
+		if (*buff == '"')
+			continue;
+		if (get_param) {
+			get_param = 0;
+			cmdkw->param = strdup(buff);
+			continue;
+		}
 		kw = find_key(buff);
-		FREE(buff);
-
-		if (!kw)
-			return E_SYNTAX;
-
+		if (!kw) {
+			r = E_SYNTAX;
+			goto out;
+		}
 		cmdkw = alloc_key();
-
 		if (!cmdkw) {
 			r = E_NOMEM;
 			goto out;
@@ -251,23 +256,17 @@ get_cmdvec (char * cmd, vector *v)
 		vector_set_slot(cmdvec, cmdkw);
 		cmdkw->code = kw->code;
 		cmdkw->has_param = kw->has_param;
-		
-		if (kw->has_param) {
-			if (*p == '\0')
-				goto out;
-
-			fwd = get_word(p, &buff);
-
-			if (!buff)
-				return E_NOPARM;
-
-			p += fwd;
-			cmdkw->param = buff;
-		}
+		if (kw->has_param)
+			get_param = 1;
+	}
+	if (get_param) {
+		r = E_NOPARM;
+		goto out;
 	}
 	return 0;
 
 out:
+	free_strvec(strvec);
 	free_keys(cmdvec);
 	*v = NULL;
 	return r;
@@ -406,6 +405,7 @@ cli_init (void) {
 		return 1;
 
 	add_handler(LIST+PATHS, NULL);
+	add_handler(LIST+PATHS+FMT, NULL);
 	add_handler(LIST+MAPS, NULL);
 	add_handler(LIST+MAPS+STATUS, NULL);
 	add_handler(LIST+MAPS+STATS, NULL);
diff --git a/multipathd/cli.h b/multipathd/cli.h
index a2397df..8c83eab 100644
--- a/multipathd/cli.h
+++ b/multipathd/cli.h
@@ -19,6 +19,7 @@ enum {
 	__CONFIG,
 	__BLACKLIST,
 	__DEVICES,
+	__FMT,
 };
 
 #define LIST		(1 << __LIST)
@@ -41,6 +42,7 @@ enum {
 #define CONFIG		(1 << __CONFIG)
 #define BLACKLIST	(1 << __BLACKLIST)
 #define DEVICES  	(1 << __DEVICES)
+#define FMT 	 	(1 << __FMT)
 
 #define INITIAL_REPLY_LEN 1000
 
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 7bae02a..c84805a 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -28,7 +28,7 @@ show_paths (char ** r, int * len, struct vectors * vecs, char * style)
 	unsigned int maxlen = INITIAL_REPLY_LEN;
 	int again = 1;
 
-	get_path_layout(vecs->pathvec);
+	get_path_layout(vecs->pathvec, 1);
 	reply = MALLOC(maxlen);
 
 	while (again) {
@@ -94,7 +94,7 @@ show_maps_topology (char ** r, int * len, struct vectors * vecs)
 	unsigned int maxlen = INITIAL_REPLY_LEN;
 	int again = 1;
  
-	get_path_layout(vecs->pathvec);
+	get_path_layout(vecs->pathvec, 0);
 	reply = MALLOC(maxlen);
 
 	while (again) {
@@ -185,13 +185,24 @@ cli_list_paths (void * v, char ** reply, int * len, void * data)
 }
 
 int
+cli_list_paths_fmt (void * v, char ** reply, int * len, void * data)
+{
+	struct vectors * vecs = (struct vectors *)data;
+	char * fmt = get_keyparam(v, FMT);
+
+	condlog(3, "list paths (operator)");
+
+	return show_paths(reply, len, vecs, fmt);
+}
+
+int
 cli_list_map_topology (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);
+	get_path_layout(vecs->pathvec, 0);
 	mpp = find_mp_by_str(vecs->mpvec, param);
 
 	if (!mpp)
@@ -222,7 +233,7 @@ show_maps (char ** r, int *len, struct vectors * vecs, char * style)
 	unsigned int maxlen = INITIAL_REPLY_LEN;
 	int again = 1;
 
-	get_multipath_layout(vecs->mpvec);
+	get_multipath_layout(vecs->mpvec, 1);
 	reply = MALLOC(maxlen);
 
 	while (again) {
@@ -431,6 +442,7 @@ cli_reinstate(void * v, char ** reply, int * len, void * data)
 	condlog(2, "%s: reinstate path %s (operator)",
 		pp->mpp->alias, pp->dev_t);
 
+	checker_enable(&pp->checker);
 	return dm_reinstate_path(pp->mpp->alias, pp->dev_t);
 }
 
@@ -440,6 +452,7 @@ cli_fail(void * v, char ** reply, int * len, void * data)
 	struct vectors * vecs = (struct vectors *)data;
 	char * param = get_keyparam(v, PATH);
 	struct path * pp;
+	int r;
 	
 	pp = find_path_by_dev(vecs->pathvec, param);
 
@@ -452,7 +465,13 @@ cli_fail(void * v, char ** reply, int * len, void * data)
 	condlog(2, "%s: fail path %s (operator)",
 		pp->mpp->alias, pp->dev_t);
 
-	return dm_fail_path(pp->mpp->alias, pp->dev_t);
+	r = dm_fail_path(pp->mpp->alias, pp->dev_t);
+	/*
+	 * Suspend path checking to avoid auto-reinstating the path
+	 */
+	if (!r)
+		checker_disable(&pp->checker);
+	return r;
 }
 
 int
diff --git a/multipathd/cli_handlers.h b/multipathd/cli_handlers.h
index 863694b..a688481 100644
--- a/multipathd/cli_handlers.h
+++ b/multipathd/cli_handlers.h
@@ -1,4 +1,5 @@
 int cli_list_paths (void * v, char ** reply, int * len, void * data);
+int cli_list_paths_fmt (void * v, char ** reply, int * len, void * data);
 int cli_list_maps (void * v, char ** reply, int * len, void * data);
 int cli_list_maps_status (void * v, char ** reply, int * len, void * data);
 int cli_list_maps_stats (void * v, char ** reply, int * len, void * data);
diff --git a/multipathd/main.c b/multipathd/main.c
index da5fd8f..8d74cb9 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -12,6 +12,8 @@
 #include <sys/types.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 
 /*
  * libcheckers
@@ -43,6 +45,7 @@
 #include <switchgroup.h>
 #include <print.h>
 #include <configure.h>
+#include <prio.h>
 
 #include "main.h"
 #include "pidfile.h"
@@ -62,6 +65,8 @@
 pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
 pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+int logsink;
+
 /*
  * global copy of vecs for use in sig handlers
  */
@@ -116,7 +121,7 @@ coalesce_maps(struct vectors *vecs, vector nmpv)
 			 * remove all current maps not allowed by the
 			 * current configuration
 			 */
-			if (dm_flush_map(ompp->alias, DEFAULT_TARGET)) {
+			if (dm_flush_map(ompp->alias)) {
 				condlog(0, "%s: unable to flush devmap",
 					ompp->alias);
 				/*
@@ -135,7 +140,7 @@ coalesce_maps(struct vectors *vecs, vector nmpv)
 			}
 			else {
 				dm_lib_release();
-				condlog(3, "%s devmap removed", ompp->alias);
+				condlog(2, "%s devmap removed", ompp->alias);
 			}
 		}
 	}
@@ -149,6 +154,9 @@ sync_map_state(struct multipath *mpp)
 	struct path *pp;
 	unsigned int i, j;
 
+	if (!mpp->pg)
+		return;
+
 	vector_foreach_slot (mpp->pg, pgp, i){
 		vector_foreach_slot (pgp->paths, pp, j){
 			if (pp->state <= PATH_UNCHECKED)
@@ -183,7 +191,7 @@ flush_map(struct multipath * mpp, struct vectors * vecs)
 	 * clear references to this map before flushing so we can ignore
 	 * the spurious uevent we may generate with the dm_flush_map call below
 	 */
-	if (dm_flush_map(mpp->alias, DEFAULT_TARGET)) {
+	if (dm_flush_map(mpp->alias)) {
 		/*
 		 * May not really be an error -- if the map was already flushed
 		 * from the device mapper by dmsetup(8) for instance.
@@ -193,11 +201,11 @@ flush_map(struct multipath * mpp, struct vectors * vecs)
 	}
 	else {
 		dm_lib_release();
-		condlog(3, "%s: devmap removed", mpp->alias);
+		condlog(2, "%s: devmap removed", mpp->alias);
 	}
 
 	orphan_paths(vecs->pathvec, mpp);
-	remove_map(mpp, vecs, stop_waiter_thread, 1);
+	remove_map_and_stop_waiter(mpp, vecs, 1);
 
 	return 0;
 }
@@ -232,7 +240,7 @@ ev_add_map (struct sysfs_device * dev, struct vectors * vecs)
 
 	map_present = dm_map_present(alias);
 
-	if (map_present && dm_type(alias, DEFAULT_TARGET) <= 0) {
+	if (map_present && dm_type(alias, TGT_MPATH) <= 0) {
 		condlog(4, "%s: not a multipath map", alias);
 		return 0;
 	}
@@ -253,21 +261,20 @@ ev_add_map (struct sysfs_device * dev, struct vectors * vecs)
 	/*
 	 * now we can register the map
 	 */
-	if (map_present && (mpp = add_map_without_path(vecs, minor, alias,
-					start_waiter_thread))) {
+	if (map_present && (mpp = add_map_without_path(vecs, minor, alias))) {
 		sync_map_state(mpp);
-		condlog(3, "%s: devmap %s added", alias, dev->kernel);
+		condlog(2, "%s: devmap %s added", alias, dev->kernel);
 		return 0;
 	}
 	refwwid = get_refwwid(dev->kernel, DEV_DEVMAP, vecs->pathvec);
 
 	if (refwwid) {
-		r = coalesce_paths(vecs, NULL, refwwid);
+		r = coalesce_paths(vecs, NULL, refwwid, 0);
 		dm_lib_release();
 	}
 
 	if (!r)
-		condlog(3, "%s: devmap %s added", alias, dev->kernel);
+		condlog(2, "%s: devmap %s added", alias, dev->kernel);
 	else
 		condlog(0, "%s: uev_add_map %s failed", alias, dev->kernel);
 
@@ -290,7 +297,7 @@ ev_remove_map (char * devname, struct vectors * vecs)
 	mpp = find_mp_by_str(vecs->mpvec, devname);
 
 	if (!mpp) {
-		condlog(3, "%s: devmap not registered, can't remove",
+		condlog(2, "%s: devmap not registered, can't remove",
 			devname);
 		return 0;
 	}
@@ -368,7 +375,7 @@ ev_add_path (char * devname, struct vectors * vecs)
 		condlog(0, "%s: failed to get path uid", devname);
 		return 1; /* leave path added to pathvec */
 	}
-	if (filter_path(conf, pp)){
+	if (filter_path(conf, pp) > 0){
 		int i = find_slot(vecs->pathvec, (void *)pp);
 		if (i != -1)
 			vector_del_slot(vecs->pathvec, i);
@@ -431,11 +438,11 @@ rescan:
 	    start_waiter_thread(mpp, vecs))
 			goto out;
 
-	condlog(3, "%s path added to devmap %s", devname, mpp->alias);
+	condlog(2, "%s path added to devmap %s", devname, mpp->alias);
 	return 0;
 
 out:
-	remove_map(mpp, vecs, NULL, 1);
+	remove_map(mpp, vecs, 1);
 	return 1;
 }
 
@@ -457,8 +464,7 @@ ev_remove_path (char * devname, struct vectors * vecs)
 {
 	struct multipath * mpp;
 	struct path * pp;
-	int i;
-	int rm_path = 1;
+	int i, retval = 0;
 
 	pp = find_path_by_dev(vecs->pathvec, devname);
 
@@ -468,100 +474,81 @@ ev_remove_path (char * devname, struct vectors * vecs)
 	}
 
 	/*
-	 * avoid referring to the map of an orphanned path
+	 * avoid referring to the map of an orphaned path
 	 */
 	if ((mpp = pp->mpp)) {
+		/*
+		 * transform the mp->pg vector of vectors of paths
+		 * into a mp->params string to feed the device-mapper
+		 */
+		if (update_mpp_paths(mpp, vecs->pathvec)) {
+			condlog(0, "%s: failed to update paths",
+				mpp->alias);
+			goto out;
+		}
+		if ((i = find_slot(mpp->paths, (void *)pp)) != -1)
+			vector_del_slot(mpp->paths, i);
 
 		/*
 		 * remove the map IFF removing the last path
 		 */
-		if (pathcount(mpp, PATH_WILD) > 1) {
-			vector rpvec = vector_alloc();
+		if (VECTOR_SIZE(mpp->paths) == 0) {
+			char alias[WWID_SIZE];
 
 			/*
-			 * transform the mp->pg vector of vectors of paths
-			 * into a mp->params string to feed the device-mapper
+			 * flush_map will fail if the device is open
 			 */
-			update_mpp_paths(mpp, vecs->pathvec);
-			if ((i = find_slot(mpp->paths, (void *)pp)) != -1)
-				vector_del_slot(mpp->paths, i);
-
-			if (VECTOR_SIZE(mpp->paths) == 0) {
-				char alias[WWID_SIZE];
-
-				/*
-				 * flush_map will fail if the device is open
-				 */
-				strncpy(alias, mpp->alias, WWID_SIZE);
-				if (flush_map(mpp, vecs))
-					rm_path = 0;
-				else
-					condlog(3, "%s: removed map after removing"
-						" multiple paths", alias);
-			}
-			else {
-				if (setup_map(mpp)) {
-					condlog(0, "%s: failed to setup map for"
-						" removal of path %s", mpp->alias, devname);
-					free_pathvec(rpvec, KEEP_PATHS);
-					goto out;
-				}
-				/*
-				 * reload the map
-				 */
-				mpp->action = ACT_RELOAD;
-				if (domap(mpp) <= 0) {
-					condlog(0, "%s: failed in domap for "
-						"removal of path %s",
-						mpp->alias, devname);
-					/*
-					 * Delete path from pathvec so that
-					 * update_mpp_paths wont find it later
-					 * when/if another path is removed.
-					 */
-					if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1)
-						vector_del_slot(vecs->pathvec, i);
-					free_path(pp);
-					return 1;
-				}
-				/*
-				 * update our state from kernel
-				 */
-				if (setup_multipath(vecs, mpp)) {
-					free_pathvec(rpvec, KEEP_PATHS);
-					goto out;
-				}
-				sync_map_state(mpp);
-
-				condlog(3, "%s: path removed from map %s",
-					devname, mpp->alias);
+			strncpy(alias, mpp->alias, WWID_SIZE);
+			if (!flush_map(mpp, vecs)) {
+				condlog(2, "%s: removed map after"
+					" removing all paths",
+					alias);
+				free_path(pp);
+				return 0;
 			}
-			free_pathvec(rpvec, KEEP_PATHS);
+			/*
+			 * Not an error, continue
+			 */
 		}
-		else {
-			char alias[WWID_SIZE];
 
+		if (setup_map(mpp)) {
+			condlog(0, "%s: failed to setup map for"
+				" removal of path %s", mpp->alias,
+				devname);
+			goto out;
+		}
+		/*
+		 * reload the map
+		 */
+		mpp->action = ACT_RELOAD;
+		if (domap(mpp) <= 0) {
+			condlog(0, "%s: failed in domap for "
+				"removal of path %s",
+				mpp->alias, devname);
+			retval = 1;
+		} else {
 			/*
-			 * flush_map will fail if the device is open
+			 * update our state from kernel
 			 */
-			strncpy(alias, mpp->alias, WWID_SIZE);
-			if (flush_map(mpp, vecs))
-				rm_path = 0;
-			else
-				condlog(3, "%s: removed map", alias);
+			if (setup_multipath(vecs, mpp)) {
+				goto out;
+			}
+			sync_map_state(mpp);
+
+			condlog(2, "%s: path removed from map %s",
+				devname, mpp->alias);
 		}
 	}
 
-	if (rm_path) {
-		if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1)
-			vector_del_slot(vecs->pathvec, i);
-		free_path(pp);
-	}
+	if ((i = find_slot(vecs->pathvec, (void *)pp)) != -1)
+		vector_del_slot(vecs->pathvec, i);
 
-	return 0;
+	free_path(pp);
+
+	return retval;
 
 out:
-	remove_map(mpp, vecs, stop_waiter_thread, 1);
+	remove_map_and_stop_waiter(mpp, vecs, 1);
 	return 1;
 }
 
@@ -571,7 +558,7 @@ map_discovery (struct vectors * vecs)
 	struct multipath * mpp;
 	unsigned int i;
 
-	if (dm_get_maps(vecs->mpvec, "multipath"))
+	if (dm_get_maps(vecs->mpvec))
 		return 1;
 
 	vector_foreach_slot (vecs->mpvec, mpp, i)
@@ -704,6 +691,7 @@ uxlsnrloop (void * ap)
 		return NULL;
 
 	set_handler_callback(LIST+PATHS, cli_list_paths);
+	set_handler_callback(LIST+PATHS+FMT, cli_list_paths_fmt);
 	set_handler_callback(LIST+MAPS, cli_list_maps);
 	set_handler_callback(LIST+MAPS+STATUS, cli_list_maps_status);
 	set_handler_callback(LIST+MAPS+STATS, cli_list_maps_stats);
@@ -809,7 +797,7 @@ mpvec_garbage_collector (struct vectors * vecs)
 	vector_foreach_slot (vecs->mpvec, mpp, i) {
 		if (mpp && mpp->alias && !dm_map_present(mpp->alias)) {
 			condlog(2, "%s: remove dead map", mpp->alias);
-			remove_map(mpp, vecs, stop_waiter_thread, 1);
+			remove_map_and_stop_waiter(mpp, vecs, 1);
 			i--;
 		}
 	}
@@ -852,171 +840,182 @@ retry_count_tick(vector mpvec)
 	}
 }
 
-static void *
-checkerloop (void *ap)
+void
+check_path (struct vectors * vecs, struct path * pp)
 {
-	struct vectors *vecs;
-	struct path *pp;
-	int count = 0;
 	int newstate;
-	unsigned int i;
 
-	mlockall(MCL_CURRENT | MCL_FUTURE);
-	vecs = (struct vectors *)ap;
-	condlog(2, "path checkers start up");
+	if (!pp->mpp)
+		return;
+
+	if (pp->tick && --pp->tick)
+		return; /* don't check this path yet */
 
 	/*
-	 * init the path check interval
+	 * provision a next check soonest,
+	 * in case we exit abnormaly from here
 	 */
-	vector_foreach_slot (vecs->pathvec, pp, i) {
-		pp->checkint = conf->checkint;
+	pp->tick = conf->checkint;
+
+	if (!checker_selected(&pp->checker)) {
+		pathinfo(pp, conf->hwtable, DI_SYSFS);
+		select_checker(pp);
 	}
+	if (!checker_selected(&pp->checker)) {
+		condlog(0, "%s: checker is not set", pp->dev);
+		return;
+	}
+	/*
+	 * Set checker in async mode.
+	 * Honored only by checker implementing the said mode.
+	 */
+	checker_set_async(&pp->checker);
 
-	while (1) {
-		pthread_cleanup_push(cleanup_lock, vecs->lock);
-		lock(vecs->lock);
-		condlog(4, "tick");
+	newstate = checker_check(&pp->checker);
 
-		vector_foreach_slot (vecs->pathvec, pp, i) {
-			if (!pp->mpp)
-				continue;
+	if (newstate < 0) {
+		condlog(2, "%s: unusable path", pp->dev);
+		pathinfo(pp, conf->hwtable, 0);
+		return;
+	}
+	/*
+	 * Async IO in flight. Keep the previous path state
+	 * and reschedule as soon as possible
+	 */
+	if (newstate == PATH_PENDING) {
+		pp->tick = 1;
+		return;
+	}
+	if (newstate != pp->state) {
+		int oldstate = pp->state;
+		pp->state = newstate;
+		LOG_MSG(1, checker_message(&pp->checker));
 
-			if (pp->tick && --pp->tick)
-				continue; /* don't check this path yet */
+		/*
+		 * upon state change, reset the checkint
+		 * to the shortest delay
+		 */
+		pp->checkint = conf->checkint;
 
+		if (newstate == PATH_DOWN || newstate == PATH_SHAKY ||
+		    update_multipath_strings(pp->mpp, vecs->pathvec)) {
 			/*
-			 * provision a next check soonest,
-			 * in case we exit abnormaly from here
+			 * proactively fail path in the DM
 			 */
-			pp->tick = conf->checkint;
+			if (oldstate == PATH_UP ||
+			    oldstate == PATH_GHOST)
+				fail_path(pp, 1);
+			else
+				fail_path(pp, 0);
 
-			if (!checker_selected(&pp->checker)) {
-				pathinfo(pp, conf->hwtable, DI_SYSFS);
-				select_checker(pp);
-			}
-			if (!checker_selected(&pp->checker)) {
-				condlog(0, "%s: checker is not set", pp->dev);
-				continue;
-			}
 			/*
-			 * Set checker in async mode.
-			 * Honored only by checker implementing the said mode.
+			 * cancel scheduled failback
 			 */
-			checker_set_async(&pp->checker);
+			pp->mpp->failback_tick = 0;
+
+			pp->mpp->stat_path_failures++;
+			return;
+		}
 
-			newstate = checker_check(&pp->checker);
+		/*
+		 * reinstate this path
+		 */
+		if (oldstate != PATH_UP &&
+		    oldstate != PATH_GHOST)
+			reinstate_path(pp, 1);
+		else
+			reinstate_path(pp, 0);
 
-			if (newstate < 0) {
-				condlog(2, "%s: unusable path", pp->dev);
-				pathinfo(pp, conf->hwtable, 0);
-				continue;
-			}
-			/*
-			 * Async IO in flight. Keep the previous path state
-			 * and reschedule as soon as possible
-			 */
-			if (newstate == PATH_PENDING) {
-				pp->tick = 1;
-				continue;
-			}
-			if (newstate != pp->state) {
-				int oldstate = pp->state;
-				pp->state = newstate;
-				LOG_MSG(1, checker_message(&pp->checker));
+		/*
+		 * schedule [defered] failback
+		 */
+		if (pp->mpp->pgfailback > 0)
+			pp->mpp->failback_tick =
+				pp->mpp->pgfailback + 1;
+		else if (pp->mpp->pgfailback == -FAILBACK_IMMEDIATE &&
+		    need_switch_pathgroup(pp->mpp, 1))
+			switch_pathgroup(pp->mpp);
 
-				/*
-				 * upon state change, reset the checkint
-				 * to the shortest delay
-				 */
-				pp->checkint = conf->checkint;
-
-				if (newstate == PATH_DOWN ||
-				    newstate == PATH_SHAKY ||
-				    update_multipath_strings(pp->mpp,
-							     vecs->pathvec)) {
-					/*
-					 * proactively fail path in the DM
-					 */
-					if (oldstate == PATH_UP ||
-					    oldstate == PATH_GHOST)
-						fail_path(pp, 1);
-					else
-						fail_path(pp, 0);
-
-					/*
-					 * cancel scheduled failback
-					 */
-					pp->mpp->failback_tick = 0;
-
-					pp->mpp->stat_path_failures++;
-					continue;
-				}
+		/*
+		 * if at least one path is up in a group, and
+		 * the group is disabled, re-enable it
+		 */
+		if (newstate == PATH_UP)
+			enable_group(pp);
+	}
+	else if (newstate == PATH_UP || newstate == PATH_GHOST) {
+		LOG_MSG(4, checker_message(&pp->checker));
+		/*
+		 * double the next check delay.
+		 * max at conf->max_checkint
+		 */
+		if (pp->checkint < (conf->max_checkint / 2))
+			pp->checkint = 2 * pp->checkint;
+		else
+			pp->checkint = conf->max_checkint;
 
-				/*
-				 * reinstate this path
-				 */
-				if (oldstate != PATH_UP &&
-				    oldstate != PATH_GHOST)
-					reinstate_path(pp, 1);
-				else
-					reinstate_path(pp, 0);
+		pp->tick = pp->checkint;
+		condlog(4, "%s: delay next check %is",
+				pp->dev_t, pp->tick);
+	}
+	else if (newstate == PATH_DOWN)
+		LOG_MSG(2, checker_message(&pp->checker));
 
-				/*
-				 * schedule [defered] failback
-				 */
-				if (pp->mpp->pgfailback > 0)
-					pp->mpp->failback_tick =
-						pp->mpp->pgfailback + 1;
-				else if (pp->mpp->pgfailback == -FAILBACK_IMMEDIATE &&
-				    need_switch_pathgroup(pp->mpp, 1))
-					switch_pathgroup(pp->mpp);
+	pp->state = newstate;
 
-				/*
-				 * if at least one path is up in a group, and
-				 * the group is disabled, re-enable it
-				 */
-				if (newstate == PATH_UP)
-					enable_group(pp);
-			}
-			else if (newstate == PATH_UP || newstate == PATH_GHOST) {
-				LOG_MSG(4, checker_message(&pp->checker));
-				/*
-				 * double the next check delay.
-				 * max at conf->max_checkint
-				 */
-				if (pp->checkint < (conf->max_checkint / 2))
-					pp->checkint = 2 * pp->checkint;
-				else
-					pp->checkint = conf->max_checkint;
-
-				pp->tick = pp->checkint;
-				condlog(4, "%s: delay next check %is",
-						pp->dev_t, pp->tick);
-			}
-			else if (newstate == PATH_DOWN)
-				LOG_MSG(2, checker_message(&pp->checker));
+	/*
+	 * path prio refreshing
+	 */
+	condlog(4, "path prio refresh");
+	pathinfo(pp, conf->hwtable, DI_PRIO);
 
-			pp->state = newstate;
+	/*
+	 * pathgroup failback policy
+	 */
+	if (need_switch_pathgroup(pp->mpp, 0)) {
+		if (pp->mpp->pgfailback > 0 &&
+		    pp->mpp->failback_tick <= 0)
+			pp->mpp->failback_tick =
+				pp->mpp->pgfailback + 1;
+		else if (pp->mpp->pgfailback ==
+				-FAILBACK_IMMEDIATE)
+			switch_pathgroup(pp->mpp);
+	}
+}
 
-			/*
-			 * path prio refreshing
-			 */
-			condlog(4, "path prio refresh");
-			pathinfo(pp, conf->hwtable, DI_PRIO);
-
-			if (need_switch_pathgroup(pp->mpp, 0)) {
-				if (pp->mpp->pgfailback > 0 &&
-				    pp->mpp->failback_tick <= 0)
-					pp->mpp->failback_tick =
-						pp->mpp->pgfailback + 1;
-				else if (pp->mpp->pgfailback ==
-						-FAILBACK_IMMEDIATE)
-					switch_pathgroup(pp->mpp);
+static void *
+checkerloop (void *ap)
+{
+	struct vectors *vecs;
+	struct path *pp;
+	int count = 0;
+	unsigned int i;
+
+	mlockall(MCL_CURRENT | MCL_FUTURE);
+	vecs = (struct vectors *)ap;
+	condlog(2, "path checkers start up");
+
+	/*
+	 * init the path check interval
+	 */
+	vector_foreach_slot (vecs->pathvec, pp, i) {
+		pp->checkint = conf->checkint;
+	}
+
+	while (1) {
+		pthread_cleanup_push(cleanup_lock, vecs->lock);
+		lock(vecs->lock);
+		condlog(4, "tick");
+
+		if (vecs->pathvec) {
+			vector_foreach_slot (vecs->pathvec, pp, i) {
+				check_path(vecs, pp);
 			}
 		}
-		defered_failback_tick(vecs->mpvec);
-		retry_count_tick(vecs->mpvec);
-
+		if (vecs->mpvec) {
+			defered_failback_tick(vecs->mpvec);
+			retry_count_tick(vecs->mpvec);
+		}
 		if (count)
 			count--;
 		else {
@@ -1054,7 +1053,7 @@ configure (struct vectors * vecs, int start_waiters)
 	path_discovery(vecs->pathvec, conf, DI_ALL);
 
 	vector_foreach_slot (vecs->pathvec, pp, i){
-		if (filter_path(conf, pp)){
+		if (filter_path(conf, pp) > 0){
 			vector_del_slot(vecs->pathvec, i);
 			free_path(pp);
 			i--;
@@ -1068,7 +1067,7 @@ configure (struct vectors * vecs, int start_waiters)
 	/*
 	 * create new set of maps & push changed ones into dm
 	 */
-	if (coalesce_paths(vecs, mpvec, NULL))
+	if (coalesce_paths(vecs, mpvec, NULL, 0))
 		return 1;
 
 	/*
@@ -1085,7 +1084,7 @@ configure (struct vectors * vecs, int start_waiters)
 	/*
 	 * purge dm of old maps
 	 */
-	remove_maps(vecs, NULL);
+	remove_maps(vecs);
 
 	/*
 	 * save new set of maps formed by considering current path state
@@ -1115,7 +1114,7 @@ reconfigure (struct vectors * vecs)
 	 * free old map and path vectors ... they use old conf state
 	 */
 	if (VECTOR_SIZE(vecs->mpvec))
-		remove_maps(vecs, stop_waiter_thread);
+		remove_maps_and_stop_waiters(vecs);
 
 	if (VECTOR_SIZE(vecs->pathvec))
 		free_pathvec(vecs->pathvec, FREE_PATHS);
@@ -1265,6 +1264,15 @@ child (void * param)
 	if (load_config(DEFAULT_CONFIGFILE))
 		exit(1);
 
+	if (init_checkers()) {
+		condlog(0, "failed to initialize checkers");
+		exit(1);
+	}
+	if (init_prio()) {
+		condlog(0, "failed to initialize prioritizers");
+		exit(1);
+	}
+
 	setlogmask(LOG_UPTO(conf->verbosity + 3));
 
 	/*
@@ -1275,6 +1283,21 @@ child (void * param)
 		conf->max_checkint = MAX_CHECKINT(conf->checkint);
 	}
 
+	if (conf->max_fds) {
+		struct rlimit fd_limit;
+		if (conf->max_fds > 0) {
+			fd_limit.rlim_cur = conf->max_fds;
+			fd_limit.rlim_max = conf->max_fds;
+		}
+		else {
+			fd_limit.rlim_cur = RLIM_INFINITY;
+			fd_limit.rlim_max = RLIM_INFINITY;
+		}
+		if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0)
+			condlog(0, "can't set open fds limit to %d : %s\n",
+				conf->max_fds, strerror(errno));
+	}
+
 	if (pidfile_create(DEFAULT_PIDFILE, getpid())) {
 		if (logsink)
 			log_thread_stop();
@@ -1319,7 +1342,7 @@ child (void * param)
 	 * exit path
 	 */
 	lock(vecs->lock);
-	remove_maps(vecs, stop_waiter_thread);
+	remove_maps_and_stop_waiters(vecs);
 	free_pathvec(vecs->pathvec, FREE_PATHS);
 
 	pthread_cancel(check_thr);
@@ -1340,8 +1363,6 @@ child (void * param)
 	vecs->lock = NULL;
 	FREE(vecs);
 	vecs = NULL;
-	free_config(conf);
-	conf = NULL;
 
 	condlog(2, "--------shut down-------");
 
@@ -1351,6 +1372,14 @@ child (void * param)
 	dm_lib_release();
 	dm_lib_exit();
 
+	/*
+	 * Freeing config must be done after condlog() and dm_lib_exit(),
+	 * because logging functions like dlog() and dm_write_log()
+	 * reference the config.
+	 */
+	free_config(conf);
+	conf = NULL;
+
 #ifdef _DEBUG_
 	dbg_free_final(NULL);
 #endif
diff --git a/path_priority/pp_alua/LICENSE b/path_priority/pp_alua/LICENSE
deleted file mode 100644
index 9e31bbf..0000000
--- a/path_priority/pp_alua/LICENSE
+++ /dev/null
@@ -1,483 +0,0 @@
-
-		  GNU LIBRARY GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
-
- Copyright (C) 1991 Free Software Foundation, Inc.
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the library GPL.  It is
- numbered 2 because it goes with version 2 of the ordinary GPL.]
-
-			    Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
-  This license, the Library General Public License, applies to some
-specially designated Free Software Foundation software, and to any
-other libraries whose authors decide to use it.  You can use it for
-your libraries, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if
-you distribute copies of the library, or if you modify it.
-
-  For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you.  You must make sure that they, too, receive or can get the source
-code.  If you link a program with the library, you must provide
-complete object files to the recipients so that they can relink them
-with the library, after making changes to the library and recompiling
-it.  And you must show them these terms so they know their rights.
-
-  Our method of protecting your rights has two steps: (1) copyright
-the library, and (2) offer you this license which gives you legal
-permission to copy, distribute and/or modify the library.
-
-  Also, for each distributor's protection, we want to make certain
-that everyone understands that there is no warranty for this free
-library.  If the library is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original
-version, so that any problems introduced by others will not reflect on
-the original authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that companies distributing free
-software will individually obtain patent licenses, thus in effect
-transforming the program into proprietary software.  To prevent this,
-we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
-
-  Most GNU software, including some libraries, is covered by the ordinary
-GNU General Public License, which was designed for utility programs.  This
-license, the GNU Library General Public License, applies to certain
-designated libraries.  This license is quite different from the ordinary
-one; be sure to read it in full, and don't assume that anything in it is
-the same as in the ordinary license.
-
-  The reason we have a separate public license for some libraries is that
-they blur the distinction we usually make between modifying or adding to a
-program and simply using it.  Linking a program with a library, without
-changing the library, is in some sense simply using the library, and is
-analogous to running a utility program or application program.  However, in
-a textual and legal sense, the linked executable is a combined work, a
-derivative of the original library, and the ordinary General Public License
-treats it as such.
-
-  Because of this blurred distinction, using the ordinary General
-Public License for libraries did not effectively promote software
-sharing, because most developers did not use the libraries.  We
-concluded that weaker conditions might promote sharing better.
-
-  However, unrestricted linking of non-free programs would deprive the
-users of those programs of all benefit from the free status of the
-libraries themselves.  This Library General Public License is intended to
-permit developers of non-free programs to use free libraries, while
-preserving your freedom as a user of such programs to change the free
-libraries that are incorporated in them.  (We have not seen how to achieve
-this as regards changes in header files, but we have achieved it as regards
-changes in the actual functions of the Library.)  The hope is that this
-will lead to faster development of free libraries.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.  Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library".  The
-former contains code derived from the library, while the latter only
-works together with the library.
-
-  Note that it is possible for a library to be covered by the ordinary
-General Public License rather than by this special one.
-
-		  GNU LIBRARY GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License Agreement applies to any software library which
-contains a notice placed by the copyright holder or other authorized
-party saying it may be distributed under the terms of this Library
-General Public License (also called "this License").  Each licensee is
-addressed as "you".
-
-  A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
-  The "Library", below, refers to any such software library or work
-which has been distributed under these terms.  A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language.  (Hereinafter, translation is
-included without limitation in the term "modification".)
-
-  "Source code" for a work means the preferred form of the work for
-making modifications to it.  For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
-  Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it).  Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-  
-  1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
-  You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-
-  2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) The modified work must itself be a software library.
-
-    b) You must cause the files modified to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    c) You must cause the whole of the work to be licensed at no
-    charge to all third parties under the terms of this License.
-
-    d) If a facility in the modified Library refers to a function or a
-    table of data to be supplied by an application program that uses
-    the facility, other than as an argument passed when the facility
-    is invoked, then you must make a good faith effort to ensure that,
-    in the event an application does not supply such function or
-    table, the facility still operates, and performs whatever part of
-    its purpose remains meaningful.
-
-    (For example, a function in a library to compute square roots has
-    a purpose that is entirely well-defined independent of the
-    application.  Therefore, Subsection 2d requires that any
-    application-supplied function or table used by this function must
-    be optional: if the application does not supply it, the square
-    root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library.  To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License.  (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.)  Do not make any other change in
-these notices.
-
-  Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
-  This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
-  4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
-  If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library".  Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
-  However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library".  The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
-  When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library.  The
-threshold for this to be true is not precisely defined by law.
-
-  If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work.  (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
-  Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-
-  6. As an exception to the Sections above, you may also compile or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
-  You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License.  You must supply a copy of this License.  If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License.  Also, you must do one
-of these things:
-
-    a) Accompany the work with the complete corresponding
-    machine-readable source code for the Library including whatever
-    changes were used in the work (which must be distributed under
-    Sections 1 and 2 above); and, if the work is an executable linked
-    with the Library, with the complete machine-readable "work that
-    uses the Library", as object code and/or source code, so that the
-    user can modify the Library and then relink to produce a modified
-    executable containing the modified Library.  (It is understood
-    that the user who changes the contents of definitions files in the
-    Library will not necessarily be able to recompile the application
-    to use the modified definitions.)
-
-    b) Accompany the work with a written offer, valid for at
-    least three years, to give the same user the materials
-    specified in Subsection 6a, above, for a charge no more
-    than the cost of performing this distribution.
-
-    c) If distribution of the work is made by offering access to copy
-    from a designated place, offer equivalent access to copy the above
-    specified materials from the same place.
-
-    d) Verify that the user has already received a copy of these
-    materials or that you have already sent this user a copy.
-
-  For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it.  However, as a special exception,
-the source code distributed need not include anything that is normally
-distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
-  It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system.  Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-
-  7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
-    a) Accompany the combined library with a copy of the same work
-    based on the Library, uncombined with any other library
-    facilities.  This must be distributed under the terms of the
-    Sections above.
-
-    b) Give prominent notice with the combined library of the fact
-    that part of it is a work based on the Library, and explaining
-    where to find the accompanying uncombined form of the same work.
-
-  8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License.  Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License.  However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
-  9. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Library or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
-  10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded.  In such case, this License incorporates the limitation as if
-written in the body of this License.
-
-  13. The Free Software Foundation may publish revised and/or new
-versions of the Library General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation.  If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-
-  14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission.  For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this.  Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
-			    NO WARRANTY
-
-  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-
-     Appendix: How to Apply These Terms to Your New Libraries
-
-  If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change.  You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
-  To apply these terms, attach the following notices to the library.  It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the library's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This library is free software; you can redistribute it and/or
-    modify it under the terms of the GNU Library General Public
-    License as published by the Free Software Foundation; either
-    version 2 of the License, or (at your option) any later version.
-
-    This library is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-    Library General Public License for more details.
-
-    You should have received a copy of the GNU Library General Public
-    License along with this library; if not, write to the Free
-    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
-    MA 02111-1307, USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the
-  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
-  <signature of Ty Coon>, 1 April 1990
-  Ty Coon, President of Vice
-
-That's all there is to it!
diff --git a/path_priority/pp_alua/Makefile b/path_priority/pp_alua/Makefile
deleted file mode 100644
index 6f356a1..0000000
--- a/path_priority/pp_alua/Makefile
+++ /dev/null
@@ -1,54 +0,0 @@
-#==============================================================================
-# (C) Copyright IBM Corp. 2004, 2005   All Rights Reserved.
-#
-# Makefile
-#
-# Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
-# It determines the ALUA state of a device and prints a priority value to
-# stdout.
-#
-# Author(s): Jan Kunigk
-#            S. Bader <shbader@de.ibm.com>
-#
-# This file is released under the GPL.
-#==============================================================================
-EXEC		= mpath_prio_alua
-BUILD		= glibc
-DEBUG		= 0
-DEBUG_DUMPHEX	= 0
-OBJS		= main.o rtpg.o
-INSTALL		= install -D
-
-TOPDIR	= ../..
-
-ifneq ($(shell ls $(TOPDIR)/Makefile.inc 2>/dev/null),)
-include $(TOPDIR)/Makefile.inc
-endif
-
-CFLAGS += -DDEBUG=$(DEBUG)
-
-all: $(BUILD)
-
-glibc:	$(OBJS)
-	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
-
-klibc:	$(OBJS)
-	$(CC) -static -o $(EXEC) $(OBJS)
-
-install: $(EXEC) $(EXEC).8.gz
-	$(INSTALL) -s -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
-	$(INSTALL) -m 644 $(EXEC).8.gz $(DESTDIR)$(mandir)/$(EXEC).8.gz
-
-uninstall:
-	rm $(DESTDIR)$(bindir)/$(EXEC)
-	rm $(DESTDIR)$(mandir)/$(EXEC).8.gz
-
-clean:	
-	rm -f *.o *.gz $(EXEC)
-
-$(EXEC).8.gz:	$(EXEC).8
-	$(GZIP) $< >$@
-
-main.o:	main.c rtpg.h spc3.h
-
-rtpg.o:	rtpg.c rtpg.h spc3.h
diff --git a/path_priority/pp_alua/main.c b/path_priority/pp_alua/main.c
deleted file mode 100644
index ba8da99..0000000
--- a/path_priority/pp_alua/main.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * (C) Copyright IBM Corp. 2004, 2005   All Rights Reserved.
- *
- * main.c
- *
- * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
- * It determines the ALUA state of a device and prints a priority value to
- * stdout.
- *
- * Author(s): Jan Kunigk
- *            S. Bader <shbader@de.ibm.com>
- * 
- * This file is released under the GPL.
- */
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <strings.h>
-
-#include "rtpg.h"
-
-#define ALUA_PRIO_SUCCESS			0
-#define ALUA_PRIO_INVALID_COMMANDLINE		1
-#define ALUA_PRIO_OPEN_FAILED			2
-#define ALUA_PRIO_NOT_SUPPORTED			3
-#define ALUA_PRIO_RTPG_FAILED			4
-#define ALUA_PRIO_GETAAS_FAILED			5
-
-#define ALUA_PRIO_MAJOR				0
-#define ALUA_PRIO_MINOR				6
-
-#define PRINT_ERROR(f, a...) \
-		if (verbose) \
-		fprintf(stderr, "ERROR: " f, ##a)
-#define PRINT_VERBOSE(f, a...) \
-		if (verbose) \
-			printf(f, ##a)
-
-char *	devicename	= NULL;
-int	verbose		= 0;
-
-char *basename(char *p)
-{
-	char *r;
-
-	for(r = p; *r != '\0'; r++);
-	for(; r > p && *(r - 1) != '/'; r--);
-
-	return r;
-}
-
-void
-print_help(char *command)
-{
-	printf("Usage: %s <options> <device> [<device> [...]]\n\n",
-		basename(command));
-	printf("Options are:\n");
-
-	printf("\t-d <device directory>\n");
-	printf("\t\tSets the directory prefix for relative path names and");
-	printf(" created\n\t\tpath names. (default = \"/dev\")\n");
-
-	printf("\t-h\n");
-	printf("\t\tPrint this help.\n");
-
-	printf("\t-v\n");
-	printf("\t\tTurn on verbose output.\n");
-
-	printf("\t-V\n");
-	printf("\t\tPrints the version number and exits.\n");
-
-	printf("\nDevice may be an absolute or relative path to a device ");
-	printf("node or a major and\nminor number seperated by a colon (:).");
-	printf(" In this case a temporary device node\nwill be created in ");
-	printf("the device directory.\n");
-}
-
-void
-print_version(char *command)
-{
-	printf("(C) Copyright IBM Corp. 2004, 2005  All Rights Reserved.\n");
-	printf("This is %s version %u.%u\n",
-		basename(command),
-		ALUA_PRIO_MAJOR,
-		ALUA_PRIO_MINOR
-	);
-}
-
-int
-open_block_device(char *name)
-{
-	int		fd;
-	struct stat	st;
-
-	if (stat(name, &st) != 0) {
-		PRINT_ERROR("Cannot get file status from %s (errno = %i)!\n",
-			name, errno);
-		return -ALUA_PRIO_OPEN_FAILED;
-	}
-	if (!S_ISBLK(st.st_mode)) {
-		PRINT_ERROR("%s is not a block device!\n", name);
-		return -ALUA_PRIO_OPEN_FAILED;
-	}
-	fd = open(name, O_RDONLY);
-	if (fd < 0) {
-		PRINT_ERROR("Couldn't open %s (errno = %i)!\n", name, errno);
-		return -ALUA_PRIO_OPEN_FAILED;
-	}
-	return fd;
-}
-
-int
-close_block_device(int fd)
-{
-	return close(fd);
-}
-
-int
-get_alua_info(int fd)
-{
-	char *	aas_string[] = {
-		[AAS_OPTIMIZED]		= "active/optimized",
-		[AAS_NON_OPTIMIZED]	= "active/non-optimized",
-		[AAS_STANDBY]		= "standby",
-		[AAS_UNAVAILABLE]	= "unavailable",
-		[AAS_TRANSITIONING]	= "transitioning between states",
-	};
-	int	rc;
-	int	tpg;
-
-	rc = get_target_port_group_support(fd);
-	if (rc < 0)
-		return rc;
-
-	if (verbose) {
-		printf("Target port groups are ");
-		switch(rc) {
-			case TPGS_NONE:
-				printf("not");
-				break;
-			case TPGS_IMPLICIT:
-				printf("implicitly");
-				break;
-			case TPGS_EXPLICIT:
-				printf("explicitly");
-				break;
-			case TPGS_BOTH:
-				printf("implicitly and explicitly");
-				break;
-		}
-		printf(" supported.\n");
-	}
-
-	if (rc == TPGS_NONE)
-		return -ALUA_PRIO_NOT_SUPPORTED;
-
-	tpg = get_target_port_group(fd);
-	if (tpg < 0) {
-		PRINT_ERROR("Couldn't get target port group!\n");
-		return -ALUA_PRIO_RTPG_FAILED;
-	}
-	PRINT_VERBOSE("Reported target port group is %i", tpg);
-
-	rc = get_asymmetric_access_state(fd, tpg);
-	if (rc < 0) {
-		PRINT_VERBOSE(" [get AAS failed]\n");
-		PRINT_ERROR("Couln't get asymmetric access state!\n");
-		return -ALUA_PRIO_GETAAS_FAILED;
-	}
-	PRINT_VERBOSE(" [%s]\n",
-		(aas_string[rc]) ? aas_string[rc] : "invalid/reserved"
-	);
-
-	return rc;
-}
-
-int
-main (int argc, char **argv)
-{
-	char		devicepath[PATH_MAX];
-	char *		devicedir;
-	char *		s_opts = "d:hvV";
-	char *		pos;
-	int		fd;
-	int		rc;
-	int		c;
-
-	devicedir = "/dev";
-	while ((c = getopt(argc, argv, s_opts)) >= 0) {
-		switch(c) {
-			case 'd':
-				devicedir = optarg;
-				break;
-			case 'h':
-				print_help(argv[0]);
-				return ALUA_PRIO_SUCCESS;
-			case 'V':
-				print_version(argv[0]);
-				return ALUA_PRIO_SUCCESS;
-			case 'v':
-				verbose = 1;
-				break;
-			case '?':
-			case ':':
-			default:
-				return ALUA_PRIO_INVALID_COMMANDLINE;
-		}
-	}
-
-	if (optind == argc) {
-		print_help(argv[0]);
-		printf("\n");
-		PRINT_ERROR("No device specified!\n");
-		return ALUA_PRIO_INVALID_COMMANDLINE;
-	}
-
-	rc = ALUA_PRIO_SUCCESS;
-	for(c = optind; c < argc && !rc; c++) {
-		if (argv[c][0] == '/') {
-			pos = NULL;
-			sprintf(devicepath, "%s", argv[c]);
-		} else if ((pos = index(argv[c], ':')) == NULL) {
-			sprintf(devicepath, "%s/%s", devicedir, argv[c]);
-		} else {
-			int major;
-			int minor;
-
-			major = atoi(argv[c]);
-			minor = atoi(++pos);
-			sprintf(devicepath, "%s/tmpdev-%u:%u-%u",
-				devicedir, major, minor, getpid()
-			);
-			mknod(
-				devicepath,
-				S_IFBLK|S_IRUSR|S_IWUSR,
-				makedev(major, minor)
-			);
-			
-		}
-
-		fd = open_block_device(devicepath);
-		if (fd < 0) {
-			if (pos != NULL)
-				unlink(devicepath);
-			return -fd;
-		}
-		rc = get_alua_info(fd);
-		if (rc >= 0) {
-			switch(rc) {
-				case AAS_OPTIMIZED:
-					rc = 50;
-					break;
-				case AAS_NON_OPTIMIZED:
-					rc = 10;
-					break;
-				case AAS_STANDBY:
-					rc = 1;
-					break;
-				default:
-					rc = 0;
-			}
-			printf("%u\n", rc);
-			rc = ALUA_PRIO_SUCCESS;
-		}
-		close_block_device(fd);
-
-		/* The path was created before. */
-		if (pos != NULL)
-			unlink(devicepath);
-	}
-
-	return -rc;
-}
diff --git a/path_priority/pp_alua/mpath_prio_alua.8 b/path_priority/pp_alua/mpath_prio_alua.8
deleted file mode 100644
index 58568a5..0000000
--- a/path_priority/pp_alua/mpath_prio_alua.8
+++ /dev/null
@@ -1,162 +0,0 @@
-.TH MPATH_PRIO_ALUA 8 "July 2006" "multipath-tools" \
-"Linux Administrator's Manual"
-.SH NAME
-mpath_prio_alua \- Path priority tool based on Asymmetric LUn Access
-.SH SYNOPSIS
-.B mpath_prio_alua
-.RB [\| \-d\ \c
-.IR directory \|]
-.RB [\| \-h \|]
-.RB [\| \-v \|]
-.RB [\| \-V \|]
-.IR device " \|[ " device " \|[ " ... " \|]\|]"
-.SH DESCRIPTION
-.B mpath_prio_alua
-is used as a priority callout for the multipath command. It returns a number
-that is used by multipath to group devices with the same priority together.
-.SH OPTIONS
-.TP
-.BI \-d " directory"
-target directory for devices given as relative device names or devices given
-as
-.IR major : minor \c
- number.
-Default is "/dev".
-.TP
-.B \-h
-displays the command line help.
-.TP
-.B  \-v
-turns on verbose output. This shows all results in human readable format.
-This includes information about the port group the device is in and its
-current state.
-.TP
-.B  \-V
-shows the version number and exits.
-.TP
-.BI device
-specifies the device to query (the device must be a SCSI device that supports
-the \*[lq]Report Target Port Groups\*[rq] command).
-One of the following three formats may be used:
-.RS
-.IP \(bu 2
-The full path name that starts with '/' (e.g. /dev/sda).
-.IP \(bu
-The device name only. This will prefix the directory name given by the
-\-d option (e.g. sda).
-.IP \(bu
-The major and minor number of the device separated by ':'. This will
-create a temporary device node in the device directory (e.g. 8:0). The
-temporary name will be
-.RB \*[lq] tmpdev-<major>:<minor>-<pid> \*[rq].
-.SH "RETURN VALUE"
-The mpath_prio_alua command returns the following values:
-.IP \fB0
-on success. In this case the priority for the device is printed to
-stdout. The priority value is:
-.RS
-.IP \fB50\fP
-for devices that are in the active, optimized group
-.IP \fB10
-for devices that are in an active but non-optimized group
-.IP \fB1
-for devices that are in the standby group
-.IP \fB0
-for all other groups
-.RE
-.IP ""
-The reason for the widely spaced priority values is the way multipath handles
-them. It will multiply the number of paths in a group with the priority value
-and select the group with the highest result. Thus, if there are six paths in
-the active, non-optimized group and only one in the active, optimized one,
-the non-optimized group would be used.
-.IP \fB1
-Indicates an error parsing the command line.
-.IP \fB2
-The given devices could not be opened for reading.
-.IP \fB3
-The device does not support target port groups.
-.IP \fB4
-The inquiry command did not return a target port group for the given device.
-.IP \fB5
-The report target port group command failed or did not return a target
-port group that was obtained from the inquiry command.
-.SH "EXAMPLES"
-This example queries a device directly and returns the priority string:
-.P
-.RS
-.B #> mpath_prio_alua /dev/sda
-.br
-50
-.RE
-.P
-Now the major and minor number is used to specify the device and verbose
-output is selected:
-.P
-.RS
-.B #> mpath_prio_alua -v 8:0
-.br
-Target port groups are implicitly supported.
-.br
-Reported target port group is 0 [active/optimized]
-.br
-50
-.RE
-.P
-The following example shows the entries in the devices section of the
-.RI "multipath-tool configuration file (" /etc/multipath.conf )
-to support an IBM DS6000 storage system:
-.P
-.RS
-.PD 0
-device {
-.RS
-.TP 22
-.B  vendor
-"IBM       "
-.TP
-.B  product
-"1750500         "
-.TP
-.B  path_grouping_policy
-group_by_prio
-.TP
-.B  prio_callout
-"/sbin/mpath_prio_alua -d/tmp %d"
-.TP
-.B  features
-"1 queue_if_no_path"
-.TP
-.B  path_checker
-tur
-.RE
-}
-.PD
-.RE
-.TP
-.B  Notes:
-.IP \(bu 2
-Depending on your default configuration not all keywords are required
-.RB "(e.g. if your " path_checker " is set to tur you don't have to"
-.RB "use the " path_checker " statement in the device section)."
-.IP \(bu
-.RB "The entries for " vendor " and " product " must be strings that are 8"
-.RB "characters long (for " vendor ") and 16 characters long (for " product ")."
-The strings have to be padded with blanks if necessary.
-.IP \(bu
-If you are working with hotpluggable devices whose device nodes are created
-by udev you should use the %d flag in the
-.BR prio_callout " statement."
-This is because a short time elapses between the devices being available
-and udev creating the device nodes.
-.IP \(bu
-If under certain circumstances your storage subsystem temporarily reports
-.RB "failures on all paths, you should use the " features " statement showed"
-in the example.
-This will configure the multipath volume to requeue I/O until a path becomes
-available again, instead of reporting failures in that case.
-.SH "SEE ALSO"
-.BR multipath (8),
-.SH AUTHORS
-.B mpath_prio_alua
-was developed by Jan Kunigk and adapted by Stefan Bader <shbader@de.ibm.com>
diff --git a/path_priority/pp_alua/rtpg.c b/path_priority/pp_alua/rtpg.c
deleted file mode 100644
index 701f9d5..0000000
--- a/path_priority/pp_alua/rtpg.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * (C) Copyright IBM Corp. 2004, 2005   All Rights Reserved.
- *
- * rtpg.c
- *
- * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
- * It determines the ALUA state of a device and prints a priority value to
- * stdout.
- *
- * Author(s): Jan Kunigk
- *            S. Bader <shbader@de.ibm.com>
- * 
- * This file is released under the GPL.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-#include <inttypes.h>
-
-#define __user
-#include <scsi/sg.h>
-
-#include "rtpg.h"
-
-#define SENSE_BUFF_LEN  32
-#define DEF_TIMEOUT     300000
-
-/*
- * Macro used to print debug messaged.
- */
-#if DEBUG > 0
-#define PRINT_DEBUG(f, a...) \
-		fprintf(stderr, "DEBUG: " f, ##a)
-#else
-#define PRINT_DEBUG(f, a...)
-#endif
-
-/*
- * Optionally print the commands sent and the data received a hex dump.
- */
-#if DEBUG > 0
-#if DEBUG_DUMPHEX > 0
-#define PRINT_HEX(p, l)	print_hex(p, l)
-void
-print_hex(unsigned char *p, unsigned long len)
-{
-	int	i;
-
-	for(i = 0; i < len; i++) {
-		if (i % 16 == 0)
-			printf("%04x: ", i);
-		printf("%02x%s", p[i], (((i + 1) % 16) == 0) ? "\n" : " ");
-	}
-	printf("\n");
-}
-#else
-#define PRINT_HEX(p, l)
-#endif
-#else
-#define PRINT_HEX(p, l)
-#endif
-
-/*
- * Returns 0 if the SCSI command either was successful or if the an error was
- * recovered, otherwise 1. (definitions taken from sg_err.h)
- */
-#define SCSI_CHECK_CONDITION    0x2
-#define SCSI_COMMAND_TERMINATED 0x22
-#define SG_ERR_DRIVER_SENSE     0x08
-#define RECOVERED_ERROR 0x01
-
-static int
-scsi_error(struct sg_io_hdr *hdr)
-{
-	/* Treat SG_ERR here to get rid of sg_err.[ch] */
-        hdr->status &= 0x7e;
-
-	if (
-		(hdr->status == 0)        &&
-		(hdr->host_status == 0)   &&
-		(hdr->driver_status == 0)
-	) {
-		return 0;
-	}
-
-	if (
-		(hdr->status == SCSI_CHECK_CONDITION)    ||
-		(hdr->status == SCSI_COMMAND_TERMINATED) ||
-		((hdr->driver_status & 0xf) == SG_ERR_DRIVER_SENSE)
-	) {
-		if (hdr->sbp && (hdr->sb_len_wr > 2)) {
-			int		sense_key;
-			unsigned char *	sense_buffer = hdr->sbp;
-
-			if (sense_buffer[0] & 0x2)
-				sense_key = sense_buffer[1] & 0xf;
-			else
-				sense_key = sense_buffer[2] & 0xf;
-
-			if (sense_key == RECOVERED_ERROR)
-				return 0;
-		}
-	}
-
-	return 1;
-}
-
-/*
- * Helper function to setup and run a SCSI inquiry command.
- */
-int
-do_inquiry(int fd, int evpd, unsigned int codepage, void *resp, int resplen)
-{
-	struct inquiry_command	cmd;
-	struct sg_io_hdr	hdr;
-	unsigned char		sense[SENSE_BUFF_LEN];
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.op = OPERATION_CODE_INQUIRY;
-	if (evpd) {
-		inquiry_command_set_evpd(&cmd);
-		cmd.page = codepage;
-	}
-	set_uint16(cmd.length, resplen);
-	PRINT_HEX((unsigned char *) &cmd, sizeof(cmd));
-
-        memset(&hdr, 0, sizeof(hdr));
-        hdr.interface_id	= 'S';
-        hdr.cmdp		= (unsigned char *) &cmd;
-        hdr.cmd_len		= sizeof(cmd);
-        hdr.dxfer_direction	= SG_DXFER_FROM_DEV;
-        hdr.dxferp		= resp;
-        hdr.dxfer_len		= resplen;
-        hdr.sbp			= sense;
-        hdr.mx_sb_len		= sizeof(sense);
-        hdr.timeout		= DEF_TIMEOUT;
- 
-        if (ioctl(fd, SG_IO, &hdr) < 0) {
-		PRINT_DEBUG("do_inquiry: IOCTL failed!\n");
-		return -RTPG_INQUIRY_FAILED;
-	}
-
-	if (scsi_error(&hdr)) {
-		PRINT_DEBUG("do_inquiry: SCSI error!\n");
-		return -RTPG_INQUIRY_FAILED;
-	}
-	PRINT_HEX((unsigned char *) resp, resplen);
- 
-        return 0;
-}
-
-/*
- * This function returns the support for target port groups by evaluating the
- * data returned by the standard inquiry command.
- */
-int
-get_target_port_group_support(int fd)
-{
-	struct inquiry_data	inq;
-	int			rc;
-
-	rc = do_inquiry(fd, 0, 0x00, &inq, sizeof(inq));
-	if (!rc) {
-		rc = inquiry_data_get_tpgs(&inq);
-	}
-
-	return rc;
-}
-
-int
-get_target_port_group(int fd)
-{
-	unsigned char		buf[128];
-	struct vpd83_data *	vpd83;
-	struct vpd83_dscr *	dscr;
-	int			rc;
-
-	rc = do_inquiry(fd, 1, 0x83, buf, sizeof(buf));
-	if (!rc) {
-		vpd83 = (struct vpd83_data *) buf;
-
-		rc = -RTPG_NO_TPG_IDENTIFIER;
-		FOR_EACH_VPD83_DSCR(vpd83, dscr) {
-			if ((((char *) dscr) - ((char *) vpd83)) > sizeof(buf))
-				break;
-
-			if (vpd83_dscr_istype(dscr, IDTYPE_TARGET_PORT_GROUP)) {
-				struct vpd83_tpg_dscr *	p;
-
-				if (rc != -RTPG_NO_TPG_IDENTIFIER) {
-					PRINT_DEBUG("get_target_port_group: "
-						"more than one TPG identifier "
-						"found!\n");
-					continue;
-				}
-
-				p  = (struct vpd83_tpg_dscr *) dscr->data;
-				rc = get_uint16(p->tpg);
-			}
-		}
-		if (rc == -RTPG_NO_TPG_IDENTIFIER) {
-			PRINT_DEBUG("get_target_port_group: "
-				"no TPG identifier found!\n");
-		}
-	}
-
-	return rc;
-}
-
-int
-do_rtpg(int fd, void* resp, long resplen)
-{
-	struct rtpg_command	cmd;
-	struct sg_io_hdr	hdr;
-	unsigned char		sense[SENSE_BUFF_LEN];
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.op			= OPERATION_CODE_RTPG;
-	rtpg_command_set_service_action(&cmd);
-	set_uint32(cmd.length, resplen);
-	PRINT_HEX((unsigned char *) &cmd, sizeof(cmd));
-
-        memset(&hdr, 0, sizeof(hdr));
-	hdr.interface_id	= 'S';
-        hdr.cmdp		= (unsigned char *) &cmd;
-        hdr.cmd_len		= sizeof(cmd);
-        hdr.dxfer_direction	= SG_DXFER_FROM_DEV;
-        hdr.dxferp		= resp;
-        hdr.dxfer_len		= resplen;
-        hdr.mx_sb_len		= sizeof(sense);
-        hdr.sbp			= sense;
-        hdr.timeout		= DEF_TIMEOUT;
- 
-	if (ioctl(fd, SG_IO, &hdr) < 0)
-                return -RTPG_RTPG_FAILED;
-
-	if (scsi_error(&hdr)) {
-		PRINT_DEBUG("do_rtpg: SCSI error!\n");
-		return -RTPG_RTPG_FAILED;
-	}
-	PRINT_HEX(resp, resplen);
-
-        return 0;
-} 
-
-int
-get_asymmetric_access_state(int fd, unsigned int tpg)
-{
-	unsigned char		*buf;
-	struct rtpg_data *	tpgd;
-	struct rtpg_tpg_dscr *	dscr;
-	int			rc;
-	int			buflen;
-	uint32_t		scsi_buflen;
-
-	buflen = 128; /* Initial value from old code */
-	buf = (unsigned char *)malloc(buflen);
-	if (!buf) {
-		PRINT_DEBUG ("malloc failed: could not allocate"
-			"%u bytes\n", buflen);
-		return -RTPG_RTPG_FAILED;
-	}
-	rc = do_rtpg(fd, buf, buflen);
-	if (rc < 0)
-		return rc;
-	scsi_buflen = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
-	if (buflen < (scsi_buflen + 4)) {
-		free(buf);
-		buf = (unsigned char *)malloc(scsi_buflen);
-		if (!buf) {
-			PRINT_DEBUG ("malloc failed: could not allocate"
-				"%u bytes\n", scsi_buflen);
-			return -RTPG_RTPG_FAILED;
-		}
-		buflen = scsi_buflen;
-		rc = do_rtpg(fd, buf, buflen);
-		if (rc < 0)
-			goto out;
-	}
-		
-
-	tpgd = (struct rtpg_data *) buf;
-	rc   = -RTPG_TPG_NOT_FOUND;
-	RTPG_FOR_EACH_PORT_GROUP(tpgd, dscr) {
-		if (get_uint16(dscr->tpg) == tpg) {
-			if (rc != -RTPG_TPG_NOT_FOUND) {
-				PRINT_DEBUG("get_asymmetric_access_state: "
-					"more than one entry with same port "
-					"group.\n");
-			} else {
-				PRINT_DEBUG("pref=%i\n", dscr->pref);
-				rc = rtpg_tpg_dscr_get_aas(dscr);
-			}
-		}
-	}
-out:
-	free(buf);
-	return rc;
-}
-
diff --git a/path_priority/pp_alua/rtpg.h b/path_priority/pp_alua/rtpg.h
deleted file mode 100644
index 3c5dcf1..0000000
--- a/path_priority/pp_alua/rtpg.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * (C) Copyright IBM Corp. 2004, 2005   All Rights Reserved.
- *
- * rtpg.h
- *
- * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
- * It determines the ALUA state of a device and prints a priority value to
- * stdout.
- *
- * Author(s): Jan Kunigk
- *            S. Bader <shbader@de.ibm.com>
- * 
- * This file is released under the GPL.
- */
-#ifndef __RTPG_H__
-#define __RTPG_H__
-#include "spc3.h"
-
-#define RTPG_SUCCESS				0
-#define RTPG_INQUIRY_FAILED			1
-#define RTPG_NO_TPG_IDENTIFIER			2
-#define RTPG_RTPG_FAILED			3
-#define RTPG_TPG_NOT_FOUND			4
-
-int get_target_port_group_support(int fd);
-int get_target_port_group(int fd);
-int get_asymmetric_access_state(int fd, unsigned int tpg);
-
-#endif /* __RTPG_H__ */
-
diff --git a/path_priority/pp_alua/spc3.h b/path_priority/pp_alua/spc3.h
deleted file mode 100644
index bddbbdd..0000000
--- a/path_priority/pp_alua/spc3.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * (C) Copyright IBM Corp. 2004, 2005   All Rights Reserved.
- *
- * spc3.h
- *
- * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
- * It determines the ALUA state of a device and prints a priority value to
- * stdout.
- *
- * Author(s): Jan Kunigk
- *            S. Bader <shbader@de.ibm.com>
- * 
- * This file is released under the GPL.
- */
-#ifndef __SPC3_H__
-#define __SPC3_H__
-/*=============================================================================
- * Some helper functions for getting and setting 16 and 32 bit values.
- *=============================================================================
- */
-static inline unsigned short
-get_uint16(unsigned char *p)
-{
-	return (p[0] << 8) + p[1];
-}
-
-static inline void
-set_uint16(unsigned char *p, unsigned short v)
-{
-	p[0] = (v >> 8) & 0xff;
-	p[1] = v & 0xff;
-}
-
-static inline unsigned int
-get_uint32(unsigned char *p)
-{
-	return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
-}
-
-static inline void
-set_uint32(unsigned char *p, unsigned int v)
-{
-	p[0] = (v >> 24) & 0xff;
-	p[1] = (v >> 16) & 0xff;
-	p[2] = (v >>  8) & 0xff;
-	p[3] = v & 0xff;
-}
-
-/*=============================================================================
- * Definitions to support the standard inquiry command as defined in SPC-3.
- * If the evpd (enable vital product data) bit is set the data that will be
- * returned is selected by the page field. This field must be 0 if the evpd
- * bit is not set.
- *=============================================================================
- */
-#define OPERATION_CODE_INQUIRY		0x12
-
-struct inquiry_command {
-	unsigned char	op;
-	unsigned char	b1;		/* xxxxxx.. = reserved               */
-					/* ......x. = obsolete               */
-					/* .......x = evpd                   */
-	unsigned char	page;
-	unsigned char	length[2];
-	unsigned char	control;
-} __attribute__((packed));
-
-static inline void
-inquiry_command_set_evpd(struct inquiry_command *ic)
-{
-	ic->b1 |= 1;
-}
-
-/*-----------------------------------------------------------------------------
- * Data returned by the standard inquiry command.
- *-----------------------------------------------------------------------------
- *
- * Peripheral qualifier codes.
- */
-#define PQ_CONNECTED					0x0
-#define PQ_DISCONNECTED					0x1
-#define PQ_UNSUPPORTED					0x3
-
-/* Defined peripheral device types. */
-#define PDT_DIRECT_ACCESS				0x00
-#define PDT_SEQUENTIAL_ACCESS				0x01
-#define PDT_PRINTER					0x02
-#define PDT_PROCESSOR					0x03
-#define PDT_WRITE_ONCE					0x04
-#define PDT_CD_DVD					0x05
-#define PDT_SCANNER					0x06
-#define PDT_OPTICAL_MEMORY				0x07
-#define PDT_MEDIUM_CHANGER				0x08
-#define PDT_COMMUNICATIONS				0x09
-#define PDT_STORAGE_ARRAY_CONTROLLER			0x0c
-#define PDT_ENCLOSURE_SERVICES				0x0d
-#define PDT_SIMPLIFIED_DIRECT_ACCESS			0x0e
-#define PDT_OPTICAL_CARD_READER_WRITER			0x0f
-#define PDT_BRIDGE_CONTROLLER				0x10
-#define PDT_OBJECT_BASED				0x11
-#define PDT_AUTOMATION_INTERFACE			0x12
-#define PDT_LUN						0x1e
-#define PDT_UNKNOWN					0x1f
-
-/* Defined version codes. */
-#define VERSION_NONE					0x00
-#define VERSION_SPC					0x03
-#define VERSION_SPC2					0x04
-#define VERSION_SPC3					0x05
-
-/* Defined TPGS field values. */
-#define TPGS_NONE					0x0
-#define TPGS_IMPLICIT					0x1
-#define TPGS_EXPLICIT					0x2
-#define TPGS_BOTH					0x3
-
-struct inquiry_data {
-	unsigned char	b0;		/* xxx..... = peripheral_qualifier   */
-					/* ...xxxxx = peripheral_device_type */
-	unsigned char	b1;             /* x....... = removable medium       */
-					/* .xxxxxxx = reserverd              */
-	unsigned char	version;
-	unsigned char	b3;		/* xx...... = obsolete               */
-					/* ..x..... = normal aca supported   */
-					/* ...x.... = hirarchichal lun supp. */
-					/* ....xxxx = response format        */
-					/*            2 is spc-3 format      */
-	unsigned char	length;
-	unsigned char	b5;		/* x....... = storage controller     */
-					/*            component supported    */
-					/* .x...... = access controls coord. */
-					/* ..xx.... = target port group supp.*/
-					/* ....x... = third party copy supp. */
-					/* .....xx. = reserved               */
-					/* .......x = protection info supp.  */
-	unsigned char	b6;		/* x....... = bque                   */
-					/* .x...... = enclosure services sup.*/
-					/* ..x..... = vs1                    */
-					/* ...x.... = multiport support      */
-					/* ....x... = medium changer         */
-					/* .....xx. = obsolete               */
-					/* .......x = add16                  */
-	unsigned char	b7;		/* xx...... = obsolete               */
-					/* ..x..... = wbus16                 */
-					/* ...x.... = sync                   */
-					/* ....x... = linked commands supp.  */
-					/* .....x.. = obsolete               */
-					/* ......x. = command queue support  */
-					/* .......x = vs2                    */
-	unsigned char	vendor_identification[8];
-	unsigned char	product_identification[16];
-	unsigned char	product_revision[4];
-	unsigned char	vendor_specific[20];
-	unsigned char	b56;		/* xxxx.... = reserved               */
-					/* ....xx.. = clocking               */
-					/* ......x. = qas                    */
-					/* .......x = ius                    */
-	unsigned char	reserved4;
-	unsigned char	version_descriptor[8][2];
-	unsigned char	reserved5[22];
-	unsigned char	vendor_parameters[0];
-} __attribute__((packed));
-
-static inline int
-inquiry_data_get_tpgs(struct inquiry_data *id)
-{
-	return (id->b5 >> 4) & 3;
-}
-
-/*-----------------------------------------------------------------------------
- * Inquiry data returned when requesting vital product data page 0x83.
- *-----------------------------------------------------------------------------
- */
-#define CODESET_BINARY			0x1
-#define CODESET_ACSII			0x2
-#define CODESET_UTF8			0x3
-
-#define ASSOCIATION_UNIT		0x0
-#define ASSOCIATION_PORT		0x1
-#define ASSOCIATION_DEVICE		0x2
-
-#define IDTYPE_VENDOR_SPECIFIC		0x0
-#define IDTYPE_T10_VENDOR_ID		0x1
-#define IDTYPE_EUI64			0x2
-#define IDTYPE_NAA			0x3
-#define IDTYPE_RELATIVE_TPG_ID		0x4
-#define IDTYPE_TARGET_PORT_GROUP	0x5
-#define IDTYPE_LUN_GROUP		0x6
-#define IDTYPE_MD5_LUN_ID		0x7
-#define IDTYPE_SCSI_NAME_STRING		0x8
-
-struct vpd83_tpg_dscr {
-	unsigned char		reserved1[2];
-	unsigned char		tpg[2];
-} __attribute__((packed));
-
-struct vpd83_dscr {
-	unsigned char		b0;	/* xxxx.... = protocol id            */
-					/* ....xxxx = codeset                */
-	unsigned char		b1;	/* x....... = protocol id valid      */
-					/* .x...... = reserved               */
-					/* ..xx.... = association            */
-					/* ....xxxx = id type                */
-	unsigned char		reserved2;
-	unsigned char		length;				/* size-4    */
-	unsigned char		data[0];
-} __attribute__((packed));
-
-static inline int
-vpd83_dscr_istype(struct vpd83_dscr *d, unsigned char type)
-{
-	return ((d->b1 & 7) == type);
-}
-
-struct vpd83_data {
-	unsigned char		b0;	/* xxx..... = peripheral_qualifier   */
-					/* ...xxxxx = peripheral_device_type */
-	unsigned char		page_code;			/* 0x83      */
-	unsigned char		length[2];			/* size-4    */
-	struct vpd83_dscr	data[0];
-} __attribute__((packed));
-
-/*-----------------------------------------------------------------------------
- * This macro should be used to walk through all identification descriptors
- * defined in the code page 0x83.
- * The argument p is a pointer to the code page 0x83 data and d is used to
- * point to the current descriptor.
- *-----------------------------------------------------------------------------
- */
-#define FOR_EACH_VPD83_DSCR(p, d) \
-		for( \
-			d = p->data; \
-			(((char *) d) - ((char *) p)) < \
-			get_uint16(p->length); \
-			d = (struct vpd83_dscr *) \
-				((char *) d + d->length + 4) \
-		)
-
-/*=============================================================================
- * The following stuctures and macros are used to call the report target port
- * groups command defined in SPC-3.
- * This command is used to get information about the target port groups (which
- * states are supported, which ports belong to this group, and so on) and the
- * current state of each target port group.
- *=============================================================================
- */
-#define OPERATION_CODE_RTPG		0xa3
-#define SERVICE_ACTION_RTPG		0x0a
-
-struct rtpg_command {
-	unsigned char		op;	/* 0xa3                              */
-	unsigned char		b1;	/* xxx..... = reserved               */
-					/* ...xxxxx = service action (0x0a)  */
-	unsigned char			reserved2[4];
-	unsigned char			length[4];
-	unsigned char			reserved3;
-	unsigned char			control;
-} __attribute__((packed));
-
-static inline void
-rtpg_command_set_service_action(struct rtpg_command *cmd)
-{
-	cmd->b1 = (cmd->b1 & 0xe0) | SERVICE_ACTION_RTPG;
-}
-
-struct rtpg_tp_dscr {
-	unsigned char			obsolete1[2];
-	/* The Relative Target Port Identifier of a target port. */
-	unsigned char			rtpi[2];
-} __attribute__((packed));
-
-#define AAS_OPTIMIZED			0x0
-#define AAS_NON_OPTIMIZED		0x1
-#define AAS_STANDBY			0x2
-#define AAS_UNAVAILABLE			0x3
-#define AAS_TRANSITIONING		0xf
-
-#define TPG_STATUS_NONE			0x0
-#define TPG_STATUS_SET			0x1
-#define TPG_STATUS_IMPLICIT_CHANGE	0x2
-
-struct rtpg_tpg_dscr {
-	unsigned char	b0;		/* x....... = pref(ered) port        */
-					/* .xxx.... = reserved               */
-					/* ....xxxx = asymetric access state */
-	unsigned char	b1;		/* xxxx.... = reserved               */
-					/* ....x... = unavailable support    */
-					/* .....x.. = standby support        */
-					/* ......x. = non-optimized support  */
-					/* .......x = optimized support      */
-	unsigned char			tpg[2];
-	unsigned char			reserved3;
-	unsigned char			status;
-	unsigned char			vendor_unique;
-	unsigned char			port_count;
-	struct rtpg_tp_dscr		data[0];
-} __attribute__((packed));
-
-static inline int
-rtpg_tpg_dscr_get_aas(struct rtpg_tpg_dscr *d)
-{
-	return (d->b0 & 0x0f);
-}
-
-struct rtpg_data {
-	unsigned char			length[4];		/* size-4 */
-	struct rtpg_tpg_dscr		data[0];
-} __attribute__((packed));
-
-#define RTPG_FOR_EACH_PORT_GROUP(p, g) \
-		for( \
-			g = &(p->data[0]); \
-			(((char *) g) - ((char *) p)) < get_uint32(p->length); \
-			g = (struct rtpg_tpg_dscr *) ( \
-				((char *) g) + \
-				sizeof(struct rtpg_tpg_dscr) + \
-				g->port_count * sizeof(struct rtpg_tp_dscr) \
-			) \
-		)
-
-#endif /* __SPC3_H__ */
-
diff --git a/path_priority/pp_balance_units/Makefile b/path_priority/pp_balance_units/Makefile
deleted file mode 100644
index cb1e6c6..0000000
--- a/path_priority/pp_balance_units/Makefile
+++ /dev/null
@@ -1,44 +0,0 @@
-# Makefile
-#
-# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
-#
-BUILD = glibc
-DEBUG = 0
-
-TOPDIR	= ../..
-include $(TOPDIR)/Makefile.inc
-
-ifeq ($(strip $(BUILD)),klibc)
-	CFLAGS += -I/usr/include -DDEBUG=$(DEBUG)
-	OBJS = pp_balance_units.o $(MULTIPATHLIB)-$(BUILD).a
-else
-	CFLAGS += -I$(multipathdir) -DDEBUG=$(DEBUG)
-	LDFLAGS = -ldevmapper
-	OBJS = pp_balance_units.o $(MULTIPATHLIB)-$(BUILD).a
-endif
-
-EXEC = mpath_prio_balance_units
-
-all: $(BUILD)
-
-prepare:
-	rm -f core *.o *.gz
-
-glibc: prepare $(OBJS)
-	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
-
-klibc: prepare $(OBJS)
-	$(CC) -static -o $(EXEC) $(CRT0) $(OBJS) $(KLIBC) $(LIBGCC)
-
-$(MULTIPATHLIB)-$(BUILD).a:
-	make -C $(multipathdir) BUILD=$(BUILD) $(BUILD)
-
-install:
-	install -d $(DESTDIR)$(bindir)
-	$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/
-
-uninstall:
-	rm $(DESTDIR)$(bindir)/$(EXEC)
-
-clean:
-	rm -f core *.o $(EXEC) *.gz
diff --git a/path_priority/pp_balance_units/pp_balance_units.c b/path_priority/pp_balance_units/pp_balance_units.c
deleted file mode 100644
index ea70f13..0000000
--- a/path_priority/pp_balance_units/pp_balance_units.c
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- * Christophe Varoqui (2004)
- * This code is GPLv2, see license file
- *
- * This path prioritizer aims to balance logical units over all
- * controllers available. The logic is :
- *
- * - list all paths in all primary path groups
- * - for each path, get the controller's serial
- * - compute the number of active paths attached to each controller
- * - compute the max number of paths attached to the same controller
- * - if sums are already balanced or if the path passed as parameter is
- *   attached to controller with less active paths, then return 
- *   (max_path_attached_to_one_controller - number_of_paths_on_this_controller)
- * - else, or if anything goes wrong, return 1 as a default prio
- *
- */
-#define __user
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <libdevmapper.h>
-#include <vector.h>
-#include <memory.h>
-
-#include <string.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <scsi/sg.h>
-
-#define SERIAL_SIZE 255
-#define WORD_SIZE 255
-#define PARAMS_SIZE 255
-#define FILE_NAME_SIZE 255
-#define INQUIRY_CMDLEN  6
-#define INQUIRY_CMD     0x12
-#define SENSE_BUFF_LEN  32
-#define DEF_TIMEOUT     300000
-#define RECOVERED_ERROR 0x01
-#define MX_ALLOC_LEN    255
-#define SCSI_CHECK_CONDITION    0x2
-#define SCSI_COMMAND_TERMINATED 0x22
-#define SG_ERR_DRIVER_SENSE     0x08
-
-#if DEBUG
-#define debug(format, arg...) fprintf(stderr, format "\n", ##arg)
-#else
-#define debug(format, arg...) do {} while(0)
-#endif
-
-#define safe_sprintf(var, format, args...)	\
-	snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
-#define safe_snprintf(var, size, format, args...)      \
-	snprintf(var, size, format, ##args) >= size
-
-struct path {
-	char dev_t[WORD_SIZE];
-	char serial[SERIAL_SIZE];
-};
-
-struct controller {
-	char serial[SERIAL_SIZE];
-	int path_count;
-};
-
-static int
-exit_tool (int ret)
-{
-	printf("1\n");
-	exit(ret);
-}
-
-static int
-opennode (char * devt, int mode)
-{
-	char devpath[FILE_NAME_SIZE];
-	unsigned int major;
-	unsigned int minor;
-	int fd;
-
-	sscanf(devt, "%u:%u", &major, &minor);
-	memset(devpath, 0, FILE_NAME_SIZE);
-	
-	if (safe_sprintf(devpath, "/tmp/.pp_balance.%u.%u.devnode",
-			 major, minor)) {
-		fprintf(stderr, "devpath too small\n");
-		return -1;
-	}
-	unlink (devpath);
-	mknod(devpath, S_IFBLK|S_IRUSR|S_IWUSR, makedev(major, minor));
-	fd = open(devpath, mode);
-	
-	if (fd < 0)
-		unlink(devpath);
-
-	return fd;
-
-}
-
-static void
-closenode (char * devt, int fd)
-{
-	char devpath[FILE_NAME_SIZE];
-	unsigned int major;
-	unsigned int minor;
-
-	if (fd >= 0)
-		close(fd);
-
-	sscanf(devt, "%u:%u", &major, &minor);
-	if (safe_sprintf(devpath, "/tmp/.pp_balance.%u.%u.devnode",
-			 major, minor)) {
-		fprintf(stderr, "devpath too small\n");
-		return;
-	}
-	unlink(devpath);
-}
-
-static int
-do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
-       void *resp, int mx_resp_len, int noisy)
-{
-        unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
-            { INQUIRY_CMD, 0, 0, 0, 0, 0 };
-        unsigned char sense_b[SENSE_BUFF_LEN];
-        struct sg_io_hdr io_hdr;
-                                                                                                                 
-        if (cmddt)
-                inqCmdBlk[1] |= 2;
-        if (evpd)
-                inqCmdBlk[1] |= 1;
-        inqCmdBlk[2] = (unsigned char) pg_op;
-	inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
-	inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
-        memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-        io_hdr.interface_id = 'S';
-        io_hdr.cmd_len = sizeof (inqCmdBlk);
-        io_hdr.mx_sb_len = sizeof (sense_b);
-        io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-        io_hdr.dxfer_len = mx_resp_len;
-        io_hdr.dxferp = resp;
-        io_hdr.cmdp = inqCmdBlk;
-        io_hdr.sbp = sense_b;
-        io_hdr.timeout = DEF_TIMEOUT;
- 
-        if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
-                return -1;
- 
-        /* treat SG_ERR here to get rid of sg_err.[ch] */
-        io_hdr.status &= 0x7e;
-        if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
-            (0 == io_hdr.driver_status))
-                return 0;
-        if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
-            (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
-            (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
-                if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
-                        int sense_key;
-                        unsigned char * sense_buffer = io_hdr.sbp;
-                        if (sense_buffer[0] & 0x2)
-                                sense_key = sense_buffer[1] & 0xf;
-                        else
-                                sense_key = sense_buffer[2] & 0xf;
-                        if(RECOVERED_ERROR == sense_key)
-                                return 0;
-                }
-        }
-        return -1;
-}
-
-static int
-get_serial (char * str, int maxlen, char * devt)
-{
-	int fd;
-        int len;
-        char buff[MX_ALLOC_LEN + 1];
-
-	fd = opennode(devt, O_RDONLY);
-
-	if (fd < 0)
-                return 1;
-
-	if (0 == do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
-		len = buff[3];
-		if (len >= maxlen)
-			return 1;
-		if (len > 0) {
-			memcpy(str, buff + 4, len);
-			buff[len] = '\0';
-		}
-		close(fd);
-		return 0;
-	}
-
-	closenode(devt, fd);
-        return 1;
-}
-
-static void *
-get_params (void)
-{
-	struct dm_task *dmt, *dmt1;
-	struct dm_names *names = NULL;
-	unsigned next = 0;
-	void *nexttgt;
-	uint64_t start, length;
-	char *target_type = NULL;
-	char *params;
-	char *pp;
-	vector paramsvec = NULL;
-
-	if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
-		return NULL;
-
-	if (!dm_task_run(dmt))
-		goto out;
-
-	if (!(names = dm_task_get_names(dmt)))
-		goto out;
-
-	if (!names->dev) {
-		debug("no devmap found");
-		goto out;
-	}
-	do {
-		/*
-		 * keep only multipath maps
-		 */
-		names = (void *) names + next;
-		nexttgt = NULL;
-		debug("devmap %s :", names->name);
-
-		if (!(dmt1 = dm_task_create(DM_DEVICE_TABLE)))
-			goto out;
-
-		if (!dm_task_set_name(dmt1, names->name))
-			goto out1;
-
-		if (!dm_task_run(dmt1))
-			goto out1;
-
-		do {
-			nexttgt = dm_get_next_target(dmt1, nexttgt,
-						     &start,
-						     &length,
-						     &target_type,
-						     &params);
-			debug("\\_ %lu %lu %s", (unsigned long) start,
-				(unsigned long) length,
-				target_type);
-
-			if (!target_type) {
-				debug("unknown target type");
-				goto out1;
-			}
-
-			if (!strncmp(target_type, "multipath", 9)) {
-				if (!paramsvec)
-					paramsvec = vector_alloc();
-
-				pp = malloc(PARAMS_SIZE);
-				strncpy(pp, params, PARAMS_SIZE);
-				vector_alloc_slot(paramsvec);
-				vector_set_slot(paramsvec, pp);
-			} else
-				debug("skip non multipath target");
-		} while (nexttgt);
-out1:
-		dm_task_destroy(dmt1);
-		next = names->next;
-	} while (next);
-out:
-	dm_task_destroy(dmt);
-	return paramsvec;
-}
-
-static int
-get_word (char *sentence, char *word)
-{
-	char *p;
-	int skip = 0;
-	
-	while (*sentence ==  ' ') {
-		sentence++;
-		skip++;
-	}
-	p = sentence;
-
-	while (*p !=  ' ' && *p != '\0')
-		p++;
-
-	skip += (p - sentence);
-
-	if (p - sentence > WORD_SIZE) {
-		fprintf(stderr, "word too small\n");
-		exit_tool(1);
-	}
-	strncpy(word, sentence, WORD_SIZE);
-	word += p - sentence;
-	*word = '\0';
-
-	if (*p == '\0')
-		return 0;
-
-	return skip;
-}
-
-static int
-is_path (char * word)
-{
-	char *p;
-
-	if (!word)
-		return 0;
-
-	p = word;
-
-	while (*p != '\0') {
-		if (*p == ':')
-			return 1;
-		p++;
-	}
-	return 0;
-}
-
-static int
-get_paths (vector pathvec)
-{
-	vector paramsvec = NULL;
-	char * str;
-	struct path * pp;
-	int i;
-	enum where {BEFOREPG, INPG, AFTERPG};
-	int pos = BEFOREPG;
-
-	if (!pathvec)
-		return 1;
-
-	if (!(paramsvec = get_params()))
-		exit_tool(0);
-
-	vector_foreach_slot (paramsvec, str, i) {
-		debug("params %s", str);
-		while (pos != AFTERPG) {
-			pp = zalloc(sizeof(struct path));
-			str += get_word(str, pp->dev_t);
-
-			if (!is_path(pp->dev_t)) {
-				debug("skip \"%s\"", pp->dev_t);
-				free(pp);
-
-				if (pos == INPG)
-					pos = AFTERPG;
-				
-				continue;
-			}
-			if (pos == BEFOREPG)
-				pos = INPG;
-
-			get_serial(pp->serial, SERIAL_SIZE, pp->dev_t);
-			vector_alloc_slot(pathvec);
-			vector_set_slot(pathvec, pp);
-			debug("store %s [%s]",
-				pp->dev_t, pp->serial);
-		}
-		pos = BEFOREPG;
-	}
-	return 0;
-}
-
-static void *
-find_controller (vector controllers, char * serial)
-{
-	int i;
-	struct controller * cp;
-
-	if (!controllers)
-		return NULL;
-
-	vector_foreach_slot (controllers, cp, i)
-		if (!strncmp(cp->serial, serial, SERIAL_SIZE))
-				return cp;
-	return NULL;
-}
-
-static void
-get_controllers (vector controllers, vector pathvec)
-{
-	int i;
-	struct path * pp;
-	struct controller * cp;
-	
-	if (!controllers)
-		return;
-
-	vector_foreach_slot (pathvec, pp, i) {
-		if (!pp || !strlen(pp->serial))
-			continue;
-		
-		cp = find_controller(controllers, pp->serial);
-
-		if (!cp) {
-			cp = zalloc(sizeof(struct controller));
-			vector_alloc_slot(controllers);
-			vector_set_slot(controllers, cp);
-			strncpy(cp->serial, pp->serial, SERIAL_SIZE);
-		}
-		cp->path_count++;	
-	}
-}
-
-static int
-get_max_path_count (vector controllers)
-{
-	int i;
-	int max = 0;
-	struct controller * cp;
-
-	if (!controllers)
-		return 0;
-
-	vector_foreach_slot (controllers, cp, i) {
-		debug("controller %s : %i paths", cp->serial, cp->path_count);
-		if(cp->path_count > max)
-			max = cp->path_count;
-	}
-	debug("max_path_count = %i", max);
-	return max;
-}
-
-int
-main (int argc, char **argv)
-{
-	vector pathvec = NULL;
-	vector controllers = NULL;
-	struct path * ref_path = NULL;
-	struct controller * cp = NULL;
-	int max_path_count = 0;
-
-	ref_path = zalloc(sizeof(struct path));
-
-	if (!ref_path)
-		exit_tool(1);
-
-	if (argc != 2)
-		exit_tool(1);
-
-	if (optind<argc)
-		strncpy(ref_path->dev_t, argv[optind], WORD_SIZE);
-
-	get_serial(ref_path->serial, SERIAL_SIZE, ref_path->dev_t);
-
-	if (!ref_path->serial || !strlen(ref_path->serial))
-		exit_tool(0);
-
-	pathvec = vector_alloc();
-	controllers = vector_alloc();
-
-	get_paths(pathvec);
-	get_controllers(controllers, pathvec);
-	max_path_count = get_max_path_count(controllers);
-	cp = find_controller(controllers, ref_path->serial);
-
-	if (!cp) {
-		debug("no other active path on serial %s\n",
-			ref_path->serial);
-		exit_tool(0);
-	}
-
-	printf("%i\n", max_path_count - cp->path_count + 1);
-
-	return(0);
-}
diff --git a/path_priority/pp_emc/Makefile b/path_priority/pp_emc/Makefile
deleted file mode 100644
index 93e6075..0000000
--- a/path_priority/pp_emc/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-EXEC		= mpath_prio_emc
-BUILD		= glibc
-OBJS		= pp_emc.o
-
-TOPDIR		= ../..
-include $(TOPDIR)/Makefile.inc
-
-all: $(BUILD)
-
-glibc:	$(OBJS)
-	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
-
-klibc:	$(OBJS)
-	$(CC) -static -o $(EXEC) $(OBJS)
-
-install: $(EXEC)
-	$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
-
-uninstall:
-	rm $(DESTDIR)$(bindir)/$(EXEC)
-clean:	
-	rm -f *.o $(EXEC)
-
-%.o:	%.c
-	$(CC) $(CFLAGS) -c -o $@ $<
diff --git a/path_priority/pp_emc/pp_emc.c b/path_priority/pp_emc/pp_emc.c
deleted file mode 100644
index 4031720..0000000
--- a/path_priority/pp_emc/pp_emc.c
+++ /dev/null
@@ -1,101 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-#include "../../libmultipath/sg_include.h"
-
-#define INQUIRY_CMD     0x12
-#define INQUIRY_CMDLEN  6
-
-int emc_clariion_prio(const char *dev)
-{
-	unsigned char sense_buffer[256];
-	unsigned char sb[128];
-	unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
-						sizeof(sb), 0};
-	struct sg_io_hdr io_hdr;
-	int ret = 0;
-	int fd;
-
-	fd = open(dev, O_RDWR|O_NONBLOCK);
-
-	if (fd <= 0) {
-		fprintf(stderr, "Opening the device failed.\n");
-		goto out;
-	}
-
-	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-	io_hdr.interface_id = 'S';
-	io_hdr.cmd_len = sizeof (inqCmdBlk);
-	io_hdr.mx_sb_len = sizeof (sb);
-	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-	io_hdr.dxfer_len = sizeof (sense_buffer);
-	io_hdr.dxferp = sense_buffer;
-	io_hdr.cmdp = inqCmdBlk;
-	io_hdr.sbp = sb;
-	io_hdr.timeout = 60000;
-	io_hdr.pack_id = 0;
-	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
-		fprintf(stderr, "sending query command failed\n");
-		goto out;
-	}
-	if (io_hdr.info & SG_INFO_OK_MASK) {
-		fprintf(stderr, "query command indicates error");
-		goto out;
-	}
-
-	close(fd);
-	
-	if (/* Verify the code page - right page & revision */
-	    sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) {
-		fprintf(stderr, "Path unit report page in unknown format");
-		goto out;
-	}
-	
-	if ( /* Effective initiator type */
-	    	sense_buffer[27] != 0x03
-		/*
-		 * Failover mode should be set to 1 (PNR failover mode)
-		 * or 4 (ALUA failover mode).
-		 */
-		|| (((sense_buffer[28] & 0x07) != 0x04) &&
-		    ((sense_buffer[28] & 0x07) != 0x06))
-		/* Arraycommpath should be set to 1 */
-		|| (sense_buffer[30] & 0x04) != 0x04) {
-		fprintf(stderr, "Path not correctly configured for failover");
-	}
-
-	if ( /* LUN operations should indicate normal operations */
-		sense_buffer[48] != 0x00) {
-		fprintf(stderr, "Path not available for normal operations");
-	}
-
-	/* Is the default owner equal to this path? */
-	/* Note this will switch to the default priority group, even if
-	 * it is not the currently active one. */
-	ret = (sense_buffer[5] == sense_buffer[8]) ? 1 : 0;
-	
-out:
-	return(ret);
-}
-
-int
-main (int argc, char **argv)
-{
-	int prio;
-	if (argc != 2) {
-		fprintf(stderr, "Arguments wrong!\n");
-		prio = 0;
-	} else
-		prio = emc_clariion_prio(argv[1]);
-
-	printf("%d\n", prio);
-	exit(0);
-}
-
diff --git a/path_priority/pp_hds_modular/Makefile b/path_priority/pp_hds_modular/Makefile
deleted file mode 100644
index ca00ca7..0000000
--- a/path_priority/pp_hds_modular/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-EXEC		= mpath_prio_hds_modular
-BUILD		= glibc
-OBJS		= pp_hds_modular.o
-
-TOPDIR		= ../..
-include $(TOPDIR)/Makefile.inc
-
-all: $(BUILD)
-
-glibc:	$(OBJS)
-	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
-
-klibc:	$(OBJS)
-	$(CC) -static -o $(EXEC) $(OBJS)
-
-install: $(EXEC)
-	$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
-
-uninstall:
-	rm $(DESTDIR)$(bindir)/$(EXEC)
-clean:	
-	rm -f *.o $(EXEC)
diff --git a/path_priority/pp_hds_modular/pp_hds_modular.c b/path_priority/pp_hds_modular/pp_hds_modular.c
deleted file mode 100644
index 7411508..0000000
--- a/path_priority/pp_hds_modular/pp_hds_modular.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * (C) Copyright HDS GmbH 2006. All Rights Reserved.
- *
- * pp_hds_modular.c
- * Version 2.00
- *
- * Prioritizer for Device Mapper Multipath and HDS Storage
- *
- * Hitachis Modular Storage contains two controllers for redundancy. The 
- * Storage internal LUN (LDEV) will normally allocated via two pathes to the 
- * server (one path per controller). For performance reasons should the server 
- * access to a LDEV only via one controller. The other path to the other
- * controller is stand-by. It is also possible to allocate more as one path 
- * for a LDEV per controller. Here is active/active access allowed. The other 
- * pathes via the other controller are stand-by.
- *
- * This prioritizer checks with inquiry command the represented LDEV and 
- * Controller number and gives back a priority followed by this scheme:
- *
- * CONTROLLER ODD  and LDEV  ODD: PRIORITY 1
- * CONTROLLER ODD  and LDEV EVEN: PRIORITY 0
- * CONTROLLER EVEN and LDEV  ODD: PRIORITY 0
- * CONTROLLER EVEN and LDEV EVEN: PRIORITY 1
- *
- * In the storage you can define for each LDEV a owner controller. If the 
- * server makes IOs via the other controller the storage will switch the 
- * ownership automatically. In this case you can see in the storage that the 
- * current controller is different from the default controller, but this is
- * absolutely no problem.
- *
- * With this prioritizer it is possible to establish a static load balancing. 
- * Half of the LUNs are accessed via one HBA/storage controller and the other 
- * half via the other HBA/storage controller.
- *
- * In cluster environmemnts (RAC) it also guarantees that all cluster nodes have
- * access to the LDEVs via the same controller.
- * 
- * You can run the prioritizer manually in verbose mode:
- * # pp_hds_modular -v 8:224
- * VENDOR:  HITACHI
- * PRODUCT: DF600F-CM
- * SERIAL:  0x0105
- * LDEV:    0x00C6
- * CTRL:    1
- * PORT:    B
- * CTRL ODD, LDEV EVEN, PRIO 0
- *
- * To compile this source please execute # cc pp_hds_modular.c -o /sbin/mpath_prio_hds_modular
- *
- * Changes 2006-07-16:
- *         - Changed to forward declaration of functions
- *         - The switch-statement was changed to a logical expression
- *         - unlinking of the devpath now also occurs at the end of 
- *           hds_modular_prio to avoid old /tmp/.pp_balance.%u.%u.devnode
- *           entries in /tmp-Directory
- *         - The for-statements for passing variables where changed to
- *           snprintf-commands in verbose mode
- * Changes 2006-08-10:
- *         - Back to the old switch statements because the regular expression does
- *           not work under RHEL4 U3 i386
- * Changes 2007-06-27:
- *	- switched from major:minor argument to device node argument
- *
- * This file is released under the GPL.
- *
- */
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <stdlib.h>
-#include <libdevmapper.h>
-#include <memory.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <scsi/sg.h>
-
-#define INQ_REPLY_LEN 255
-#define INQ_CMD_CODE 0x12
-#define INQ_CMD_LEN 6
-#define FILE_NAME_SIZE 255
-
-int verbose=0;
-
-void print_help (void);
-int hds_modular_prio (const char *);
-
-int main (int argc, char **argv)
-{
-	int prio;
-	if (argc == 2)
-	{
-		if (strcmp (argv[1], "-h") == 0)
-		{
-			print_help ();
-			exit (0);
-		}
-		else
-		{
-			verbose = 0;
-			prio = hds_modular_prio (argv[1]);
-			printf ("%d\n", prio);
-			exit (0);
-		}
-	}
-	if ((argc == 3) && (strcmp (argv[1], "-v")) == 0)
-	{
-		verbose = 1;
-		prio = hds_modular_prio (argv[2]);
-		printf ("%d\n", prio);
-		exit (0);
-	}
-	print_help ();
-	exit (1);
-}
-
-int hds_modular_prio (const char *dev)
-{
-	int sg_fd, k;
-	char vendor[8];
-	char product[32];
-	char serial[32];
-	char ldev[32];
-	char ctrl[32];
-	char port[32];
-	unsigned char inqCmdBlk[INQ_CMD_LEN] = { INQ_CMD_CODE, 0, 0, 0, INQ_REPLY_LEN, 0 };
-	unsigned char inqBuff[INQ_REPLY_LEN];
-	unsigned char *inqBuffp = inqBuff;
-	unsigned char sense_buffer[32];
-	sg_io_hdr_t io_hdr;
-
-	if ((sg_fd = open (dev, O_RDONLY)) < 0) exit (1);
-	if ((ioctl (sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) exit (1);
-
-	memset (&io_hdr, 0, sizeof (sg_io_hdr_t));
-	io_hdr.interface_id = 'S';
-	io_hdr.cmd_len = sizeof (inqCmdBlk);
-	io_hdr.mx_sb_len = sizeof (sense_buffer);
-	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-	io_hdr.dxfer_len = INQ_REPLY_LEN;
-	io_hdr.dxferp = inqBuff;
-	io_hdr.cmdp = inqCmdBlk;
-	io_hdr.sbp = sense_buffer;
-	io_hdr.timeout = 2000;	/* TimeOut = 2 seconds */
-
-	if (ioctl (sg_fd, SG_IO, &io_hdr) < 0) exit (1);
-	if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) exit (1);
-
-	snprintf (vendor, 9, "%.8s\n", inqBuffp + 8);
-	snprintf (product, 17, "%.16s", inqBuffp + 16);
-	snprintf (serial, 5, "%.4s", inqBuffp + 40);
-	snprintf (ldev, 5, "%.4s", inqBuffp + 44);
-	snprintf (ctrl, 2, "%.1s", inqBuffp + 49);
-	snprintf (port, 2, "%.1s", inqBuffp + 50);
-
-	close (sg_fd);
-
-	if (verbose)
-	{
-		printf ("VENDOR:  %s\n", vendor);
-		printf ("PRODUCT: %s\n", product);
-		printf ("SERIAL:  0x%s\n", serial);
-		printf ("LDEV:    0x%s\n", ldev);
-		printf ("CTRL:    %s\n", ctrl);
-		printf ("PORT:    %s\n", port);
-	}
-
-	switch (ctrl[0]) {
-	case '0': case '2': case '4': case '6': case '8':
-		switch (ldev[3]) {
-		case '0': case '2': case '4': case '6': case '8': case 'A': case 'C': case 'E':
-			if (1 == verbose) printf("CTRL EVEN, LDEV EVEN, PRIO 1\n");
-			return 1;
-			break;
-		case '1': case '3': case '5': case '7': case '9': case 'B': case 'D': case 'F':
-			if (1 == verbose) printf("CTRL EVEN, LDEV ODD, PRIO 0\n");
-			return 0;
-			break;
-		}
-	case '1': case '3': case '5': case '7': case '9':
-		switch (ldev[3]) {
-		case '0': case '2': case '4': case '6': case '8': case 'A': case 'C': case 'E':
-			if (1 == verbose) printf("CTRL ODD, LDEV EVEN, PRIO 0\n");
-			return 0;
-			break;
-		case '1': case '3': case '5': case '7': case '9': case 'B': case 'D': case 'F':
-			if (1 == verbose) printf("CTRL ODD, LDEV ODD, PRIO 1\n");
-			return 1;
-			break;
-		}
-	}
-	return 0;
-}
-
-void print_help (void)
-{
-	printf ("\n");
-	printf ("Usage:       pp_hds_modular [-v] <device>\n");
-	printf ("Option:      -v verbose mode\n");
-	printf ("Description: Prioritizer for Device Mapper Multipath and HDS Storage\n");
-	printf ("Version:     2.00\n");
-	printf ("Author:      Matthias Rudolph <matthias.rudolph@hds.com>\n");
-	printf ("Remarks:     Prioritizer CTRL#1 corresponds to hardware CTRL#0\n");
-	printf ("             Prioritizer CTRL#2 corresponds to hardware CTRL#1\n");
-	printf ("\n");
-	return;
-}
-
diff --git a/path_priority/pp_hp_sw/Makefile b/path_priority/pp_hp_sw/Makefile
deleted file mode 100644
index e7debf5..0000000
--- a/path_priority/pp_hp_sw/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-EXEC		= mpath_prio_hp_sw
-BUILD		= glibc
-OBJS		= pp_hp_sw.o
-
-TOPDIR		= ../..
-include $(TOPDIR)/Makefile.inc
-
-all: $(BUILD)
-
-glibc:	$(OBJS)
-	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
-
-klibc:	$(OBJS)
-	$(CC) -static -o $(EXEC) $(OBJS)
-
-install: $(EXEC)
-	install -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
-
-uninstall:
-	rm $(DESTDIR)$(bindir)/$(EXEC)
-clean:	
-	rm -f *.o $(EXEC)
-
-%.o:	%.c
-	$(CC) $(CFLAGS) -c -o $@ $<
diff --git a/path_priority/pp_hp_sw/pp_hp_sw.c b/path_priority/pp_hp_sw/pp_hp_sw.c
deleted file mode 100644
index e4a18b1..0000000
--- a/path_priority/pp_hp_sw/pp_hp_sw.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Path priority checker for HP active/standby controller
- *
- * Check the path state and sort them into groups.
- * There is actually a preferred path in the controller;
- * we should ask HP on how to retrieve that information.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-#define TUR_CMD_LEN		6
-#define SCSI_CHECK_CONDITION	0x2
-#define SCSI_COMMAND_TERMINATED	0x22
-#define SG_ERR_DRIVER_SENSE	0x08
-#define RECOVERED_ERROR		0x01
-#define NOT_READY		0x02
-#define UNIT_ATTENTION		0x06
-
-#define HP_PATH_ACTIVE		0x04
-#define HP_PATH_STANDBY		0x02
-#define HP_PATH_FAILED		0x00
-
-#include "../../libmultipath/sg_include.h"
-
-int hp_sw_prio(const char *dev)
-{
-        unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
-	unsigned char sb[128];
-	struct sg_io_hdr io_hdr;
-	int ret = HP_PATH_FAILED;
-	int fd;
-
-	fd = open(dev, O_RDWR|O_NONBLOCK);
-
-	if (fd <= 0) {
-		fprintf(stderr, "Opening the device failed.\n");
-		goto out;
-	}
-
-	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-	io_hdr.interface_id = 'S';
-	io_hdr.cmd_len = sizeof (turCmdBlk);
-	io_hdr.mx_sb_len = sizeof (sb);
-	io_hdr.dxfer_direction = SG_DXFER_NONE;
-	io_hdr.cmdp = turCmdBlk;
-	io_hdr.sbp = sb;
-	io_hdr.timeout = 60000;
-	io_hdr.pack_id = 0;
- retry:
-	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
-		fprintf(stderr, "sending tur command failed\n");
-		goto out;
-	}
-        io_hdr.status &= 0x7e;
-        if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
-            (0 == io_hdr.driver_status)) {
-		/* Command completed normally, path is active */
-                ret = HP_PATH_ACTIVE;
-	}
-
-        if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
-            (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
-            (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
-                if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
-                        int sense_key, asc, asq;
-                        unsigned char * sense_buffer = io_hdr.sbp;
-                        if (sense_buffer[0] & 0x2) {
-                                sense_key = sense_buffer[1] & 0xf;
-				asc = sense_buffer[2];
-				asq = sense_buffer[3];
-			} else {
-                                sense_key = sense_buffer[2] & 0xf;
-				asc = sense_buffer[12];
-				asq = sense_buffer[13];
-			}
-                        if(RECOVERED_ERROR == sense_key)
-                                ret = HP_PATH_ACTIVE;
-			if(NOT_READY == sense_key) {
-				if (asc == 0x04 && asq == 0x02) {
-					/* This is a standby path */
-					ret = HP_PATH_STANDBY;
-				}
-			}
-			if(UNIT_ATTENTION == sense_key) {
-				if (asc == 0x29) {
-					/* Retry for device reset */
-					goto retry;
-				}
-			}
-                }
-        }
-
-	close(fd);
-
-out:
-	return(ret);
-}
-
-int
-main (int argc, char **argv)
-{
-	int prio;
-	if (argc != 2) {
-		fprintf(stderr, "Arguments wrong!\n");
-		prio = 0;
-	} else
-		prio = hp_sw_prio(argv[1]);
-
-	printf("%d\n", prio);
-	exit(0);
-}
-
diff --git a/path_priority/pp_netapp/Makefile b/path_priority/pp_netapp/Makefile
deleted file mode 100644
index b29d002..0000000
--- a/path_priority/pp_netapp/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-EXEC		= mpath_prio_netapp
-BUILD		= glibc
-OBJS		= pp_netapp.o
-
-TOPDIR		= ../..
-include $(TOPDIR)/Makefile.inc
-
-all: $(BUILD)
-
-glibc:	$(OBJS)
-	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
-
-klibc:	$(OBJS)
-	$(CC) -static -o $(EXEC) $(OBJS)
-
-install: $(EXEC)
-	$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
-
-uninstall:
-	rm $(DESTDIR)$(bindir)/$(EXEC)
-clean:	
-	rm -f *.o $(EXEC)
diff --git a/path_priority/pp_netapp/pp_netapp.c b/path_priority/pp_netapp/pp_netapp.c
deleted file mode 100644
index 8562a95..0000000
--- a/path_priority/pp_netapp/pp_netapp.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/* 
- * Copyright 2005 Network Appliance, Inc., All Rights Reserved
- * Author:  David Wysochanski available at davidw@netapp.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of 
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License v2 for more details.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <assert.h>
-
-#include "../../libmultipath/sg_include.h"
-
-#define INQUIRY_CMD	0x12
-#define INQUIRY_CMDLEN	6
-#define DEFAULT_PRIO	10
-#define RESULTS_MAX	256
-#define SG_TIMEOUT	30000
-
-
-static void dump_cdb(unsigned char *cdb, int size)
-{
-	int i;
-	
-	fprintf(stderr, "- SCSI CDB: ");
-	for (i=0; i<size; i++) {
-		fprintf(stderr, "0x%02x ", cdb[i]);
-	}
-	fprintf(stderr, "\n");
-}
-
-static void process_sg_error(struct sg_io_hdr *io_hdr)
-{
-	int i;
-	
-	fprintf(stderr, "- masked_status=0x%02x, host_status=0x%02x, "
-		"driver_status=0x%02x\n", io_hdr->masked_status,
-		io_hdr->host_status, io_hdr->driver_status);
-	if (io_hdr->sb_len_wr > 0) {
-		fprintf(stderr, "- SCSI sense data: ");
-		for (i=0; i<io_hdr->sb_len_wr; i++) {
-			fprintf(stderr, "0x%02x ", io_hdr->sbp[i]);
-		}
-		fprintf(stderr, "\n");
-	}
-}
-
-/*
- * Returns:
- * -1: error, errno set
- *  0: success
- */
-static int send_gva(const char *dev, unsigned char pg,
-		    unsigned char *results, int *results_size)
-{
-	unsigned char sb[128];
-	unsigned char cdb[10] = {0xc0, 0, 0x1, 0xa, 0x98, 0xa,
-				 pg, sizeof(sb), 0, 0};
-	struct sg_io_hdr io_hdr;
-	int ret = -1;
-	int fd;
-
-	fd = open(dev, O_RDWR|O_NONBLOCK);
-
-	if (fd <= 0) {
-		fprintf(stderr, "Opening %s failed, errno=%d.\n", dev, errno);
-		goto out_no_close;
-	}
-
-	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-	io_hdr.interface_id = 'S';
-	io_hdr.cmd_len = sizeof (cdb);
-	io_hdr.mx_sb_len = sizeof (sb);
-	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-	io_hdr.dxfer_len = *results_size;
-	io_hdr.dxferp = results;
-	io_hdr.cmdp = cdb;
-	io_hdr.sbp = sb;
-	io_hdr.timeout = SG_TIMEOUT;
-	io_hdr.pack_id = 0;
-	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
-		fprintf(stderr, "SG_IO ioctl failed, errno=%d\n", errno);
-		dump_cdb(cdb, sizeof(cdb));
-		goto out;
-	}
-	if (io_hdr.info & SG_INFO_OK_MASK) {
-		fprintf(stderr, "SCSI error\n");
-		dump_cdb(cdb, sizeof(cdb));
-		process_sg_error(&io_hdr);
-		goto out;
-	}
-
-	if (results[4] != 0x0a || results[5] != 0x98 ||
-	    results[6] != 0x0a ||results[7] != 0x01) {
-		dump_cdb(cdb, sizeof(cdb));
-		fprintf(stderr, "GVA return wrong format ");
-		fprintf(stderr, "results[4-7] = 0x%02x 0x%02x 0x%02x 0x%02x\n",
-			results[4], results[5], results[6], results[7]);
-		goto out;
-	}
-	ret = 0;
- out:
-	close(fd);
- out_no_close:
-	return(ret);
-}
-
-/*
- * Retuns:
- * -1: Unable to obtain proxy info
- *  0: Device _not_ proxy path
- *  1: Device _is_ proxy path
- */
-static int get_proxy(const char *dev)
-{
-	unsigned char results[256];
-	unsigned char sb[128];
-	unsigned char cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xc1, 0,
-						   sizeof(sb), 0};
-	struct sg_io_hdr io_hdr;
-	int ret = -1;
-	int fd;
-
-	fd = open(dev, O_RDWR|O_NONBLOCK);
-
-	if (fd <= 0) {
-		fprintf(stderr, "Opening %s failed, errno=%d.\n", dev, errno);
-		goto out_no_close;
-	}
-
-	memset(&results, 0, sizeof (results));
-	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-	io_hdr.interface_id = 'S';
-	io_hdr.cmd_len = sizeof (cdb);
-	io_hdr.mx_sb_len = sizeof (sb);
-	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-	io_hdr.dxfer_len = sizeof (results);
-	io_hdr.dxferp = results;
-	io_hdr.cmdp = cdb;
-	io_hdr.sbp = sb;
-	io_hdr.timeout = SG_TIMEOUT;
-	io_hdr.pack_id = 0;
-	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
-		fprintf(stderr, "ioctl sending inquiry command failed, "
-			"errno=%d\n", errno);
-		dump_cdb(cdb, sizeof(cdb));
-		goto out;
-	}
-	if (io_hdr.info & SG_INFO_OK_MASK) {
-		fprintf(stderr, "SCSI error\n");
-		dump_cdb(cdb, sizeof(cdb));
-		process_sg_error(&io_hdr);
-		goto out;
-	}
-
-	if (results[1] != 0xc1 || results[8] != 0x0a ||
-	    results[9] != 0x98 || results[10] != 0x0a ||
-	    results[11] != 0x0 || results[12] != 0xc1 ||
-	    results[13] != 0x0) {
-		fprintf(stderr,"Proxy info page in unknown format - ");
-		fprintf(stderr,"results[8-13]=0x%02x 0x%02x 0x%02x 0x%02x "
-			"0x%02x 0x%02x\n",
-			results[8], results[9], results[10],
-			results[11], results[12], results[13]);
-		dump_cdb(cdb, sizeof(cdb));
-		goto out;
-	}
-	ret = (results[19] & 0x02) >> 1;
-
- out:
-	close(fd);
- out_no_close:
-	return(ret);
-}
-
-/*
- * Returns priority of device based on device info.
- *
- * 4: FCP non-proxy, FCP proxy unknown, or unable to determine protocol
- * 3: iSCSI HBA
- * 2: iSCSI software
- * 1: FCP proxy
- */
-static int netapp_prio(const char *dev)
-{
-	unsigned char results[RESULTS_MAX];
-	int results_size=RESULTS_MAX;
-	int rc;
-	int is_proxy;
-	int is_iscsi_software;
-	int is_iscsi_hardware;
-	int tot_len;
-
-	is_iscsi_software = is_iscsi_hardware = is_proxy = 0;
-
-	memset(&results, 0, sizeof (results));
-	rc = send_gva(dev, 0x41, results, &results_size);
-	if (rc == 0) {
-		tot_len = results[0] << 24 | results[1] << 16 |
-			  results[2] << 8 | results[3];
-		if (tot_len <= 8) {
-			goto try_fcp_proxy;
-		}
-		if (results[8] != 0x41) {
-			fprintf(stderr, "GVA page 0x41 error - "
-				"results[8] = 0x%x\n", results[8]);
-			goto try_fcp_proxy;
-		}
-		if ((strncmp((char *)&results[12], "ism_sw", 6) == 0) ||
-		    (strncmp((char *)&results[12], "iswt", 4) == 0)) {
-			is_iscsi_software = 1;
-			goto prio_select;
-		}
-		else if (strncmp((char *)&results[12], "ism_sn", 6) == 0) {
-			is_iscsi_hardware = 1;
-			goto prio_select;
-		}
-	}
-	
- try_fcp_proxy:	
-	rc = get_proxy(dev);
-	if (rc >= 0) {
-		is_proxy = rc;
-	}
-
- prio_select:
-	if (is_iscsi_hardware) {
-		return 3;
-	} else if (is_iscsi_software) {
-		return 2;
-	} else {
-		if (is_proxy) {
-			return 1;
-		} else {
-			/* Either non-proxy, or couldn't get proxy info */
-			return 4;
-		}
-	}
-}
-
-int
-main (int argc, char **argv)
-{
-	int prio;
-	if (argc != 2) {
-		fprintf(stderr, "Arguments wrong!\n");
-		prio = 0;
-	} else
-		prio = netapp_prio(argv[1]);
-	
-	printf("%d\n", prio);
-	exit(0);
-}
-
diff --git a/path_priority/pp_random/Makefile b/path_priority/pp_random/Makefile
deleted file mode 100644
index 85d7c2f..0000000
--- a/path_priority/pp_random/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-EXEC		= mpath_prio_random
-BUILD		= glibc
-OBJS		= pp_random.o
-
-TOPDIR		= ../..
-include $(TOPDIR)/Makefile.inc
-
-all: $(BUILD)
-
-glibc:	$(OBJS)
-	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
-
-klibc:	$(OBJS)
-	$(CC) -static -o $(EXEC) $(OBJS)
-
-install: $(EXEC)
-	$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
-
-uninstall:
-	rm $(DESTDIR)$(bindir)/$(EXEC)
-clean:	
-	rm -f *.o $(EXEC)
diff --git a/path_priority/pp_random/pp_random.c b/path_priority/pp_random/pp_random.c
deleted file mode 100644
index 05c4b8d..0000000
--- a/path_priority/pp_random/pp_random.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <time.h>
-
-int main(void)
-{
-	struct timeval tv;
-	
-	gettimeofday(&tv, NULL);
-	srand((unsigned int)tv.tv_usec);
-	printf("%i\n", 1+(int) (10.0*rand()/(RAND_MAX+1.0)));
-	return 0;
-}
diff --git a/path_priority/pp_rdac/Makefile b/path_priority/pp_rdac/Makefile
deleted file mode 100644
index 64ed4c3..0000000
--- a/path_priority/pp_rdac/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-EXEC		= mpath_prio_rdac
-BUILD		= glibc
-OBJS		= pp_rdac.o
-
-TOPDIR		= ../..
-include $(TOPDIR)/Makefile.inc
-
-all: $(BUILD)
-
-glibc:	$(OBJS)
-	$(CC) -o $(EXEC) $(OBJS) $(LDFLAGS)
-
-klibc:	$(OBJS)
-	$(CC) -static -o $(EXEC) $(OBJS)
-
-install: $(EXEC)
-	$(INSTALL_PROGRAM) -m 755 $(EXEC) $(DESTDIR)$(bindir)/$(EXEC)
-
-uninstall:
-	rm $(DESTDIR)$(bindir)/$(EXEC)
-clean:	
-	rm -f *.o $(EXEC)
diff --git a/path_priority/pp_rdac/pp_rdac.c b/path_priority/pp_rdac/pp_rdac.c
deleted file mode 100644
index 49a13cf..0000000
--- a/path_priority/pp_rdac/pp_rdac.c
+++ /dev/null
@@ -1,112 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-#include "../../libmultipath/sg_include.h"
-
-#define INQUIRY_CMD     0x12
-#define INQUIRY_CMDLEN  6
-
-int rdac_prio(const char *dev)
-{
-	unsigned char sense_buffer[256];
-	unsigned char sb[128];
-	unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC9, 0,
-						sizeof(sb), 0};
-	struct sg_io_hdr io_hdr;
-	int ret = 0;
-	int fd;
-
-	fd = open(dev, O_RDWR|O_NONBLOCK);
-
-	if (fd <= 0) {
-		fprintf(stderr, "opening of the device failed.\n");
-		goto out;
-	}
-
-	memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-	io_hdr.interface_id = 'S';
-	io_hdr.cmd_len = sizeof (inqCmdBlk);
-	io_hdr.mx_sb_len = sizeof (sb);
-	io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-	io_hdr.dxfer_len = sizeof (sense_buffer);
-	io_hdr.dxferp = sense_buffer;
-	io_hdr.cmdp = inqCmdBlk;
-	io_hdr.sbp = sb;
-	io_hdr.timeout = 60000;
-	io_hdr.pack_id = 0;
-	if (ioctl(fd, SG_IO, &io_hdr) < 0) {
-		fprintf(stderr, "sending inquiry command failed\n");
-		goto out;
-	}
-	if (io_hdr.info & SG_INFO_OK_MASK) {
-		fprintf(stderr, "inquiry command indicates error");
-		goto out;
-	}
-
-	close(fd);
-	
-	if (/* Verify the code page - right page & page identifier */
-	    sense_buffer[1] != 0xc9 || 
-	    sense_buffer[3] != 0x2c ||
-	    sense_buffer[4] != 'v' ||
-	    sense_buffer[5] != 'a' ||
-	    sense_buffer[6] != 'c' ) {
-		fprintf(stderr, "Volume access control page in unknown format");
-		goto out;
-	}
-	
-	if ( /* Current Volume Path Bit */
-		( sense_buffer[8] & 0x01) == 0x01 ) {
-		/* 
-		 * This volume was owned by the controller receiving
-		 * the inquiry command.
-		 */
-		ret |= 0x01;
-	}
-
-	/* Volume Preferred Path Priority */
-	switch ( sense_buffer[9] & 0x0F ) {
-	case 0x01:
-		/* 
-		 * Access to this volume is most preferred through
-		 * this path and other paths with this value.
-		 */
-		ret |= 0x02;
-		break;
-	case 0x02:
-		/*
-		 * Access to this volume through this path is to be used
-		 * as a secondary path. Typically this path would be used
-		 * for fail-over situations.
-		 */
-		/* Fallthrough */
-	default:
-		/* Reserved values */
-		break;
-	}
-	
-out:
-	return(ret);
-}
-
-int
-main (int argc, char **argv)
-{
-	int prio;
-	if (argc != 2) {
-		fprintf(stderr, "Wrong number of arguments.\n");
-		fprintf(stderr, "Usage: %s device\n", argv[0]);
-		prio = 0;
-	} else
-		prio = rdac_prio(argv[1]);
-
-	printf("%d\n", prio);
-	exit(0);
-}
openSUSE Build Service is sponsored by