ibm.c 4.6 KB

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