summaryrefslogtreecommitdiff
path: root/drivers/s390/block/dasd_genhd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block/dasd_genhd.c')
-rw-r--r--drivers/s390/block/dasd_genhd.c216
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;