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