1 // SPDX-License-Identifier: GPL-2.0
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 * Copyright IBM Corp. 1999, 2012
9 #include <linux/buffer_head.h>
10 #include <linux/hdreg.h>
11 #include <linux/slab.h>
13 #include <asm/ebcdic.h>
14 #include <linux/uaccess.h>
16 #include <linux/module.h>
17 #include <linux/dasd_mod.h>
22 struct vtoc_volume_label_cdl vol
;
23 struct vtoc_volume_label_ldl lnx
;
24 struct vtoc_cms_label cms
;
28 * compute the block number from a
29 * cyl-cyl-head-head structure
31 static sector_t
cchh2blk(struct vtoc_cchh
*ptr
, struct hd_geometry
*geo
)
36 /* decode cylinder and heads for large volumes */
37 cyl
= ptr
->hh
& 0xFFF0;
40 head
= ptr
->hh
& 0x000F;
41 return cyl
* geo
->heads
* geo
->sectors
+
46 * compute the block number from a
47 * cyl-cyl-head-head-block structure
49 static sector_t
cchhb2blk(struct vtoc_cchhb
*ptr
, struct hd_geometry
*geo
)
54 /* decode cylinder and heads for large volumes */
55 cyl
= ptr
->hh
& 0xFFF0;
58 head
= ptr
->hh
& 0x000F;
59 return cyl
* geo
->heads
* geo
->sectors
+
64 static int find_label(struct parsed_partitions
*state
,
65 dasd_information2_t
*info
,
66 struct hd_geometry
*geo
,
76 unsigned char temp
[5];
80 /* There a three places where we may find a valid label:
81 * - on an ECKD disk it's block 2
82 * - on an FBA disk it's block 1
83 * - on an CMS formatted FBA disk it is sector 1, even if the block size
84 * is larger than 512 bytes (possible if the DIAG discipline is used)
85 * If we have a valid info structure, then we know exactly which case we
86 * have, otherwise we just search through all possebilities.
89 if ((info
->cu_type
== 0x6310 && info
->dev_type
== 0x9336) ||
90 (info
->cu_type
== 0x3880 && info
->dev_type
== 0x3370))
91 testsect
[0] = info
->label_block
;
93 testsect
[0] = info
->label_block
* (blocksize
>> 9);
97 testsect
[1] = (blocksize
>> 9);
98 testsect
[2] = 2 * (blocksize
>> 9);
101 for (i
= 0; i
< testcount
; ++i
) {
102 data
= read_part_sector(state
, testsect
[i
], §
);
105 memcpy(label
, data
, sizeof(*label
));
106 memcpy(temp
, data
, 4);
109 put_dev_sector(sect
);
110 if (!strcmp(temp
, "VOL1") ||
111 !strcmp(temp
, "LNX1") ||
112 !strcmp(temp
, "CMS1")) {
113 if (!strcmp(temp
, "VOL1")) {
114 strncpy(type
, label
->vol
.vollbl
, 4);
115 strncpy(name
, label
->vol
.volid
, 6);
117 strncpy(type
, label
->lnx
.vollbl
, 4);
118 strncpy(name
, label
->lnx
.volid
, 6);
122 *labelsect
= testsect
[i
];
128 memset(label
, 0, sizeof(*label
));
133 static int find_vol1_partitions(struct parsed_partitions
*state
,
134 struct hd_geometry
*geo
,
137 union label_t
*label
)
145 struct vtoc_format1_label f1
;
148 snprintf(tmp
, sizeof(tmp
), "VOL1/%8s:", name
);
149 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
151 * get start of VTOC from the disk label and then search for format1
154 secperblk
= blocksize
>> 9;
155 blk
= cchhb2blk(&label
->vol
.vtoc
, geo
) + 1;
157 data
= read_part_sector(state
, blk
* secperblk
, §
);
158 while (data
!= NULL
) {
159 memcpy(&f1
, data
, sizeof(struct vtoc_format1_label
));
160 put_dev_sector(sect
);
161 /* skip FMT4 / FMT5 / FMT7 labels */
162 if (f1
.DS1FMTID
== _ascebc
['4']
163 || f1
.DS1FMTID
== _ascebc
['5']
164 || f1
.DS1FMTID
== _ascebc
['7']
165 || f1
.DS1FMTID
== _ascebc
['9']) {
167 data
= read_part_sector(state
, blk
* secperblk
, §
);
170 /* only FMT1 and 8 labels valid at this point */
171 if (f1
.DS1FMTID
!= _ascebc
['1'] &&
172 f1
.DS1FMTID
!= _ascebc
['8'])
174 /* OK, we got valid partition data */
175 offset
= cchh2blk(&f1
.DS1EXT1
.llimit
, geo
);
176 size
= cchh2blk(&f1
.DS1EXT1
.ulimit
, geo
) -
177 offset
+ geo
->sectors
;
180 if (counter
>= state
->limit
)
182 put_partition(state
, counter
+ 1, offset
, size
);
185 data
= read_part_sector(state
, blk
* secperblk
, §
);
187 strlcat(state
->pp_buf
, "\n", PAGE_SIZE
);
195 static int find_lnx1_partitions(struct parsed_partitions
*state
,
196 struct hd_geometry
*geo
,
199 union label_t
*label
,
202 dasd_information2_t
*info
)
204 loff_t offset
, geo_size
, size
;
208 snprintf(tmp
, sizeof(tmp
), "LNX1/%8s:", name
);
209 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
210 secperblk
= blocksize
>> 9;
211 if (label
->lnx
.ldl_version
== 0xf2) {
212 size
= label
->lnx
.formatted_blocks
* secperblk
;
215 * Formated w/o large volume support. If the sanity check
216 * 'size based on geo == size based on i_size' is true, then
217 * we can safely assume that we know the formatted size of
218 * the disk, otherwise we need additional information
219 * that we can only get from a real DASD device.
221 geo_size
= geo
->cylinders
* geo
->heads
222 * geo
->sectors
* secperblk
;
224 if (size
!= geo_size
) {
226 strlcat(state
->pp_buf
, "\n", PAGE_SIZE
);
229 if (!strcmp(info
->type
, "ECKD"))
232 /* else keep size based on i_size */
235 /* first and only partition starts in the first block after the label */
236 offset
= labelsect
+ secperblk
;
237 put_partition(state
, 1, offset
, size
- offset
);
238 strlcat(state
->pp_buf
, "\n", PAGE_SIZE
);
242 static int find_cms1_partitions(struct parsed_partitions
*state
,
243 struct hd_geometry
*geo
,
246 union label_t
*label
,
254 * VM style CMS1 labeled disk
256 blocksize
= label
->cms
.block_size
;
257 secperblk
= blocksize
>> 9;
258 if (label
->cms
.disk_offset
!= 0) {
259 snprintf(tmp
, sizeof(tmp
), "CMS1/%8s(MDSK):", name
);
260 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
261 /* disk is reserved minidisk */
262 offset
= label
->cms
.disk_offset
* secperblk
;
263 size
= (label
->cms
.block_count
- 1) * secperblk
;
265 snprintf(tmp
, sizeof(tmp
), "CMS1/%8s:", name
);
266 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
268 * Special case for FBA devices:
269 * If an FBA device is CMS formatted with blocksize > 512 byte
270 * and the DIAG discipline is used, then the CMS label is found
271 * in sector 1 instead of block 1. However, the partition is
272 * still supposed to start in block 2.
275 offset
= 2 * secperblk
;
277 offset
= labelsect
+ secperblk
;
278 size
= label
->cms
.block_count
* secperblk
;
281 put_partition(state
, 1, offset
, size
-offset
);
282 strlcat(state
->pp_buf
, "\n", PAGE_SIZE
);
288 * This is the main function, called by check.c
290 int ibm_partition(struct parsed_partitions
*state
)
292 int (*fn
)(struct gendisk
*disk
, dasd_information2_t
*info
);
293 struct block_device
*bdev
= state
->bdev
;
294 struct gendisk
*disk
= bdev
->bd_disk
;
296 loff_t i_size
, offset
, size
;
297 dasd_information2_t
*info
;
298 struct hd_geometry
*geo
;
302 union label_t
*label
;
305 if (!disk
->fops
->getgeo
)
307 fn
= symbol_get(dasd_biodasdinfo
);
308 blocksize
= bdev_logical_block_size(bdev
);
311 i_size
= i_size_read(bdev
->bd_inode
);
314 info
= kmalloc(sizeof(dasd_information2_t
), GFP_KERNEL
);
317 geo
= kmalloc(sizeof(struct hd_geometry
), GFP_KERNEL
);
320 label
= kmalloc(sizeof(union label_t
), GFP_KERNEL
);
323 /* set start if not filled by getgeo function e.g. virtblk */
324 geo
->start
= get_start_sect(bdev
);
325 if (disk
->fops
->getgeo(bdev
, geo
))
327 if (!fn
|| fn(disk
, info
)) {
332 if (find_label(state
, info
, geo
, blocksize
, &labelsect
, name
, type
,
334 if (!strncmp(type
, "VOL1", 4)) {
335 res
= find_vol1_partitions(state
, geo
, blocksize
, name
,
337 } else if (!strncmp(type
, "LNX1", 4)) {
338 res
= find_lnx1_partitions(state
, geo
, blocksize
, name
,
339 label
, labelsect
, i_size
,
341 } else if (!strncmp(type
, "CMS1", 4)) {
342 res
= find_cms1_partitions(state
, geo
, blocksize
, name
,
347 * ugly but needed for backward compatibility:
348 * If the block device is a DASD (i.e. BIODASDINFO2 works),
349 * then we claim it in any case, even though it has no valid
350 * label. If it has the LDL format, then we simply define a
351 * partition as if it had an LNX1 label.
354 if (info
->format
== DASD_FORMAT_LDL
) {
355 strlcat(state
->pp_buf
, "(nonl)", PAGE_SIZE
);
357 offset
= (info
->label_block
+ 1) * (blocksize
>> 9);
358 put_partition(state
, 1, offset
, size
-offset
);
359 strlcat(state
->pp_buf
, "\n", PAGE_SIZE
);
372 symbol_put(dasd_biodasdinfo
);