linux/drivers/s390/block/dasd_genhd.c
<<
>>
Prefs
   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/fs.h>
  18#include <linux/blkpg.h>
  19
  20#include <linux/uaccess.h>
  21
  22/* This is ugly... */
  23#define PRINTK_HEADER "dasd_gendisk:"
  24
  25#include "dasd_int.h"
  26
  27static struct lock_class_key dasd_bio_compl_lkclass;
  28
  29/*
  30 * Allocate and register gendisk structure for device.
  31 */
  32int dasd_gendisk_alloc(struct dasd_block *block)
  33{
  34        struct gendisk *gdp;
  35        struct dasd_device *base;
  36        int len;
  37
  38        /* Make sure the minor for this device exists. */
  39        base = block->base;
  40        if (base->devindex >= DASD_PER_MAJOR)
  41                return -EBUSY;
  42
  43        gdp = __alloc_disk_node(block->request_queue, NUMA_NO_NODE,
  44                                &dasd_bio_compl_lkclass);
  45        if (!gdp)
  46                return -ENOMEM;
  47
  48        /* Initialize gendisk structure. */
  49        gdp->major = DASD_MAJOR;
  50        gdp->first_minor = base->devindex << DASD_PARTN_BITS;
  51        gdp->minors = 1 << DASD_PARTN_BITS;
  52        gdp->fops = &dasd_device_operations;
  53
  54        /*
  55         * Set device name.
  56         *   dasda - dasdz : 26 devices
  57         *   dasdaa - dasdzz : 676 devices, added up = 702
  58         *   dasdaaa - dasdzzz : 17576 devices, added up = 18278
  59         *   dasdaaaa - dasdzzzz : 456976 devices, added up = 475252
  60         */
  61        len = sprintf(gdp->disk_name, "dasd");
  62        if (base->devindex > 25) {
  63                if (base->devindex > 701) {
  64                        if (base->devindex > 18277)
  65                                len += sprintf(gdp->disk_name + len, "%c",
  66                                               'a'+(((base->devindex-18278)
  67                                                     /17576)%26));
  68                        len += sprintf(gdp->disk_name + len, "%c",
  69                                       'a'+(((base->devindex-702)/676)%26));
  70                }
  71                len += sprintf(gdp->disk_name + len, "%c",
  72                               'a'+(((base->devindex-26)/26)%26));
  73        }
  74        len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26));
  75
  76        if (base->features & DASD_FEATURE_READONLY ||
  77            test_bit(DASD_FLAG_DEVICE_RO, &base->flags))
  78                set_disk_ro(gdp, 1);
  79        dasd_add_link_to_gendisk(gdp, base);
  80        block->gdp = gdp;
  81        set_capacity(block->gdp, 0);
  82        device_add_disk(&base->cdev->dev, block->gdp, NULL);
  83        return 0;
  84}
  85
  86/*
  87 * Unregister and free gendisk structure for device.
  88 */
  89void dasd_gendisk_free(struct dasd_block *block)
  90{
  91        if (block->gdp) {
  92                del_gendisk(block->gdp);
  93                block->gdp->private_data = NULL;
  94                put_disk(block->gdp);
  95                block->gdp = NULL;
  96        }
  97}
  98
  99/*
 100 * Trigger a partition detection.
 101 */
 102int dasd_scan_partitions(struct dasd_block *block)
 103{
 104        struct block_device *bdev;
 105        int rc;
 106
 107        bdev = blkdev_get_by_dev(disk_devt(block->gdp), FMODE_READ, NULL);
 108        if (IS_ERR(bdev)) {
 109                DBF_DEV_EVENT(DBF_ERR, block->base,
 110                              "scan partitions error, blkdev_get returned %ld",
 111                              PTR_ERR(bdev));
 112                return -ENODEV;
 113        }
 114
 115        mutex_lock(&block->gdp->open_mutex);
 116        rc = bdev_disk_changed(block->gdp, false);
 117        mutex_unlock(&block->gdp->open_mutex);
 118        if (rc)
 119                DBF_DEV_EVENT(DBF_ERR, block->base,
 120                                "scan partitions error, rc %d", rc);
 121
 122        /*
 123         * Since the matching blkdev_put call to the blkdev_get in
 124         * this function is not called before dasd_destroy_partitions
 125         * the offline open_count limit needs to be increased from
 126         * 0 to 1. This is done by setting device->bdev (see
 127         * dasd_generic_set_offline). As long as the partition
 128         * detection is running no offline should be allowed. That
 129         * is why the assignment to device->bdev is done AFTER
 130         * the BLKRRPART ioctl.
 131         */
 132        block->bdev = bdev;
 133        return 0;
 134}
 135
 136/*
 137 * Remove all inodes in the system for a device, delete the
 138 * partitions and make device unusable by setting its size to zero.
 139 */
 140void dasd_destroy_partitions(struct dasd_block *block)
 141{
 142        struct block_device *bdev;
 143
 144        /*
 145         * Get the bdev pointer from the device structure and clear
 146         * device->bdev to lower the offline open_count limit again.
 147         */
 148        bdev = block->bdev;
 149        block->bdev = NULL;
 150
 151        mutex_lock(&bdev->bd_disk->open_mutex);
 152        bdev_disk_changed(bdev->bd_disk, true);
 153        mutex_unlock(&bdev->bd_disk->open_mutex);
 154
 155        /* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
 156        blkdev_put(bdev, FMODE_READ);
 157}
 158
 159int dasd_gendisk_init(void)
 160{
 161        int rc;
 162
 163        /* Register to static dasd major 94 */
 164        rc = register_blkdev(DASD_MAJOR, "dasd");
 165        if (rc != 0) {
 166                pr_warn("Registering the device driver with major number %d failed\n",
 167                        DASD_MAJOR);
 168                return rc;
 169        }
 170        return 0;
 171}
 172
 173void dasd_gendisk_exit(void)
 174{
 175        unregister_blkdev(DASD_MAJOR, "dasd");
 176}
 177