0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/buffer_head.h>
0010 #include <linux/hdreg.h>
0011 #include <linux/slab.h>
0012 #include <asm/dasd.h>
0013 #include <asm/ebcdic.h>
0014 #include <linux/uaccess.h>
0015 #include <asm/vtoc.h>
0016 #include <linux/module.h>
0017 #include <linux/dasd_mod.h>
0018
0019 #include "check.h"
0020
0021 union label_t {
0022 struct vtoc_volume_label_cdl vol;
0023 struct vtoc_volume_label_ldl lnx;
0024 struct vtoc_cms_label cms;
0025 };
0026
0027
0028
0029
0030
0031 static sector_t cchh2blk(struct vtoc_cchh *ptr, struct hd_geometry *geo)
0032 {
0033 sector_t cyl;
0034 __u16 head;
0035
0036
0037 cyl = ptr->hh & 0xFFF0;
0038 cyl <<= 12;
0039 cyl |= ptr->cc;
0040 head = ptr->hh & 0x000F;
0041 return cyl * geo->heads * geo->sectors +
0042 head * geo->sectors;
0043 }
0044
0045
0046
0047
0048
0049 static sector_t cchhb2blk(struct vtoc_cchhb *ptr, struct hd_geometry *geo)
0050 {
0051 sector_t cyl;
0052 __u16 head;
0053
0054
0055 cyl = ptr->hh & 0xFFF0;
0056 cyl <<= 12;
0057 cyl |= ptr->cc;
0058 head = ptr->hh & 0x000F;
0059 return cyl * geo->heads * geo->sectors +
0060 head * geo->sectors +
0061 ptr->b;
0062 }
0063
0064 static int find_label(struct parsed_partitions *state,
0065 dasd_information2_t *info,
0066 struct hd_geometry *geo,
0067 int blocksize,
0068 sector_t *labelsect,
0069 char name[],
0070 char type[],
0071 union label_t *label)
0072 {
0073 Sector sect;
0074 unsigned char *data;
0075 sector_t testsect[3];
0076 unsigned char temp[5];
0077 int found = 0;
0078 int i, testcount;
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088 if (info) {
0089 if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
0090 (info->cu_type == 0x3880 && info->dev_type == 0x3370))
0091 testsect[0] = info->label_block;
0092 else
0093 testsect[0] = info->label_block * (blocksize >> 9);
0094 testcount = 1;
0095 } else {
0096 testsect[0] = 1;
0097 testsect[1] = (blocksize >> 9);
0098 testsect[2] = 2 * (blocksize >> 9);
0099 testcount = 3;
0100 }
0101 for (i = 0; i < testcount; ++i) {
0102 data = read_part_sector(state, testsect[i], §);
0103 if (data == NULL)
0104 continue;
0105 memcpy(label, data, sizeof(*label));
0106 memcpy(temp, data, 4);
0107 temp[4] = 0;
0108 EBCASC(temp, 4);
0109 put_dev_sector(sect);
0110 if (!strcmp(temp, "VOL1") ||
0111 !strcmp(temp, "LNX1") ||
0112 !strcmp(temp, "CMS1")) {
0113 if (!strcmp(temp, "VOL1")) {
0114 strncpy(type, label->vol.vollbl, 4);
0115 strncpy(name, label->vol.volid, 6);
0116 } else {
0117 strncpy(type, label->lnx.vollbl, 4);
0118 strncpy(name, label->lnx.volid, 6);
0119 }
0120 EBCASC(type, 4);
0121 EBCASC(name, 6);
0122 *labelsect = testsect[i];
0123 found = 1;
0124 break;
0125 }
0126 }
0127 if (!found)
0128 memset(label, 0, sizeof(*label));
0129
0130 return found;
0131 }
0132
0133 static int find_vol1_partitions(struct parsed_partitions *state,
0134 struct hd_geometry *geo,
0135 int blocksize,
0136 char name[],
0137 union label_t *label)
0138 {
0139 sector_t blk;
0140 int counter;
0141 char tmp[64];
0142 Sector sect;
0143 unsigned char *data;
0144 loff_t offset, size;
0145 struct vtoc_format1_label f1;
0146 int secperblk;
0147
0148 snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name);
0149 strlcat(state->pp_buf, tmp, PAGE_SIZE);
0150
0151
0152
0153
0154 secperblk = blocksize >> 9;
0155 blk = cchhb2blk(&label->vol.vtoc, geo) + 1;
0156 counter = 0;
0157 data = read_part_sector(state, blk * secperblk, §);
0158 while (data != NULL) {
0159 memcpy(&f1, data, sizeof(struct vtoc_format1_label));
0160 put_dev_sector(sect);
0161
0162 if (f1.DS1FMTID == _ascebc['4']
0163 || f1.DS1FMTID == _ascebc['5']
0164 || f1.DS1FMTID == _ascebc['7']
0165 || f1.DS1FMTID == _ascebc['9']) {
0166 blk++;
0167 data = read_part_sector(state, blk * secperblk, §);
0168 continue;
0169 }
0170
0171 if (f1.DS1FMTID != _ascebc['1'] &&
0172 f1.DS1FMTID != _ascebc['8'])
0173 break;
0174
0175 offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
0176 size = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
0177 offset + geo->sectors;
0178 offset *= secperblk;
0179 size *= secperblk;
0180 if (counter >= state->limit)
0181 break;
0182 put_partition(state, counter + 1, offset, size);
0183 counter++;
0184 blk++;
0185 data = read_part_sector(state, blk * secperblk, §);
0186 }
0187 strlcat(state->pp_buf, "\n", PAGE_SIZE);
0188
0189 if (!data)
0190 return -1;
0191
0192 return 1;
0193 }
0194
0195 static int find_lnx1_partitions(struct parsed_partitions *state,
0196 struct hd_geometry *geo,
0197 int blocksize,
0198 char name[],
0199 union label_t *label,
0200 sector_t labelsect,
0201 sector_t nr_sectors,
0202 dasd_information2_t *info)
0203 {
0204 loff_t offset, geo_size, size;
0205 char tmp[64];
0206 int secperblk;
0207
0208 snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name);
0209 strlcat(state->pp_buf, tmp, PAGE_SIZE);
0210 secperblk = blocksize >> 9;
0211 if (label->lnx.ldl_version == 0xf2) {
0212 size = label->lnx.formatted_blocks * secperblk;
0213 } else {
0214
0215
0216
0217
0218
0219
0220
0221 geo_size = geo->cylinders * geo->heads
0222 * geo->sectors * secperblk;
0223 size = nr_sectors;
0224 if (size != geo_size) {
0225 if (!info) {
0226 strlcat(state->pp_buf, "\n", PAGE_SIZE);
0227 return 1;
0228 }
0229 if (!strcmp(info->type, "ECKD"))
0230 if (geo_size < size)
0231 size = geo_size;
0232
0233 }
0234 }
0235
0236 offset = labelsect + secperblk;
0237 put_partition(state, 1, offset, size - offset);
0238 strlcat(state->pp_buf, "\n", PAGE_SIZE);
0239 return 1;
0240 }
0241
0242 static int find_cms1_partitions(struct parsed_partitions *state,
0243 struct hd_geometry *geo,
0244 int blocksize,
0245 char name[],
0246 union label_t *label,
0247 sector_t labelsect)
0248 {
0249 loff_t offset, size;
0250 char tmp[64];
0251 int secperblk;
0252
0253
0254
0255
0256 blocksize = label->cms.block_size;
0257 secperblk = blocksize >> 9;
0258 if (label->cms.disk_offset != 0) {
0259 snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name);
0260 strlcat(state->pp_buf, tmp, PAGE_SIZE);
0261
0262 offset = label->cms.disk_offset * secperblk;
0263 size = (label->cms.block_count - 1) * secperblk;
0264 } else {
0265 snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name);
0266 strlcat(state->pp_buf, tmp, PAGE_SIZE);
0267
0268
0269
0270
0271
0272
0273
0274 if (labelsect == 1)
0275 offset = 2 * secperblk;
0276 else
0277 offset = labelsect + secperblk;
0278 size = label->cms.block_count * secperblk;
0279 }
0280
0281 put_partition(state, 1, offset, size-offset);
0282 strlcat(state->pp_buf, "\n", PAGE_SIZE);
0283 return 1;
0284 }
0285
0286
0287
0288
0289
0290 int ibm_partition(struct parsed_partitions *state)
0291 {
0292 int (*fn)(struct gendisk *disk, dasd_information2_t *info);
0293 struct gendisk *disk = state->disk;
0294 struct block_device *bdev = disk->part0;
0295 int blocksize, res;
0296 loff_t offset, size;
0297 sector_t nr_sectors;
0298 dasd_information2_t *info;
0299 struct hd_geometry *geo;
0300 char type[5] = {0,};
0301 char name[7] = {0,};
0302 sector_t labelsect;
0303 union label_t *label;
0304
0305 res = 0;
0306 if (!disk->fops->getgeo)
0307 goto out_exit;
0308 fn = symbol_get(dasd_biodasdinfo);
0309 blocksize = bdev_logical_block_size(bdev);
0310 if (blocksize <= 0)
0311 goto out_symbol;
0312 nr_sectors = bdev_nr_sectors(bdev);
0313 if (nr_sectors == 0)
0314 goto out_symbol;
0315 info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
0316 if (info == NULL)
0317 goto out_symbol;
0318 geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL);
0319 if (geo == NULL)
0320 goto out_nogeo;
0321 label = kmalloc(sizeof(union label_t), GFP_KERNEL);
0322 if (label == NULL)
0323 goto out_nolab;
0324
0325 geo->start = get_start_sect(bdev);
0326 if (disk->fops->getgeo(bdev, geo))
0327 goto out_freeall;
0328 if (!fn || fn(disk, info)) {
0329 kfree(info);
0330 info = NULL;
0331 }
0332
0333 if (find_label(state, info, geo, blocksize, &labelsect, name, type,
0334 label)) {
0335 if (!strncmp(type, "VOL1", 4)) {
0336 res = find_vol1_partitions(state, geo, blocksize, name,
0337 label);
0338 } else if (!strncmp(type, "LNX1", 4)) {
0339 res = find_lnx1_partitions(state, geo, blocksize, name,
0340 label, labelsect, nr_sectors,
0341 info);
0342 } else if (!strncmp(type, "CMS1", 4)) {
0343 res = find_cms1_partitions(state, geo, blocksize, name,
0344 label, labelsect);
0345 }
0346 } else if (info) {
0347
0348
0349
0350
0351
0352
0353
0354 res = 1;
0355 if (info->format == DASD_FORMAT_LDL) {
0356 strlcat(state->pp_buf, "(nonl)", PAGE_SIZE);
0357 size = nr_sectors;
0358 offset = (info->label_block + 1) * (blocksize >> 9);
0359 put_partition(state, 1, offset, size-offset);
0360 strlcat(state->pp_buf, "\n", PAGE_SIZE);
0361 }
0362 } else
0363 res = 0;
0364
0365 out_freeall:
0366 kfree(label);
0367 out_nolab:
0368 kfree(geo);
0369 out_nogeo:
0370 kfree(info);
0371 out_symbol:
0372 if (fn)
0373 symbol_put(dasd_biodasdinfo);
0374 out_exit:
0375 return res;
0376 }