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