--- multipath-tools/libcheckers/checkers.h	2009/11/24 20:03:16	1.5.2.4
+++ multipath-tools/libcheckers/checkers.h	2010/01/27 16:46:48	1.5.2.5
@@ -24,21 +24,6 @@
 #define DEFAULT_CHECKER READSECTOR0
 
 /*
- * 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
-
-/*
  * strings lengths
  */
 #define CHECKER_NAME_LEN 16
@@ -49,6 +34,7 @@
 struct checker {
 	int fd;
 	int sync;
+	unsigned int timeout;
 	char name[CHECKER_NAME_LEN];
 	char message[CHECKER_MSG_LEN];       /* comm with callers */
 	char wwid[WWID_SIZE];                /* LUN wwid */
--- multipath-tools/libcheckers/emc_clariion.c	2007/04/16 18:32:52	1.6.2.1
+++ multipath-tools/libcheckers/emc_clariion.c	2010/01/27 16:46:48	1.6.2.2
@@ -57,7 +57,7 @@
 	io_hdr.dxferp = sense_buffer;
 	io_hdr.cmdp = inqCmdBlk;
 	io_hdr.sbp = sb;
-	io_hdr.timeout = DEF_TIMEOUT;
+	io_hdr.timeout = c->timeout;
 	io_hdr.pack_id = 0;
 	if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
 		MSG(c, "emc_clariion_checker: sending query command failed");
--- multipath-tools/libcheckers/hp_sw.c	2006/07/13 19:49:22	1.4
+++ multipath-tools/libcheckers/hp_sw.c	2010/01/27 16:46:48	1.4.2.1
@@ -46,7 +46,7 @@
 
 static int
 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
-       void *resp, int mx_resp_len, int noisy)
+       void *resp, int mx_resp_len, int noisy, unsigned int timeout)
 {
         unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
             { INQUIRY_CMD, 0, 0, 0, 0, 0 };
@@ -69,7 +69,7 @@
         io_hdr.dxferp = resp;
         io_hdr.cmdp = inqCmdBlk;
         io_hdr.sbp = sense_b;
-        io_hdr.timeout = DEF_TIMEOUT;
+        io_hdr.timeout = timeout;
  
         if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
                 return 1;
@@ -97,7 +97,7 @@
 }
 
 static int
