diff options
Diffstat (limited to 'drivers/s390/block/dasd_genhd.c')
| -rw-r--r-- | drivers/s390/block/dasd_genhd.c | 216 |
1 files changed, 135 insertions, 81 deletions
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index f64921756ad6..6ee3d952412e 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Horst Hummel <Horst.Hummel@de.ibm.com> @@ -10,87 +11,145 @@ * */ -#define KMSG_COMPONENT "dasd" - #include <linux/interrupt.h> +#include <linux/major.h> #include <linux/fs.h> #include <linux/blkpg.h> -#include <asm/uaccess.h> - -/* This is ugly... */ -#define PRINTK_HEADER "dasd_gendisk:" +#include <linux/uaccess.h> #include "dasd_int.h" +static unsigned int queue_depth = 32; +static unsigned int nr_hw_queues = 4; +static void dasd_gd_free(struct gendisk *gdp); + +module_param(queue_depth, uint, 0444); +MODULE_PARM_DESC(queue_depth, "Default queue depth for new DASD devices"); + +module_param(nr_hw_queues, uint, 0444); +MODULE_PARM_DESC(nr_hw_queues, "Default number of hardware queues for new DASD devices"); + +/* + * Set device name. + * dasda - dasdz : 26 devices + * dasdaa - dasdzz : 676 devices, added up = 702 + * dasdaaa - dasdzzz : 17576 devices, added up = 18278 + * dasdaaaa - dasdzzzz : 456976 devices, added up = 475252 + */ +static int dasd_name_format(char *prefix, int index, char *buf, int buflen) +{ + const int base = 'z' - 'a' + 1; + char *begin = buf + strlen(prefix); + char *end = buf + buflen; + char *p; + int unit; + + p = end - 1; + *p = '\0'; + unit = base; + do { + if (p == begin) + return -EINVAL; + *--p = 'a' + (index % unit); + index = (index / unit) - 1; + } while (index >= 0); + + memmove(begin, p, end - p); + memcpy(buf, prefix, strlen(prefix)); + + return 0; +} + /* * Allocate and register gendisk structure for device. */ int dasd_gendisk_alloc(struct dasd_block *block) { + struct queue_limits lim = { + /* + * With page sized segments, each segment can be translated into + * one idaw/tidaw. + */ + .max_segment_size = PAGE_SIZE, + .seg_boundary_mask = PAGE_SIZE - 1, + .max_segments = USHRT_MAX, + }; struct gendisk *gdp; struct dasd_device *base; - int len; + unsigned int devindex; + int rc; /* Make sure the minor for this device exists. */ base = block->base; - if (base->devindex >= DASD_PER_MAJOR) + devindex = base->devindex; + if (devindex >= DASD_PER_MAJOR) return -EBUSY; - gdp = alloc_disk(1 << DASD_PARTN_BITS); - if (!gdp) - return -ENOMEM; + block->tag_set.ops = &dasd_mq_ops; + block->tag_set.cmd_size = sizeof(struct dasd_ccw_req); + block->tag_set.nr_hw_queues = nr_hw_queues; + block->tag_set.queue_depth = queue_depth; + block->tag_set.numa_node = NUMA_NO_NODE; + rc = blk_mq_alloc_tag_set(&block->tag_set); + if (rc) + return rc; + + gdp = blk_mq_alloc_disk(&block->tag_set, &lim, block); + if (IS_ERR(gdp)) { + blk_mq_free_tag_set(&block->tag_set); + return PTR_ERR(gdp); + } /* Initialize gendisk structure. */ gdp->major = DASD_MAJOR; - gdp->first_minor = base->devindex << DASD_PARTN_BITS; + gdp->first_minor = devindex << DASD_PARTN_BITS; + gdp->minors = 1 << DASD_PARTN_BITS; gdp->fops = &dasd_device_operations; - gdp->driverfs_dev = &base->cdev->dev; - /* - * Set device name. - * dasda - dasdz : 26 devices - * dasdaa - dasdzz : 676 devices, added up = 702 - * dasdaaa - dasdzzz : 17576 devices, added up = 18278 - * dasdaaaa - dasdzzzz : 456976 devices, added up = 475252 - */ - len = sprintf(gdp->disk_name, "dasd"); - if (base->devindex > 25) { - if (base->devindex > 701) { - if (base->devindex > 18277) - len += sprintf(gdp->disk_name + len, "%c", - 'a'+(((base->devindex-18278) - /17576)%26)); - len += sprintf(gdp->disk_name + len, "%c", - 'a'+(((base->devindex-702)/676)%26)); - } - len += sprintf(gdp->disk_name + len, "%c", - 'a'+(((base->devindex-26)/26)%26)); + rc = dasd_name_format("dasd", devindex, gdp->disk_name, sizeof(gdp->disk_name)); + if (rc) { + DBF_DEV_EVENT(DBF_ERR, block->base, + "setting disk name failed, rc %d", rc); + dasd_gd_free(gdp); + return rc; } - len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26)); if (base->features & DASD_FEATURE_READONLY || test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) set_disk_ro(gdp, 1); dasd_add_link_to_gendisk(gdp, base); - gdp->queue = block->request_queue; block->gdp = gdp; set_capacity(block->gdp, 0); - add_disk(block->gdp); + + rc = device_add_disk(&base->cdev->dev, block->gdp, NULL); + if (rc) { + dasd_gendisk_free(block); + return rc; + } + return 0; } /* + * Free gendisk structure + */ +static void dasd_gd_free(struct gendisk *gd) +{ + del_gendisk(gd); + gd->private_data = NULL; + put_disk(gd); +} + +/* * Unregister and free gendisk structure for device. */ void dasd_gendisk_free(struct dasd_block *block) { if (block->gdp) { - del_gendisk(block->gdp); - block->gdp->queue = NULL; - block->gdp->private_data = NULL; - put_disk(block->gdp); + dasd_gd_free(block->gdp); block->gdp = NULL; + blk_mq_free_tag_set(&block->tag_set); } } @@ -99,27 +158,35 @@ void dasd_gendisk_free(struct dasd_block *block) */ int dasd_scan_partitions(struct dasd_block *block) { - struct block_device *bdev; + struct file *bdev_file; + int rc; - bdev = bdget_disk(block->gdp, 0); - if (!bdev || blkdev_get(bdev, FMODE_READ, NULL) < 0) + bdev_file = bdev_file_open_by_dev(disk_devt(block->gdp), BLK_OPEN_READ, + NULL, NULL); + if (IS_ERR(bdev_file)) { + DBF_DEV_EVENT(DBF_ERR, block->base, + "scan partitions error, blkdev_get returned %ld", + PTR_ERR(bdev_file)); return -ENODEV; + } + + mutex_lock(&block->gdp->open_mutex); + rc = bdev_disk_changed(block->gdp, false); + mutex_unlock(&block->gdp->open_mutex); + if (rc) + DBF_DEV_EVENT(DBF_ERR, block->base, + "scan partitions error, rc %d", rc); + /* - * See fs/partition/check.c:register_disk,rescan_partitions - * Can't call rescan_partitions directly. Use ioctl. - */ - ioctl_by_bdev(bdev, BLKRRPART, 0); - /* - * Since the matching blkdev_put call to the blkdev_get in - * this function is not called before dasd_destroy_partitions - * the offline open_count limit needs to be increased from - * 0 to 1. This is done by setting device->bdev (see - * dasd_generic_set_offline). As long as the partition - * detection is running no offline should be allowed. That - * is why the assignment to device->bdev is done AFTER - * the BLKRRPART ioctl. + * Since the matching fput() call to the + * bdev_file_open_by_path() in this function is not called before + * dasd_destroy_partitions the offline open_count limit needs to be + * increased from 0 to 1. This is done by setting device->bdev_file + * (see dasd_generic_set_offline). As long as the partition detection + * is running no offline should be allowed. That is why the assignment + * to block->bdev_file is done AFTER the BLKRRPART ioctl. */ - block->bdev = bdev; + block->bdev_file = bdev_file; return 0; } @@ -129,34 +196,21 @@ int dasd_scan_partitions(struct dasd_block *block) */ void dasd_destroy_partitions(struct dasd_block *block) { - /* The two structs have 168/176 byte on 31/64 bit. */ - struct blkpg_partition bpart; - struct blkpg_ioctl_arg barg; - struct block_device *bdev; + struct file *bdev_file; /* - * Get the bdev pointer from the device structure and clear - * device->bdev to lower the offline open_count limit again. + * Get the bdev_file pointer from the device structure and clear + * device->bdev_file to lower the offline open_count limit again. */ - bdev = block->bdev; - block->bdev = NULL; + bdev_file = block->bdev_file; + block->bdev_file = NULL; + + mutex_lock(&file_bdev(bdev_file)->bd_disk->open_mutex); + bdev_disk_changed(file_bdev(bdev_file)->bd_disk, true); + mutex_unlock(&file_bdev(bdev_file)->bd_disk->open_mutex); - /* - * See fs/partition/check.c:delete_partition - * Can't call delete_partitions directly. Use ioctl. - * The ioctl also does locking and invalidation. - */ - memset(&bpart, 0, sizeof(struct blkpg_partition)); - memset(&barg, 0, sizeof(struct blkpg_ioctl_arg)); - barg.data = (void __force __user *) &bpart; - barg.op = BLKPG_DEL_PARTITION; - for (bpart.pno = block->gdp->minors - 1; bpart.pno > 0; bpart.pno--) - ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg); - - invalidate_partition(block->gdp, 0); /* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */ - blkdev_put(bdev, FMODE_READ); - set_capacity(block->gdp, 0); + fput(bdev_file); } int dasd_gendisk_init(void) @@ -166,8 +220,8 @@ int dasd_gendisk_init(void) /* Register to static dasd major 94 */ rc = register_blkdev(DASD_MAJOR, "dasd"); if (rc != 0) { - pr_warning("Registering the device driver with major number " - "%d failed\n", DASD_MAJOR); + pr_warn("Registering the device driver with major number %d failed\n", + DASD_MAJOR); return rc; } return 0; |
