From: NeilBrown <neilb@suse.de>
Date: Fri, 2 Dec 2011 10:40:37 +0100
Subject: Add failfast_expires configuration to dasd
Patch-mainline: Unlikely
References: Fate#311379

Add 'failfast_expires' attributes settable via sysfs similar to the
'expires' attributes.
failfast_expires is used for REQ_FAILFAST_DEV requests as might be
created by md/raid1/failfast.  'expires' is used for all other requests.

Acked-by: Neil Brown <neilb@suse.de>
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Hannes Reinecke <hare@suse.de>

diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index d71511c..f7ebdaf 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -1209,6 +1209,51 @@ dasd_expires_store(struct device *dev, struct device_attribute *attr,
 
 static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store);
 
+/*
+ * expiration time for failfast requests
+ */
+static ssize_t
+dasd_failfast_expires_show(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct dasd_device *device;
+	int len;
+
+	device = dasd_device_from_cdev(to_ccwdev(dev));
+	if (IS_ERR(device))
+		return -ENODEV;
+	len = snprintf(buf, PAGE_SIZE, "%lu\n", device->failfast_expires);
+	dasd_put_device(device);
+	return len;
+}
+
+static ssize_t
+dasd_failfast_expires_store(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	struct dasd_device *device;
+	unsigned long val;
+
+	device = dasd_device_from_cdev(to_ccwdev(dev));
+	if (IS_ERR(device))
+		return -ENODEV;
+
+	if ((strict_strtoul(buf, 10, &val) != 0) ||
+	    (val > DASD_EXPIRES_MAX) || val == 0) {
+		dasd_put_device(device);
+		return -EINVAL;
+	}
+
+	if (val)
+		device->failfast_expires = val;
+
+	dasd_put_device(device);
+	return count;
+}
+
+static DEVICE_ATTR(failfast_expires, 0644,
+		   dasd_failfast_expires_show, dasd_failfast_expires_store);
+
 static ssize_t dasd_reservation_policy_show(struct device *dev,
 					    struct device_attribute *attr,
 					    char *buf)
@@ -1319,6 +1364,7 @@ static struct attribute * dasd_attrs[] = {
 	&dev_attr_erplog.attr,
 	&dev_attr_failfast.attr,
 	&dev_attr_expires.attr,
+	&dev_attr_failfast_expires.attr,
 	&dev_attr_reservation_policy.attr,
 	&dev_attr_last_known_reservation_state.attr,
 	NULL,
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 46784b8..ffdaf41 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -360,6 +360,7 @@ dasd_diag_check_device(struct dasd_device *device)
 	}
 
 	device->default_expires = DIAG_TIMEOUT;
+	device->failfast_expires = DIAG_TIMEOUT;
 
 	/* Figure out position of label block */
 	switch (private->rdc_data.vdev_class) {
@@ -564,7 +565,10 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
 	cqr->startdev = memdev;
 	cqr->memdev = memdev;
 	cqr->block = block;
-	cqr->expires = memdev->default_expires * HZ;
+	if (req->cmd_flags & REQ_FAILFAST_DEV)
+		cqr->expires = memdev->failfast_expires * HZ;
+	else
+		cqr->expires = memdev->default_expires * HZ;
 	cqr->status = DASD_CQR_FILLED;
 	return cqr;
 }
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 182ca76..bd30ac7 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1434,6 +1434,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
 		if (value != 0 && value <= DASD_EXPIRES_MAX)
 			device->default_expires = value;
 	}
+	device->failfast_expires = device->default_expires;
 
 	/* Generate device unique id */
 	rc = dasd_eckd_generate_uid(device);
@@ -2267,7 +2268,10 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
 	cqr->startdev = startdev;
 	cqr->memdev = startdev;
 	cqr->block = block;
-	cqr->expires = startdev->default_expires * HZ;	/* default 5 minutes */
+	if (req->cmd_flags & REQ_FAILFAST_DEV)
+		cqr->expires = startdev->failfast_expires * HZ;
+	else
+		cqr->expires = startdev->default_expires * HZ;
 	cqr->lpm = startdev->path_data.ppm;
 	cqr->retries = 256;
 	cqr->buildclk = get_clock();
@@ -2442,7 +2446,10 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
 	cqr->startdev = startdev;
 	cqr->memdev = startdev;
 	cqr->block = block;
-	cqr->expires = startdev->default_expires * HZ;	/* default 5 minutes */
+	if (req->cmd_flags & REQ_FAILFAST_DEV)
+		cqr->expires = startdev->failfast_expires * HZ;
+	else
+		cqr->expires = startdev->default_expires * HZ;
 	cqr->lpm = startdev->path_data.ppm;
 	cqr->retries = 256;
 	cqr->buildclk = get_clock();
@@ -2730,7 +2737,10 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
 	cqr->startdev = startdev;
 	cqr->memdev = startdev;
 	cqr->block = block;
-	cqr->expires = startdev->default_expires * HZ;	/* default 5 minutes */
+	if (req->cmd_flags & REQ_FAILFAST_DEV)
+		cqr->expires = startdev->failfast_expires * HZ;
+	else
+		cqr->expires = startdev->default_expires * HZ;
 	cqr->lpm = startdev->path_data.ppm;
 	cqr->retries = 256;
 	cqr->buildclk = get_clock();
@@ -2930,7 +2940,10 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
 	cqr->startdev = startdev;
 	cqr->memdev = startdev;
 	cqr->block = block;
-	cqr->expires = startdev->default_expires * HZ;
+	if (req->cmd_flags & REQ_FAILFAST_DEV)
+		cqr->expires = startdev->failfast_expires * HZ;
+	else
+		cqr->expires = startdev->default_expires * HZ;
 	cqr->lpm = startdev->path_data.ppm;
 	cqr->retries = 256;
 	cqr->buildclk = get_clock();
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index a62a753..7ab4a34 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -168,6 +168,7 @@ dasd_fba_check_characteristics(struct dasd_device *device)
 	}
 
 	device->default_expires = DASD_EXPIRES;
+	device->failfast_expires = DASD_EXPIRES;
 	device->path_data.opm = LPM_ANYPATH;
 
 	readonly = dasd_device_is_ro(device);
@@ -369,7 +370,10 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
 	cqr->startdev = memdev;
 	cqr->memdev = memdev;
 	cqr->block = block;
-	cqr->expires = memdev->default_expires * HZ;	/* default 5 minutes */
+	if (req->cmd_flags & REQ_FAILFAST_DEV)
+		cqr->expires = memdev->failfast_expires * HZ;
+	else
+		cqr->expires = memdev->default_expires * HZ;
 	cqr->retries = 32;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index fd0af8e..296df14 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -431,6 +431,7 @@ struct dasd_device {
 
 	/* default expiration time in s */
 	unsigned long default_expires;
+	unsigned long failfast_expires;
 };
 
 struct dasd_block {
