2 * File...........: linux/fs/partitions/ibm.c
3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4 * Volker Sameske <sameske@de.ibm.com>
5 * Bugreports.to..: <Linux390@de.ibm.com>
6 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
8 * History of changes (starts July 2000)
9 * 07/10/00 Fixed detection of CMS formatted disks
10 * 02/13/00 VTOC partition support added
11 * 12/27/01 fixed PL030593 (CMS reserved minidisk not detected on 64 bit)
14 #include <linux/config.h>
16 #include <linux/genhd.h>
17 #include <linux/kernel.h>
18 #include <linux/major.h>
19 #include <linux/string.h>
20 #include <linux/blk.h>
21 #include <linux/slab.h>
22 #include <linux/hdreg.h>
23 #include <linux/ioctl.h>
24 #include <linux/version.h>
25 #include <asm/ebcdic.h>
26 #include <asm/uaccess.h>
34 * compute the block number from a
35 * cyl-cyl-head-head structure
38 cchh2blk (cchh_t *ptr, struct hd_geometry *geo) {
39 return ptr->cc * geo->heads * geo->sectors +
40 ptr->hh * geo->sectors;
45 * compute the block number from a
46 * cyl-cyl-head-head-block structure
49 cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) {
50 return ptr->cc * geo->heads * geo->sectors +
51 ptr->hh * geo->sectors +
56 * We used to use ioctl_by_bdev in early 2.4, but it broke
57 * between 2.4.9 and 2.4.18 somewhere.
59 extern int (*genhd_dasd_ioctl)(struct inode *inp, struct file *filp,
60 unsigned int no, unsigned long data);
63 ibm_ioctl_unopened(struct block_device *bdev, unsigned cmd, unsigned long arg)
66 mm_segment_t old_fs = get_fs();
68 if (genhd_dasd_ioctl == NULL)
73 __MOD_INC_USE_COUNT(bdev->bd_op->owner);
77 res = (*genhd_dasd_ioctl)(bdev->bd_inode, NULL, cmd, arg);
82 __MOD_DEV_USE_COUNT(bd_ops->owner);
91 ibm_partition(struct gendisk *hd, struct block_device *bdev,
92 unsigned long first_sector, int first_part_minor)
94 int blocksize, offset, size;
95 dasd_information_t *info;
96 struct hd_geometry *geo;
99 volume_label_t *vlabel;
103 if ( first_sector != 0 )
106 if ((info = kmalloc(sizeof(dasd_information_t), GFP_KERNEL)) == NULL)
108 if ((geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL)) == NULL)
110 if ((vlabel = kmalloc(sizeof(volume_label_t), GFP_KERNEL)) == NULL)
113 if (ibm_ioctl_unopened(bdev, BIODASDINFO, (unsigned long)info) != 0 ||
114 ibm_ioctl_unopened(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
117 if ((blocksize = get_hardsect_size(to_kdev_t(bdev->bd_dev))) <= 0)
121 * Get volume label, extract name and type.
123 data = read_dev_sector(bdev, info->label_block*(blocksize/512), §);
126 strncpy (type, data, 4);
127 if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD")))
128 strncpy(name, data + 8, 6);
130 strncpy(name, data + 4, 6);
131 memcpy (vlabel, data, sizeof(volume_label_t));
132 put_dev_sector(sect);
138 * Three different types: CMS1, VOL1 and LNX1/unlabeled
140 if (strncmp(type, "CMS1", 4) == 0) {
142 * VM style CMS1 labeled disk
144 int *label = (int *) data;
146 if (label[13] != 0) {
147 printk("CMS1/%8s(MDSK):", name);
148 /* disk is reserved minidisk */
149 blocksize = label[3];
151 size = (label[7] - 1)*(blocksize >> 9);
153 printk("CMS1/%8s:", name);
154 offset = (info->label_block + 1);
155 size = bdev->bd_inode->i_size >> 9;
157 // add_gd_partition(hd, first_part_minor - 1, 0, size);
158 add_gd_partition(hd, first_part_minor,
159 offset*(blocksize >> 9),
160 size-offset*(blocksize >> 9));
161 } else if (strncmp(type, "VOL1", 4) == 0) {
163 * New style VOL1 labeled disk
168 printk("VOL1/%8s:", name);
170 /* get block number and read then go through format1 labels */
171 blk = cchhb2blk(&vlabel->vtoc, geo) + 1;
173 while ((data = read_dev_sector(bdev, blk*(blocksize/512),
177 memcpy(&f1, data, sizeof(format1_label_t));
178 put_dev_sector(sect);
180 /* skip FMT4 / FMT5 / FMT7 labels */
181 if (f1.DS1FMTID == _ascebc['4']
182 || f1.DS1FMTID == _ascebc['5']
183 || f1.DS1FMTID == _ascebc['7']) {
188 /* only FMT1 valid at this point */
189 if (f1.DS1FMTID != _ascebc['1'])
192 /* OK, we got valid partition data */
193 offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
194 size = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
195 offset + geo->sectors;
196 if (counter >= hd->max_p)
198 add_gd_partition(hd, first_part_minor + counter,
199 offset * (blocksize >> 9),
200 size * (blocksize >> 9));
206 * Old style LNX1 or unlabeled disk
208 if (strncmp(type, "LNX1", 4) == 0)
209 printk ("LNX1/%8s:", name);
211 printk("(nonl)/%8s:", name);
212 offset = (info->label_block + 1);
213 size = (bdev->bd_inode->i_size >> 9);
214 // add_gd_partition(hd, first_part_minor - 1, 0, size);
215 add_gd_partition(hd, first_part_minor,
216 offset*(blocksize >> 9),
217 size-offset*(blocksize >> 9));