File Index
Files and directories
Sign in
FILE

dasd_genhd.c

File preview with syntax highlighting.

linux-6.19.14/drivers/s390/block/dasd_genhd.c C
  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#include <linux/interrupt.h>
 15#include <linux/major.h>
 16#include <linux/fs.h>
 17#include <linux/blkpg.h>
 18
 19#include <linux/uaccess.h>
 20
 21#include "dasd_int.h"
 22
 23static unsigned int queue_depth = 32;
 24static unsigned int nr_hw_queues = 4;
 25static void dasd_gd_free(struct gendisk *gdp);
 26
 27module_param(queue_depth, uint, 0444);
 28MODULE_PARM_DESC(queue_depth, "Default queue depth for new DASD devices");
 29
 30module_param(nr_hw_queues, uint, 0444);
 31MODULE_PARM_DESC(nr_hw_queues, "Default number of hardware queues for new DASD devices");
 32
 33/*
 34 * Set device name.
 35 *   dasda - dasdz : 26 devices
 36 *   dasdaa - dasdzz : 676 devices, added up = 702
 37 *   dasdaaa - dasdzzz : 17576 devices, added up = 18278
 38 *   dasdaaaa - dasdzzzz : 456976 devices, added up = 475252
 39 */
 40static int dasd_name_format(char *prefix, int index, char *buf, int buflen)
 41{
 42	const int base = 'z' - 'a' + 1;
 43	char *begin = buf + strlen(prefix);
 44	char *end = buf + buflen;
 45	char *p;
 46	int unit;
 47
 48	p = end - 1;
 49	*p = '\0';
 50	unit = base;
 51	do {
 52		if (p == begin)
 53			return -EINVAL;
 54		*--p = 'a' + (index % unit);
 55		index = (index / unit) - 1;
 56	} while (index >= 0);
 57
 58	memmove(begin, p, end - p);
 59	memcpy(buf, prefix, strlen(prefix));
 60
 61	return 0;
 62}
 63
 64/*
 65 * Allocate and register gendisk structure for device.
 66 */
 67int dasd_gendisk_alloc(struct dasd_block *block)
 68{
 69	struct queue_limits lim = {
 70		/*
 71		 * With page sized segments, each segment can be translated into
 72		 * one idaw/tidaw.
 73		 */
 74		.max_segment_size = PAGE_SIZE,
 75		.seg_boundary_mask = PAGE_SIZE - 1,
 76		.max_segments = USHRT_MAX,
 77	};
 78	struct gendisk *gdp;
 79	struct dasd_device *base;
 80	unsigned int devindex;
 81	int rc;
 82
 83	/* Make sure the minor for this device exists. */
 84	base = block->base;
 85	devindex = base->devindex;
 86	if (devindex >= DASD_PER_MAJOR)
 87		return -EBUSY;
 88
 89	block->tag_set.ops = &dasd_mq_ops;
 90	block->tag_set.cmd_size = sizeof(struct dasd_ccw_req);
 91	block->tag_set.nr_hw_queues = nr_hw_queues;
 92	block->tag_set.queue_depth = queue_depth;
 93	block->tag_set.numa_node = NUMA_NO_NODE;
 94	rc = blk_mq_alloc_tag_set(&block->tag_set);
 95	if (rc)
 96		return rc;
 97
 98	gdp = blk_mq_alloc_disk(&block->tag_set, &lim, block);
 99	if (IS_ERR(gdp)) {
100		blk_mq_free_tag_set(&block->tag_set);
101		return PTR_ERR(gdp);
102	}
103
104	/* Initialize gendisk structure. */
105	gdp->major = DASD_MAJOR;
106	gdp->first_minor = devindex << DASD_PARTN_BITS;
107	gdp->minors = 1 << DASD_PARTN_BITS;
108	gdp->fops = &dasd_device_operations;
109
110	rc = dasd_name_format("dasd", devindex, gdp->disk_name, sizeof(gdp->disk_name));
111	if (rc) {
112		DBF_DEV_EVENT(DBF_ERR, block->base,
113			      "setting disk name failed, rc %d", rc);
114		dasd_gd_free(gdp);
115		return rc;
116	}
117
118	if (base->features & DASD_FEATURE_READONLY ||
119	    test_bit(DASD_FLAG_DEVICE_RO, &base->flags))
120		set_disk_ro(gdp, 1);
121	dasd_add_link_to_gendisk(gdp, base);
122	block->gdp = gdp;
123	set_capacity(block->gdp, 0);
124
125	rc = device_add_disk(&base->cdev->dev, block->gdp, NULL);
126	if (rc) {
127		dasd_gendisk_free(block);
128		return rc;
129	}
130
131	return 0;
132}
133
134/*
135 * Free gendisk structure
136 */
137static void dasd_gd_free(struct gendisk *gd)
138{
139	del_gendisk(gd);
140	gd->private_data = NULL;
141	put_disk(gd);
142}
143
144/*
145 * Unregister and free gendisk structure for device.
146 */
147void dasd_gendisk_free(struct dasd_block *block)
148{
149	if (block->gdp) {
150		dasd_gd_free(block->gdp);
151		block->gdp = NULL;
152		blk_mq_free_tag_set(&block->tag_set);
153	}
154}
155
156/*
157 * Trigger a partition detection.
158 */
159int dasd_scan_partitions(struct dasd_block *block)
160{
161	struct file *bdev_file;
162	int rc;
163
164	bdev_file = bdev_file_open_by_dev(disk_devt(block->gdp), BLK_OPEN_READ,
165				       NULL, NULL);
166	if (IS_ERR(bdev_file)) {
167		DBF_DEV_EVENT(DBF_ERR, block->base,
168			      "scan partitions error, blkdev_get returned %ld",
169			      PTR_ERR(bdev_file));
170		return -ENODEV;
171	}
172
173	mutex_lock(&block->gdp->open_mutex);
174	rc = bdev_disk_changed(block->gdp, false);
175	mutex_unlock(&block->gdp->open_mutex);
176	if (rc)
177		DBF_DEV_EVENT(DBF_ERR, block->base,
178				"scan partitions error, rc %d", rc);
179
180	/*
181	 * Since the matching fput() call to the
182	 * bdev_file_open_by_path() in this function is not called before
183	 * dasd_destroy_partitions the offline open_count limit needs to be
184	 * increased from 0 to 1. This is done by setting device->bdev_file
185	 * (see dasd_generic_set_offline). As long as the partition detection
186	 * is running no offline should be allowed. That is why the assignment
187	 * to block->bdev_file is done AFTER the BLKRRPART ioctl.
188	 */
189	block->bdev_file = bdev_file;
190	return 0;
191}
192
193/*
194 * Remove all inodes in the system for a device, delete the
195 * partitions and make device unusable by setting its size to zero.
196 */
197void dasd_destroy_partitions(struct dasd_block *block)
198{
199	struct file *bdev_file;
200
201	/*
202	 * Get the bdev_file pointer from the device structure and clear
203	 * device->bdev_file to lower the offline open_count limit again.
204	 */
205	bdev_file = block->bdev_file;
206	block->bdev_file = NULL;
207
208	mutex_lock(&file_bdev(bdev_file)->bd_disk->open_mutex);
209	bdev_disk_changed(file_bdev(bdev_file)->bd_disk, true);
210	mutex_unlock(&file_bdev(bdev_file)->bd_disk->open_mutex);
211
212	/* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
213	fput(bdev_file);
214}
215
216int dasd_gendisk_init(void)
217{
218	int rc;
219
220	/* Register to static dasd major 94 */
221	rc = register_blkdev(DASD_MAJOR, "dasd");
222	if (rc != 0) {
223		pr_warn("Registering the device driver with major number %d failed\n",
224			DASD_MAJOR);
225		return rc;
226	}
227	return 0;
228}
229
230void dasd_gendisk_exit(void)
231{
232	unregister_blkdev(DASD_MAJOR, "dasd");
233}
~/ Read-only file preview.