File: /usr/src/linux/fs/partitions/ibm.c
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
13 #include <linux/config.h>
14 #include <linux/fs.h>
15 #include <linux/genhd.h>
16 #include <linux/kernel.h>
17 #include <linux/major.h>
18 #include <linux/string.h>
19 #include <linux/blk.h>
20 #include <linux/slab.h>
21 #include <linux/hdreg.h>
22 #include <linux/ioctl.h>
23 #include <linux/version.h>
24 #include <asm/ebcdic.h>
25 #include <asm/uaccess.h>
26 #include <asm/dasd.h>
27
28 #include "ibm.h"
29 #include "check.h"
30 #include <asm/vtoc.h>
31
32 typedef enum {
33 ibm_partition_lnx1 = 0,
34 ibm_partition_vol1 = 1,
35 ibm_partition_cms1 = 2,
36 ibm_partition_none = 3
37 } ibm_partition_t;
38
39 static char* part_names[] = { [ibm_partition_lnx1] = "LNX1",
40 [ibm_partition_vol1] = "VOL1",
41 [ibm_partition_cms1] = "CMS1",
42 [ibm_partition_none] = "(nonl)"
43 };
44
45 static int
46 get_drive_geometry(int kdev,struct hd_geometry *geo)
47 {
48 struct block_device *bdev = bdget(kdev_t_to_nr(kdev));
49 int rc = blkdev_get(bdev, 0, 1, BDEV_FILE);
50 if ( rc == 0 ) {
51 rc = ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo);
52 blkdev_put(bdev, BDEV_FILE);
53 }
54 return rc;
55 }
56
57 static int
58 get_drive_info(int kdev,dasd_information_t *info)
59 {
60 struct block_device *bdev = bdget(kdev_t_to_nr(kdev));
61 int rc = blkdev_get(bdev, 0, 1, BDEV_FILE);
62 if ( rc == 0 ) {
63 rc = ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)(info));
64 blkdev_put(bdev, BDEV_FILE);
65 }
66 return rc;
67 }
68
69 static ibm_partition_t
70 get_partition_type ( char * type )
71 {
72 int i;
73 for ( i = 0; i < 3; i ++) {
74 if ( ! strncmp (type,part_names[i],4) )
75 break;
76 }
77 return i;
78 }
79
80 /*
81 * add the two default partitions
82 * - whole dasd
83 * - whole dasd without "offset"
84 */
85 static inline void
86 two_partitions(struct gendisk *hd,
87 int minor,
88 int blocksize,
89 int offset,
90 int size) {
91
92 add_gd_partition( hd, minor, 0,size);
93 add_gd_partition( hd, minor + 1,
94 offset * (blocksize >> 9),
95 size-offset*(blocksize>>9));
96 }
97
98
99 /*
100 * compute the block number from a
101 * cyl-cyl-head-head structure
102 */
103 static inline int
104 cchh2blk (cchh_t *ptr, struct hd_geometry *geo) {
105 return ptr->cc * geo->heads * geo->sectors +
106 ptr->hh * geo->sectors;
107 }
108
109
110 /*
111 * compute the block number from a
112 * cyl-cyl-head-head-block structure
113 */
114 static inline int
115 cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) {
116 return ptr->cc * geo->heads * geo->sectors +
117 ptr->hh * geo->sectors +
118 ptr->b;
119 }
120
121 int
122 ibm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int
123 first_part_minor)
124 {
125 struct buffer_head *bh, *buf;
126 ibm_partition_t partition_type;
127 char type[5] = {0,};
128 char name[7] = {0,};
129 struct hd_geometry *geo;
130 int blocksize;
131 int offset=0, size=0, psize=0, counter=0;
132 unsigned int blk;
133 format1_label_t f1;
134 volume_label_t vlabel;
135 dasd_information_t *info;
136
137 if ( first_sector != 0 ) {
138 BUG();
139 }
140 info = (struct dasd_information_t *)kmalloc(sizeof(dasd_information_t),
141 GFP_KERNEL);
142 if ( info == NULL )
143 return 0;
144 if (get_drive_info (dev,info))
145 return 0;
146 geo = (struct hd_geometry *)kmalloc(sizeof(struct hd_geometry),
147 GFP_KERNEL);
148 if ( geo == NULL )
149 return 0;
150 if (get_drive_geometry (dev,geo))
151 return 0;
152 blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
153 if ( blocksize <= 0 ) {
154 return 0;
155 }
156
157 set_blocksize(dev, blocksize); /* OUCH !! */
158 if ( ( bh = bread( dev, info->label_block, blocksize) ) != NULL ) {
159 strncpy ( type,bh -> b_data + 0, 4);
160 if ((!info->FBA_layout) && (!strcmp(info->type,"ECKD"))) {
161
162 strncpy ( name,bh -> b_data + 8, 6);
163 } else {
164 strncpy ( name,bh -> b_data + 4, 6);
165 }
166 memcpy (&vlabel, bh->b_data, sizeof(volume_label_t));
167 } else {
168 return 0;
169 }
170 EBCASC(type,4);
171 EBCASC(name,6);
172
173 partition_type = get_partition_type(type);
174 printk ( "%4s/%8s:",part_names[partition_type],name);
175 switch ( partition_type ) {
176 case ibm_partition_cms1:
177 if (* (((long *)bh->b_data) + 13) != 0) {
178 /* disk is reserved minidisk */
179 long *label=(long*)bh->b_data;
180 blocksize = label[3];
181 offset = label[13];
182 size = (label[7]-1)*(blocksize>>9);
183 printk ("(MDSK)");
184 } else {
185 offset = (info->label_block + 1);
186 size = hd -> sizes[MINOR(dev)]<<1;
187 }
188 two_partitions( hd, MINOR(dev), blocksize, offset, size);
189 break;
190 case ibm_partition_lnx1:
191 case ibm_partition_none:
192 offset = (info->label_block + 1);
193 size = hd -> sizes[MINOR(dev)]<<1;
194 two_partitions( hd, MINOR(dev), blocksize, offset, size);
195 break;
196 case ibm_partition_vol1:
197 size = hd -> sizes[MINOR(dev)]<<1;
198 add_gd_partition(hd, MINOR(dev), 0, size);
199
200 /* get block number and read then first format1 label */
201 blk = cchhb2blk(&vlabel.vtoc, geo) + 1;
202 if ((buf = bread( dev, blk, blocksize)) != NULL) {
203 memcpy (&f1, buf->b_data, sizeof(format1_label_t));
204 bforget(buf);
205 }
206
207 while (f1.DS1FMTID == _ascebc['1']) {
208 offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
209 psize = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
210 offset + geo->sectors;
211
212 counter++;
213 add_gd_partition(hd, MINOR(dev) + counter,
214 offset * (blocksize >> 9),
215 psize * (blocksize >> 9));
216
217 blk++;
218 if ((buf = bread( dev, blk, blocksize)) != NULL) {
219 memcpy (&f1, buf->b_data,
220 sizeof(format1_label_t));
221 bforget(buf);
222 }
223 }
224 break;
225 default:
226 add_gd_partition( hd, MINOR(dev), 0, 0);
227 add_gd_partition( hd, MINOR(dev) + 1, 0, 0);
228 }
229
230 printk ( "\n" );
231 bforget(bh);
232 return 1;
233 }
234