1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4 * Horst Hummel <Horst.Hummel@de.ibm.com>
5 * Carsten Otte <Cotte@de.ibm.com>
6 * Martin Schwidefsky <schwidefsky@de.ibm.com>
7 * Bugreports.to..: <Linux390@de.ibm.com>
8 * Copyright IBM Corp. 1999, 2001
9 *
10 * gendisk related functions for the dasd driver.
11 *
12 */
13
14#define KMSG_COMPONENT "dasd"
15
16#include <linux/interrupt.h>
17#include <linux/major.h>
18#include <linux/fs.h>
19#include <linux/blkpg.h>
20
21#include <linux/uaccess.h>
22
23/* This is ugly... */
24#define PRINTK_HEADER "dasd_gendisk:"
25
26#include "dasd_int.h"
27
28static unsigned int queue_depth = 32;
29static unsigned int nr_hw_queues = 4;
30
31module_param(queue_depth, uint, 0444);
32MODULE_PARM_DESC(queue_depth, "Default queue depth for new DASD devices");
33
34module_param(nr_hw_queues, uint, 0444);
35MODULE_PARM_DESC(nr_hw_queues, "Default number of hardware queues for new DASD devices");
36
37/*
38 * Allocate and register gendisk structure for device.
39 */
40int dasd_gendisk_alloc(struct dasd_block *block)
41{
42 struct gendisk *gdp;
43 struct dasd_device *base;
44 int len, rc;
45
46 /* Make sure the minor for this device exists. */
47 base = block->base;
48 if (base->devindex >= DASD_PER_MAJOR)
49 return -EBUSY;
50
51 block->tag_set.ops = &dasd_mq_ops;
52 block->tag_set.cmd_size = sizeof(struct dasd_ccw_req);
53 block->tag_set.nr_hw_queues = nr_hw_queues;
54 block->tag_set.queue_depth = queue_depth;
55 block->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
56 block->tag_set.numa_node = NUMA_NO_NODE;
57 rc = blk_mq_alloc_tag_set(set: &block->tag_set);
58 if (rc)
59 return rc;
60
61 gdp = blk_mq_alloc_disk(&block->tag_set, block);
62 if (IS_ERR(ptr: gdp)) {
63 blk_mq_free_tag_set(set: &block->tag_set);
64 return PTR_ERR(ptr: gdp);
65 }
66
67 /* Initialize gendisk structure. */
68 gdp->major = DASD_MAJOR;
69 gdp->first_minor = base->devindex << DASD_PARTN_BITS;
70 gdp->minors = 1 << DASD_PARTN_BITS;
71 gdp->fops = &dasd_device_operations;
72
73 /*
74 * Set device name.
75 * dasda - dasdz : 26 devices
76 * dasdaa - dasdzz : 676 devices, added up = 702
77 * dasdaaa - dasdzzz : 17576 devices, added up = 18278
78 * dasdaaaa - dasdzzzz : 456976 devices, added up = 475252
79 */
80 len = sprintf(buf: gdp->disk_name, fmt: "dasd");
81 if (base->devindex > 25) {
82 if (base->devindex > 701) {
83 if (base->devindex > 18277)
84 len += sprintf(buf: gdp->disk_name + len, fmt: "%c",
85 'a'+(((base->devindex-18278)
86 /17576)%26));
87 len += sprintf(buf: gdp->disk_name + len, fmt: "%c",
88 'a'+(((base->devindex-702)/676)%26));
89 }
90 len += sprintf(buf: gdp->disk_name + len, fmt: "%c",
91 'a'+(((base->devindex-26)/26)%26));
92 }
93 len += sprintf(buf: gdp->disk_name + len, fmt: "%c", 'a'+(base->devindex%26));
94
95 if (base->features & DASD_FEATURE_READONLY ||
96 test_bit(DASD_FLAG_DEVICE_RO, &base->flags))
97 set_disk_ro(disk: gdp, read_only: 1);
98 dasd_add_link_to_gendisk(gdp, base);
99 block->gdp = gdp;
100 set_capacity(disk: block->gdp, size: 0);
101
102 rc = device_add_disk(parent: &base->cdev->dev, disk: block->gdp, NULL);
103 if (rc) {
104 dasd_gendisk_free(block);
105 return rc;
106 }
107
108 return 0;
109}
110
111/*
112 * Unregister and free gendisk structure for device.
113 */
114void dasd_gendisk_free(struct dasd_block *block)
115{
116 if (block->gdp) {
117 del_gendisk(gp: block->gdp);
118 block->gdp->private_data = NULL;
119 put_disk(disk: block->gdp);
120 block->gdp = NULL;
121 blk_mq_free_tag_set(set: &block->tag_set);
122 }
123}
124
125/*
126 * Trigger a partition detection.
127 */
128int dasd_scan_partitions(struct dasd_block *block)
129{
130 struct bdev_handle *bdev_handle;
131 int rc;
132
133 bdev_handle = bdev_open_by_dev(dev: disk_devt(disk: block->gdp), BLK_OPEN_READ,
134 NULL, NULL);
135 if (IS_ERR(ptr: bdev_handle)) {
136 DBF_DEV_EVENT(DBF_ERR, block->base,
137 "scan partitions error, blkdev_get returned %ld",
138 PTR_ERR(bdev_handle));
139 return -ENODEV;
140 }
141
142 mutex_lock(&block->gdp->open_mutex);
143 rc = bdev_disk_changed(disk: block->gdp, invalidate: false);
144 mutex_unlock(lock: &block->gdp->open_mutex);
145 if (rc)
146 DBF_DEV_EVENT(DBF_ERR, block->base,
147 "scan partitions error, rc %d", rc);
148
149 /*
150 * Since the matching bdev_release() call to the
151 * bdev_open_by_path() in this function is not called before
152 * dasd_destroy_partitions the offline open_count limit needs to be
153 * increased from 0 to 1. This is done by setting device->bdev_handle
154 * (see dasd_generic_set_offline). As long as the partition detection
155 * is running no offline should be allowed. That is why the assignment
156 * to block->bdev_handle is done AFTER the BLKRRPART ioctl.
157 */
158 block->bdev_handle = bdev_handle;
159 return 0;
160}
161
162/*
163 * Remove all inodes in the system for a device, delete the
164 * partitions and make device unusable by setting its size to zero.
165 */
166void dasd_destroy_partitions(struct dasd_block *block)
167{
168 struct bdev_handle *bdev_handle;
169
170 /*
171 * Get the bdev_handle pointer from the device structure and clear
172 * device->bdev_handle to lower the offline open_count limit again.
173 */
174 bdev_handle = block->bdev_handle;
175 block->bdev_handle = NULL;
176
177 mutex_lock(&bdev_handle->bdev->bd_disk->open_mutex);
178 bdev_disk_changed(disk: bdev_handle->bdev->bd_disk, invalidate: true);
179 mutex_unlock(lock: &bdev_handle->bdev->bd_disk->open_mutex);
180
181 /* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
182 bdev_release(handle: bdev_handle);
183}
184
185int dasd_gendisk_init(void)
186{
187 int rc;
188
189 /* Register to static dasd major 94 */
190 rc = register_blkdev(DASD_MAJOR, "dasd");
191 if (rc != 0) {
192 pr_warn("Registering the device driver with major number %d failed\n",
193 DASD_MAJOR);
194 return rc;
195 }
196 return 0;
197}
198
199void dasd_gendisk_exit(void)
200{
201 unregister_blkdev(DASD_MAJOR, name: "dasd");
202}
203

source code of linux/drivers/s390/block/dasd_genhd.c