diff options
Diffstat (limited to 'drivers/s390/block/dasd_devmap.c')
| -rw-r--r-- | drivers/s390/block/dasd_devmap.c | 328 |
1 files changed, 320 insertions, 8 deletions
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 8d41f3ed38d..2ead7e78c45 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -1,11 +1,10 @@ /* - * File...........: linux/drivers/s390/block/dasd_devmap.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Horst Hummel <Horst.Hummel@de.ibm.com> * Carsten Otte <Cotte@de.ibm.com> * Martin Schwidefsky <schwidefsky@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 + * Copyright IBM Corp. 1999,2001 * * Device mapping and dasd= parameter parsing functions. All devmap * functions may not be called from interrupt context. In particular @@ -208,6 +207,8 @@ dasd_feature_list(char *str, char **endp) features |= DASD_FEATURE_READONLY; else if (len == 4 && !strncmp(str, "diag", 4)) features |= DASD_FEATURE_USEDIAG; + else if (len == 3 && !strncmp(str, "raw", 3)) + features |= DASD_FEATURE_USERAW; else if (len == 6 && !strncmp(str, "erplog", 6)) features |= DASD_FEATURE_ERPLOG; else if (len == 8 && !strncmp(str, "failfast", 8)) @@ -300,7 +301,7 @@ dasd_parse_keyword( char *parsestring ) { /* * Try to interprete the first element on the comma separated parse string * as a device number or a range of devices. If the interpretation is - * successfull, create the matching dasd_devmap entries and return a pointer + * successful, create the matching dasd_devmap entries and return a pointer * to the residual string. * If interpretation fails or in case of an error, return an error code. */ @@ -409,8 +410,7 @@ dasd_add_busid(const char *bus_id, int features) struct dasd_devmap *devmap, *new, *tmp; int hash; - new = (struct dasd_devmap *) - kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL); + new = kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL); if (!new) return ERR_PTR(-ENOMEM); spin_lock(&dasd_devmap_lock); @@ -639,6 +639,7 @@ dasd_put_device_wake(struct dasd_device *device) { wake_up(&dasd_delete_wq); } +EXPORT_SYMBOL_GPL(dasd_put_device_wake); /* * Return dasd_device structure associated with cdev. @@ -671,6 +672,36 @@ dasd_device_from_cdev(struct ccw_device *cdev) return device; } +void dasd_add_link_to_gendisk(struct gendisk *gdp, struct dasd_device *device) +{ + struct dasd_devmap *devmap; + + devmap = dasd_find_busid(dev_name(&device->cdev->dev)); + if (IS_ERR(devmap)) + return; + spin_lock(&dasd_devmap_lock); + gdp->private_data = devmap; + spin_unlock(&dasd_devmap_lock); +} + +struct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp) +{ + struct dasd_device *device; + struct dasd_devmap *devmap; + + if (!gdp->private_data) + return NULL; + device = NULL; + spin_lock(&dasd_devmap_lock); + devmap = gdp->private_data; + if (devmap && devmap->device) { + device = devmap->device; + dasd_get_device(device); + } + spin_unlock(&dasd_devmap_lock); + return device; +} + /* * SECTION: files in sysfs */ @@ -856,7 +887,7 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, spin_lock(&dasd_devmap_lock); /* Changing diag discipline flag is only allowed in offline state. */ rc = count; - if (!devmap->device) { + if (!devmap->device && !(devmap->features & DASD_FEATURE_USERAW)) { if (val) devmap->features |= DASD_FEATURE_USEDIAG; else @@ -869,6 +900,89 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store); +/* + * use_raw controls whether the driver should give access to raw eckd data or + * operate in standard mode + */ +static ssize_t +dasd_use_raw_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dasd_devmap *devmap; + int use_raw; + + devmap = dasd_find_busid(dev_name(dev)); + if (!IS_ERR(devmap)) + use_raw = (devmap->features & DASD_FEATURE_USERAW) != 0; + else + use_raw = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USERAW) != 0; + return sprintf(buf, use_raw ? "1\n" : "0\n"); +} + +static ssize_t +dasd_use_raw_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dasd_devmap *devmap; + ssize_t rc; + unsigned long val; + + devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); + if (IS_ERR(devmap)) + return PTR_ERR(devmap); + + if ((kstrtoul(buf, 10, &val) != 0) || val > 1) + return -EINVAL; + + spin_lock(&dasd_devmap_lock); + /* Changing diag discipline flag is only allowed in offline state. */ + rc = count; + if (!devmap->device && !(devmap->features & DASD_FEATURE_USEDIAG)) { + if (val) + devmap->features |= DASD_FEATURE_USERAW; + else + devmap->features &= ~DASD_FEATURE_USERAW; + } else + rc = -EPERM; + spin_unlock(&dasd_devmap_lock); + return rc; +} + +static DEVICE_ATTR(raw_track_access, 0644, dasd_use_raw_show, + dasd_use_raw_store); + +static ssize_t +dasd_safe_offline_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ccw_device *cdev = to_ccwdev(dev); + struct dasd_device *device; + int rc; + + device = dasd_device_from_cdev(cdev); + if (IS_ERR(device)) { + rc = PTR_ERR(device); + goto out; + } + + if (test_bit(DASD_FLAG_OFFLINE, &device->flags) || + test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) { + /* Already doing offline processing */ + dasd_put_device(device); + rc = -EBUSY; + goto out; + } + + set_bit(DASD_FLAG_SAFE_OFFLINE, &device->flags); + dasd_put_device(device); + + rc = ccw_device_set_offline(cdev); + +out: + return rc ? rc : count; +} + +static DEVICE_ATTR(safe_offline, 0200, NULL, dasd_safe_offline_store); + static ssize_t dasd_discipline_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1111,7 +1225,7 @@ dasd_expires_store(struct device *dev, struct device_attribute *attr, if (IS_ERR(device)) return -ENODEV; - if ((strict_strtoul(buf, 10, &val) != 0) || + if ((kstrtoul(buf, 10, &val) != 0) || (val > DASD_EXPIRES_MAX) || val == 0) { dasd_put_device(device); return -EINVAL; @@ -1126,6 +1240,198 @@ dasd_expires_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store); +static ssize_t +dasd_retries_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_retries); + dasd_put_device(device); + return len; +} + +static ssize_t +dasd_retries_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 ((kstrtoul(buf, 10, &val) != 0) || + (val > DASD_RETRIES_MAX)) { + dasd_put_device(device); + return -EINVAL; + } + + if (val) + device->default_retries = val; + + dasd_put_device(device); + return count; +} + +static DEVICE_ATTR(retries, 0644, dasd_retries_show, dasd_retries_store); + +static ssize_t +dasd_timeout_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->blk_timeout); + dasd_put_device(device); + return len; +} + +static ssize_t +dasd_timeout_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dasd_device *device; + struct request_queue *q; + unsigned long val, flags; + + device = dasd_device_from_cdev(to_ccwdev(dev)); + if (IS_ERR(device) || !device->block) + return -ENODEV; + + if ((kstrtoul(buf, 10, &val) != 0) || + val > UINT_MAX / HZ) { + dasd_put_device(device); + return -EINVAL; + } + q = device->block->request_queue; + if (!q) { + dasd_put_device(device); + return -ENODEV; + } + spin_lock_irqsave(&device->block->request_queue_lock, flags); + if (!val) + blk_queue_rq_timed_out(q, NULL); + else + blk_queue_rq_timed_out(q, dasd_times_out); + + device->blk_timeout = val; + + blk_queue_rq_timeout(q, device->blk_timeout * HZ); + spin_unlock_irqrestore(&device->block->request_queue_lock, flags); + + dasd_put_device(device); + return count; +} + +static DEVICE_ATTR(timeout, 0644, + dasd_timeout_show, dasd_timeout_store); + +static ssize_t dasd_reservation_policy_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dasd_devmap *devmap; + int rc = 0; + + devmap = dasd_find_busid(dev_name(dev)); + if (IS_ERR(devmap)) { + rc = snprintf(buf, PAGE_SIZE, "ignore\n"); + } else { + spin_lock(&dasd_devmap_lock); + if (devmap->features & DASD_FEATURE_FAILONSLCK) + rc = snprintf(buf, PAGE_SIZE, "fail\n"); + else + rc = snprintf(buf, PAGE_SIZE, "ignore\n"); + spin_unlock(&dasd_devmap_lock); + } + return rc; +} + +static ssize_t dasd_reservation_policy_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dasd_devmap *devmap; + int rc; + + devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); + if (IS_ERR(devmap)) + return PTR_ERR(devmap); + rc = 0; + spin_lock(&dasd_devmap_lock); + if (sysfs_streq("ignore", buf)) + devmap->features &= ~DASD_FEATURE_FAILONSLCK; + else if (sysfs_streq("fail", buf)) + devmap->features |= DASD_FEATURE_FAILONSLCK; + else + rc = -EINVAL; + if (devmap->device) + devmap->device->features = devmap->features; + spin_unlock(&dasd_devmap_lock); + if (rc) + return rc; + else + return count; +} + +static DEVICE_ATTR(reservation_policy, 0644, + dasd_reservation_policy_show, dasd_reservation_policy_store); + +static ssize_t dasd_reservation_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dasd_device *device; + int rc = 0; + + device = dasd_device_from_cdev(to_ccwdev(dev)); + if (IS_ERR(device)) + return snprintf(buf, PAGE_SIZE, "none\n"); + + if (test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) + rc = snprintf(buf, PAGE_SIZE, "reserved\n"); + else if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags)) + rc = snprintf(buf, PAGE_SIZE, "lost\n"); + else + rc = snprintf(buf, PAGE_SIZE, "none\n"); + dasd_put_device(device); + return rc; +} + +static ssize_t dasd_reservation_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dasd_device *device; + int rc = 0; + + device = dasd_device_from_cdev(to_ccwdev(dev)); + if (IS_ERR(device)) + return -ENODEV; + if (sysfs_streq("reset", buf)) + clear_bit(DASD_FLAG_LOCK_STOLEN, &device->flags); + else + rc = -EINVAL; + dasd_put_device(device); + + if (rc) + return rc; + else + return count; +} + +static DEVICE_ATTR(last_known_reservation_state, 0644, + dasd_reservation_state_show, dasd_reservation_state_store); + static struct attribute * dasd_attrs[] = { &dev_attr_readonly.attr, &dev_attr_discipline.attr, @@ -1134,10 +1440,16 @@ static struct attribute * dasd_attrs[] = { &dev_attr_vendor.attr, &dev_attr_uid.attr, &dev_attr_use_diag.attr, + &dev_attr_raw_track_access.attr, &dev_attr_eer_enabled.attr, &dev_attr_erplog.attr, &dev_attr_failfast.attr, &dev_attr_expires.attr, + &dev_attr_retries.attr, + &dev_attr_timeout.attr, + &dev_attr_reservation_policy.attr, + &dev_attr_last_known_reservation_state.attr, + &dev_attr_safe_offline.attr, NULL, }; @@ -1162,7 +1474,7 @@ dasd_get_feature(struct ccw_device *cdev, int feature) /* * Set / reset given feature. - * Flag indicates wether to set (!=0) or the reset (=0) the feature. + * Flag indicates whether to set (!=0) or the reset (=0) the feature. */ int dasd_set_feature(struct ccw_device *cdev, int feature, int flag) |
