ibm.c 6.8 KB

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