ibm.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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/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. #include "check.h"
  16. #include "ibm.h"
  17. /*
  18. * compute the block number from a
  19. * cyl-cyl-head-head structure
  20. */
  21. static sector_t
  22. cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) {
  23. sector_t cyl;
  24. __u16 head;
  25. /*decode cylinder and heads for large volumes */
  26. cyl = ptr->hh & 0xFFF0;
  27. cyl <<= 12;
  28. cyl |= ptr->cc;
  29. head = ptr->hh & 0x000F;
  30. return cyl * geo->heads * geo->sectors +
  31. head * geo->sectors;
  32. }
  33. /*
  34. * compute the block number from a
  35. * cyl-cyl-head-head-block structure
  36. */
  37. static sector_t
  38. cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) {
  39. sector_t cyl;
  40. __u16 head;
  41. /*decode cylinder and heads for large volumes */
  42. cyl = ptr->hh & 0xFFF0;
  43. cyl <<= 12;
  44. cyl |= ptr->cc;
  45. head = ptr->hh & 0x000F;
  46. return cyl * geo->heads * geo->sectors +
  47. head * geo->sectors +
  48. ptr->b;
  49. }
  50. /*
  51. */
  52. int ibm_partition(struct parsed_partitions *state)
  53. {
  54. struct block_device *bdev = state->bdev;
  55. int blocksize, res;
  56. loff_t i_size, offset, size, fmt_size;
  57. dasd_information2_t *info;
  58. struct hd_geometry *geo;
  59. char type[5] = {0,};
  60. char name[7] = {0,};
  61. union label_t {
  62. struct vtoc_volume_label_cdl vol;
  63. struct vtoc_volume_label_ldl lnx;
  64. struct vtoc_cms_label cms;
  65. } *label;
  66. unsigned char *data;
  67. Sector sect;
  68. sector_t labelsect;
  69. res = 0;
  70. blocksize = bdev_logical_block_size(bdev);
  71. if (blocksize <= 0)
  72. goto out_exit;
  73. i_size = i_size_read(bdev->bd_inode);
  74. if (i_size == 0)
  75. goto out_exit;
  76. info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
  77. if (info == NULL)
  78. goto out_exit;
  79. geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL);
  80. if (geo == NULL)
  81. goto out_nogeo;
  82. label = kmalloc(sizeof(union label_t), GFP_KERNEL);
  83. if (label == NULL)
  84. goto out_nolab;
  85. if (ioctl_by_bdev(bdev, BIODASDINFO2, (unsigned long)info) != 0 ||
  86. ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
  87. goto out_freeall;
  88. /*
  89. * Special case for FBA disks: label sector does not depend on
  90. * blocksize.
  91. */
  92. if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
  93. (info->cu_type == 0x3880 && info->dev_type == 0x3370))
  94. labelsect = info->label_block;
  95. else
  96. labelsect = info->label_block * (blocksize >> 9);
  97. /*
  98. * Get volume label, extract name and type.
  99. */
  100. data = read_part_sector(state, labelsect, &sect);
  101. if (data == NULL)
  102. goto out_readerr;
  103. memcpy(label, data, sizeof(union label_t));
  104. put_dev_sector(sect);
  105. if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) {
  106. strncpy(type, label->vol.vollbl, 4);
  107. strncpy(name, label->vol.volid, 6);
  108. } else {
  109. strncpy(type, label->lnx.vollbl, 4);
  110. strncpy(name, label->lnx.volid, 6);
  111. }
  112. EBCASC(type, 4);
  113. EBCASC(name, 6);
  114. res = 1;
  115. /*
  116. * Three different formats: LDL, CDL and unformated disk
  117. *
  118. * identified by info->format
  119. *
  120. * unformated disks we do not have to care about
  121. */
  122. if (info->format == DASD_FORMAT_LDL) {
  123. if (strncmp(type, "CMS1", 4) == 0) {
  124. /*
  125. * VM style CMS1 labeled disk
  126. */
  127. blocksize = label->cms.block_size;
  128. if (label->cms.disk_offset != 0) {
  129. printk("CMS1/%8s(MDSK):", name);
  130. /* disk is reserved minidisk */
  131. offset = label->cms.disk_offset;
  132. size = (label->cms.block_count - 1)
  133. * (blocksize >> 9);
  134. } else {
  135. printk("CMS1/%8s:", name);
  136. offset = (info->label_block + 1);
  137. size = label->cms.block_count
  138. * (blocksize >> 9);
  139. }
  140. put_partition(state, 1, offset*(blocksize >> 9),
  141. size-offset*(blocksize >> 9));
  142. } else {
  143. if (strncmp(type, "LNX1", 4) == 0) {
  144. printk("LNX1/%8s:", name);
  145. if (label->lnx.ldl_version == 0xf2) {
  146. fmt_size = label->lnx.formatted_blocks
  147. * (blocksize >> 9);
  148. } else if (!strcmp(info->type, "ECKD")) {
  149. /* formated w/o large volume support */
  150. fmt_size = geo->cylinders * geo->heads
  151. * geo->sectors * (blocksize >> 9);
  152. } else {
  153. /* old label and no usable disk geometry
  154. * (e.g. DIAG) */
  155. fmt_size = i_size >> 9;
  156. }
  157. size = i_size >> 9;
  158. if (fmt_size < size)
  159. size = fmt_size;
  160. offset = (info->label_block + 1);
  161. } else {
  162. /* unlabeled disk */
  163. printk("(nonl)");
  164. size = i_size >> 9;
  165. offset = (info->label_block + 1);
  166. }
  167. put_partition(state, 1, offset*(blocksize >> 9),
  168. size-offset*(blocksize >> 9));
  169. }
  170. } else if (info->format == DASD_FORMAT_CDL) {
  171. /*
  172. * New style CDL formatted disk
  173. */
  174. sector_t blk;
  175. int counter;
  176. /*
  177. * check if VOL1 label is available
  178. * if not, something is wrong, skipping partition detection
  179. */
  180. if (strncmp(type, "VOL1", 4) == 0) {
  181. printk("VOL1/%8s:", name);
  182. /*
  183. * get block number and read then go through format1
  184. * labels
  185. */
  186. blk = cchhb2blk(&label->vol.vtoc, geo) + 1;
  187. counter = 0;
  188. data = read_part_sector(state, blk * (blocksize/512),
  189. &sect);
  190. while (data != NULL) {
  191. struct vtoc_format1_label f1;
  192. memcpy(&f1, data,
  193. sizeof(struct vtoc_format1_label));
  194. put_dev_sector(sect);
  195. /* skip FMT4 / FMT5 / FMT7 labels */
  196. if (f1.DS1FMTID == _ascebc['4']
  197. || f1.DS1FMTID == _ascebc['5']
  198. || f1.DS1FMTID == _ascebc['7']
  199. || f1.DS1FMTID == _ascebc['9']) {
  200. blk++;
  201. data = read_part_sector(state,
  202. blk * (blocksize/512), &sect);
  203. continue;
  204. }
  205. /* only FMT1 and 8 labels valid at this point */
  206. if (f1.DS1FMTID != _ascebc['1'] &&
  207. f1.DS1FMTID != _ascebc['8'])
  208. break;
  209. /* OK, we got valid partition data */
  210. offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
  211. size = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
  212. offset + geo->sectors;
  213. if (counter >= state->limit)
  214. break;
  215. put_partition(state, counter + 1,
  216. offset * (blocksize >> 9),
  217. size * (blocksize >> 9));
  218. counter++;
  219. blk++;
  220. data = read_part_sector(state,
  221. blk * (blocksize/512), &sect);
  222. }
  223. if (!data)
  224. /* Are we not supposed to report this ? */
  225. goto out_readerr;
  226. } else
  227. printk(KERN_WARNING "Warning, expected Label VOL1 not "
  228. "found, treating as CDL formated Disk");
  229. }
  230. printk("\n");
  231. goto out_freeall;
  232. out_readerr:
  233. res = -1;
  234. out_freeall:
  235. kfree(label);
  236. out_nolab:
  237. kfree(geo);
  238. out_nogeo:
  239. kfree(info);
  240. out_exit:
  241. return res;
  242. }