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], §); 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, §); 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, §); 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, §); 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