^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Volker Sameske <sameske@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Bugreports.to..: <Linux390@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright IBM Corp. 1999, 2012
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/buffer_head.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/hdreg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/dasd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/ebcdic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/vtoc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/dasd_mod.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "check.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) union label_t {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct vtoc_volume_label_cdl vol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct vtoc_volume_label_ldl lnx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct vtoc_cms_label cms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * compute the block number from a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * cyl-cyl-head-head structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static sector_t cchh2blk(struct vtoc_cchh *ptr, struct hd_geometry *geo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) sector_t cyl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) __u16 head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /* decode cylinder and heads for large volumes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) cyl = ptr->hh & 0xFFF0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) cyl <<= 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) cyl |= ptr->cc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) head = ptr->hh & 0x000F;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return cyl * geo->heads * geo->sectors +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) head * geo->sectors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * compute the block number from a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * cyl-cyl-head-head-block structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static sector_t cchhb2blk(struct vtoc_cchhb *ptr, struct hd_geometry *geo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) sector_t cyl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) __u16 head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /* decode cylinder and heads for large volumes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) cyl = ptr->hh & 0xFFF0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) cyl <<= 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) cyl |= ptr->cc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) head = ptr->hh & 0x000F;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return cyl * geo->heads * geo->sectors +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) head * geo->sectors +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) ptr->b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int find_label(struct parsed_partitions *state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) dasd_information2_t *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct hd_geometry *geo,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int blocksize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) sector_t *labelsect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) char name[],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) char type[],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) union label_t *label)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) Sector sect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) unsigned char *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) sector_t testsect[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned char temp[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) int found = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) int i, testcount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* There a three places where we may find a valid label:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * - on an ECKD disk it's block 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * - on an FBA disk it's block 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * - on an CMS formatted FBA disk it is sector 1, even if the block size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * is larger than 512 bytes (possible if the DIAG discipline is used)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * If we have a valid info structure, then we know exactly which case we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * have, otherwise we just search through all possebilities.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) (info->cu_type == 0x3880 && info->dev_type == 0x3370))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) testsect[0] = info->label_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) testsect[0] = info->label_block * (blocksize >> 9);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) testcount = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) testsect[0] = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) testsect[1] = (blocksize >> 9);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) testsect[2] = 2 * (blocksize >> 9);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) testcount = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) for (i = 0; i < testcount; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) data = read_part_sector(state, testsect[i], §);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (data == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) memcpy(label, data, sizeof(*label));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) memcpy(temp, data, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) temp[4] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) EBCASC(temp, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) put_dev_sector(sect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (!strcmp(temp, "VOL1") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) !strcmp(temp, "LNX1") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) !strcmp(temp, "CMS1")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (!strcmp(temp, "VOL1")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) strncpy(type, label->vol.vollbl, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) strncpy(name, label->vol.volid, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) strncpy(type, label->lnx.vollbl, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) strncpy(name, label->lnx.volid, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) EBCASC(type, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) EBCASC(name, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) *labelsect = testsect[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) found = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (!found)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) memset(label, 0, sizeof(*label));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static int find_vol1_partitions(struct parsed_partitions *state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct hd_geometry *geo,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) int blocksize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) char name[],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) union label_t *label)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) sector_t blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) int counter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) char tmp[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) Sector sect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) unsigned char *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) loff_t offset, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct vtoc_format1_label f1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) int secperblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) strlcat(state->pp_buf, tmp, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * get start of VTOC from the disk label and then search for format1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * and format8 labels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) secperblk = blocksize >> 9;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) blk = cchhb2blk(&label->vol.vtoc, geo) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) counter = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) data = read_part_sector(state, blk * secperblk, §);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) while (data != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) memcpy(&f1, data, sizeof(struct vtoc_format1_label));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) put_dev_sector(sect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) /* skip FMT4 / FMT5 / FMT7 labels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (f1.DS1FMTID == _ascebc['4']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) || f1.DS1FMTID == _ascebc['5']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) || f1.DS1FMTID == _ascebc['7']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) || f1.DS1FMTID == _ascebc['9']) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) blk++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) data = read_part_sector(state, blk * secperblk, §);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /* only FMT1 and 8 labels valid at this point */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (f1.DS1FMTID != _ascebc['1'] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) f1.DS1FMTID != _ascebc['8'])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) /* OK, we got valid partition data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) size = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) offset + geo->sectors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) offset *= secperblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) size *= secperblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (counter >= state->limit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) put_partition(state, counter + 1, offset, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) counter++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) blk++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) data = read_part_sector(state, blk * secperblk, §);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) strlcat(state->pp_buf, "\n", PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) static int find_lnx1_partitions(struct parsed_partitions *state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) struct hd_geometry *geo,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) int blocksize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) char name[],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) union label_t *label,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) sector_t labelsect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) loff_t i_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) dasd_information2_t *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) loff_t offset, geo_size, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) char tmp[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) int secperblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) strlcat(state->pp_buf, tmp, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) secperblk = blocksize >> 9;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (label->lnx.ldl_version == 0xf2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) size = label->lnx.formatted_blocks * secperblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * Formated w/o large volume support. If the sanity check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * 'size based on geo == size based on i_size' is true, then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * we can safely assume that we know the formatted size of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * the disk, otherwise we need additional information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * that we can only get from a real DASD device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) geo_size = geo->cylinders * geo->heads
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * geo->sectors * secperblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) size = i_size >> 9;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (size != geo_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (!info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) strlcat(state->pp_buf, "\n", PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (!strcmp(info->type, "ECKD"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (geo_size < size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) size = geo_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) /* else keep size based on i_size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) /* first and only partition starts in the first block after the label */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) offset = labelsect + secperblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) put_partition(state, 1, offset, size - offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) strlcat(state->pp_buf, "\n", PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) static int find_cms1_partitions(struct parsed_partitions *state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) struct hd_geometry *geo,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) int blocksize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) char name[],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) union label_t *label,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) sector_t labelsect)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) loff_t offset, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) char tmp[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) int secperblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * VM style CMS1 labeled disk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) blocksize = label->cms.block_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) secperblk = blocksize >> 9;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (label->cms.disk_offset != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) strlcat(state->pp_buf, tmp, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) /* disk is reserved minidisk */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) offset = label->cms.disk_offset * secperblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) size = (label->cms.block_count - 1) * secperblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) strlcat(state->pp_buf, tmp, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) * Special case for FBA devices:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) * If an FBA device is CMS formatted with blocksize > 512 byte
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) * and the DIAG discipline is used, then the CMS label is found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) * in sector 1 instead of block 1. However, the partition is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * still supposed to start in block 2.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (labelsect == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) offset = 2 * secperblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) offset = labelsect + secperblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) size = label->cms.block_count * secperblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) put_partition(state, 1, offset, size-offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) strlcat(state->pp_buf, "\n", PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) * This is the main function, called by check.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) int ibm_partition(struct parsed_partitions *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) int (*fn)(struct gendisk *disk, dasd_information2_t *info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) struct block_device *bdev = state->bdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct gendisk *disk = bdev->bd_disk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) int blocksize, res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) loff_t i_size, offset, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) dasd_information2_t *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) struct hd_geometry *geo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) char type[5] = {0,};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) char name[7] = {0,};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) sector_t labelsect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) union label_t *label;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (!disk->fops->getgeo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) goto out_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) fn = symbol_get(dasd_biodasdinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) blocksize = bdev_logical_block_size(bdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (blocksize <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) goto out_symbol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) i_size = i_size_read(bdev->bd_inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (i_size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) goto out_symbol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (info == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) goto out_symbol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (geo == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) goto out_nogeo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) label = kmalloc(sizeof(union label_t), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (label == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) goto out_nolab;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) /* set start if not filled by getgeo function e.g. virtblk */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) geo->start = get_start_sect(bdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (disk->fops->getgeo(bdev, geo))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) goto out_freeall;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (!fn || fn(disk, info)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) info = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (find_label(state, info, geo, blocksize, &labelsect, name, type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) label)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if (!strncmp(type, "VOL1", 4)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) res = find_vol1_partitions(state, geo, blocksize, name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) label);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) } else if (!strncmp(type, "LNX1", 4)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) res = find_lnx1_partitions(state, geo, blocksize, name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) label, labelsect, i_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) } else if (!strncmp(type, "CMS1", 4)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) res = find_cms1_partitions(state, geo, blocksize, name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) label, labelsect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) } else if (info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) * ugly but needed for backward compatibility:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) * If the block device is a DASD (i.e. BIODASDINFO2 works),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) * then we claim it in any case, even though it has no valid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) * label. If it has the LDL format, then we simply define a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) * partition as if it had an LNX1 label.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) res = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) if (info->format == DASD_FORMAT_LDL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) strlcat(state->pp_buf, "(nonl)", PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) size = i_size >> 9;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) offset = (info->label_block + 1) * (blocksize >> 9);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) put_partition(state, 1, offset, size-offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) strlcat(state->pp_buf, "\n", PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) out_freeall:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) kfree(label);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) out_nolab:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) kfree(geo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) out_nogeo:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) out_symbol:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (fn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) symbol_put(dasd_biodasdinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) out_exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }