ibm.c 4.5 KB

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