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