2005-04-17 02:20:36 +04:00
/*
* File . . . . . . . . . . . : linux / fs / partitions / ibm . c
* 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
* History of changes ( starts July 2000 )
* 07 / 10 / 00 Fixed detection of CMS formatted disks
* 02 / 13 / 00 VTOC partition support added
* 12 / 27 / 01 fixed PL030593 ( CMS reserved minidisk not detected on 64 bit )
* 07 / 24 / 03 no longer using contents of freed page for CMS label recognition ( BZ3611 )
*/
# include <linux/config.h>
# 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"
/*
* compute the block number from a
* 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 ;
}
/*
* compute the block number from a
* 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 ;
}
/*
*/
int
ibm_partition ( struct parsed_partitions * state , struct block_device * bdev )
{
int blocksize , offset , size ;
dasd_information_t * info ;
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 ;
if ( ( info = kmalloc ( sizeof ( dasd_information_t ) , GFP_KERNEL ) ) = = NULL )
goto out_noinfo ;
if ( ( geo = kmalloc ( sizeof ( struct hd_geometry ) , GFP_KERNEL ) ) = = NULL )
goto out_nogeo ;
2006-01-06 11:19:09 +03:00
if ( ( label = kmalloc ( sizeof ( union label_t ) , GFP_KERNEL ) ) = = NULL )
goto out_nolab ;
2005-04-17 02:20:36 +04:00
if ( ioctl_by_bdev ( bdev , BIODASDINFO , ( unsigned long ) info ) ! = 0 | |
ioctl_by_bdev ( bdev , HDIO_GETGEO , ( unsigned long ) geo ) ! = 0 )
goto out_noioctl ;
if ( ( blocksize = bdev_hardsect_size ( bdev ) ) < = 0 )
goto out_badsect ;
/*
* 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 ) ;
/*
* Three different types : CMS1 , VOL1 and LNX1 / unlabeled
*/
if ( strncmp ( type , " CMS1 " , 4 ) = = 0 ) {
/*
* VM style CMS1 labeled disk
*/
2006-01-06 11:19:09 +03:00
if ( label - > cms . disk_offset ! = 0 ) {
2005-04-17 02:20:36 +04:00
printk ( " CMS1/%8s(MDSK): " , name ) ;
/* disk is reserved minidisk */
2006-01-06 11:19:09 +03:00
blocksize = label - > cms . block_size ;
offset = label - > cms . disk_offset ;
size = ( label - > cms . block_count - 1 ) * ( blocksize > > 9 ) ;
2005-04-17 02:20:36 +04:00
} else {
printk ( " CMS1/%8s: " , name ) ;
offset = ( info - > label_block + 1 ) ;
size = bdev - > bd_inode - > i_size > > 9 ;
}
put_partition ( state , 1 , offset * ( blocksize > > 9 ) ,
size - offset * ( blocksize > > 9 ) ) ;
} else if ( ( strncmp ( type , " VOL1 " , 4 ) = = 0 ) & &
( ! info - > FBA_layout ) & & ( ! strcmp ( info - > type , " ECKD " ) ) ) {
/*
* New style VOL1 labeled disk
*/
unsigned int blk ;
int counter ;
printk ( " VOL1/%8s: " , name ) ;
/* get block number and read then go through format1 labels */
2006-01-06 11:19:09 +03:00
blk = cchhb2blk ( & label - > vol . vtoc , geo ) + 1 ;
2005-04-17 02:20:36 +04:00
counter = 0 ;
while ( ( data = read_dev_sector ( bdev , blk * ( blocksize / 512 ) ,
& sect ) ) ! = NULL ) {
2005-11-07 11:59:09 +03:00
struct vtoc_format1_label f1 ;
2005-04-17 02:20:36 +04:00
2005-11-07 11:59:09 +03:00
memcpy ( & f1 , data , sizeof ( struct vtoc_format1_label ) ) ;
2005-04-17 02:20:36 +04:00
put_dev_sector ( sect ) ;
/* skip FMT4 / FMT5 / FMT7 labels */
if ( f1 . DS1FMTID = = _ascebc [ ' 4 ' ]
| | f1 . DS1FMTID = = _ascebc [ ' 5 ' ]
| | f1 . DS1FMTID = = _ascebc [ ' 7 ' ] ) {
blk + + ;
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 + + ;
}
} else {
/*
* Old style LNX1 or unlabeled disk
*/
if ( strncmp ( type , " LNX1 " , 4 ) = = 0 )
printk ( " LNX1/%8s: " , name ) ;
else
printk ( " (nonl)/%8s: " , name ) ;
offset = ( info - > label_block + 1 ) ;
size = ( bdev - > bd_inode - > i_size > > 9 ) ;
put_partition ( state , 1 , offset * ( blocksize > > 9 ) ,
size - offset * ( blocksize > > 9 ) ) ;
}
printk ( " \n " ) ;
2006-01-06 11:19:09 +03:00
kfree ( label ) ;
2005-04-17 02:20:36 +04:00
kfree ( geo ) ;
kfree ( info ) ;
return 1 ;
out_readerr :
out_badsect :
out_noioctl :
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 ) ;
out_noinfo :
return 0 ;
}