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