1 /*
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
7
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)
12 */
13
14 #include <linux/config.h>
15 #include <linux/fs.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>
27 #include <asm/dasd.h>
28
29 #include "ibm.h"
30 #include "check.h"
31 #include <asm/vtoc.h>
32
33 /*
34 * compute the block number from a
35 * cyl-cyl-head-head structure
36 */
37 static inline int
38 cchh2blk (cchh_t *ptr, struct hd_geometry *geo) {
39 return ptr->cc * geo->heads * geo->sectors +
40 ptr->hh * geo->sectors;
41 }
42
43
44 /*
45 * compute the block number from a
46 * cyl-cyl-head-head-block structure
47 */
48 static inline int
49 cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) {
50 return ptr->cc * geo->heads * geo->sectors +
51 ptr->hh * geo->sectors +
52 ptr->b;
53 }
54
55 /*
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.
58 */
59 extern int (*genhd_dasd_ioctl)(struct inode *inp, struct file *filp,
60 unsigned int no, unsigned long data);
61
62 static int
63 ibm_ioctl_unopened(struct block_device *bdev, unsigned cmd, unsigned long arg)
64 {
65 int res;
66 mm_segment_t old_fs = get_fs();
67
68 if (genhd_dasd_ioctl == NULL)
69 return -ENODEV;
70 #if 0
71 lock_kernel();
72 if (bd_ops->owner)
73 __MOD_INC_USE_COUNT(bdev->bd_op->owner);
74 unlock_kernel();
75 #endif
76 set_fs(KERNEL_DS);
77 res = (*genhd_dasd_ioctl)(bdev->bd_inode, NULL, cmd, arg);
78 set_fs(old_fs);
79 #if 0
80 lock_kernel();
81 if (bd_ops->owner)
82 __MOD_DEV_USE_COUNT(bd_ops->owner);
83 unlock_kernel();
84 #endif
85 return res;
86 }
87
88 /*
89 */
90 int
91 ibm_partition(struct gendisk *hd, struct block_device *bdev,
92 unsigned long first_sector, int first_part_minor)
93 {
94 int blocksize, offset, size;
95 dasd_information_t *info;
96 struct hd_geometry *geo;
97 char type[5] = {0,};
98 char name[7] = {0,};
99 volume_label_t *vlabel;
100 unsigned char *data;
101 Sector sect;
102
103 if ( first_sector != 0 )
104 BUG();
105
106 if ((info = kmalloc(sizeof(dasd_information_t), GFP_KERNEL)) == NULL)
107 goto out_noinfo;
108 if ((geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL)) == NULL)
109 goto out_nogeo;
110 if ((vlabel = kmalloc(sizeof(volume_label_t), GFP_KERNEL)) == NULL)
111 goto out_novlab;
112
113 if (ibm_ioctl_unopened(bdev, BIODASDINFO, (unsigned long)info) != 0 ||
114 ibm_ioctl_unopened(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
115 goto out_noioctl;
116
117 if ((blocksize = get_hardsect_size(to_kdev_t(bdev->bd_dev))) <= 0)
118 goto out_badsect;
119
120 /*
121 * Get volume label, extract name and type.
122 */
123 data = read_dev_sector(bdev, info->label_block*(blocksize/512), §);
124 if (data == NULL)
125 goto out_readerr;
126 strncpy (type, data, 4);
127 if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD")))
128 strncpy(name, data + 8, 6);
129 else
130 strncpy(name, data + 4, 6);
131 memcpy (vlabel, data, sizeof(volume_label_t));
132 put_dev_sector(sect);
133
134 EBCASC(type, 4);
135 EBCASC(name, 6);
136
137 /*
138 * Three different types: CMS1, VOL1 and LNX1/unlabeled
139 */
140 if (strncmp(type, "CMS1", 4) == 0) {
141 /*
142 * VM style CMS1 labeled disk
143 */
144 int *label = (int *) data;
145
146 if (label[13] != 0) {
147 printk("CMS1/%8s(MDSK):", name);
148 /* disk is reserved minidisk */
149 blocksize = label[3];
150 offset = label[13];
151 size = (label[7] - 1)*(blocksize >> 9);
152 } else {
153 printk("CMS1/%8s:", name);
154 offset = (info->label_block + 1);
155 size = bdev->bd_inode->i_size >> 9;
156 }
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) {
162 /*
163 * New style VOL1 labeled disk
164 */
165 unsigned int blk;
166 int counter;
167
168 printk("VOL1/%8s:", name);
169
170 /* get block number and read then go through format1 labels */
171 blk = cchhb2blk(&vlabel->vtoc, geo) + 1;
172 counter = 0;
173 while ((data = read_dev_sector(bdev, blk*(blocksize/512),
174 §)) != NULL) {
175 format1_label_t f1;
176
177 memcpy(&f1, data, sizeof(format1_label_t));
178 put_dev_sector(sect);
179
180 /* skip FMT4 / FMT5 / FMT7 labels */
181 if (f1.DS1FMTID == _ascebc['4']
182 || f1.DS1FMTID == _ascebc['5']
183 || f1.DS1FMTID == _ascebc['7']) {
184 blk++;
185 continue;
186 }
187
188 /* only FMT1 valid at this point */
189 if (f1.DS1FMTID != _ascebc['1'])
190 break;
191
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)
197 break;
198 add_gd_partition(hd, first_part_minor + counter,
199 offset * (blocksize >> 9),
200 size * (blocksize >> 9));
201 counter++;
202 blk++;
203 }
204 } else {
205 /*
206 * Old style LNX1 or unlabeled disk
207 */
208 if (strncmp(type, "LNX1", 4) == 0)
209 printk ("LNX1/%8s:", name);
210 else
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));
218 }
219
220 printk("\n");
221 kfree(vlabel);
222 kfree(geo);
223 kfree(info);
224 return 1;
225
226 out_readerr:
227 out_badsect:
228 out_noioctl:
229 kfree(vlabel);
230 out_novlab:
231 kfree(geo);
232 out_nogeo:
233 kfree(info);
234 out_noinfo:
235 return 0;
236 }
Cache object: b91fa2bf888157ef2c2190bc7049590d
|