2005-04-17 02:20:36 +04:00
/*
* File . . . . . . . . . . . : linux / drivers / s390 / block / dasd_genhd . c
* Author ( s ) . . . . . . : Holger Smolinski < Holger . Smolinski @ de . ibm . com >
* Horst Hummel < Horst . Hummel @ de . ibm . com >
* Carsten Otte < Cotte @ de . ibm . com >
* Martin Schwidefsky < schwidefsky @ de . ibm . com >
* Bugreports . to . . : < Linux390 @ de . ibm . com >
* ( C ) IBM Corporation , IBM Deutschland Entwicklung GmbH , 1999 - 2001
*
* gendisk related functions for the dasd driver .
*
*/
# include <linux/interrupt.h>
# include <linux/fs.h>
# include <linux/blkpg.h>
# include <asm/uaccess.h>
/* This is ugly... */
# define PRINTK_HEADER "dasd_gendisk:"
# include "dasd_int.h"
/*
* Allocate and register gendisk structure for device .
*/
2008-01-26 16:11:23 +03:00
int dasd_gendisk_alloc ( struct dasd_block * block )
2005-04-17 02:20:36 +04:00
{
struct gendisk * gdp ;
2008-01-26 16:11:23 +03:00
struct dasd_device * base ;
2005-09-04 02:57:58 +04:00
int len ;
2005-04-17 02:20:36 +04:00
/* Make sure the minor for this device exists. */
2008-01-26 16:11:23 +03:00
base = block - > base ;
if ( base - > devindex > = DASD_PER_MAJOR )
2005-04-17 02:20:36 +04:00
return - EBUSY ;
gdp = alloc_disk ( 1 < < DASD_PARTN_BITS ) ;
if ( ! gdp )
return - ENOMEM ;
/* Initialize gendisk structure. */
gdp - > major = DASD_MAJOR ;
2008-01-26 16:11:23 +03:00
gdp - > first_minor = base - > devindex < < DASD_PARTN_BITS ;
2005-04-17 02:20:36 +04:00
gdp - > fops = & dasd_device_operations ;
2008-01-26 16:11:23 +03:00
gdp - > driverfs_dev = & base - > cdev - > dev ;
2005-04-17 02:20:36 +04:00
/*
* Set device name .
* dasda - dasdz : 26 devices
* dasdaa - dasdzz : 676 devices , added up = 702
* dasdaaa - dasdzzz : 17576 devices , added up = 18278
* dasdaaaa - dasdzzzz : 456976 devices , added up = 475252
*/
len = sprintf ( gdp - > disk_name , " dasd " ) ;
2008-01-26 16:11:23 +03:00
if ( base - > devindex > 25 ) {
if ( base - > devindex > 701 ) {
if ( base - > devindex > 18277 )
2005-04-17 02:20:36 +04:00
len + = sprintf ( gdp - > disk_name + len , " %c " ,
2008-01-26 16:11:23 +03:00
' a ' + ( ( ( base - > devindex - 18278 )
2005-04-17 02:20:36 +04:00
/ 17576 ) % 26 ) ) ;
len + = sprintf ( gdp - > disk_name + len , " %c " ,
2008-01-26 16:11:23 +03:00
' a ' + ( ( ( base - > devindex - 702 ) / 676 ) % 26 ) ) ;
2005-04-17 02:20:36 +04:00
}
len + = sprintf ( gdp - > disk_name + len , " %c " ,
2008-01-26 16:11:23 +03:00
' a ' + ( ( ( base - > devindex - 26 ) / 26 ) % 26 ) ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-26 16:11:23 +03:00
len + = sprintf ( gdp - > disk_name + len , " %c " , ' a ' + ( base - > devindex % 26 ) ) ;
2005-04-17 02:20:36 +04:00
2008-01-26 16:11:23 +03:00
if ( block - > base - > features & DASD_FEATURE_READONLY )
2005-04-17 02:20:36 +04:00
set_disk_ro ( gdp , 1 ) ;
2008-01-26 16:11:23 +03:00
gdp - > private_data = block ;
gdp - > queue = block - > request_queue ;
block - > gdp = gdp ;
set_capacity ( block - > gdp , 0 ) ;
add_disk ( block - > gdp ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Unregister and free gendisk structure for device .
*/
2008-01-26 16:11:23 +03:00
void dasd_gendisk_free ( struct dasd_block * block )
2005-04-17 02:20:36 +04:00
{
2008-01-26 16:11:23 +03:00
if ( block - > gdp ) {
del_gendisk ( block - > gdp ) ;
block - > gdp - > queue = NULL ;
put_disk ( block - > gdp ) ;
block - > gdp = NULL ;
2006-08-30 16:33:33 +04:00
}
2005-04-17 02:20:36 +04:00
}
/*
* Trigger a partition detection .
*/
2008-01-26 16:11:23 +03:00
int dasd_scan_partitions ( struct dasd_block * block )
2005-04-17 02:20:36 +04:00
{
struct block_device * bdev ;
2008-01-26 16:11:23 +03:00
bdev = bdget_disk ( block - > gdp , 0 ) ;
2007-10-08 21:24:05 +04:00
if ( ! bdev | | blkdev_get ( bdev , FMODE_READ ) < 0 )
2005-04-17 02:20:36 +04:00
return - ENODEV ;
/*
* See fs / partition / check . c : register_disk , rescan_partitions
* Can ' t call rescan_partitions directly . Use ioctl .
*/
ioctl_by_bdev ( bdev , BLKRRPART , 0 ) ;
/*
* Since the matching blkdev_put call to the blkdev_get in
* this function is not called before dasd_destroy_partitions
* the offline open_count limit needs to be increased from
* 0 to 1. This is done by setting device - > bdev ( see
* dasd_generic_set_offline ) . As long as the partition
* detection is running no offline should be allowed . That
* is why the assignment to device - > bdev is done AFTER
* the BLKRRPART ioctl .
*/
2008-01-26 16:11:23 +03:00
block - > bdev = bdev ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Remove all inodes in the system for a device , delete the
* partitions and make device unusable by setting its size to zero .
*/
2008-01-26 16:11:23 +03:00
void dasd_destroy_partitions ( struct dasd_block * block )
2005-04-17 02:20:36 +04:00
{
/* The two structs have 168/176 byte on 31/64 bit. */
struct blkpg_partition bpart ;
struct blkpg_ioctl_arg barg ;
struct block_device * bdev ;
/*
* Get the bdev pointer from the device structure and clear
* device - > bdev to lower the offline open_count limit again .
*/
2008-01-26 16:11:23 +03:00
bdev = block - > bdev ;
block - > bdev = NULL ;
2005-04-17 02:20:36 +04:00
/*
* See fs / partition / check . c : delete_partition
* Can ' t call delete_partitions directly . Use ioctl .
* The ioctl also does locking and invalidation .
*/
memset ( & bpart , 0 , sizeof ( struct blkpg_partition ) ) ;
memset ( & barg , 0 , sizeof ( struct blkpg_ioctl_arg ) ) ;
2007-02-05 23:16:47 +03:00
barg . data = ( void __force __user * ) & bpart ;
2005-04-17 02:20:36 +04:00
barg . op = BLKPG_DEL_PARTITION ;
2008-01-26 16:11:23 +03:00
for ( bpart . pno = block - > gdp - > minors - 1 ; bpart . pno > 0 ; bpart . pno - - )
2005-04-17 02:20:36 +04:00
ioctl_by_bdev ( bdev , BLKPG , ( unsigned long ) & barg ) ;
2008-01-26 16:11:23 +03:00
invalidate_partition ( block - > gdp , 0 ) ;
2005-04-17 02:20:36 +04:00
/* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
2008-02-23 04:40:24 +03:00
blkdev_put ( bdev , FMODE_READ ) ;
2008-01-26 16:11:23 +03:00
set_capacity ( block - > gdp , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-26 16:11:23 +03:00
int dasd_gendisk_init ( void )
2005-04-17 02:20:36 +04:00
{
int rc ;
/* Register to static dasd major 94 */
rc = register_blkdev ( DASD_MAJOR , " dasd " ) ;
if ( rc ! = 0 ) {
MESSAGE ( KERN_WARNING ,
" Couldn't register successfully to "
" major no %d " , DASD_MAJOR ) ;
return rc ;
}
return 0 ;
}
2008-01-26 16:11:23 +03:00
void dasd_gendisk_exit ( void )
2005-04-17 02:20:36 +04:00
{
unregister_blkdev ( DASD_MAJOR , " dasd " ) ;
}