diff options
Diffstat (limited to 'drivers/s390/block')
-rw-r--r-- | drivers/s390/block/dasd.c | 8 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 44 | ||||
-rw-r--r-- | drivers/s390/block/dasd_diag.c | 6 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 94 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.h | 7 | ||||
-rw-r--r-- | drivers/s390/block/dasd_fba.c | 4 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 8 | ||||
-rw-r--r-- | drivers/s390/block/dcssblk.c | 5 |
8 files changed, 153 insertions, 23 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 33975e922d6..1a84fae155e 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -21,6 +21,7 @@ #include <linux/hdreg.h> #include <linux/async.h> #include <linux/mutex.h> +#include <linux/smp_lock.h> #include <asm/ccwdev.h> #include <asm/ebcdic.h> @@ -2196,7 +2197,7 @@ static void dasd_setup_queue(struct dasd_block *block) */ blk_queue_max_segment_size(block->request_queue, PAGE_SIZE); blk_queue_segment_boundary(block->request_queue, PAGE_SIZE - 1); - blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN, NULL); + blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN); } /* @@ -2235,6 +2236,7 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) if (!block) return -ENODEV; + lock_kernel(); base = block->base; atomic_inc(&block->open_count); if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { @@ -2269,12 +2271,14 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) goto out; } + unlock_kernel(); return 0; out: module_put(base->discipline->owner); unlock: atomic_dec(&block->open_count); + unlock_kernel(); return rc; } @@ -2282,8 +2286,10 @@ static int dasd_release(struct gendisk *disk, fmode_t mode) { struct dasd_block *block = disk->private_data; + lock_kernel(); atomic_dec(&block->open_count); module_put(block->base->discipline->owner); + unlock_kernel(); return 0; } diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index bed7b4634cc..8d41f3ed38d 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -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, }; diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 687f323cdc3..2b3bc3ec054 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -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; } diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index ab84da5592e..66360c24bd4 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -82,6 +82,14 @@ static struct ccw_driver dasd_eckd_driver; /* see below */ #define INIT_CQR_UNFORMATTED 1 #define INIT_CQR_ERROR 2 +/* emergency request for reserve/release */ +static struct { + struct dasd_ccw_req cqr; + struct ccw1 ccw; + char data[32]; +} *dasd_reserve_req; +static DEFINE_MUTEX(dasd_reserve_mutex); + /* initial attempt at a probe function. this can be simplified once * the other detection code is gone */ @@ -1107,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, @@ -1143,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) @@ -1973,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(); @@ -2150,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(); @@ -2398,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(); @@ -2645,15 +2666,23 @@ dasd_eckd_release(struct dasd_device *device) struct dasd_ccw_req *cqr; int rc; struct ccw1 *ccw; + int useglobal; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + useglobal = 0; cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { - DBF_DEV_EVENT(DBF_WARNING, device, "%s", - "Could not allocate initialization request"); - return PTR_ERR(cqr); + mutex_lock(&dasd_reserve_mutex); + useglobal = 1; + cqr = &dasd_reserve_req->cqr; + memset(cqr, 0, sizeof(*cqr)); + memset(&dasd_reserve_req->ccw, 0, + sizeof(dasd_reserve_req->ccw)); + cqr->cpaddr = &dasd_reserve_req->ccw; + cqr->data = &dasd_reserve_req->data; + cqr->magic = DASD_ECKD_MAGIC; } ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_RELEASE; @@ -2671,7 +2700,10 @@ dasd_eckd_release(struct dasd_device *device) rc = dasd_sleep_on_immediatly(cqr); - dasd_sfree_request(cqr, cqr->memdev); + if (useglobal) + mutex_unlock(&dasd_reserve_mutex); + else + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -2687,15 +2719,23 @@ dasd_eckd_reserve(struct dasd_device *device) struct dasd_ccw_req *cqr; int rc; struct ccw1 *ccw; + int useglobal; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + useglobal = 0; cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { - DBF_DEV_EVENT(DBF_WARNING, device, "%s", - "Could not allocate initialization request"); - return PTR_ERR(cqr); + mutex_lock(&dasd_reserve_mutex); + useglobal = 1; + cqr = &dasd_reserve_req->cqr; + memset(cqr, 0, sizeof(*cqr)); + memset(&dasd_reserve_req->ccw, 0, + sizeof(dasd_reserve_req->ccw)); + cqr->cpaddr = &dasd_reserve_req->ccw; + cqr->data = &dasd_reserve_req->data; + cqr->magic = DASD_ECKD_MAGIC; } ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_RESERVE; @@ -2713,7 +2753,10 @@ dasd_eckd_reserve(struct dasd_device *device) rc = dasd_sleep_on_immediatly(cqr); - dasd_sfree_request(cqr, cqr->memdev); + if (useglobal) + mutex_unlock(&dasd_reserve_mutex); + else + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -2728,15 +2771,23 @@ dasd_eckd_steal_lock(struct dasd_device *device) struct dasd_ccw_req *cqr; int rc; struct ccw1 *ccw; + int useglobal; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + useglobal = 0; cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { - DBF_DEV_EVENT(DBF_WARNING, device, "%s", - "Could not allocate initialization request"); - return PTR_ERR(cqr); + mutex_lock(&dasd_reserve_mutex); + useglobal = 1; + cqr = &dasd_reserve_req->cqr; + memset(cqr, 0, sizeof(*cqr)); + memset(&dasd_reserve_req->ccw, 0, + sizeof(dasd_reserve_req->ccw)); + cqr->cpaddr = &dasd_reserve_req->ccw; + cqr->data = &dasd_reserve_req->data; + cqr->magic = DASD_ECKD_MAGIC; } ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_SLCK; @@ -2754,7 +2805,10 @@ dasd_eckd_steal_lock(struct dasd_device *device) rc = dasd_sleep_on_immediatly(cqr); - dasd_sfree_request(cqr, cqr->memdev); + if (useglobal) + mutex_unlock(&dasd_reserve_mutex); + else + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -3488,10 +3542,15 @@ dasd_eckd_init(void) int ret; ASCEBC(dasd_eckd_discipline.ebcname, 4); + dasd_reserve_req = kmalloc(sizeof(*dasd_reserve_req), + GFP_KERNEL | GFP_DMA); + if (!dasd_reserve_req) + return -ENOMEM; ret = ccw_driver_register(&dasd_eckd_driver); if (!ret) wait_for_device_probe(); - + else + kfree(dasd_reserve_req); return ret; } @@ -3499,6 +3558,7 @@ static void __exit dasd_eckd_cleanup(void) { ccw_driver_unregister(&dasd_eckd_driver); + kfree(dasd_reserve_req); } module_init(dasd_eckd_init); diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index dd6385a5af1..0eb49655a6c 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -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)); diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 37282b90eec..bec5486e0e6 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -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; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 49b431d135e..500678d7116 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -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 { diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 9b43ae94beb..2bd72aa34c5 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -14,6 +14,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/blkdev.h> +#include <linux/smp_lock.h> #include <linux/completion.h> #include <linux/interrupt.h> #include <linux/platform_device.h> @@ -775,6 +776,7 @@ dcssblk_open(struct block_device *bdev, fmode_t mode) struct dcssblk_dev_info *dev_info; int rc; + lock_kernel(); dev_info = bdev->bd_disk->private_data; if (NULL == dev_info) { rc = -ENODEV; @@ -784,6 +786,7 @@ dcssblk_open(struct block_device *bdev, fmode_t mode) bdev->bd_block_size = 4096; rc = 0; out: + unlock_kernel(); return rc; } @@ -794,6 +797,7 @@ dcssblk_release(struct gendisk *disk, fmode_t mode) struct segment_info *entry; int rc; + lock_kernel(); if (!dev_info) { rc = -ENODEV; goto out; @@ -811,6 +815,7 @@ dcssblk_release(struct gendisk *disk, fmode_t mode) up_write(&dcssblk_devices_sem); rc = 0; out: + unlock_kernel(); return rc; } |