patch-2.4.4 linux/fs/partitions/ibm.c

Next file: linux/fs/proc/array.c
Previous file: linux/fs/partitions/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.3/linux/fs/partitions/ibm.c linux/fs/partitions/ibm.c
@@ -1,14 +1,17 @@
 /*
  * 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               
-
+ * 07/10/00 Fixed detection of CMS formatted disks     
+ * 02/13/00 VTOC partition support added
  */
 
+#include <linux/config.h>
+#include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/kernel.h>
@@ -25,145 +28,177 @@
 
 #include "ibm.h"
 #include "check.h"
+#include <asm/vtoc.h>
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 /* We hook in when DASD is a module... */
 int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
+int (*genhd_dasd_fillgeo)(int,struct hd_geometry *) = NULL;
+EXPORT_SYMBOL(genhd_dasd_fillgeo);
+EXPORT_SYMBOL(genhd_dasd_name);
 #endif /* LINUX_IS_24 */
 
 typedef enum {
-  ibm_partition_none = 0,
-  ibm_partition_lnx1 = 1,
-  ibm_partition_vol1 = 3,
-  ibm_partition_cms1 = 4
+  ibm_partition_lnx1 = 0,
+  ibm_partition_vol1 = 1,
+  ibm_partition_cms1 = 2,
+  ibm_partition_none = 3
 } ibm_partition_t;
 
+static char* part_names[] = {   [ibm_partition_lnx1] = "LNX1",
+			     [ibm_partition_vol1] = "VOL1",
+			     [ibm_partition_cms1] = "CMS1",
+			     [ibm_partition_none] = "(nonl)"
+};
+
 static ibm_partition_t
 get_partition_type ( char * type )
 {
-        static char lnx[5]="LNX1";
-        static char vol[5]="VOL1";
-        static char cms[5]="CMS1";
-        if ( ! strncmp ( lnx, "LNX1",4 ) ) {
-                ASCEBC(lnx,4);
-                ASCEBC(vol,4);
-                ASCEBC(cms,4);
-        }
-        if ( ! strncmp (type,lnx,4) ||
-             ! strncmp (type,"LNX1",4) )
-                return ibm_partition_lnx1;
-        if ( ! strncmp (type,vol,4) )
-                return ibm_partition_vol1;
-        if ( ! strncmp (type,cms,4) )
-                return ibm_partition_cms1;
-        return ibm_partition_none;
+	int i;
+	for ( i = 0; i < 3; i ++) {
+		if ( ! strncmp (type,part_names[i],4) ) 
+			break;
+	}
+        return i;
+}
+
+/*
+ * add the two default partitions
+ * - whole dasd
+ * - whole dasd without "offset"
+ */
+static inline void
+two_partitions(struct gendisk *hd,
+	       int minor,
+	       int blocksize,
+	       int offset,
+	       int size) {
+
+        add_gd_partition( hd, minor, 0,size);
+	add_gd_partition( hd, minor + 1, 
+			   offset * (blocksize >> 9),
+			   size-offset*(blocksize>>9));
+}
+
+
+/*
+ * compute the block number from a 
+ * cyl-cyl-head-head structure
+ */
+static inline int
+cchh2blk (cchh_t *ptr, struct hd_geometry *geo) {
+        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
+cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) {
+        return ptr->cc * geo->heads * geo->sectors +
+		ptr->hh * geo->sectors +
+		ptr->b;
 }
 
 int 
 ibm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int
 first_part_minor)
 {
-	struct buffer_head *bh;
+	struct buffer_head *bh, *buf;
 	ibm_partition_t partition_type;
 	char type[5] = {0,};
 	char name[7] = {0,};
 	struct hd_geometry geo;
-	mm_segment_t old_fs;
 	int blocksize;
-	struct file *filp = NULL;
-	struct inode *inode = NULL;
-	int offset, size;
+	int offset=0, size=0, psize=0, counter=0;
+	unsigned int blk;
+	format1_label_t f1;
+	volume_label_t vlabel;
 
+	if ( first_sector != 0 ) {
+		BUG();
+	}
+	if ( !genhd_dasd_fillgeo ) {
+		return 0;
+	}
+	genhd_dasd_fillgeo(dev,&geo);
 	blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
 	if ( blocksize <= 0 ) {
 		return 0;
 	}
-	set_blocksize(dev, blocksize);  /* OUCH !! */
-
-	/* find out offset of volume label (partn table) */
-	inode = get_empty_inode();
-	inode -> i_rdev = dev;
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	inode -> i_bdev = bdget(kdev_t_to_nr(dev));
-#endif /* KERNEL_VERSION */
-	filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL);
-	if (!filp)
-		return 0;
-	memset(filp,0,sizeof(struct file));
-	filp ->f_mode = 1; /* read only */
-	blkdev_open(inode,filp);
-	old_fs=get_fs();
-	set_fs(KERNEL_DS);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	inode-> i_bdev -> bd_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo));
-#else
-	filp->f_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo));
-#endif /* KERNEL_VERSION */
-	set_fs(old_fs);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
-        blkdev_put(inode->i_bdev,BDEV_FILE);
-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	blkdev_close(inode,filp);
-#else
-	blkdev_release(inode);
-#endif /* LINUX_VERSION_CODE */
 
