162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> 462306a36Sopenharmony_ci * Volker Sameske <sameske@de.ibm.com> 562306a36Sopenharmony_ci * Bugreports.to..: <Linux390@de.ibm.com> 662306a36Sopenharmony_ci * Copyright IBM Corp. 1999, 2012 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/buffer_head.h> 1062306a36Sopenharmony_ci#include <linux/hdreg.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <asm/dasd.h> 1362306a36Sopenharmony_ci#include <asm/ebcdic.h> 1462306a36Sopenharmony_ci#include <linux/uaccess.h> 1562306a36Sopenharmony_ci#include <asm/vtoc.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/dasd_mod.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "check.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciunion label_t { 2262306a36Sopenharmony_ci struct vtoc_volume_label_cdl vol; 2362306a36Sopenharmony_ci struct vtoc_volume_label_ldl lnx; 2462306a36Sopenharmony_ci struct vtoc_cms_label cms; 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * compute the block number from a 2962306a36Sopenharmony_ci * cyl-cyl-head-head structure 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_cistatic sector_t cchh2blk(struct vtoc_cchh *ptr, struct hd_geometry *geo) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci sector_t cyl; 3462306a36Sopenharmony_ci __u16 head; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci /* decode cylinder and heads for large volumes */ 3762306a36Sopenharmony_ci cyl = ptr->hh & 0xFFF0; 3862306a36Sopenharmony_ci cyl <<= 12; 3962306a36Sopenharmony_ci cyl |= ptr->cc; 4062306a36Sopenharmony_ci head = ptr->hh & 0x000F; 4162306a36Sopenharmony_ci return cyl * geo->heads * geo->sectors + 4262306a36Sopenharmony_ci head * geo->sectors; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * compute the block number from a 4762306a36Sopenharmony_ci * cyl-cyl-head-head-block structure 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_cistatic sector_t cchhb2blk(struct vtoc_cchhb *ptr, struct hd_geometry *geo) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci sector_t cyl; 5262306a36Sopenharmony_ci __u16 head; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* decode cylinder and heads for large volumes */ 5562306a36Sopenharmony_ci cyl = ptr->hh & 0xFFF0; 5662306a36Sopenharmony_ci cyl <<= 12; 5762306a36Sopenharmony_ci cyl |= ptr->cc; 5862306a36Sopenharmony_ci head = ptr->hh & 0x000F; 5962306a36Sopenharmony_ci return cyl * geo->heads * geo->sectors + 6062306a36Sopenharmony_ci head * geo->sectors + 6162306a36Sopenharmony_ci ptr->b; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int find_label(struct parsed_partitions *state, 6562306a36Sopenharmony_ci dasd_information2_t *info, 6662306a36Sopenharmony_ci struct hd_geometry *geo, 6762306a36Sopenharmony_ci int blocksize, 6862306a36Sopenharmony_ci sector_t *labelsect, 6962306a36Sopenharmony_ci char name[], 7062306a36Sopenharmony_ci char type[], 7162306a36Sopenharmony_ci union label_t *label) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci Sector sect; 7462306a36Sopenharmony_ci unsigned char *data; 7562306a36Sopenharmony_ci sector_t testsect[3]; 7662306a36Sopenharmony_ci unsigned char temp[5]; 7762306a36Sopenharmony_ci int found = 0; 7862306a36Sopenharmony_ci int i, testcount; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* There a three places where we may find a valid label: 8162306a36Sopenharmony_ci * - on an ECKD disk it's block 2 8262306a36Sopenharmony_ci * - on an FBA disk it's block 1 8362306a36Sopenharmony_ci * - on an CMS formatted FBA disk it is sector 1, even if the block size 8462306a36Sopenharmony_ci * is larger than 512 bytes (possible if the DIAG discipline is used) 8562306a36Sopenharmony_ci * If we have a valid info structure, then we know exactly which case we 8662306a36Sopenharmony_ci * have, otherwise we just search through all possebilities. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci if (info) { 8962306a36Sopenharmony_ci if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) || 9062306a36Sopenharmony_ci (info->cu_type == 0x3880 && info->dev_type == 0x3370)) 9162306a36Sopenharmony_ci testsect[0] = info->label_block; 9262306a36Sopenharmony_ci else 9362306a36Sopenharmony_ci testsect[0] = info->label_block * (blocksize >> 9); 9462306a36Sopenharmony_ci testcount = 1; 9562306a36Sopenharmony_ci } else { 9662306a36Sopenharmony_ci testsect[0] = 1; 9762306a36Sopenharmony_ci testsect[1] = (blocksize >> 9); 9862306a36Sopenharmony_ci testsect[2] = 2 * (blocksize >> 9); 9962306a36Sopenharmony_ci testcount = 3; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci for (i = 0; i < testcount; ++i) { 10262306a36Sopenharmony_ci data = read_part_sector(state, testsect[i], §); 10362306a36Sopenharmony_ci if (data == NULL) 10462306a36Sopenharmony_ci continue; 10562306a36Sopenharmony_ci memcpy(label, data, sizeof(*label)); 10662306a36Sopenharmony_ci memcpy(temp, data, 4); 10762306a36Sopenharmony_ci temp[4] = 0; 10862306a36Sopenharmony_ci EBCASC(temp, 4); 10962306a36Sopenharmony_ci put_dev_sector(sect); 11062306a36Sopenharmony_ci if (!strcmp(temp, "VOL1") || 11162306a36Sopenharmony_ci !strcmp(temp, "LNX1") || 11262306a36Sopenharmony_ci !strcmp(temp, "CMS1")) { 11362306a36Sopenharmony_ci if (!strcmp(temp, "VOL1")) { 11462306a36Sopenharmony_ci strncpy(type, label->vol.vollbl, 4); 11562306a36Sopenharmony_ci strncpy(name, label->vol.volid, 6); 11662306a36Sopenharmony_ci } else { 11762306a36Sopenharmony_ci strncpy(type, label->lnx.vollbl, 4); 11862306a36Sopenharmony_ci strncpy(name, label->lnx.volid, 6); 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci EBCASC(type, 4); 12162306a36Sopenharmony_ci EBCASC(name, 6); 12262306a36Sopenharmony_ci *labelsect = testsect[i]; 12362306a36Sopenharmony_ci found = 1; 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci if (!found) 12862306a36Sopenharmony_ci memset(label, 0, sizeof(*label)); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci return found; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int find_vol1_partitions(struct parsed_partitions *state, 13462306a36Sopenharmony_ci struct hd_geometry *geo, 13562306a36Sopenharmony_ci int blocksize, 13662306a36Sopenharmony_ci char name[], 13762306a36Sopenharmony_ci union label_t *label) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci sector_t blk; 14062306a36Sopenharmony_ci int counter; 14162306a36Sopenharmony_ci char tmp[64]; 14262306a36Sopenharmony_ci Sector sect; 14362306a36Sopenharmony_ci unsigned char *data; 14462306a36Sopenharmony_ci loff_t offset, size; 14562306a36Sopenharmony_ci struct vtoc_format1_label f1; 14662306a36Sopenharmony_ci int secperblk; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name); 14962306a36Sopenharmony_ci strlcat(state->pp_buf, tmp, PAGE_SIZE); 15062306a36Sopenharmony_ci /* 15162306a36Sopenharmony_ci * get start of VTOC from the disk label and then search for format1 15262306a36Sopenharmony_ci * and format8 labels 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci secperblk = blocksize >> 9; 15562306a36Sopenharmony_ci blk = cchhb2blk(&label->vol.vtoc, geo) + 1; 15662306a36Sopenharmony_ci counter = 0; 15762306a36Sopenharmony_ci data = read_part_sector(state, blk * secperblk, §); 15862306a36Sopenharmony_ci while (data != NULL) { 15962306a36Sopenharmony_ci memcpy(&f1, data, sizeof(struct vtoc_format1_label)); 16062306a36Sopenharmony_ci put_dev_sector(sect); 16162306a36Sopenharmony_ci /* skip FMT4 / FMT5 / FMT7 labels */ 16262306a36Sopenharmony_ci if (f1.DS1FMTID == _ascebc['4'] 16362306a36Sopenharmony_ci || f1.DS1FMTID == _ascebc['5'] 16462306a36Sopenharmony_ci || f1.DS1FMTID == _ascebc['7'] 16562306a36Sopenharmony_ci || f1.DS1FMTID == _ascebc['9']) { 16662306a36Sopenharmony_ci blk++; 16762306a36Sopenharmony_ci data = read_part_sector(state, blk * secperblk, §); 16862306a36Sopenharmony_ci continue; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci /* only FMT1 and 8 labels valid at this point */ 17162306a36Sopenharmony_ci if (f1.DS1FMTID != _ascebc['1'] && 17262306a36Sopenharmony_ci f1.DS1FMTID != _ascebc['8']) 17362306a36Sopenharmony_ci break; 17462306a36Sopenharmony_ci /* OK, we got valid partition data */ 17562306a36Sopenharmony_ci offset = cchh2blk(&f1.DS1EXT1.llimit, geo); 17662306a36Sopenharmony_ci size = cchh2blk(&f1.DS1EXT1.ulimit, geo) - 17762306a36Sopenharmony_ci offset + geo->sectors; 17862306a36Sopenharmony_ci offset *= secperblk; 17962306a36Sopenharmony_ci size *= secperblk; 18062306a36Sopenharmony_ci if (counter >= state->limit) 18162306a36Sopenharmony_ci break; 18262306a36Sopenharmony_ci put_partition(state, counter + 1, offset, size); 18362306a36Sopenharmony_ci counter++; 18462306a36Sopenharmony_ci blk++; 18562306a36Sopenharmony_ci data = read_part_sector(state, blk * secperblk, §); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (!data) 19062306a36Sopenharmony_ci return -1; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return 1; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic int find_lnx1_partitions(struct parsed_partitions *state, 19662306a36Sopenharmony_ci struct hd_geometry *geo, 19762306a36Sopenharmony_ci int blocksize, 19862306a36Sopenharmony_ci char name[], 19962306a36Sopenharmony_ci union label_t *label, 20062306a36Sopenharmony_ci sector_t labelsect, 20162306a36Sopenharmony_ci sector_t nr_sectors, 20262306a36Sopenharmony_ci dasd_information2_t *info) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci loff_t offset, geo_size, size; 20562306a36Sopenharmony_ci char tmp[64]; 20662306a36Sopenharmony_ci int secperblk; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name); 20962306a36Sopenharmony_ci strlcat(state->pp_buf, tmp, PAGE_SIZE); 21062306a36Sopenharmony_ci secperblk = blocksize >> 9; 21162306a36Sopenharmony_ci if (label->lnx.ldl_version == 0xf2) { 21262306a36Sopenharmony_ci size = label->lnx.formatted_blocks * secperblk; 21362306a36Sopenharmony_ci } else { 21462306a36Sopenharmony_ci /* 21562306a36Sopenharmony_ci * Formated w/o large volume support. If the sanity check 21662306a36Sopenharmony_ci * 'size based on geo == size based on nr_sectors' is true, then 21762306a36Sopenharmony_ci * we can safely assume that we know the formatted size of 21862306a36Sopenharmony_ci * the disk, otherwise we need additional information 21962306a36Sopenharmony_ci * that we can only get from a real DASD device. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ci geo_size = geo->cylinders * geo->heads 22262306a36Sopenharmony_ci * geo->sectors * secperblk; 22362306a36Sopenharmony_ci size = nr_sectors; 22462306a36Sopenharmony_ci if (size != geo_size) { 22562306a36Sopenharmony_ci if (!info) { 22662306a36Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 22762306a36Sopenharmony_ci return 1; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci if (!strcmp(info->type, "ECKD")) 23062306a36Sopenharmony_ci if (geo_size < size) 23162306a36Sopenharmony_ci size = geo_size; 23262306a36Sopenharmony_ci /* else keep size based on nr_sectors */ 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci /* first and only partition starts in the first block after the label */ 23662306a36Sopenharmony_ci offset = labelsect + secperblk; 23762306a36Sopenharmony_ci put_partition(state, 1, offset, size - offset); 23862306a36Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 23962306a36Sopenharmony_ci return 1; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic int find_cms1_partitions(struct parsed_partitions *state, 24362306a36Sopenharmony_ci struct hd_geometry *geo, 24462306a36Sopenharmony_ci int blocksize, 24562306a36Sopenharmony_ci char name[], 24662306a36Sopenharmony_ci union label_t *label, 24762306a36Sopenharmony_ci sector_t labelsect) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci loff_t offset, size; 25062306a36Sopenharmony_ci char tmp[64]; 25162306a36Sopenharmony_ci int secperblk; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* 25462306a36Sopenharmony_ci * VM style CMS1 labeled disk 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci blocksize = label->cms.block_size; 25762306a36Sopenharmony_ci secperblk = blocksize >> 9; 25862306a36Sopenharmony_ci if (label->cms.disk_offset != 0) { 25962306a36Sopenharmony_ci snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name); 26062306a36Sopenharmony_ci strlcat(state->pp_buf, tmp, PAGE_SIZE); 26162306a36Sopenharmony_ci /* disk is reserved minidisk */ 26262306a36Sopenharmony_ci offset = label->cms.disk_offset * secperblk; 26362306a36Sopenharmony_ci size = (label->cms.block_count - 1) * secperblk; 26462306a36Sopenharmony_ci } else { 26562306a36Sopenharmony_ci snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name); 26662306a36Sopenharmony_ci strlcat(state->pp_buf, tmp, PAGE_SIZE); 26762306a36Sopenharmony_ci /* 26862306a36Sopenharmony_ci * Special case for FBA devices: 26962306a36Sopenharmony_ci * If an FBA device is CMS formatted with blocksize > 512 byte 27062306a36Sopenharmony_ci * and the DIAG discipline is used, then the CMS label is found 27162306a36Sopenharmony_ci * in sector 1 instead of block 1. However, the partition is 27262306a36Sopenharmony_ci * still supposed to start in block 2. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_ci if (labelsect == 1) 27562306a36Sopenharmony_ci offset = 2 * secperblk; 27662306a36Sopenharmony_ci else 27762306a36Sopenharmony_ci offset = labelsect + secperblk; 27862306a36Sopenharmony_ci size = label->cms.block_count * secperblk; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci put_partition(state, 1, offset, size-offset); 28262306a36Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 28362306a36Sopenharmony_ci return 1; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/* 28862306a36Sopenharmony_ci * This is the main function, called by check.c 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ciint ibm_partition(struct parsed_partitions *state) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci int (*fn)(struct gendisk *disk, dasd_information2_t *info); 29362306a36Sopenharmony_ci struct gendisk *disk = state->disk; 29462306a36Sopenharmony_ci struct block_device *bdev = disk->part0; 29562306a36Sopenharmony_ci int blocksize, res; 29662306a36Sopenharmony_ci loff_t offset, size; 29762306a36Sopenharmony_ci sector_t nr_sectors; 29862306a36Sopenharmony_ci dasd_information2_t *info; 29962306a36Sopenharmony_ci struct hd_geometry *geo; 30062306a36Sopenharmony_ci char type[5] = {0,}; 30162306a36Sopenharmony_ci char name[7] = {0,}; 30262306a36Sopenharmony_ci sector_t labelsect; 30362306a36Sopenharmony_ci union label_t *label; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci res = 0; 30662306a36Sopenharmony_ci if (!disk->fops->getgeo) 30762306a36Sopenharmony_ci goto out_exit; 30862306a36Sopenharmony_ci fn = symbol_get(dasd_biodasdinfo); 30962306a36Sopenharmony_ci blocksize = bdev_logical_block_size(bdev); 31062306a36Sopenharmony_ci if (blocksize <= 0) 31162306a36Sopenharmony_ci goto out_symbol; 31262306a36Sopenharmony_ci nr_sectors = bdev_nr_sectors(bdev); 31362306a36Sopenharmony_ci if (nr_sectors == 0) 31462306a36Sopenharmony_ci goto out_symbol; 31562306a36Sopenharmony_ci info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL); 31662306a36Sopenharmony_ci if (info == NULL) 31762306a36Sopenharmony_ci goto out_symbol; 31862306a36Sopenharmony_ci geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL); 31962306a36Sopenharmony_ci if (geo == NULL) 32062306a36Sopenharmony_ci goto out_nogeo; 32162306a36Sopenharmony_ci label = kmalloc(sizeof(union label_t), GFP_KERNEL); 32262306a36Sopenharmony_ci if (label == NULL) 32362306a36Sopenharmony_ci goto out_nolab; 32462306a36Sopenharmony_ci /* set start if not filled by getgeo function e.g. virtblk */ 32562306a36Sopenharmony_ci geo->start = get_start_sect(bdev); 32662306a36Sopenharmony_ci if (disk->fops->getgeo(bdev, geo)) 32762306a36Sopenharmony_ci goto out_freeall; 32862306a36Sopenharmony_ci if (!fn || fn(disk, info)) { 32962306a36Sopenharmony_ci kfree(info); 33062306a36Sopenharmony_ci info = NULL; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (find_label(state, info, geo, blocksize, &labelsect, name, type, 33462306a36Sopenharmony_ci label)) { 33562306a36Sopenharmony_ci if (!strncmp(type, "VOL1", 4)) { 33662306a36Sopenharmony_ci res = find_vol1_partitions(state, geo, blocksize, name, 33762306a36Sopenharmony_ci label); 33862306a36Sopenharmony_ci } else if (!strncmp(type, "LNX1", 4)) { 33962306a36Sopenharmony_ci res = find_lnx1_partitions(state, geo, blocksize, name, 34062306a36Sopenharmony_ci label, labelsect, nr_sectors, 34162306a36Sopenharmony_ci info); 34262306a36Sopenharmony_ci } else if (!strncmp(type, "CMS1", 4)) { 34362306a36Sopenharmony_ci res = find_cms1_partitions(state, geo, blocksize, name, 34462306a36Sopenharmony_ci label, labelsect); 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci } else if (info) { 34762306a36Sopenharmony_ci /* 34862306a36Sopenharmony_ci * ugly but needed for backward compatibility: 34962306a36Sopenharmony_ci * If the block device is a DASD (i.e. BIODASDINFO2 works), 35062306a36Sopenharmony_ci * then we claim it in any case, even though it has no valid 35162306a36Sopenharmony_ci * label. If it has the LDL format, then we simply define a 35262306a36Sopenharmony_ci * partition as if it had an LNX1 label. 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_ci res = 1; 35562306a36Sopenharmony_ci if (info->format == DASD_FORMAT_LDL) { 35662306a36Sopenharmony_ci strlcat(state->pp_buf, "(nonl)", PAGE_SIZE); 35762306a36Sopenharmony_ci size = nr_sectors; 35862306a36Sopenharmony_ci offset = (info->label_block + 1) * (blocksize >> 9); 35962306a36Sopenharmony_ci put_partition(state, 1, offset, size-offset); 36062306a36Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci } else 36362306a36Sopenharmony_ci res = 0; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ciout_freeall: 36662306a36Sopenharmony_ci kfree(label); 36762306a36Sopenharmony_ciout_nolab: 36862306a36Sopenharmony_ci kfree(geo); 36962306a36Sopenharmony_ciout_nogeo: 37062306a36Sopenharmony_ci kfree(info); 37162306a36Sopenharmony_ciout_symbol: 37262306a36Sopenharmony_ci if (fn) 37362306a36Sopenharmony_ci symbol_put(dasd_biodasdinfo); 37462306a36Sopenharmony_ciout_exit: 37562306a36Sopenharmony_ci return res; 37662306a36Sopenharmony_ci} 377