/*
- * File...........: linux/fs/partitions/ibm.c
+ * 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 "ibm.h"
/*
- * compute the block number from a
+ * compute the block number from a
* cyl-cyl-head-head structure
*/
static inline int
-cchh2blk (cchh_t *ptr, struct hd_geometry *geo) {
+cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) {
return ptr->cc * geo->heads * geo->sectors +
ptr->hh * geo->sectors;
}
-
/*
- * compute the block number from a
+ * compute the block number from a
* cyl-cyl-head-head-block structure
*/
static inline int
-cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) {
+cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) {
return ptr->cc * geo->heads * geo->sectors +
ptr->hh * geo->sectors +
ptr->b;
/*
*/
-int
+int
ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
{
- int blocksize, offset, size;
- dasd_information_t *info;
+ int blocksize, offset, size,res;
+ loff_t i_size;
+ dasd_information2_t *info;
struct hd_geometry *geo;
char type[5] = {0,};
char name[7] = {0,};
- volume_label_t *vlabel;
+ union label_t {
+ struct vtoc_volume_label vol;
+ struct vtoc_cms_label cms;
+ } *label;
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)
+ res = 0;
+ blocksize = bdev_hardsect_size(bdev);
+ if (blocksize <= 0)
+ goto out_exit;
+ i_size = i_size_read(bdev->bd_inode);
+ if (i_size == 0)
+ goto out_exit;
+
+ info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
+ if (info == NULL)
+ goto out_exit;
+ geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL);
+ if (geo == NULL)
goto out_nogeo;
- if ((vlabel = kmalloc(sizeof(volume_label_t), GFP_KERNEL)) == NULL)
- goto out_novlab;
-
- if (ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)info) != 0 ||
+ label = kmalloc(sizeof(union label_t), GFP_KERNEL);
+ if (label == NULL)
+ goto out_nolab;
+
+ if (ioctl_by_bdev(bdev, BIODASDINFO2, (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;
+ goto out_freeall;
/*
* Get volume label, extract name and type.
strncpy(name, data + 8, 6);
else
strncpy(name, data + 4, 6);
- memcpy (vlabel, data, sizeof(volume_label_t));
+ memcpy(label, data, sizeof(union label_t));
put_dev_sector(sect);
EBCASC(type, 4);
EBCASC(name, 6);
+ res = 1;
+
/*
- * Three different types: CMS1, VOL1 and LNX1/unlabeled
+ * Three different formats: LDL, CDL and unformated disk
+ *
+ * identified by info->format
+ *
+ * unformated disks we do not have to care about
*/
- if (strncmp(type, "CMS1", 4) == 0) {
- /*
- * VM style CMS1 labeled disk
- */
- int *label = (int *) vlabel;
-
- if (label[13] != 0) {
- printk("CMS1/%8s(MDSK):", name);
- /* disk is reserved minidisk */
- blocksize = label[3];
- offset = label[13];
- size = (label[7] - 1)*(blocksize >> 9);
+ 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;
+ }
} else {
- printk("CMS1/%8s:", name);
+ /*
+ * Old style LNX1 or unlabeled disk
+ */
+ if (strncmp(type, "LNX1", 4) == 0)
+ printk ("LNX1/%8s:", name);
+ else
+ printk("(nonl)");
offset = (info->label_block + 1);
- size = bdev->bd_inode->i_size >> 9;
+ size = 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"))) {
+ size-offset*(blocksize >> 9));
+ } else if (info->format == DASD_FORMAT_CDL) {
/*
- * New style VOL1 labeled disk
+ * New style CDL formatted disk
*/
unsigned int blk;
int counter;
- printk("VOL1/%8s:", name);
-
- /* get block number and read then go through format1 labels */
- blk = cchhb2blk(&vlabel->vtoc, geo) + 1;
- counter = 0;
- while ((data = read_dev_sector(bdev, blk*(blocksize/512),
- §)) != NULL) {
- format1_label_t f1;
-
- memcpy(&f1, data, sizeof(format1_label_t));
- 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
+ * check if VOL1 label is available
+ * if not, something is wrong, skipping partition detection
*/
- 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));
+ 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),
+ §);
+ 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),
+ §);
+ 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),
+ §);
+ }
+
+ 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");
+
}
printk("\n");
- kfree(vlabel);
- kfree(geo);
- kfree(info);
- return 1;
-
+ goto out_freeall;
+
+
out_readerr:
-out_badsect:
-out_noioctl:
- kfree(vlabel);
-out_novlab:
+ res = -1;
+out_freeall:
+ kfree(label);
+out_nolab:
kfree(geo);
out_nogeo:
kfree(info);
-out_noinfo:
- return 0;
+out_exit:
+ return res;
}