clean
[linux-2.4.21-pre4.git] / drivers / ide / ide-geometry.c
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
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  * The only "perfect" way to handle this would be to modify the setup.[cS] code
28  * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
29  * for us during initialization.  I have the necessary docs -- any takers?  -ml
30  *
31  * I did this, but it doesn't work - there is no reasonable way to find the
32  * correspondence between the BIOS numbering of the disks and the Linux
33  * numbering. -aeb
34  *
35  * The code below is bad. One of the problems is that drives 1 and 2
36  * may be SCSI disks (even when IDE disks are present), so that
37  * the geometry we read here from BIOS is attributed to the wrong disks.
38  * Consequently, also the former "drive->present = 1" below was a mistake.
39  *
40  * Eventually the entire routine below should be removed.
41  *
42  * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS
43  * chip.
44  */
45
46 void probe_cmos_for_drives (ide_hwif_t *hwif)
47 {
48 #ifdef __i386__
49         extern struct drive_info_struct drive_info;
50         u8 cmos_disks, *BIOS = (u8 *) &drive_info;
51         int unit;
52         unsigned long flags;
53
54         if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
55                 return;
56
57         spin_lock_irqsave(&rtc_lock, flags);
58         cmos_disks = CMOS_READ(0x12);
59         spin_unlock_irqrestore(&rtc_lock, flags);
60         /* Extract drive geometry from CMOS+BIOS if not already setup */
61         for (unit = 0; unit < MAX_DRIVES; ++unit) {
62                 ide_drive_t *drive = &hwif->drives[unit];
63
64                 if ((cmos_disks & (0xf0 >> (unit*4)))
65                    && !drive->present && !drive->nobios) {
66                         u16 cyl = *(u16 *)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 ignored\n",
76                                        unit+'a', cyl, head, sect);
77                         }
78                 }
79
80                 BIOS += 16;
81         }
82 #endif
83 }
84
85
86 extern ide_drive_t * get_info_ptr(kdev_t);
87 extern unsigned long current_capacity (ide_drive_t *);
88
89 /*
90  * If heads is nonzero: find a translation with this many heads and S=63.
91  * Otherwise: find out how OnTrack Disk Manager would translate the disk.
92  */
93
94 static void ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) 
95 {
96         static const u8 dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
97         const u8 *headp = dm_head_vals;
98         unsigned long total;
99
100         /*
101          * The specs say: take geometry as obtained from Identify,
102          * compute total capacity C*H*S from that, and truncate to
103          * 1024*255*63. Now take S=63, H the first in the sequence
104          * 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total.
105          * [Please tell aeb@cwi.nl in case this computes a
106          * geometry different from what OnTrack uses.]
107          */
108         total = DRIVER(drive)->capacity(drive);
109
110         *s = 63;
111
112         if (heads) {
113                 *h = heads;
114                 *c = total / (63 * heads);
115                 return;
116         }
117
118         while (63 * headp[0] * 1024 < total && headp[1] != 0)
119                  headp++;
120         *h = headp[0];
121         *c = total / (63 * headp[0]);
122 }
123
124 /*
125  * This routine is called from the partition-table code in pt/msdos.c.
126  * It has two tasks:
127  * (i) to handle Ontrack DiskManager by offsetting everything by 63 sectors,
128  *  or to handle EZdrive by remapping sector 0 to sector 1.
129  * (ii) to invent a translated geometry.
130  * Part (i) is suppressed if the user specifies the "noremap" option
131  * on the command line.
132  * Part (ii) is suppressed if the user specifies an explicit geometry.
133  *
134  * The ptheads parameter is either 0 or tells about the number of
135  * heads shown by the end of the first nonempty partition.
136  * If this is either 16, 32, 64, 128, 240 or 255 we'll believe it.
137  *
138  * The xparm parameter has the following meaning:
139  *       0 = convert to CHS with fewer than 1024 cyls
140  *           using the same method as Ontrack DiskManager.
141  *       1 = same as "0", plus offset everything by 63 sectors.
142  *      -1 = similar to "0", plus redirect sector 0 to sector 1.
143  *       2 = convert to a CHS geometry with "ptheads" heads.
144  *
145  * Returns 0 if the translation was not possible, if the device was not 
146  * an IDE disk drive, or if a geometry was "forced" on the commandline.
147  * Returns 1 if the geometry translation was successful.
148  */
149
150 int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
151 {
152         ide_drive_t *drive;
153         const char *msg1 = "";
154         int heads = 0;
155         int c, h, s;
156         int transl = 1;         /* try translation */
157         int ret = 0;
158
159         drive = get_info_ptr(i_rdev);
160         if (!drive)
161                 return 0;
162
163         /* remap? */
164         if (drive->remap_0_to_1 != 2) {
165                 if (xparm == 1) {               /* DM */
166                         drive->sect0 = 63;
167                         msg1 = " [remap +63]";
168                         ret = 1;
169                 } else if (xparm == -1) {       /* EZ-Drive */
170                         if (drive->remap_0_to_1 == 0) {
171                                 drive->remap_0_to_1 = 1;
172                                 msg1 = " [remap 0->1]";
173                                 ret = 1;
174                         }
175                 }
176         }
177
178         /* There used to be code here that assigned drive->id->CHS
179            to drive->CHS and that to drive->bios_CHS. However,
180            some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB.
181            In such cases that code was wrong.  Moreover,
182            there seems to be no reason to do any of these things. */
183
184         /* translate? */
185         if (drive->forced_geom)
186                 transl = 0;
187
188         /* does ptheads look reasonable? */
189         if (ptheads == 32 || ptheads == 64 || ptheads == 128 ||
190             ptheads == 240 || ptheads == 255)
191                 heads = ptheads;
192
193         if (xparm == 2) {
194                 if (!heads ||
195                    (drive->bios_head >= heads && drive->bios_sect == 63))
196                         transl = 0;
197         }
198         if (xparm == -1) {
199                 if (drive->bios_head > 16)
200                         transl = 0;     /* we already have a translation */
201         }
202
203         if (transl) {
204                 ontrack(drive, heads, &c, &h, &s);
205                 drive->bios_cyl = c;
206                 drive->bios_head = h;
207                 drive->bios_sect = s;
208                 ret = 1;
209         }
210
211         drive->part[0].nr_sects = current_capacity(drive);
212
213         if (ret)
214                 printk(KERN_INFO "%s%s [%d/%d/%d]", msg, msg1,
215                        drive->bios_cyl, drive->bios_head, drive->bios_sect);
216         return ret;
217 }