18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> 48c2ecf20Sopenharmony_ci * Horst Hummel <Horst.Hummel@de.ibm.com> 58c2ecf20Sopenharmony_ci * Carsten Otte <Cotte@de.ibm.com> 68c2ecf20Sopenharmony_ci * Martin Schwidefsky <schwidefsky@de.ibm.com> 78c2ecf20Sopenharmony_ci * Bugreports.to..: <Linux390@de.ibm.com> 88c2ecf20Sopenharmony_ci * Copyright IBM Corp. 1999, 2001 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * gendisk related functions for the dasd driver. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "dasd" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/fs.h> 188c2ecf20Sopenharmony_ci#include <linux/blkpg.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* This is ugly... */ 238c2ecf20Sopenharmony_ci#define PRINTK_HEADER "dasd_gendisk:" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "dasd_int.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * Allocate and register gendisk structure for device. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ciint dasd_gendisk_alloc(struct dasd_block *block) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct gendisk *gdp; 338c2ecf20Sopenharmony_ci struct dasd_device *base; 348c2ecf20Sopenharmony_ci int len; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* Make sure the minor for this device exists. */ 378c2ecf20Sopenharmony_ci base = block->base; 388c2ecf20Sopenharmony_ci if (base->devindex >= DASD_PER_MAJOR) 398c2ecf20Sopenharmony_ci return -EBUSY; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci gdp = alloc_disk(1 << DASD_PARTN_BITS); 428c2ecf20Sopenharmony_ci if (!gdp) 438c2ecf20Sopenharmony_ci return -ENOMEM; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* Initialize gendisk structure. */ 468c2ecf20Sopenharmony_ci gdp->major = DASD_MAJOR; 478c2ecf20Sopenharmony_ci gdp->first_minor = base->devindex << DASD_PARTN_BITS; 488c2ecf20Sopenharmony_ci gdp->fops = &dasd_device_operations; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* 518c2ecf20Sopenharmony_ci * Set device name. 528c2ecf20Sopenharmony_ci * dasda - dasdz : 26 devices 538c2ecf20Sopenharmony_ci * dasdaa - dasdzz : 676 devices, added up = 702 548c2ecf20Sopenharmony_ci * dasdaaa - dasdzzz : 17576 devices, added up = 18278 558c2ecf20Sopenharmony_ci * dasdaaaa - dasdzzzz : 456976 devices, added up = 475252 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci len = sprintf(gdp->disk_name, "dasd"); 588c2ecf20Sopenharmony_ci if (base->devindex > 25) { 598c2ecf20Sopenharmony_ci if (base->devindex > 701) { 608c2ecf20Sopenharmony_ci if (base->devindex > 18277) 618c2ecf20Sopenharmony_ci len += sprintf(gdp->disk_name + len, "%c", 628c2ecf20Sopenharmony_ci 'a'+(((base->devindex-18278) 638c2ecf20Sopenharmony_ci /17576)%26)); 648c2ecf20Sopenharmony_ci len += sprintf(gdp->disk_name + len, "%c", 658c2ecf20Sopenharmony_ci 'a'+(((base->devindex-702)/676)%26)); 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci len += sprintf(gdp->disk_name + len, "%c", 688c2ecf20Sopenharmony_ci 'a'+(((base->devindex-26)/26)%26)); 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26)); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (base->features & DASD_FEATURE_READONLY || 738c2ecf20Sopenharmony_ci test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) 748c2ecf20Sopenharmony_ci set_disk_ro(gdp, 1); 758c2ecf20Sopenharmony_ci dasd_add_link_to_gendisk(gdp, base); 768c2ecf20Sopenharmony_ci gdp->queue = block->request_queue; 778c2ecf20Sopenharmony_ci block->gdp = gdp; 788c2ecf20Sopenharmony_ci set_capacity(block->gdp, 0); 798c2ecf20Sopenharmony_ci device_add_disk(&base->cdev->dev, block->gdp, NULL); 808c2ecf20Sopenharmony_ci return 0; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* 848c2ecf20Sopenharmony_ci * Unregister and free gendisk structure for device. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_civoid dasd_gendisk_free(struct dasd_block *block) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci if (block->gdp) { 898c2ecf20Sopenharmony_ci del_gendisk(block->gdp); 908c2ecf20Sopenharmony_ci block->gdp->private_data = NULL; 918c2ecf20Sopenharmony_ci put_disk(block->gdp); 928c2ecf20Sopenharmony_ci block->gdp = NULL; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* 978c2ecf20Sopenharmony_ci * Trigger a partition detection. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ciint dasd_scan_partitions(struct dasd_block *block) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct block_device *bdev; 1028c2ecf20Sopenharmony_ci int rc; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci bdev = blkdev_get_by_dev(disk_devt(block->gdp), FMODE_READ, NULL); 1058c2ecf20Sopenharmony_ci if (IS_ERR(bdev)) { 1068c2ecf20Sopenharmony_ci DBF_DEV_EVENT(DBF_ERR, block->base, 1078c2ecf20Sopenharmony_ci "scan partitions error, blkdev_get returned %ld", 1088c2ecf20Sopenharmony_ci PTR_ERR(bdev)); 1098c2ecf20Sopenharmony_ci return -ENODEV; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci mutex_lock(&bdev->bd_mutex); 1138c2ecf20Sopenharmony_ci rc = bdev_disk_changed(bdev, false); 1148c2ecf20Sopenharmony_ci mutex_unlock(&bdev->bd_mutex); 1158c2ecf20Sopenharmony_ci if (rc) 1168c2ecf20Sopenharmony_ci DBF_DEV_EVENT(DBF_ERR, block->base, 1178c2ecf20Sopenharmony_ci "scan partitions error, rc %d", rc); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* 1208c2ecf20Sopenharmony_ci * Since the matching blkdev_put call to the blkdev_get in 1218c2ecf20Sopenharmony_ci * this function is not called before dasd_destroy_partitions 1228c2ecf20Sopenharmony_ci * the offline open_count limit needs to be increased from 1238c2ecf20Sopenharmony_ci * 0 to 1. This is done by setting device->bdev (see 1248c2ecf20Sopenharmony_ci * dasd_generic_set_offline). As long as the partition 1258c2ecf20Sopenharmony_ci * detection is running no offline should be allowed. That 1268c2ecf20Sopenharmony_ci * is why the assignment to device->bdev is done AFTER 1278c2ecf20Sopenharmony_ci * the BLKRRPART ioctl. 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci block->bdev = bdev; 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* 1348c2ecf20Sopenharmony_ci * Remove all inodes in the system for a device, delete the 1358c2ecf20Sopenharmony_ci * partitions and make device unusable by setting its size to zero. 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_civoid dasd_destroy_partitions(struct dasd_block *block) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct block_device *bdev; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* 1428c2ecf20Sopenharmony_ci * Get the bdev pointer from the device structure and clear 1438c2ecf20Sopenharmony_ci * device->bdev to lower the offline open_count limit again. 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci bdev = block->bdev; 1468c2ecf20Sopenharmony_ci block->bdev = NULL; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci mutex_lock(&bdev->bd_mutex); 1498c2ecf20Sopenharmony_ci blk_drop_partitions(bdev); 1508c2ecf20Sopenharmony_ci mutex_unlock(&bdev->bd_mutex); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */ 1538c2ecf20Sopenharmony_ci blkdev_put(bdev, FMODE_READ); 1548c2ecf20Sopenharmony_ci set_capacity(block->gdp, 0); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ciint dasd_gendisk_init(void) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci int rc; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Register to static dasd major 94 */ 1628c2ecf20Sopenharmony_ci rc = register_blkdev(DASD_MAJOR, "dasd"); 1638c2ecf20Sopenharmony_ci if (rc != 0) { 1648c2ecf20Sopenharmony_ci pr_warn("Registering the device driver with major number %d failed\n", 1658c2ecf20Sopenharmony_ci DASD_MAJOR); 1668c2ecf20Sopenharmony_ci return rc; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_civoid dasd_gendisk_exit(void) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci unregister_blkdev(DASD_MAJOR, "dasd"); 1748c2ecf20Sopenharmony_ci} 175