2005-04-17 02:20:36 +04:00
/*
2006-03-24 14:15:23 +03:00
* File . . . . . . . . . . . : linux / fs / partitions / ibm . c
2005-04-17 02:20:36 +04:00
* Author ( s ) . . . . . . : Holger Smolinski < Holger . Smolinski @ de . ibm . com >
* Volker Sameske < sameske @ de . ibm . com >
* Bugreports . to . . : < Linux390 @ de . ibm . com >
* ( C ) IBM Corporation , IBM Deutschland Entwicklung GmbH , 1999 , 2000
*/
# include <linux/buffer_head.h>
# include <linux/hdreg.h>
# include <linux/slab.h>
# include <asm/dasd.h>
# include <asm/ebcdic.h>
# include <asm/uaccess.h>
# include <asm/vtoc.h>
# include "check.h"
# include "ibm.h"
/*
2006-03-24 14:15:23 +03:00
* compute the block number from a
2005-04-17 02:20:36 +04:00
* cyl - cyl - head - head structure
*/
static inline int
2005-11-07 11:59:09 +03:00
cchh2blk ( struct vtoc_cchh * ptr , struct hd_geometry * geo ) {
2005-04-17 02:20:36 +04:00
return ptr - > cc * geo - > heads * geo - > sectors +
ptr - > hh * geo - > sectors ;
}
/*
2006-03-24 14:15:23 +03:00
* compute the block number from a
2005-04-17 02:20:36 +04:00
* cyl - cyl - head - head - block structure
*/
static inline int
2005-11-07 11:59:09 +03:00
cchhb2blk ( struct vtoc_cchhb * ptr , struct hd_geometry * geo ) {
2005-04-17 02:20:36 +04:00
return ptr - > cc * geo - > heads * geo - > sectors +
ptr - > hh * geo - > sectors +
ptr - > b ;
}
/*
*/
2006-03-24 14:15:23 +03:00
int
2005-04-17 02:20:36 +04:00
ibm_partition ( struct parsed_partitions * state , struct block_device * bdev )
{
2006-12-07 07:35:16 +03:00
int blocksize , offset , size , res ;
2006-03-08 08:55:39 +03:00
loff_t i_size ;
2007-07-10 13:24:11 +04:00
dasd_information2_t * info ;
2005-04-17 02:20:36 +04:00
struct hd_geometry * geo ;
char type [ 5 ] = { 0 , } ;
char name [ 7 ] = { 0 , } ;
2006-01-06 11:19:09 +03:00
union label_t {
struct vtoc_volume_label vol ;
struct vtoc_cms_label cms ;
} * label ;
2005-04-17 02:20:36 +04:00
unsigned char * data ;
Sector sect ;
2006-12-07 07:35:16 +03:00
res = 0 ;
2006-03-08 08:55:39 +03:00
blocksize = bdev_hardsect_size ( bdev ) ;
if ( blocksize < = 0 )
2006-12-07 07:35:16 +03:00
goto out_exit ;
2006-03-08 08:55:39 +03:00
i_size = i_size_read ( bdev - > bd_inode ) ;
if ( i_size = = 0 )
2006-12-07 07:35:16 +03:00
goto out_exit ;
2006-03-08 08:55:39 +03:00
2007-07-10 13:24:11 +04:00
info = kmalloc ( sizeof ( dasd_information2_t ) , GFP_KERNEL ) ;
if ( info = = NULL )
2006-12-07 07:35:16 +03:00
goto out_exit ;
2007-07-10 13:24:11 +04:00
geo = kmalloc ( sizeof ( struct hd_geometry ) , GFP_KERNEL ) ;
if ( geo = = NULL )
2005-04-17 02:20:36 +04:00
goto out_nogeo ;
2007-07-10 13:24:11 +04:00
label = kmalloc ( sizeof ( union label_t ) , GFP_KERNEL ) ;
if ( label = = NULL )
2006-01-06 11:19:09 +03:00
goto out_nolab ;
2006-03-24 14:15:23 +03:00
2007-07-10 13:24:11 +04:00
if ( ioctl_by_bdev ( bdev , BIODASDINFO2 , ( unsigned long ) info ) ! = 0 | |
2005-04-17 02:20:36 +04:00
ioctl_by_bdev ( bdev , HDIO_GETGEO , ( unsigned long ) geo ) ! = 0 )
2006-12-07 07:35:16 +03:00
goto out_freeall ;
2005-04-17 02:20:36 +04:00
/*
* Get volume label , extract name and type .
*/
data = read_dev_sector ( bdev , info - > label_block * ( blocksize / 512 ) , & sect ) ;
if ( data = = NULL )
goto out_readerr ;
strncpy ( type , data , 4 ) ;
if ( ( ! info - > FBA_layout ) & & ( ! strcmp ( info - > type , " ECKD " ) ) )
strncpy ( name , data + 8 , 6 ) ;
else
strncpy ( name , data + 4 , 6 ) ;
2006-01-06 11:19:09 +03:00
memcpy ( label , data , sizeof ( union label_t ) ) ;
2005-04-17 02:20:36 +04:00
put_dev_sector ( sect ) ;
EBCASC ( type , 4 ) ;
EBCASC ( name , 6 ) ;
2006-12-07 07:35:16 +03:00
res = 1 ;
2005-04-17 02:20:36 +04:00
/*
2007-07-10 13:24:11 +04:00
* Three different formats : LDL , CDL and unformated disk
*
* identified by info - > format
*
* unformated disks we do not have to care about
2005-04-17 02:20:36 +04:00
*/
2007-07-10 13:24:11 +04:00
if ( info - > format = = DASD_FORMAT_LDL ) {
if ( strncmp ( type , " CMS1 " , 4 ) = = 0 ) {
/*
* VM style CMS1 labeled disk
*/
if ( label - > cms . disk_offset ! = 0 ) {
printk ( " CMS1/%8s(MDSK): " , name ) ;
/* disk is reserved minidisk */
blocksize = label - > cms . block_size ;
offset = label - > cms . disk_offset ;
size = ( label - > cms . block_count - 1 )
* ( blocksize > > 9 ) ;
} else {
printk ( " CMS1/%8s: " , name ) ;
offset = ( info - > label_block + 1 ) ;
size = i_size > > 9 ;
}
2005-04-17 02:20:36 +04:00
} else {
2007-07-10 13:24:11 +04:00
/*
* Old style LNX1 or unlabeled disk
*/
if ( strncmp ( type , " LNX1 " , 4 ) = = 0 )
printk ( " LNX1/%8s: " , name ) ;
else
printk ( " (nonl) " ) ;
2005-04-17 02:20:36 +04:00
offset = ( info - > label_block + 1 ) ;
2006-03-08 08:55:39 +03:00
size = i_size > > 9 ;
2005-04-17 02:20:36 +04:00
}
put_partition ( state , 1 , offset * ( blocksize > > 9 ) ,
2007-07-10 13:24:11 +04:00
size - offset * ( blocksize > > 9 ) ) ;
} else if ( info - > format = = DASD_FORMAT_CDL ) {
2005-04-17 02:20:36 +04:00
/*
2007-07-10 13:24:11 +04:00
* New style CDL formatted disk
2005-04-17 02:20:36 +04:00
*/
unsigned int blk ;
int counter ;
/*
2007-07-10 13:24:11 +04:00
* check if VOL1 label is available
* if not , something is wrong , skipping partition detection
2005-04-17 02:20:36 +04:00
*/
2007-07-10 13:24:11 +04:00
if ( strncmp ( type , " VOL1 " , 4 ) = = 0 ) {
printk ( " VOL1/%8s: " , name ) ;
/*
* get block number and read then go through format1
* labels
*/
blk = cchhb2blk ( & label - > vol . vtoc , geo ) + 1 ;
counter = 0 ;
data = read_dev_sector ( bdev , blk * ( blocksize / 512 ) ,
& sect ) ;
while ( data ! = NULL ) {
struct vtoc_format1_label f1 ;
memcpy ( & f1 , data ,
sizeof ( struct vtoc_format1_label ) ) ;
put_dev_sector ( sect ) ;
/* skip FMT4 / FMT5 / FMT7 labels */
if ( f1 . DS1FMTID = = _ascebc [ ' 4 ' ]
| | f1 . DS1FMTID = = _ascebc [ ' 5 ' ]
| | f1 . DS1FMTID = = _ascebc [ ' 7 ' ] ) {
blk + + ;
data = read_dev_sector ( bdev , blk *
( blocksize / 512 ) ,
& sect ) ;
continue ;
}
/* only FMT1 valid at this point */
if ( f1 . DS1FMTID ! = _ascebc [ ' 1 ' ] )
break ;
/* OK, we got valid partition data */
offset = cchh2blk ( & f1 . DS1EXT1 . llimit , geo ) ;
size = cchh2blk ( & f1 . DS1EXT1 . ulimit , geo ) -
offset + geo - > sectors ;
if ( counter > = state - > limit )
break ;
put_partition ( state , counter + 1 ,
offset * ( blocksize > > 9 ) ,
size * ( blocksize > > 9 ) ) ;
counter + + ;
blk + + ;
data = read_dev_sector ( bdev ,
blk * ( blocksize / 512 ) ,
& sect ) ;
}
if ( ! data )
/* Are we not supposed to report this ? */
goto out_readerr ;
} else
printk ( KERN_WARNING " Warning, expected Label VOL1 not "
" found, treating as CDL formated Disk " ) ;
2005-04-17 02:20:36 +04:00
}
printk ( " \n " ) ;
2006-12-07 07:35:16 +03:00
goto out_freeall ;
2006-03-24 14:15:23 +03:00
2005-04-17 02:20:36 +04:00
out_readerr :
2006-12-07 07:35:16 +03:00
res = - 1 ;
out_freeall :
2006-01-06 11:19:09 +03:00
kfree ( label ) ;
out_nolab :
2005-04-17 02:20:36 +04:00
kfree ( geo ) ;
out_nogeo :
kfree ( info ) ;
2006-12-07 07:35:16 +03:00
out_exit :
return res ;
2005-04-17 02:20:36 +04:00
}