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 "dasd_gendisk:" |
25 | |
26 | #include "dasd_int.h" |
27 | |
28 | static unsigned int queue_depth = 32; |
29 | static unsigned int nr_hw_queues = 4; |
30 | |
31 | module_param(queue_depth, uint, 0444); |
32 | MODULE_PARM_DESC(queue_depth, "Default queue depth for new DASD devices" ); |
33 | |
34 | module_param(nr_hw_queues, uint, 0444); |
35 | MODULE_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 | */ |
40 | int 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 | */ |
114 | void 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 | */ |
128 | int 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 | */ |
166 | void 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 | |
185 | int 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 | |
199 | void dasd_gendisk_exit(void) |
200 | { |
201 | unregister_blkdev(DASD_MAJOR, name: "dasd" ); |
202 | } |
203 | |