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 23 static unsigned int queue_depth = 32; 24 static unsigned int nr_hw_queues = 4; 25 static void dasd_gd_free(struct gendisk *gdp); 26 27 module_param(queue_depth, uint, 0444); 28 MODULE_PARM_DESC(queue_depth, "Default queue depth for new DASD devices"); 29 30 module_param(nr_hw_queues, uint, 0444); 31 MODULE_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 */ 40 static 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 */ 67 int 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 */ 137 static 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 */ 147 void 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 */ 159 int 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 */ 197 void 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 216 int 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 230 void dasd_gendisk_exit(void) 231 { 232 unregister_blkdev(DASD_MAJOR, "dasd"); 233 } 234