-do_tur (int fd)
+do_tur (int fd, unsigned int timeout)
 {
         unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
         struct sg_io_hdr io_hdr;
@@ -110,7 +110,7 @@
         io_hdr.dxfer_direction = SG_DXFER_NONE;
         io_hdr.cmdp = turCmdBlk;
         io_hdr.sbp = sense_buffer;
-        io_hdr.timeout = DEF_TIMEOUT;
+        io_hdr.timeout = timeout;
         io_hdr.pack_id = 0;
 
         if (ioctl(fd, SG_IO, &io_hdr) < 0)
@@ -127,12 +127,12 @@
 {
 	char buff[MX_ALLOC_LEN];
 
-	if (0 != do_inq(c->fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
+	if (0 != do_inq(c->fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0, c->timeout)) {
 		MSG(c, MSG_HP_SW_DOWN);
 		return PATH_DOWN;
 	}
 
-	if (do_tur(c->fd)) {
+	if (do_tur(c->fd, c->timeout)) {
 		MSG(c, MSG_HP_SW_GHOST);
                 return PATH_GHOST;
         }
--- multipath-tools/libcheckers/Attic/rdac.c	2009/11/04 20:21:43	1.1.2.4
+++ multipath-tools/libcheckers/Attic/rdac.c	2010/01/27 16:46:48	1.1.2.5
@@ -18,7 +18,6 @@
 #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
@@ -43,7 +42,8 @@
 }
 
 static int
-do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len)
+do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len,
+       unsigned int timeout)
 {
 	unsigned char inqCmdBlk[INQUIRY_CMDLEN] = { INQUIRY_CMD, 1, 0, 0, 0, 0 };
 	unsigned char sense_b[SENSE_BUFF_LEN];
@@ -61,7 +61,7 @@
 	io_hdr.dxferp = resp;
 	io_hdr.cmdp = inqCmdBlk;
 	io_hdr.sbp = sense_b;
-	io_hdr.timeout = RDAC_DEF_TIMEOUT;
+	io_hdr.timeout = timeout;
 
 	if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
 		return 1;
@@ -101,7 +101,8 @@
 {
 	struct volume_access_inq inq;
 
-	if (0 != do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq))) {
+	if (0 != do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq),
+			c->timeout)) {
 		MSG(c, MSG_RDAC_DOWN);
 		return PATH_DOWN;
 	} else {
--- multipath-tools/libcheckers/readsector0.c	2009/09/11 14:33:28	1.5.2.1
+++ multipath-tools/libcheckers/readsector0.c	2010/01/27 16:46:48	1.5.2.2
@@ -36,7 +36,7 @@
 }
 
 static int
-sg_read (int sg_fd, unsigned char * buff)
+sg_read (int sg_fd, unsigned char * buff, unsigned int timeout)
 {
 	/* defaults */
 	int blocks = 1;
@@ -72,7 +72,7 @@
 	io_hdr.dxferp = buff;
 	io_hdr.mx_sb_len = SENSE_BUFF_LEN;
 	io_hdr.sbp = senseBuff;
-	io_hdr.timeout = DEF_TIMEOUT;
+	io_hdr.timeout = timeout;
 	io_hdr.pack_id = (int)start_block;
 	if (diop && *diop)
 	io_hdr.flags |= SG_FLAG_DIRECT_IO;
@@ -121,7 +121,7 @@
 	unsigned char buf[512];
 	int ret;
 
-	ret = sg_read(c->fd, &buf[0]);
+	ret = sg_read(c->fd, &buf[0], c->timeout);
 
 	switch (ret)
 	{
--- multipath-tools/libcheckers/tur.c	2009/11/24 20:03:16	1.4.2.4
+++ multipath-tools/libcheckers/tur.c	2010/01/27 16:46:48	1.4.2.5
@@ -173,7 +173,7 @@
 	io_hdr.dxfer_direction = SG_DXFER_NONE;
 	io_hdr.cmdp = turCmdBlk;
 	io_hdr.sbp = sense_buffer;
-	io_hdr.timeout = DEF_TIMEOUT;
+	io_hdr.timeout = c->timeout;
 	io_hdr.pack_id = 0;
 	if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
 		MSG(c, MSG_TUR_DOWN);
--- multipath-tools/libmultipath/config.h	2009/05/15 21:01:26	1.18.2.8
+++ multipath-tools/libmultipath/config.h	2010/01/27 16:46:48	1.18.2.9
@@ -77,6 +77,7 @@
 	int attribute_flags;
 	int flush_on_last_del;
 	int queue_without_daemon;
+	int checker_timeout;
 	uid_t uid;
 	gid_t gid;
 	mode_t mode;
--- multipath-tools/libmultipath/dict.c	2009/05/15 21:01:26	1.17.2.11
+++ multipath-tools/libmultipath/dict.c	2010/01/27 16:46:48	1.17.2.12
@@ -350,6 +350,25 @@
 }
 
 static int
+def_checker_timeout_handler(vector strvec)
+{
+	unsigned int checker_timeout;
+	char *buff;
+
+	buff = set_value(strvec);
+	if (!buff)
+		return 1;
+
+	if (sscanf(buff, "%u", &checker_timeout) == 1)
+		conf->checker_timeout = checker_timeout;
+	else
+		conf->checker_timeout = 0;
+
+	free(buff);
+	return 0;
+}
+
+static int
 def_pg_timeout_handler(vector strvec)
 {
 	int pg_timeout;
@@ -1919,6 +1938,15 @@
 }
 
 static int
+snprint_def_checker_timeout (char *buff, int len, void *data)
+{
+	if (!conf->checker_timeout)
+		return 0;
+
+	return snprintf(buff, len, "%u", conf->checker_timeout);
+}
+
+static int
 snprint_def_pg_timeout (char * buff, int len, void * data)
 {
 	if (conf->pg_timeout == DEFAULT_PGTIMEOUT)
@@ -2005,6 +2033,7 @@
 	install_keyword("no_path_retry", &def_no_path_retry_handler, &snprint_def_no_path_retry);
 	install_keyword("queue_without_daemon", &def_queue_without_daemon, &snprint_def_queue_without_daemon);
 	install_keyword("flush_on_last_del", &def_flush_on_last_del_handler, &snprint_def_flush_on_last_del);
+	install_keyword("checker_timeout", &def_checker_timeout_handler, &snprint_def_checker_timeout);
 	install_keyword("pg_timeout", &def_pg_timeout_handler, &snprint_def_pg_timeout);
 	install_keyword("user_friendly_names", &names_handler, &snprint_def_user_friendly_names);
 	install_keyword("bindings_file", &bindings_file_handler, &snprint_def_bindings_file);
--- multipath-tools/libmultipath/discovery.c	2009/12/04 21:19:51	1.32.2.10
+++ multipath-tools/libmultipath/discovery.c	2010/01/27 16:46:48	1.32.2.11
@@ -238,6 +238,37 @@
 declare_sysfs_get_str(state, "%s/block/%s/device/state", 0);
 
 int
+sysfs_get_timeout (char * sysfs_path, char * dev, unsigned int *timeout)
+{
+	struct sysfs_attribute * attr;
+	char attr_path[SYSFS_PATH_SIZE];
+	int r;
+
+	if (safe_sprintf(attr_path, "%s/block/%s/device/timeout", sysfs_path,
+			 dev))
+		return 1;
+
+	attr = sysfs_open_attribute(attr_path);
+
+	if (!attr)
+		return 1;
+
+	if (0 > sysfs_read_attribute(attr))
+		goto out;
+
+	r = sscanf(attr->value, "%u\n", timeout);
+	sysfs_close_attribute(attr);
+
+	if (r != 1)
+		return 1;
+
+	return 0;
+out:
+	sysfs_close_attribute(attr);
+	return 1;
+}
+
+int
 sysfs_get_size (char * sysfs_path, char * dev, unsigned long long * size)
 {
 	struct sysfs_attribute * attr;
--- multipath-tools/libmultipath/discovery.h	2009/04/21 00:05:23	1.14.2.2
+++ multipath-tools/libmultipath/discovery.h	2010/01/27 16:46:48	1.14.2.3
@@ -32,6 +32,7 @@
 int sysfs_get_bustype (char * sysfs_path, char * dev, char * buff, int len);
 int sysfs_get_state (char * sysfs_path, char * dev, char * buff, int len);
 int sysfs_get_size (char * sysfs_path, char * dev, unsigned long long *);
+int sysfs_get_timeout (char * sysfs_path, char * dev, unsigned int *timeout);
 int path_discovery (vector pathvec, struct config * conf, int flag);
 
 void basename (char *, char *);
--- multipath-tools/libmultipath/propsel.c	2009/05/15 21:01:26	1.11.2.3
+++ multipath-tools/libmultipath/propsel.c	2010/01/27 16:46:48	1.11.2.4
@@ -16,6 +16,7 @@
 #include "alias.h"
 #include "defaults.h"
 #include "devmapper.h"
+#include "discovery.h"
 
 pgpolicyfn *pgpolicies[] = {
 	NULL,
@@ -221,17 +222,31 @@
 		checker_get(c, pp->hwe->checker);
 		condlog(3, "%s: path checker = %s (controller setting)",
 			pp->dev, checker_name(c));
-		return 0;
+		goto out;
 	}
 	if (conf->checker) {
 		checker_get(c, conf->checker);
 		condlog(3, "%s: path checker = %s (config file default)",
 			pp->dev, checker_name(c));
-		return 0;
+		goto out;
 	}
 	checker_get(c, checker_default());
 	condlog(3, "%s: path checker = %s (internal default)",
 		pp->dev, checker_name(c));
+out:
+	if (conf->checker_timeout) {
+		c->timeout = conf->checker_timeout;
+		condlog(3, "%s: checker timeout = %u (config file default)",
+			pp->dev, c->timeout);
+	}
+	else if (sysfs_get_timeout(sysfs_path, pp->dev, &c->timeout) == 0)
+		condlog(3, "%s: checker timeout = %u (sysfs setting)",
+			pp->dev, c->timeout);
+	else {
+		c->timeout = DEF_TIMEOUT;
+		condlog(3, "%s: checker timeout = %u (internal default)",
+			pp->dev, c->timeout);
+	}
 	return 0;
 }
 
