ide-geometry.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:7k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * linux/drivers/ide/ide-geometry.c
  3.  */
  4. #include <linux/config.h>
  5. #include <linux/ide.h>
  6. #include <linux/mc146818rtc.h>
  7. #include <asm/io.h>
  8. #ifdef CONFIG_BLK_DEV_IDE
  9. /*
  10.  * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
  11.  * controller that is BIOS compatible with ST-506, and thus showing up in our
  12.  * BIOS table, but not register compatible, and therefore not present in CMOS.
  13.  *
  14.  * Furthermore, we will assume that our ST-506 drives <if any> are the primary
  15.  * drives in the system -- the ones reflected as drive 1 or 2.  The first
  16.  * drive is stored in the high nibble of CMOS byte 0x12, the second in the low
  17.  * nibble.  This will be either a 4 bit drive type or 0xf indicating use byte
  18.  * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.  A non-zero value
  19.  * means we have an AT controller hard disk for that drive.
  20.  *
  21.  * Of course, there is no guarantee that either drive is actually on the
  22.  * "primary" IDE interface, but we don't bother trying to sort that out here.
  23.  * If a drive is not actually on the primary interface, then these parameters
  24.  * will be ignored.  This results in the user having to supply the logical
  25.  * drive geometry as a boot parameter for each drive not on the primary i/f.
  26.  */
  27. /*
  28.  * The only "perfect" way to handle this would be to modify the setup.[cS] code
  29.  * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
  30.  * for us during initialization.  I have the necessary docs -- any takers?  -ml
  31.  */
  32. /*
  33.  * I did this, but it doesn't work - there is no reasonable way to find the
  34.  * correspondence between the BIOS numbering of the disks and the Linux
  35.  * numbering. -aeb
  36.  *
  37.  * The code below is bad. One of the problems is that drives 1 and 2
  38.  * may be SCSI disks (even when IDE disks are present), so that
  39.  * the geometry we read here from BIOS is attributed to the wrong disks.
  40.  * Consequently, also the former "drive->present = 1" below was a mistake.
  41.  *
  42.  * Eventually the entire routine below should be removed.
  43.  *
  44.  * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS
  45.  * chip.
  46.  */
  47. void probe_cmos_for_drives (ide_hwif_t *hwif)
  48. {
  49. #ifdef __i386__
  50. extern struct drive_info_struct drive_info;
  51. byte cmos_disks, *BIOS = (byte *) &drive_info;
  52. int unit;
  53. unsigned long flags;
  54. #ifdef CONFIG_BLK_DEV_PDC4030
  55. if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
  56. return;
  57. #endif /* CONFIG_BLK_DEV_PDC4030 */
  58. spin_lock_irqsave(&rtc_lock, flags);
  59. cmos_disks = CMOS_READ(0x12);
  60. spin_unlock_irqrestore(&rtc_lock, flags);
  61. /* Extract drive geometry from CMOS+BIOS if not already setup */
  62. for (unit = 0; unit < MAX_DRIVES; ++unit) {
  63. ide_drive_t *drive = &hwif->drives[unit];
  64. if ((cmos_disks & (0xf0 >> (unit*4)))
  65.    && !drive->present && !drive->nobios) {
  66. unsigned short cyl = *(unsigned short *)BIOS;
  67. unsigned char head = *(BIOS+2);
  68. unsigned char sect = *(BIOS+14);
  69. if (cyl > 0 && head > 0 && sect > 0 && sect < 64) {
  70. drive->cyl   = drive->bios_cyl  = cyl;
  71. drive->head  = drive->bios_head = head;
  72. drive->sect  = drive->bios_sect = sect;
  73. drive->ctl   = *(BIOS+8);
  74. } else {
  75. printk("hd%c: C/H/S=%d/%d/%d from BIOS ignoredn",
  76.        unit+'a', cyl, head, sect);
  77. }
  78. }
  79. BIOS += 16;
  80. }
  81. #endif
  82. }
  83. #endif /* CONFIG_BLK_DEV_IDE */
  84. #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
  85. extern ide_drive_t * get_info_ptr(kdev_t);
  86. extern unsigned long current_capacity (ide_drive_t *);
  87. /*
  88.  * If heads is nonzero: find a translation with this many heads and S=63.
  89.  * Otherwise: find out how OnTrack Disk Manager would translate the disk.
  90.  */
  91. static void
  92. ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) {
  93. static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
  94. const byte *headp = dm_head_vals;
  95. unsigned long total;
  96. /*
  97.  * The specs say: take geometry as obtained from Identify,
  98.  * compute total capacity C*H*S from that, and truncate to
  99.  * 1024*255*63. Now take S=63, H the first in the sequence
  100.  * 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total.
  101.  * [Please tell aeb@cwi.nl in case this computes a
  102.  * geometry different from what OnTrack uses.]
  103.  */
  104. total = DRIVER(drive)->capacity(drive);
  105. *s = 63;
  106. if (heads) {
  107. *h = heads;
  108. *c = total / (63 * heads);
  109. return;
  110. }
  111. while (63 * headp[0] * 1024 < total && headp[1] != 0)
  112.  headp++;
  113. *h = headp[0];
  114. *c = total / (63 * headp[0]);
  115. }
  116. /*
  117.  * This routine is called from the partition-table code in pt/msdos.c.
  118.  * It has two tasks:
  119.  * (i) to handle Ontrack DiskManager by offsetting everything by 63 sectors,
  120.  *  or to handle EZdrive by remapping sector 0 to sector 1.
  121.  * (ii) to invent a translated geometry.
  122.  * Part (i) is suppressed if the user specifies the "noremap" option
  123.  * on the command line.
  124.  * Part (ii) is suppressed if the user specifies an explicit geometry.
  125.  *
  126.  * The ptheads parameter is either 0 or tells about the number of
  127.  * heads shown by the end of the first nonempty partition.
  128.  * If this is either 16, 32, 64, 128, 240 or 255 we'll believe it.
  129.  *
  130.  * The xparm parameter has the following meaning:
  131.  *  0 = convert to CHS with fewer than 1024 cyls
  132.  *      using the same method as Ontrack DiskManager.
  133.  *  1 = same as "0", plus offset everything by 63 sectors.
  134.  * -1 = similar to "0", plus redirect sector 0 to sector 1.
  135.  *  2 = convert to a CHS geometry with "ptheads" heads.
  136.  *
  137.  * Returns 0 if the translation was not possible, if the device was not 
  138.  * an IDE disk drive, or if a geometry was "forced" on the commandline.
  139.  * Returns 1 if the geometry translation was successful.
  140.  */
  141. int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
  142. {
  143. ide_drive_t *drive;
  144. const char *msg1 = "";
  145. int heads = 0;
  146. int c, h, s;
  147. int transl = 1; /* try translation */
  148. int ret = 0;
  149. drive = get_info_ptr(i_rdev);
  150. if (!drive)
  151. return 0;
  152. /* remap? */
  153. if (drive->remap_0_to_1 != 2) {
  154. if (xparm == 1) { /* DM */
  155. drive->sect0 = 63;
  156. msg1 = " [remap +63]";
  157. ret = 1;
  158. } else if (xparm == -1) { /* EZ-Drive */
  159. if (drive->remap_0_to_1 == 0) {
  160. drive->remap_0_to_1 = 1;
  161. msg1 = " [remap 0->1]";
  162. ret = 1;
  163. }
  164. }
  165. }
  166. /* There used to be code here that assigned drive->id->CHS
  167.    to drive->CHS and that to drive->bios_CHS. However,
  168.    some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB.
  169.    In such cases that code was wrong.  Moreover,
  170.    there seems to be no reason to do any of these things. */
  171. /* translate? */
  172. if (drive->forced_geom)
  173. transl = 0;
  174. /* does ptheads look reasonable? */
  175. if (ptheads == 32 || ptheads == 64 || ptheads == 128 ||
  176.     ptheads == 240 || ptheads == 255)
  177. heads = ptheads;
  178. if (xparm == 2) {
  179. if (!heads ||
  180.    (drive->bios_head >= heads && drive->bios_sect == 63))
  181. transl = 0;
  182. }
  183. if (xparm == -1) {
  184. if (drive->bios_head > 16)
  185. transl = 0;     /* we already have a translation */
  186. }
  187. if (transl) {
  188. ontrack(drive, heads, &c, &h, &s);
  189. drive->bios_cyl = c;
  190. drive->bios_head = h;
  191. drive->bios_sect = s;
  192. ret = 1;
  193. }
  194. drive->part[0].nr_sects = current_capacity(drive);
  195. if (ret)
  196. printk("%s%s [%d/%d/%d]", msg, msg1,
  197.        drive->bios_cyl, drive->bios_head, drive->bios_sect);
  198. return ret;
  199. }
  200. #endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */