[S390] dasd: tunable missing interrupt handler
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>
This commit is contained in:
Родитель
f932bcea6b
Коммит
7c8faa8629
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
Загрузка…
Ссылка в новой задаче