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 /* Volume Label Type/ID Length */
65 #define DASD_VOL_TYPE_LEN 4
66 #define DASD_VOL_ID_LEN 6
68 /* Volume Label Types */
69 #define DASD_VOLLBL_TYPE_VOL1 0
70 #define DASD_VOLLBL_TYPE_LNX1 1
71 #define DASD_VOLLBL_TYPE_CMS1 2
73 struct dasd_vollabel
{
78 static struct dasd_vollabel dasd_vollabels
[] = {
79 [DASD_VOLLBL_TYPE_VOL1
] = {
81 .idx
= DASD_VOLLBL_TYPE_VOL1
,
83 [DASD_VOLLBL_TYPE_LNX1
] = {
85 .idx
= DASD_VOLLBL_TYPE_LNX1
,
87 [DASD_VOLLBL_TYPE_CMS1
] = {
89 .idx
= DASD_VOLLBL_TYPE_CMS1
,
93 static int get_label_by_type(const char *type
)
97 for (i
= 0; i
< ARRAY_SIZE(dasd_vollabels
); i
++) {
98 if (!memcmp(type
, dasd_vollabels
[i
].type
, DASD_VOL_TYPE_LEN
))
99 return dasd_vollabels
[i
].idx
;
105 static int find_label(struct parsed_partitions
*state
,
106 dasd_information2_t
*info
,
107 struct hd_geometry
*geo
,
112 union label_t
*label
)
114 sector_t testsect
[3];
119 /* There a three places where we may find a valid label:
120 * - on an ECKD disk it's block 2
121 * - on an FBA disk it's block 1
122 * - on an CMS formatted FBA disk it is sector 1, even if the block size
123 * is larger than 512 bytes (possible if the DIAG discipline is used)
124 * If we have a valid info structure, then we know exactly which case we
125 * have, otherwise we just search through all possebilities.
128 if ((info
->cu_type
== 0x6310 && info
->dev_type
== 0x9336) ||
129 (info
->cu_type
== 0x3880 && info
->dev_type
== 0x3370))
130 testsect
[0] = info
->label_block
;
132 testsect
[0] = info
->label_block
* (blocksize
>> 9);
136 testsect
[1] = (blocksize
>> 9);
137 testsect
[2] = 2 * (blocksize
>> 9);
140 for (i
= 0; i
< testcount
; ++i
) {
141 data
= read_part_sector(state
, testsect
[i
], §
);
144 memcpy(label
, data
, sizeof(*label
));
145 memcpy(type
, data
, DASD_VOL_TYPE_LEN
);
146 EBCASC(type
, DASD_VOL_TYPE_LEN
);
147 put_dev_sector(sect
);
148 switch (get_label_by_type(type
)) {
149 case DASD_VOLLBL_TYPE_VOL1
:
150 memcpy(name
, label
->vol
.volid
, DASD_VOL_ID_LEN
);
151 EBCASC(name
, DASD_VOL_ID_LEN
);
152 *labelsect
= testsect
[i
];
154 case DASD_VOLLBL_TYPE_LNX1
:
155 case DASD_VOLLBL_TYPE_CMS1
:
156 memcpy(name
, label
->lnx
.volid
, DASD_VOL_ID_LEN
);
157 EBCASC(name
, DASD_VOL_ID_LEN
);
158 *labelsect
= testsect
[i
];
168 static int find_vol1_partitions(struct parsed_partitions
*state
,
169 struct hd_geometry
*geo
,
172 union label_t
*label
)
180 struct vtoc_format1_label f1
;
183 snprintf(tmp
, sizeof(tmp
), "VOL1/%8s:", name
);
184 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
186 * get start of VTOC from the disk label and then search for format1
189 secperblk
= blocksize
>> 9;
190 blk
= cchhb2blk(&label
->vol
.vtoc
, geo
) + 1;
192 data
= read_part_sector(state
, blk
* secperblk
, §
);
193 while (data
!= NULL
) {
194 memcpy(&f1
, data
, sizeof(struct vtoc_format1_label
));
195 put_dev_sector(sect
);
196 /* skip FMT4 / FMT5 / FMT7 labels */
197 if (f1
.DS1FMTID
== _ascebc
['4']
198 || f1
.DS1FMTID
== _ascebc
['5']
199 || f1
.DS1FMTID
== _ascebc
['7']
200 || f1
.DS1FMTID
== _ascebc
['9']) {
202 data
= read_part_sector(state
, blk
* secperblk
, §
);
205 /* only FMT1 and 8 labels valid at this point */
206 if (f1
.DS1FMTID
!= _ascebc
['1'] &&
207 f1
.DS1FMTID
!= _ascebc
['8'])
209 /* OK, we got valid partition data */
210 offset
= cchh2blk(&f1
.DS1EXT1
.llimit
, geo
);
211 size
= cchh2blk(&f1
.DS1EXT1
.ulimit
, geo
) -
212 offset
+ geo
->sectors
;
215 if (counter
>= state
->limit
)
217 put_partition(state
, counter
+ 1, offset
, size
);
220 data
= read_part_sector(state
, blk
* secperblk
, §
);
222 strlcat(state
->pp_buf
, "\n", PAGE_SIZE
);
230 static int find_lnx1_partitions(struct parsed_partitions
*state
,
231 struct hd_geometry
*geo
,
234 union label_t
*label
,
237 dasd_information2_t
*info
)
239 loff_t offset
, geo_size
, size
;
243 snprintf(tmp
, sizeof(tmp
), "LNX1/%8s:", name
);
244 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
245 secperblk
= blocksize
>> 9;
246 if (label
->lnx
.ldl_version
== 0xf2) {
247 size
= label
->lnx
.formatted_blocks
* secperblk
;
250 * Formated w/o large volume support. If the sanity check
251 * 'size based on geo == size based on nr_sectors' is true, then
252 * we can safely assume that we know the formatted size of
253 * the disk, otherwise we need additional information
254 * that we can only get from a real DASD device.
256 geo_size
= geo
->cylinders
* geo
->heads
257 * geo
->sectors
* secperblk
;
259 if (size
!= geo_size
) {
261 strlcat(state
->pp_buf
, "\n", PAGE_SIZE
);
264 if (!strcmp(info
->type
, "ECKD"))
267 /* else keep size based on nr_sectors */
270 /* first and only partition starts in the first block after the label */
271 offset
= labelsect
+ secperblk
;
272 put_partition(state
, 1, offset
, size
- offset
);
273 strlcat(state
->pp_buf
, "\n", PAGE_SIZE
);
277 static int find_cms1_partitions(struct parsed_partitions
*state
,
278 struct hd_geometry
*geo
,
281 union label_t
*label
,
289 * VM style CMS1 labeled disk
291 blocksize
= label
->cms
.block_size
;
292 secperblk
= blocksize
>> 9;
293 if (label
->cms
.disk_offset
!= 0) {
294 snprintf(tmp
, sizeof(tmp
), "CMS1/%8s(MDSK):", name
);
295 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
296 /* disk is reserved minidisk */
297 offset
= label
->cms
.disk_offset
* secperblk
;
298 size
= (label
->cms
.block_count
- 1) * secperblk
;
300 snprintf(tmp
, sizeof(tmp
), "CMS1/%8s:", name
);
301 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
303 * Special case for FBA devices:
304 * If an FBA device is CMS formatted with blocksize > 512 byte
305 * and the DIAG discipline is used, then the CMS label is found
306 * in sector 1 instead of block 1. However, the partition is
307 * still supposed to start in block 2.
310 offset
= 2 * secperblk
;
312 offset
= labelsect
+ secperblk
;
313 size
= label
->cms
.block_count
* secperblk
;
316 put_partition(state
, 1, offset
, size
-offset
);
317 strlcat(state
->pp_buf
, "\n", PAGE_SIZE
);
323 * This is the main function, called by check.c
325 int ibm_partition(struct parsed_partitions
*state
)
327 int (*fn
)(struct gendisk
*disk
, dasd_information2_t
*info
);
328 struct gendisk
*disk
= state
->disk
;
329 struct block_device
*bdev
= disk
->part0
;
333 dasd_information2_t
*info
;
334 struct hd_geometry
*geo
;
335 char type
[DASD_VOL_TYPE_LEN
+ 1] = "";
336 char name
[DASD_VOL_ID_LEN
+ 1] = "";
338 union label_t
*label
;
341 if (!disk
->fops
->getgeo
)
343 fn
= symbol_get(dasd_biodasdinfo
);
344 blocksize
= bdev_logical_block_size(bdev
);
347 nr_sectors
= bdev_nr_sectors(bdev
);
350 info
= kmalloc(sizeof(dasd_information2_t
), GFP_KERNEL
);
353 geo
= kmalloc(sizeof(struct hd_geometry
), GFP_KERNEL
);
356 label
= kmalloc(sizeof(union label_t
), GFP_KERNEL
);
359 /* set start if not filled by getgeo function e.g. virtblk */
360 geo
->start
= get_start_sect(bdev
);
361 if (disk
->fops
->getgeo(bdev
, geo
))
363 if (!fn
|| fn(disk
, info
)) {
368 if (find_label(state
, info
, geo
, blocksize
, &labelsect
, name
, type
, label
)) {
369 switch (get_label_by_type(type
)) {
370 case DASD_VOLLBL_TYPE_VOL1
:
371 res
= find_vol1_partitions(state
, geo
, blocksize
, name
,
374 case DASD_VOLLBL_TYPE_LNX1
:
375 res
= find_lnx1_partitions(state
, geo
, blocksize
, name
,
376 label
, labelsect
, nr_sectors
,
379 case DASD_VOLLBL_TYPE_CMS1
:
380 res
= find_cms1_partitions(state
, geo
, blocksize
, name
,
386 * ugly but needed for backward compatibility:
387 * If the block device is a DASD (i.e. BIODASDINFO2 works),
388 * then we claim it in any case, even though it has no valid
389 * label. If it has the LDL format, then we simply define a
390 * partition as if it had an LNX1 label.
393 if (info
->format
== DASD_FORMAT_LDL
) {
394 strlcat(state
->pp_buf
, "(nonl)", PAGE_SIZE
);
396 offset
= (info
->label_block
+ 1) * (blocksize
>> 9);
397 put_partition(state
, 1, offset
, size
-offset
);
398 strlcat(state
->pp_buf
, "\n", PAGE_SIZE
);
411 symbol_put(dasd_biodasdinfo
);