18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
48c2ecf20Sopenharmony_ci *                  Volker Sameske <sameske@de.ibm.com>
58c2ecf20Sopenharmony_ci * Bugreports.to..: <Linux390@de.ibm.com>
68c2ecf20Sopenharmony_ci * Copyright IBM Corp. 1999, 2012
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/buffer_head.h>
108c2ecf20Sopenharmony_ci#include <linux/hdreg.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <asm/dasd.h>
138c2ecf20Sopenharmony_ci#include <asm/ebcdic.h>
148c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
158c2ecf20Sopenharmony_ci#include <asm/vtoc.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/dasd_mod.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "check.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ciunion label_t {
228c2ecf20Sopenharmony_ci	struct vtoc_volume_label_cdl vol;
238c2ecf20Sopenharmony_ci	struct vtoc_volume_label_ldl lnx;
248c2ecf20Sopenharmony_ci	struct vtoc_cms_label cms;
258c2ecf20Sopenharmony_ci};
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/*
288c2ecf20Sopenharmony_ci * compute the block number from a
298c2ecf20Sopenharmony_ci * cyl-cyl-head-head structure
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_cistatic sector_t cchh2blk(struct vtoc_cchh *ptr, struct hd_geometry *geo)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	sector_t cyl;
348c2ecf20Sopenharmony_ci	__u16 head;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	/* decode cylinder and heads for large volumes */
378c2ecf20Sopenharmony_ci	cyl = ptr->hh & 0xFFF0;
388c2ecf20Sopenharmony_ci	cyl <<= 12;
398c2ecf20Sopenharmony_ci	cyl |= ptr->cc;
408c2ecf20Sopenharmony_ci	head = ptr->hh & 0x000F;
418c2ecf20Sopenharmony_ci	return cyl * geo->heads * geo->sectors +
428c2ecf20Sopenharmony_ci	       head * geo->sectors;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/*
468c2ecf20Sopenharmony_ci * compute the block number from a
478c2ecf20Sopenharmony_ci * cyl-cyl-head-head-block structure
488c2ecf20Sopenharmony_ci */
498c2ecf20Sopenharmony_cistatic sector_t cchhb2blk(struct vtoc_cchhb *ptr, struct hd_geometry *geo)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	sector_t cyl;
528c2ecf20Sopenharmony_ci	__u16 head;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/* decode cylinder and heads for large volumes */
558c2ecf20Sopenharmony_ci	cyl = ptr->hh & 0xFFF0;
568c2ecf20Sopenharmony_ci	cyl <<= 12;
578c2ecf20Sopenharmony_ci	cyl |= ptr->cc;
588c2ecf20Sopenharmony_ci	head = ptr->hh & 0x000F;
598c2ecf20Sopenharmony_ci	return	cyl * geo->heads * geo->sectors +
608c2ecf20Sopenharmony_ci		head * geo->sectors +
618c2ecf20Sopenharmony_ci		ptr->b;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic int find_label(struct parsed_partitions *state,
658c2ecf20Sopenharmony_ci		      dasd_information2_t *info,
668c2ecf20Sopenharmony_ci		      struct hd_geometry *geo,
678c2ecf20Sopenharmony_ci		      int blocksize,
688c2ecf20Sopenharmony_ci		      sector_t *labelsect,
698c2ecf20Sopenharmony_ci		      char name[],
708c2ecf20Sopenharmony_ci		      char type[],
718c2ecf20Sopenharmony_ci		      union label_t *label)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	Sector sect;
748c2ecf20Sopenharmony_ci	unsigned char *data;
758c2ecf20Sopenharmony_ci	sector_t testsect[3];
768c2ecf20Sopenharmony_ci	unsigned char temp[5];
778c2ecf20Sopenharmony_ci	int found = 0;
788c2ecf20Sopenharmony_ci	int i, testcount;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	/* There a three places where we may find a valid label:
818c2ecf20Sopenharmony_ci	 * - on an ECKD disk it's block 2
828c2ecf20Sopenharmony_ci	 * - on an FBA disk it's block 1
838c2ecf20Sopenharmony_ci	 * - on an CMS formatted FBA disk it is sector 1, even if the block size
848c2ecf20Sopenharmony_ci	 *   is larger than 512 bytes (possible if the DIAG discipline is used)
858c2ecf20Sopenharmony_ci	 * If we have a valid info structure, then we know exactly which case we
868c2ecf20Sopenharmony_ci	 * have, otherwise we just search through all possebilities.
878c2ecf20Sopenharmony_ci	 */
888c2ecf20Sopenharmony_ci	if (info) {
898c2ecf20Sopenharmony_ci		if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
908c2ecf20Sopenharmony_ci		    (info->cu_type == 0x3880 && info->dev_type == 0x3370))
918c2ecf20Sopenharmony_ci			testsect[0] = info->label_block;
928c2ecf20Sopenharmony_ci		else
938c2ecf20Sopenharmony_ci			testsect[0] = info->label_block * (blocksize >> 9);
948c2ecf20Sopenharmony_ci		testcount = 1;
958c2ecf20Sopenharmony_ci	} else {
968c2ecf20Sopenharmony_ci		testsect[0] = 1;
978c2ecf20Sopenharmony_ci		testsect[1] = (blocksize >> 9);
988c2ecf20Sopenharmony_ci		testsect[2] = 2 * (blocksize >> 9);
998c2ecf20Sopenharmony_ci		testcount = 3;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci	for (i = 0; i < testcount; ++i) {
1028c2ecf20Sopenharmony_ci		data = read_part_sector(state, testsect[i], &sect);
1038c2ecf20Sopenharmony_ci		if (data == NULL)
1048c2ecf20Sopenharmony_ci			continue;
1058c2ecf20Sopenharmony_ci		memcpy(label, data, sizeof(*label));
1068c2ecf20Sopenharmony_ci		memcpy(temp, data, 4);
1078c2ecf20Sopenharmony_ci		temp[4] = 0;
1088c2ecf20Sopenharmony_ci		EBCASC(temp, 4);
1098c2ecf20Sopenharmony_ci		put_dev_sector(sect);
1108c2ecf20Sopenharmony_ci		if (!strcmp(temp, "VOL1") ||
1118c2ecf20Sopenharmony_ci		    !strcmp(temp, "LNX1") ||
1128c2ecf20Sopenharmony_ci		    !strcmp(temp, "CMS1")) {
1138c2ecf20Sopenharmony_ci			if (!strcmp(temp, "VOL1")) {
1148c2ecf20Sopenharmony_ci				strncpy(type, label->vol.vollbl, 4);
1158c2ecf20Sopenharmony_ci				strncpy(name, label->vol.volid, 6);
1168c2ecf20Sopenharmony_ci			} else {
1178c2ecf20Sopenharmony_ci				strncpy(type, label->lnx.vollbl, 4);
1188c2ecf20Sopenharmony_ci				strncpy(name, label->lnx.volid, 6);
1198c2ecf20Sopenharmony_ci			}
1208c2ecf20Sopenharmony_ci			EBCASC(type, 4);
1218c2ecf20Sopenharmony_ci			EBCASC(name, 6);
1228c2ecf20Sopenharmony_ci			*labelsect = testsect[i];
1238c2ecf20Sopenharmony_ci			found = 1;
1248c2ecf20Sopenharmony_ci			break;
1258c2ecf20Sopenharmony_ci		}
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci	if (!found)
1288c2ecf20Sopenharmony_ci		memset(label, 0, sizeof(*label));
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	return found;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic int find_vol1_partitions(struct parsed_partitions *state,
1348c2ecf20Sopenharmony_ci				struct hd_geometry *geo,
1358c2ecf20Sopenharmony_ci				int blocksize,
1368c2ecf20Sopenharmony_ci				char name[],
1378c2ecf20Sopenharmony_ci				union label_t *label)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	sector_t blk;
1408c2ecf20Sopenharmony_ci	int counter;
1418c2ecf20Sopenharmony_ci	char tmp[64];
1428c2ecf20Sopenharmony_ci	Sector sect;
1438c2ecf20Sopenharmony_ci	unsigned char *data;
1448c2ecf20Sopenharmony_ci	loff_t offset, size;
1458c2ecf20Sopenharmony_ci	struct vtoc_format1_label f1;
1468c2ecf20Sopenharmony_ci	int secperblk;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name);
1498c2ecf20Sopenharmony_ci	strlcat(state->pp_buf, tmp, PAGE_SIZE);
1508c2ecf20Sopenharmony_ci	/*
1518c2ecf20Sopenharmony_ci	 * get start of VTOC from the disk label and then search for format1
1528c2ecf20Sopenharmony_ci	 * and format8 labels
1538c2ecf20Sopenharmony_ci	 */
1548c2ecf20Sopenharmony_ci	secperblk = blocksize >> 9;
1558c2ecf20Sopenharmony_ci	blk = cchhb2blk(&label->vol.vtoc, geo) + 1;
1568c2ecf20Sopenharmony_ci	counter = 0;
1578c2ecf20Sopenharmony_ci	data = read_part_sector(state, blk * secperblk, &sect);
1588c2ecf20Sopenharmony_ci	while (data != NULL) {
1598c2ecf20Sopenharmony_ci		memcpy(&f1, data, sizeof(struct vtoc_format1_label));
1608c2ecf20Sopenharmony_ci		put_dev_sector(sect);
1618c2ecf20Sopenharmony_ci		/* skip FMT4 / FMT5 / FMT7 labels */
1628c2ecf20Sopenharmony_ci		if (f1.DS1FMTID == _ascebc['4']
1638c2ecf20Sopenharmony_ci		    || f1.DS1FMTID == _ascebc['5']
1648c2ecf20Sopenharmony_ci		    || f1.DS1FMTID == _ascebc['7']
1658c2ecf20Sopenharmony_ci		    || f1.DS1FMTID == _ascebc['9']) {
1668c2ecf20Sopenharmony_ci			blk++;
1678c2ecf20Sopenharmony_ci			data = read_part_sector(state, blk * secperblk, &sect);
1688c2ecf20Sopenharmony_ci			continue;
1698c2ecf20Sopenharmony_ci		}
1708c2ecf20Sopenharmony_ci		/* only FMT1 and 8 labels valid at this point */
1718c2ecf20Sopenharmony_ci		if (f1.DS1FMTID != _ascebc['1'] &&
1728c2ecf20Sopenharmony_ci		    f1.DS1FMTID != _ascebc['8'])
1738c2ecf20Sopenharmony_ci			break;
1748c2ecf20Sopenharmony_ci		/* OK, we got valid partition data */
1758c2ecf20Sopenharmony_ci		offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
1768c2ecf20Sopenharmony_ci		size  = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
1778c2ecf20Sopenharmony_ci			offset + geo->sectors;
1788c2ecf20Sopenharmony_ci		offset *= secperblk;
1798c2ecf20Sopenharmony_ci		size *= secperblk;
1808c2ecf20Sopenharmony_ci		if (counter >= state->limit)
1818c2ecf20Sopenharmony_ci			break;
1828c2ecf20Sopenharmony_ci		put_partition(state, counter + 1, offset, size);
1838c2ecf20Sopenharmony_ci		counter++;
1848c2ecf20Sopenharmony_ci		blk++;
1858c2ecf20Sopenharmony_ci		data = read_part_sector(state, blk * secperblk, &sect);
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci	strlcat(state->pp_buf, "\n", PAGE_SIZE);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (!data)
1908c2ecf20Sopenharmony_ci		return -1;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	return 1;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic int find_lnx1_partitions(struct parsed_partitions *state,
1968c2ecf20Sopenharmony_ci				struct hd_geometry *geo,
1978c2ecf20Sopenharmony_ci				int blocksize,
1988c2ecf20Sopenharmony_ci				char name[],
1998c2ecf20Sopenharmony_ci				union label_t *label,
2008c2ecf20Sopenharmony_ci				sector_t labelsect,
2018c2ecf20Sopenharmony_ci				loff_t i_size,
2028c2ecf20Sopenharmony_ci				dasd_information2_t *info)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	loff_t offset, geo_size, size;
2058c2ecf20Sopenharmony_ci	char tmp[64];
2068c2ecf20Sopenharmony_ci	int secperblk;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name);
2098c2ecf20Sopenharmony_ci	strlcat(state->pp_buf, tmp, PAGE_SIZE);
2108c2ecf20Sopenharmony_ci	secperblk = blocksize >> 9;
2118c2ecf20Sopenharmony_ci	if (label->lnx.ldl_version == 0xf2) {
2128c2ecf20Sopenharmony_ci		size = label->lnx.formatted_blocks * secperblk;
2138c2ecf20Sopenharmony_ci	} else {
2148c2ecf20Sopenharmony_ci		/*
2158c2ecf20Sopenharmony_ci		 * Formated w/o large volume support. If the sanity check
2168c2ecf20Sopenharmony_ci		 * 'size based on geo == size based on i_size' is true, then
2178c2ecf20Sopenharmony_ci		 * we can safely assume that we know the formatted size of
2188c2ecf20Sopenharmony_ci		 * the disk, otherwise we need additional information
2198c2ecf20Sopenharmony_ci		 * that we can only get from a real DASD device.
2208c2ecf20Sopenharmony_ci		 */
2218c2ecf20Sopenharmony_ci		geo_size = geo->cylinders * geo->heads
2228c2ecf20Sopenharmony_ci			* geo->sectors * secperblk;
2238c2ecf20Sopenharmony_ci		size = i_size >> 9;
2248c2ecf20Sopenharmony_ci		if (size != geo_size) {
2258c2ecf20Sopenharmony_ci			if (!info) {
2268c2ecf20Sopenharmony_ci				strlcat(state->pp_buf, "\n", PAGE_SIZE);
2278c2ecf20Sopenharmony_ci				return 1;
2288c2ecf20Sopenharmony_ci			}
2298c2ecf20Sopenharmony_ci			if (!strcmp(info->type, "ECKD"))
2308c2ecf20Sopenharmony_ci				if (geo_size < size)
2318c2ecf20Sopenharmony_ci					size = geo_size;
2328c2ecf20Sopenharmony_ci			/* else keep size based on i_size */
2338c2ecf20Sopenharmony_ci		}
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci	/* first and only partition starts in the first block after the label */
2368c2ecf20Sopenharmony_ci	offset = labelsect + secperblk;
2378c2ecf20Sopenharmony_ci	put_partition(state, 1, offset, size - offset);
2388c2ecf20Sopenharmony_ci	strlcat(state->pp_buf, "\n", PAGE_SIZE);
2398c2ecf20Sopenharmony_ci	return 1;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic int find_cms1_partitions(struct parsed_partitions *state,
2438c2ecf20Sopenharmony_ci				struct hd_geometry *geo,
2448c2ecf20Sopenharmony_ci				int blocksize,
2458c2ecf20Sopenharmony_ci				char name[],
2468c2ecf20Sopenharmony_ci				union label_t *label,
2478c2ecf20Sopenharmony_ci				sector_t labelsect)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	loff_t offset, size;
2508c2ecf20Sopenharmony_ci	char tmp[64];
2518c2ecf20Sopenharmony_ci	int secperblk;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/*
2548c2ecf20Sopenharmony_ci	 * VM style CMS1 labeled disk
2558c2ecf20Sopenharmony_ci	 */
2568c2ecf20Sopenharmony_ci	blocksize = label->cms.block_size;
2578c2ecf20Sopenharmony_ci	secperblk = blocksize >> 9;
2588c2ecf20Sopenharmony_ci	if (label->cms.disk_offset != 0) {
2598c2ecf20Sopenharmony_ci		snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name);
2608c2ecf20Sopenharmony_ci		strlcat(state->pp_buf, tmp, PAGE_SIZE);
2618c2ecf20Sopenharmony_ci		/* disk is reserved minidisk */
2628c2ecf20Sopenharmony_ci		offset = label->cms.disk_offset * secperblk;
2638c2ecf20Sopenharmony_ci		size = (label->cms.block_count - 1) * secperblk;
2648c2ecf20Sopenharmony_ci	} else {
2658c2ecf20Sopenharmony_ci		snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name);
2668c2ecf20Sopenharmony_ci		strlcat(state->pp_buf, tmp, PAGE_SIZE);
2678c2ecf20Sopenharmony_ci		/*
2688c2ecf20Sopenharmony_ci		 * Special case for FBA devices:
2698c2ecf20Sopenharmony_ci		 * If an FBA device is CMS formatted with blocksize > 512 byte
2708c2ecf20Sopenharmony_ci		 * and the DIAG discipline is used, then the CMS label is found
2718c2ecf20Sopenharmony_ci		 * in sector 1 instead of block 1. However, the partition is
2728c2ecf20Sopenharmony_ci		 * still supposed to start in block 2.
2738c2ecf20Sopenharmony_ci		 */
2748c2ecf20Sopenharmony_ci		if (labelsect == 1)
2758c2ecf20Sopenharmony_ci			offset = 2 * secperblk;
2768c2ecf20Sopenharmony_ci		else
2778c2ecf20Sopenharmony_ci			offset = labelsect + secperblk;
2788c2ecf20Sopenharmony_ci		size = label->cms.block_count * secperblk;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	put_partition(state, 1, offset, size-offset);
2828c2ecf20Sopenharmony_ci	strlcat(state->pp_buf, "\n", PAGE_SIZE);
2838c2ecf20Sopenharmony_ci	return 1;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci/*
2888c2ecf20Sopenharmony_ci * This is the main function, called by check.c
2898c2ecf20Sopenharmony_ci */
2908c2ecf20Sopenharmony_ciint ibm_partition(struct parsed_partitions *state)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	int (*fn)(struct gendisk *disk, dasd_information2_t *info);
2938c2ecf20Sopenharmony_ci	struct block_device *bdev = state->bdev;
2948c2ecf20Sopenharmony_ci	struct gendisk *disk = bdev->bd_disk;
2958c2ecf20Sopenharmony_ci	int blocksize, res;
2968c2ecf20Sopenharmony_ci	loff_t i_size, offset, size;
2978c2ecf20Sopenharmony_ci	dasd_information2_t *info;
2988c2ecf20Sopenharmony_ci	struct hd_geometry *geo;
2998c2ecf20Sopenharmony_ci	char type[5] = {0,};
3008c2ecf20Sopenharmony_ci	char name[7] = {0,};
3018c2ecf20Sopenharmony_ci	sector_t labelsect;
3028c2ecf20Sopenharmony_ci	union label_t *label;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	res = 0;
3058c2ecf20Sopenharmony_ci	if (!disk->fops->getgeo)
3068c2ecf20Sopenharmony_ci		goto out_exit;
3078c2ecf20Sopenharmony_ci	fn = symbol_get(dasd_biodasdinfo);
3088c2ecf20Sopenharmony_ci	blocksize = bdev_logical_block_size(bdev);
3098c2ecf20Sopenharmony_ci	if (blocksize <= 0)
3108c2ecf20Sopenharmony_ci		goto out_symbol;
3118c2ecf20Sopenharmony_ci	i_size = i_size_read(bdev->bd_inode);
3128c2ecf20Sopenharmony_ci	if (i_size == 0)
3138c2ecf20Sopenharmony_ci		goto out_symbol;
3148c2ecf20Sopenharmony_ci	info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
3158c2ecf20Sopenharmony_ci	if (info == NULL)
3168c2ecf20Sopenharmony_ci		goto out_symbol;
3178c2ecf20Sopenharmony_ci	geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL);
3188c2ecf20Sopenharmony_ci	if (geo == NULL)
3198c2ecf20Sopenharmony_ci		goto out_nogeo;
3208c2ecf20Sopenharmony_ci	label = kmalloc(sizeof(union label_t), GFP_KERNEL);
3218c2ecf20Sopenharmony_ci	if (label == NULL)
3228c2ecf20Sopenharmony_ci		goto out_nolab;
3238c2ecf20Sopenharmony_ci	/* set start if not filled by getgeo function e.g. virtblk */
3248c2ecf20Sopenharmony_ci	geo->start = get_start_sect(bdev);
3258c2ecf20Sopenharmony_ci	if (disk->fops->getgeo(bdev, geo))
3268c2ecf20Sopenharmony_ci		goto out_freeall;
3278c2ecf20Sopenharmony_ci	if (!fn || fn(disk, info)) {
3288c2ecf20Sopenharmony_ci		kfree(info);
3298c2ecf20Sopenharmony_ci		info = NULL;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	if (find_label(state, info, geo, blocksize, &labelsect, name, type,
3338c2ecf20Sopenharmony_ci		       label)) {
3348c2ecf20Sopenharmony_ci		if (!strncmp(type, "VOL1", 4)) {
3358c2ecf20Sopenharmony_ci			res = find_vol1_partitions(state, geo, blocksize, name,
3368c2ecf20Sopenharmony_ci						   label);
3378c2ecf20Sopenharmony_ci		} else if (!strncmp(type, "LNX1", 4)) {
3388c2ecf20Sopenharmony_ci			res = find_lnx1_partitions(state, geo, blocksize, name,
3398c2ecf20Sopenharmony_ci						   label, labelsect, i_size,
3408c2ecf20Sopenharmony_ci						   info);
3418c2ecf20Sopenharmony_ci		} else if (!strncmp(type, "CMS1", 4)) {
3428c2ecf20Sopenharmony_ci			res = find_cms1_partitions(state, geo, blocksize, name,
3438c2ecf20Sopenharmony_ci						   label, labelsect);
3448c2ecf20Sopenharmony_ci		}
3458c2ecf20Sopenharmony_ci	} else if (info) {
3468c2ecf20Sopenharmony_ci		/*
3478c2ecf20Sopenharmony_ci		 * ugly but needed for backward compatibility:
3488c2ecf20Sopenharmony_ci		 * If the block device is a DASD (i.e. BIODASDINFO2 works),
3498c2ecf20Sopenharmony_ci		 * then we claim it in any case, even though it has no valid
3508c2ecf20Sopenharmony_ci		 * label. If it has the LDL format, then we simply define a
3518c2ecf20Sopenharmony_ci		 * partition as if it had an LNX1 label.
3528c2ecf20Sopenharmony_ci		 */
3538c2ecf20Sopenharmony_ci		res = 1;
3548c2ecf20Sopenharmony_ci		if (info->format == DASD_FORMAT_LDL) {
3558c2ecf20Sopenharmony_ci			strlcat(state->pp_buf, "(nonl)", PAGE_SIZE);
3568c2ecf20Sopenharmony_ci			size = i_size >> 9;
3578c2ecf20Sopenharmony_ci			offset = (info->label_block + 1) * (blocksize >> 9);
3588c2ecf20Sopenharmony_ci			put_partition(state, 1, offset, size-offset);
3598c2ecf20Sopenharmony_ci			strlcat(state->pp_buf, "\n", PAGE_SIZE);
3608c2ecf20Sopenharmony_ci		}
3618c2ecf20Sopenharmony_ci	} else
3628c2ecf20Sopenharmony_ci		res = 0;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ciout_freeall:
3658c2ecf20Sopenharmony_ci	kfree(label);
3668c2ecf20Sopenharmony_ciout_nolab:
3678c2ecf20Sopenharmony_ci	kfree(geo);
3688c2ecf20Sopenharmony_ciout_nogeo:
3698c2ecf20Sopenharmony_ci	kfree(info);
3708c2ecf20Sopenharmony_ciout_symbol:
3718c2ecf20Sopenharmony_ci	if (fn)
3728c2ecf20Sopenharmony_ci		symbol_put(dasd_biodasdinfo);
3738c2ecf20Sopenharmony_ciout_exit:
3748c2ecf20Sopenharmony_ci	return res;
3758c2ecf20Sopenharmony_ci}
376