[S390] dasd: tunable missing interrupt handler
authorStefan Haberland <stefan.haberland@de.ibm.com>
Mon, 9 Aug 2010 16:13:00 +0000 (18:13 +0200)
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>
Mon, 9 Aug 2010 16:12:54 +0000 (18:12 +0200)
This feature provides a user interface to specify the timeout for
missing interrupts for standard I/O operations.

Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eckd.h
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_int.h

index bed7b46..8d41f3e 100644 (file)
@@ -1083,6 +1083,49 @@ dasd_eer_store(struct device *dev, struct device_attribute *attr,
 
 static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store);
 
+/*
+ * expiration time for default requests
+ */
+static ssize_t
+dasd_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->default_expires);
+       dasd_put_device(device);
+       return len;
+}
+
+static ssize_t
+dasd_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->default_expires = val;
+
+       dasd_put_device(device);
+       return count;
+}
+
+static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store);
+
 static struct attribute * dasd_attrs[] = {
        &dev_attr_readonly.attr,
        &dev_attr_discipline.attr,
@@ -1094,6 +1137,7 @@ static struct attribute * dasd_attrs[] = {
        &dev_attr_eer_enabled.attr,
        &dev_attr_erplog.attr,
        &dev_attr_failfast.attr,
+       &dev_attr_expires.attr,
        NULL,
 };
 
index 687f323..2b3bc3e 100644 (file)
@@ -43,7 +43,7 @@ MODULE_LICENSE("GPL");
                           sizeof(struct dasd_diag_req)) / \
                           sizeof(struct dasd_diag_bio)) / 2)
 #define DIAG_MAX_RETRIES       32
-#define DIAG_TIMEOUT           50 * HZ
+#define DIAG_TIMEOUT           50
 
 static struct dasd_discipline dasd_diag_discipline;
 
@@ -360,6 +360,8 @@ dasd_diag_check_device(struct dasd_device *device)
                goto out;
        }
 
+       device->default_expires = DIAG_TIMEOUT;
+
        /* Figure out position of label block */
        switch (private->rdc_data.vdev_class) {
        case DEV_CLASS_FBA:
@@ -563,7 +565,7 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
        cqr->startdev = memdev;
        cqr->memdev = memdev;
        cqr->block = block;
-       cqr->expires = DIAG_TIMEOUT;
+       cqr->expires = memdev->default_expires * HZ;
        cqr->status = DASD_CQR_FILLED;
        return cqr;
 }
index 0483b2e..66360c2 100644 (file)
@@ -1115,8 +1115,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
        struct dasd_eckd_private *private;
        struct dasd_block *block;
        struct dasd_uid temp_uid;
-       int is_known, rc;
+       int is_known, rc, i;
        int readonly;
+       unsigned long value;
 
        if (!ccw_device_is_pathgroup(device->cdev)) {
                dev_warn(&device->cdev->dev,
@@ -1151,6 +1152,18 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
        if (rc)
                goto out_err1;
 
+       /* set default timeout */
+       device->default_expires = DASD_EXPIRES;
+       if (private->gneq) {
+               value = 1;
+               for (i = 0; i < private->gneq->timeout.value; i++)
+                       value = 10 * value;
+               value = value * private->gneq->timeout.number;
+               /* do not accept useless values */
+               if (value != 0 && value <= DASD_EXPIRES_MAX)
+                       device->default_expires = value;
+       }
+
        /* Generate device unique id */
        rc = dasd_eckd_generate_uid(device);
        if (rc)
@@ -1981,7 +1994,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
        cqr->startdev = startdev;
        cqr->memdev = startdev;
        cqr->block = block;
-       cqr->expires = 5 * 60 * HZ;     /* 5 minutes */
+       cqr->expires = startdev->default_expires * HZ;  /* default 5 minutes */
        cqr->lpm = private->path_data.ppm;
        cqr->retries = 256;
        cqr->buildclk = get_clock();
@@ -2158,7 +2171,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
        cqr->startdev = startdev;
        cqr->memdev = startdev;
        cqr->block = block;
-       cqr->expires = 5 * 60 * HZ;     /* 5 minutes */
+       cqr->expires = startdev->default_expires * HZ;  /* default 5 minutes */
        cqr->lpm = private->path_data.ppm;
        cqr->retries = 256;
        cqr->buildclk = get_clock();
@@ -2406,7 +2419,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
        cqr->startdev = startdev;
        cqr->memdev = startdev;
        cqr->block = block;
-       cqr->expires = 5 * 60 * HZ;     /* 5 minutes */
+       cqr->expires = startdev->default_expires * HZ;  /* default 5 minutes */
        cqr->lpm = private->path_data.ppm;
        cqr->retries = 256;
        cqr->buildclk = get_clock();
index dd6385a..0eb4965 100644 (file)
@@ -320,7 +320,12 @@ struct dasd_gneq {
                __u8 identifier:2;
                __u8 reserved:6;
        } __attribute__ ((packed)) flags;
-       __u8 reserved[7];
+       __u8 reserved[5];
+       struct {
+               __u8 value:2;
+               __u8 number:6;
+       } __attribute__ ((packed)) timeout;
+       __u8 reserved3;
        __u16 subsystemID;
        __u8 reserved2[22];
 } __attribute__ ((packed));
index 37282b9..bec5486 100644 (file)
@@ -163,6 +163,8 @@ dasd_fba_check_characteristics(struct dasd_device *device)
                return rc;
        }
 
+       device->default_expires = DASD_EXPIRES;
+
        readonly = dasd_device_is_ro(device);
        if (readonly)
                set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
@@ -370,7 +372,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
        cqr->startdev = memdev;
        cqr->memdev = memdev;
        cqr->block = block;
-       cqr->expires = 5 * 60 * HZ;     /* 5 minutes */
+       cqr->expires = memdev->default_expires * HZ;    /* default 5 minutes */
        cqr->retries = 32;
        cqr->buildclk = get_clock();
        cqr->status = DASD_CQR_FILLED;
index 49b431d..500678d 100644 (file)
@@ -186,7 +186,7 @@ struct dasd_ccw_req {
 
        /* ... and how */
        unsigned long starttime;        /* jiffies time of request start */
-       int expires;                    /* expiration period in jiffies */
+       unsigned long expires;          /* expiration period in jiffies */
        char lpm;                       /* logical path mask */
        void *data;                     /* pointer to data area */
 
@@ -224,6 +224,9 @@ struct dasd_ccw_req {
 #define DASD_CQR_CLEARED       0x84    /* request was cleared */
 #define DASD_CQR_SUCCESS       0x85    /* request was successful */
 
+/* default expiration time*/
+#define DASD_EXPIRES     300
+#define DASD_EXPIRES_MAX  40000000
 
 /* per dasd_ccw_req flags */
 #define DASD_CQR_FLAGS_USE_ERP   0     /* use ERP for this request */
@@ -404,6 +407,9 @@ struct dasd_device {
 
        /* hook for alias management */
        struct list_head alias_list;
+
+       /* default expiration time in s */
+       unsigned long default_expires;
 };
 
 struct dasd_block {