-	size = hd -> sizes[MINOR(dev)]<<1;
+	set_blocksize(dev, blocksize);  /* OUCH !! */
 	if ( ( bh = bread( dev, geo.start, blocksize) ) != NULL ) {
-		strncpy ( type,bh -> b_data, 4);
+		strncpy ( type,bh -> b_data + 0, 4);
 		strncpy ( name,bh -> b_data + 4, 6);
+		memcpy (&vlabel, bh->b_data, sizeof(volume_label_t));
         } else {
 		return 0;
 	}
-	if ( (*(char *)bh -> b_data) & 0x80 ) {
-		EBCASC(name,6);
-	}
-	switch ( partition_type = get_partition_type(type) ) {
-	case ibm_partition_lnx1: 
-		offset = (geo.start + 1);
-		printk ( "(LNX1)/%6s:",name);
-		break;
-	case ibm_partition_vol1:
-		offset = 0;
-		size = 0;
-		printk ( "(VOL1)/%6s:",name);
-		break;
+	EBCASC(type,4);
+	EBCASC(name,6);
+
+	partition_type = get_partition_type(type);
+	printk ( "%6s/%6s:",part_names[partition_type],name);
+	switch ( partition_type ) {
 	case ibm_partition_cms1:
-		printk ( "(CMS1)/%6s:",name);
-		if (* (((long *)bh->b_data) + 13) == 0) {
-			/* disk holds a CMS filesystem */
-			offset = (geo.start + 1);
-			printk ("(CMS)");
-		} else {
+		if (* (((long *)bh->b_data) + 13) != 0) {
 			/* disk is reserved minidisk */
-			// mdisk_setup_data.size[i] =
-			// (label[7] - 1 - label[13]) *
-			// (label[3] >> 9) >> 1;
 			long *label=(long*)bh->b_data;
 			blocksize = label[3];
 			offset = label[13];
 			size = (label[7]-1)*(blocksize>>9); 
 			printk ("(MDSK)");
+		} else {
+			offset = (geo.start + 1);
+			size = hd -> sizes[MINOR(dev)]<<1;
 		}
+		two_partitions( hd, MINOR(dev), blocksize, 
+				offset, size);
 		break;
+	case ibm_partition_lnx1: 
 	case ibm_partition_none:
-		printk ( "(nonl)/      :");
-		offset = (geo.start+1);
+		offset = (geo.start + 1);
+		size = hd -> sizes[MINOR(dev)]<<1;
+		two_partitions( hd, MINOR(dev), blocksize, 
+				offset, size);
+		break;
+	case ibm_partition_vol1:
+		add_gd_partition(hd, MINOR(dev), 0, size);
+
+		/* get block number and read then first format1 label */
+		blk = cchhb2blk(&vlabel.vtoc, &geo) + 1;
+		if ((buf = bread( dev, blk, blocksize)) != NULL) {
+		        memcpy (&f1, buf->b_data, sizeof(format1_label_t));
+			bforget(buf);
+		}
+
+		while (f1.DS1FMTID == _ascebc['1']) {
+		        offset = cchh2blk(&f1.DS1EXT1.llimit, &geo);
+			psize  = cchh2blk(&f1.DS1EXT1.ulimit, &geo) - 
+				offset + 1;
+			
+			counter++;
+			add_gd_partition(hd, MINOR(dev) + counter, 
+					  offset * (blocksize >> 9),
+					  psize * (blocksize >> 9));
+			
+			blk++;
+			if ((buf = bread( dev, blk, blocksize)) != NULL) {
+			        memcpy (&f1, buf->b_data, 
+					sizeof(format1_label_t));
+				bforget(buf);
+			}
+		}
 		break;
 	default:
-		offset = 0;
-		size = 0;
-		
+		add_gd_partition( hd, MINOR(dev), 0, 0);
+		add_gd_partition( hd, MINOR(dev) + 1, 0, 0);
 	}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	add_gd_partition( hd, MINOR(dev), 0,size);
-	add_gd_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9),
-			  size-offset*(blocksize>>9));
-#else
-	add_partition( hd, MINOR(dev), 0,size,0);
-	add_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9),
-			  size-offset*(blocksize>>9) ,0 );
-#endif /* LINUX_VERSION */
+
 	printk ( "\n" );
 	bforget(bh);
 	return 1;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)