1/* 2 * File...........: linux/fs/partitions/ibm.c 3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> 4 * Volker Sameske <sameske@de.ibm.com> 5 * Bugreports.to..: <Linux390@de.ibm.com> 6 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 7 */ 8 9#include <linux/buffer_head.h> 10#include <linux/hdreg.h> 11#include <linux/slab.h> 12#include <asm/dasd.h> 13#include <asm/ebcdic.h> 14#include <asm/uaccess.h> 15#include <asm/vtoc.h> 16 17#include "check.h" 18#include "ibm.h" 19 20/* 21 * compute the block number from a 22 * cyl-cyl-head-head structure 23 */ 24static inline int 25cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) { 26 return ptr->cc * geo->heads * geo->sectors + 27 ptr->hh * geo->sectors; 28} 29 30/* 31 * compute the block number from a 32 * cyl-cyl-head-head-block structure 33 */ 34static inline int 35cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) { 36 return ptr->cc * geo->heads * geo->sectors + 37 ptr->hh * geo->sectors + 38 ptr->b; 39} 40 41/* 42 */ 43int 44ibm_partition(struct parsed_partitions *state, struct block_device *bdev) 45{ 46 int blocksize, offset, size,res; 47 loff_t i_size; 48 dasd_information_t *info; 49 struct hd_geometry *geo; 50 char type[5] = {0,}; 51 char name[7] = {0,}; 52 union label_t { 53 struct vtoc_volume_label vol; 54 struct vtoc_cms_label cms; 55 } *label; 56 unsigned char *data; 57 Sector sect; 58 59 res = 0; 60 blocksize = bdev_hardsect_size(bdev); 61 if (blocksize <= 0) 62 goto out_exit; 63 i_size = i_size_read(bdev->bd_inode); 64 if (i_size == 0) 65 goto out_exit; 66 67 if ((info = kmalloc(sizeof(dasd_information_t), GFP_KERNEL)) == NULL) 68 goto out_exit; 69 if ((geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL)) == NULL) 70 goto out_nogeo; 71 if ((label = kmalloc(sizeof(union label_t), GFP_KERNEL)) == NULL) 72 goto out_nolab; 73 74 if (ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)info) != 0 || 75 ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0) 76 goto out_freeall; 77 78 /* 79 * Get volume label, extract name and type. 80 */ 81 data = read_dev_sector(bdev, info->label_block*(blocksize/512), §); 82 if (data == NULL) 83 goto out_readerr; 84 85 strncpy (type, data, 4); 86 if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) 87 strncpy(name, data + 8, 6); 88 else 89 strncpy(name, data + 4, 6); 90 memcpy(label, data, sizeof(union label_t)); 91 put_dev_sector(sect); 92 93 EBCASC(type, 4); 94 EBCASC(name, 6); 95 96 res = 1; 97 98 /* 99 * Three different types: CMS1, VOL1 and LNX1/unlabeled 100 */ 101 if (strncmp(type, "CMS1", 4) == 0) { 102 /* 103 * VM style CMS1 labeled disk 104 */ 105 if (label->cms.disk_offset != 0) { 106 printk("CMS1/%8s(MDSK):", name); 107 /* disk is reserved minidisk */ 108 blocksize = label->cms.block_size; 109 offset = label->cms.disk_offset; 110 size = (label->cms.block_count - 1) * (blocksize >> 9); 111 } else { 112 printk("CMS1/%8s:", name); 113 offset = (info->label_block + 1); 114 size = i_size >> 9; 115 } 116 put_partition(state, 1, offset*(blocksize >> 9), 117 size-offset*(blocksize >> 9)); 118 } else if ((strncmp(type, "VOL1", 4) == 0) && 119 (!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) { 120 /* 121 * New style VOL1 labeled disk 122 */ 123 unsigned int blk; 124 int counter; 125 126 printk("VOL1/%8s:", name); 127 128 /* get block number and read then go through format1 labels */ 129 blk = cchhb2blk(&label->vol.vtoc, geo) + 1; 130 counter = 0; 131 while ((data = read_dev_sector(bdev, blk*(blocksize/512), 132 §)) != NULL) { 133 struct vtoc_format1_label f1; 134 135 memcpy(&f1, data, sizeof(struct vtoc_format1_label)); 136 put_dev_sector(sect); 137 138 /* skip FMT4 / FMT5 / FMT7 labels */ 139 if (f1.DS1FMTID == _ascebc['4'] 140 || f1.DS1FMTID == _ascebc['5'] 141 || f1.DS1FMTID == _ascebc['7']) { 142 blk++; 143 continue; 144 } 145 146 /* only FMT1 valid at this point */ 147 if (f1.DS1FMTID != _ascebc['1']) 148 break; 149 150 /* OK, we got valid partition data */ 151 offset = cchh2blk(&f1.DS1EXT1.llimit, geo); 152 size = cchh2blk(&f1.DS1EXT1.ulimit, geo) - 153 offset + geo->sectors; 154 if (counter >= state->limit) 155 break; 156 put_partition(state, counter + 1, 157 offset * (blocksize >> 9), 158 size * (blocksize >> 9)); 159 counter++; 160 blk++; 161 } 162 if (!data) 163 /* Are we not supposed to report this ? */ 164 goto out_readerr; 165 } else { 166 /* 167 * Old style LNX1 or unlabeled disk 168 */ 169 if (strncmp(type, "LNX1", 4) == 0) 170 printk ("LNX1/%8s:", name); 171 else 172 printk("(nonl)/%8s:", name); 173 offset = (info->label_block + 1); 174 size = i_size >> 9; 175 put_partition(state, 1, offset*(blocksize >> 9), 176 size-offset*(blocksize >> 9)); 177 } 178 179 printk("\n"); 180 goto out_freeall; 181 182 183out_readerr: 184 res = -1; 185out_freeall: 186 kfree(label); 187out_nolab: 188 kfree(geo); 189out_nogeo: 190 kfree(info); 191out_exit: 192 return res; 193} 194