Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
0004  *          Horst Hummel <Horst.Hummel@de.ibm.com>
0005  *          Carsten Otte <Cotte@de.ibm.com>
0006  *          Martin Schwidefsky <schwidefsky@de.ibm.com>
0007  * Bugreports.to..: <Linux390@de.ibm.com>
0008  * Copyright IBM Corp. 1999, 2001
0009  *
0010  * gendisk related functions for the dasd driver.
0011  *
0012  */
0013 
0014 #define KMSG_COMPONENT "dasd"
0015 
0016 #include <linux/interrupt.h>
0017 #include <linux/major.h>
0018 #include <linux/fs.h>
0019 #include <linux/blkpg.h>
0020 
0021 #include <linux/uaccess.h>
0022 
0023 /* This is ugly... */
0024 #define PRINTK_HEADER "dasd_gendisk:"
0025 
0026 #include "dasd_int.h"
0027 
0028 static struct lock_class_key dasd_bio_compl_lkclass;
0029 
0030 /*
0031  * Allocate and register gendisk structure for device.
0032  */
0033 int dasd_gendisk_alloc(struct dasd_block *block)
0034 {
0035     struct gendisk *gdp;
0036     struct dasd_device *base;
0037     int len, rc;
0038 
0039     /* Make sure the minor for this device exists. */
0040     base = block->base;
0041     if (base->devindex >= DASD_PER_MAJOR)
0042         return -EBUSY;
0043 
0044     gdp = blk_mq_alloc_disk_for_queue(block->request_queue,
0045                       &dasd_bio_compl_lkclass);
0046     if (!gdp)
0047         return -ENOMEM;
0048 
0049     /* Initialize gendisk structure. */
0050     gdp->major = DASD_MAJOR;
0051     gdp->first_minor = base->devindex << DASD_PARTN_BITS;
0052     gdp->minors = 1 << DASD_PARTN_BITS;
0053     gdp->fops = &dasd_device_operations;
0054 
0055     /*
0056      * Set device name.
0057      *   dasda - dasdz : 26 devices
0058      *   dasdaa - dasdzz : 676 devices, added up = 702
0059      *   dasdaaa - dasdzzz : 17576 devices, added up = 18278
0060      *   dasdaaaa - dasdzzzz : 456976 devices, added up = 475252
0061      */
0062     len = sprintf(gdp->disk_name, "dasd");
0063     if (base->devindex > 25) {
0064         if (base->devindex > 701) {
0065             if (base->devindex > 18277)
0066                     len += sprintf(gdp->disk_name + len, "%c",
0067                            'a'+(((base->devindex-18278)
0068                              /17576)%26));
0069             len += sprintf(gdp->disk_name + len, "%c",
0070                        'a'+(((base->devindex-702)/676)%26));
0071         }
0072         len += sprintf(gdp->disk_name + len, "%c",
0073                    'a'+(((base->devindex-26)/26)%26));
0074     }
0075     len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26));
0076 
0077     if (base->features & DASD_FEATURE_READONLY ||
0078         test_bit(DASD_FLAG_DEVICE_RO, &base->flags))
0079         set_disk_ro(gdp, 1);
0080     dasd_add_link_to_gendisk(gdp, base);
0081     block->gdp = gdp;
0082     set_capacity(block->gdp, 0);
0083 
0084     rc = device_add_disk(&base->cdev->dev, block->gdp, NULL);
0085     if (rc) {
0086         dasd_gendisk_free(block);
0087         return rc;
0088     }
0089 
0090     return 0;
0091 }
0092 
0093 /*
0094  * Unregister and free gendisk structure for device.
0095  */
0096 void dasd_gendisk_free(struct dasd_block *block)
0097 {
0098     if (block->gdp) {
0099         del_gendisk(block->gdp);
0100         block->gdp->private_data = NULL;
0101         put_disk(block->gdp);
0102         block->gdp = NULL;
0103     }
0104 }
0105 
0106 /*
0107  * Trigger a partition detection.
0108  */
0109 int dasd_scan_partitions(struct dasd_block *block)
0110 {
0111     struct block_device *bdev;
0112     int rc;
0113 
0114     bdev = blkdev_get_by_dev(disk_devt(block->gdp), FMODE_READ, NULL);
0115     if (IS_ERR(bdev)) {
0116         DBF_DEV_EVENT(DBF_ERR, block->base,
0117                   "scan partitions error, blkdev_get returned %ld",
0118                   PTR_ERR(bdev));
0119         return -ENODEV;
0120     }
0121 
0122     mutex_lock(&block->gdp->open_mutex);
0123     rc = bdev_disk_changed(block->gdp, false);
0124     mutex_unlock(&block->gdp->open_mutex);
0125     if (rc)
0126         DBF_DEV_EVENT(DBF_ERR, block->base,
0127                 "scan partitions error, rc %d", rc);
0128 
0129     /*
0130      * Since the matching blkdev_put call to the blkdev_get in
0131      * this function is not called before dasd_destroy_partitions
0132      * the offline open_count limit needs to be increased from
0133      * 0 to 1. This is done by setting device->bdev (see
0134      * dasd_generic_set_offline). As long as the partition
0135      * detection is running no offline should be allowed. That
0136      * is why the assignment to device->bdev is done AFTER
0137      * the BLKRRPART ioctl.
0138      */
0139     block->bdev = bdev;
0140     return 0;
0141 }
0142 
0143 /*
0144  * Remove all inodes in the system for a device, delete the
0145  * partitions and make device unusable by setting its size to zero.
0146  */
0147 void dasd_destroy_partitions(struct dasd_block *block)
0148 {
0149     struct block_device *bdev;
0150 
0151     /*
0152      * Get the bdev pointer from the device structure and clear
0153      * device->bdev to lower the offline open_count limit again.
0154      */
0155     bdev = block->bdev;
0156     block->bdev = NULL;
0157 
0158     mutex_lock(&bdev->bd_disk->open_mutex);
0159     bdev_disk_changed(bdev->bd_disk, true);
0160     mutex_unlock(&bdev->bd_disk->open_mutex);
0161 
0162     /* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
0163     blkdev_put(bdev, FMODE_READ);
0164 }
0165 
0166 int dasd_gendisk_init(void)
0167 {
0168     int rc;
0169 
0170     /* Register to static dasd major 94 */
0171     rc = register_blkdev(DASD_MAJOR, "dasd");
0172     if (rc != 0) {
0173         pr_warn("Registering the device driver with major number %d failed\n",
0174             DASD_MAJOR);
0175         return rc;
0176     }
0177     return 0;
0178 }
0179 
0180 void dasd_gendisk_exit(void)
0181 {
0182     unregister_blkdev(DASD_MAJOR, "dasd");
0183 }