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