2 * linux/drivers/block/ide-geometry.c
4 #include <linux/config.h>
6 #ifdef CONFIG_BLK_DEV_IDE
11 extern ide_drive_t
* get_info_ptr(kdev_t
);
12 extern unsigned long current_capacity (ide_drive_t
*);
15 * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
16 * controller that is BIOS compatible with ST-506, and thus showing up in our
17 * BIOS table, but not register compatible, and therefore not present in CMOS.
19 * Furthermore, we will assume that our ST-506 drives <if any> are the primary
20 * drives in the system -- the ones reflected as drive 1 or 2. The first
21 * drive is stored in the high nibble of CMOS byte 0x12, the second in the low
22 * nibble. This will be either a 4 bit drive type or 0xf indicating use byte
23 * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value
24 * means we have an AT controller hard disk for that drive.
26 * Of course, there is no guarantee that either drive is actually on the
27 * "primary" IDE interface, but we don't bother trying to sort that out here.
28 * If a drive is not actually on the primary interface, then these parameters
29 * will be ignored. This results in the user having to supply the logical
30 * drive geometry as a boot parameter for each drive not on the primary i/f.
33 * The only "perfect" way to handle this would be to modify the setup.[cS] code
34 * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
35 * for us during initialization. I have the necessary docs -- any takers? -ml
38 * I did this, but it doesnt work - there is no reasonable way to find the
39 * correspondence between the BIOS numbering of the disks and the Linux
42 * The code below is bad. One of the problems is that drives 1 and 2
43 * may be SCSI disks (even when IDE disks are present), so that
44 * the geometry we read here from BIOS is attributed to the wrong disks.
45 * Consequently, also the "drive->present = 1" below is a mistake.
47 * Eventually the entire routine below should be removed.
49 void probe_cmos_for_drives (ide_hwif_t
*hwif
)
52 extern struct drive_info_struct drive_info
;
53 byte cmos_disks
, *BIOS
= (byte
*) &drive_info
;
56 #ifdef CONFIG_BLK_DEV_PDC4030
57 if (hwif
->chipset
== ide_pdc4030
&& hwif
->channel
!= 0)
59 #endif /* CONFIG_BLK_DEV_PDC4030 */
60 outb_p(0x12,0x70); /* specify CMOS address 0x12 */
61 cmos_disks
= inb_p(0x71); /* read the data from 0x12 */
62 /* Extract drive geometry from CMOS+BIOS if not already setup */
63 for (unit
= 0; unit
< MAX_DRIVES
; ++unit
) {
64 ide_drive_t
*drive
= &hwif
->drives
[unit
];
66 if ((cmos_disks
& (0xf0 >> (unit
*4)))
67 && !drive
->present
&& !drive
->nobios
) {
68 unsigned short cyl
= *(unsigned short *)BIOS
;
69 unsigned char head
= *(BIOS
+2);
70 unsigned char sect
= *(BIOS
+14);
71 if (cyl
> 0 && head
> 0 && sect
> 0 && sect
< 64) {
72 drive
->cyl
= drive
->bios_cyl
= cyl
;
73 drive
->head
= drive
->bios_head
= head
;
74 drive
->sect
= drive
->bios_sect
= sect
;
75 drive
->ctl
= *(BIOS
+8);
77 printk("hd%d: C/H/S=%d/%d/%d from BIOS ignored\n", unit
, cyl
, head
, sect
);
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.
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
;
98 * The specs say: take geometry as obtained from Identify,
99 * compute total capacity C*H*S from that, and truncate to
100 * 1024*255*63. Now take S=63, H the first in the sequence
101 * 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total.
102 * [Please tell aeb@cwi.nl in case this computes a
103 * geometry different from what OnTrack uses.]
105 total
= DRIVER(drive
)->capacity(drive
);
111 *c
= total
/ (63 * heads
);
115 while (63 * headp
[0] * 1024 < total
&& headp
[1] != 0)
118 *c
= total
/ (63 * headp
[0]);
122 * This routine is called from the partition-table code in pt/msdos.c.
124 * (i) to handle Ontrack DiskManager by offsetting everything by 63 sectors,
125 * or to handle EZdrive by remapping sector 0 to sector 1.
126 * (ii) to invent a translated geometry.
127 * Part (i) is suppressed if the user specifies the "noremap" option
128 * on the command line.
129 * Part (ii) is suppressed if the user specifies an explicit geometry.
131 * The ptheads parameter is either 0 or tells about the number of
132 * heads shown by the end of the first nonempty partition.
133 * If this is either 16, 32, 64, 128, 240 or 255 we'll believe it.
135 * The xparm parameter has the following meaning:
136 * 0 = convert to CHS with fewer than 1024 cyls
137 * using the same method as Ontrack DiskManager.
138 * 1 = same as "0", plus offset everything by 63 sectors.
139 * -1 = similar to "0", plus redirect sector 0 to sector 1.
140 * 2 = convert to a CHS geometry with "ptheads" heads.
142 * Returns 0 if the translation was not possible, if the device was not
143 * an IDE disk drive, or if a geometry was "forced" on the commandline.
144 * Returns 1 if the geometry translation was successful.
146 int ide_xlate_1024 (kdev_t i_rdev
, int xparm
, int ptheads
, const char *msg
)
149 const char *msg1
= "";
152 int transl
= 1; /* try translation */
155 drive
= get_info_ptr(i_rdev
);
160 if (drive
->remap_0_to_1
!= 2) {
161 if (xparm
== 1) { /* DM */
163 msg1
= " [remap +63]";
165 } else if (xparm
== -1) { /* EZ-Drive */
166 if (drive
->remap_0_to_1
== 0) {
167 drive
->remap_0_to_1
= 1;
168 msg1
= " [remap 0->1]";
174 /* There used to be code here that assigned drive->id->CHS
175 to drive->CHS and that to drive->bios_CHS. However,
176 some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB.
177 In such cases that code was wrong. Moreover,
178 there seems to be no reason to do any of these things. */
181 if (drive
->forced_geom
)
184 /* does ptheads look reasonable? */
185 if (ptheads
== 32 || ptheads
== 64 || ptheads
== 128 ||
186 ptheads
== 240 || ptheads
== 255)
191 (drive
->bios_head
>= heads
&& drive
->bios_sect
== 63))
195 if (drive
->bios_head
> 16)
196 transl
= 0; /* we already have a translation */
200 ontrack(drive
, heads
, &c
, &h
, &s
);
202 drive
->bios_head
= h
;
203 drive
->bios_sect
= s
;
207 drive
->part
[0].nr_sects
= current_capacity(drive
);
210 printk("%s%s [%d/%d/%d]", msg
, msg1
,
211 drive
->bios_cyl
, drive
->bios_head
, drive
->bios_sect
);
214 #endif /* CONFIG_BLK_DEV_IDE */