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 /*
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 doesnt 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 void probe_cmos_for_drives (ide_hwif_t *hwif)
45 {
46 #ifdef __i386__
47 extern struct drive_info_struct drive_info;
48 byte cmos_disks, *BIOS = (byte *) &drive_info;
49 int unit;
50 unsigned long flags;
51
52 #ifdef CONFIG_BLK_DEV_PDC4030
53 if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
54 return;
55 #endif /* CONFIG_BLK_DEV_PDC4030 */
56 spin_lock_irqsave(&rtc_lock, flags);
57 cmos_disks = CMOS_READ(0x12);
58 spin_unlock_irqrestore(&rtc_lock, flags);
59 /* Extract drive geometry from CMOS+BIOS if not already setup */
60 for (unit = 0; unit < MAX_DRIVES; ++unit) {
61 ide_drive_t *drive = &hwif->drives[unit];
62
63 if ((cmos_disks & (0xf0 >> (unit*4)))
64 && !drive->present && !drive->nobios) {
65 unsigned short cyl = *(unsigned short *)BIOS;
66 unsigned char head = *(BIOS+2);
67 unsigned char sect = *(BIOS+14);
68 if (cyl > 0 && head > 0 && sect > 0 && sect < 64) {
69 drive->cyl = drive->bios_cyl = cyl;
70 drive->head = drive->bios_head = head;
71 drive->sect = drive->bios_sect = sect;
72 drive->ctl = *(BIOS+8);
73 } else {
74 printk("hd%d: C/H/S=%d/%d/%d from BIOS ignored\n",
75 unit, cyl, head, sect);
76 }
77 }
78
79 BIOS += 16;
80 }
81 #endif
82 }
83
84
85 #ifdef CONFIG_BLK_DEV_IDE
86
87 extern ide_drive_t * get_info_ptr(kdev_t);
88 extern unsigned long current_capacity (ide_drive_t *);
89
90 /*
91 * If heads is nonzero: find a translation with this many heads and S=63.
92 * Otherwise: find out how OnTrack Disk Manager would translate the disk.
93 */
94 static void
95 ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) {
96 static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
97 const byte *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 "", plus offset everything by 63 sectors.
142 * -1 = similar to "", 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 int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
150 {
151 ide_drive_t *drive;
152 const char *msg1 = "";
153 int heads = 0;
154 int c, h, s;
155 int transl = 1; /* try translation */
156 int ret = 0;
157
158 drive = get_info_ptr(i_rdev);
159 if (!drive)
160 return 0;
161
162 /* remap? */
163 if (drive->remap_0_to_1 != 2) {
164 if (xparm == 1) { /* DM */
165 drive->sect0 = 63;
166 msg1 = " [remap +63]";
167 ret = 1;
168 } else if (xparm == -1) { /* EZ-Drive */
169 if (drive->remap_0_to_1 == 0) {
170 drive->remap_0_to_1 = 1;
171 msg1 = " [remap 0->1]";
172 ret = 1;
173 }
174 }
175 }
176
177 /* There used to be code here that assigned drive->id->CHS
178 to drive->CHS and that to drive->bios_CHS. However,
179 some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB.
180 In such cases that code was wrong. Moreover,
181 there seems to be no reason to do any of these things. */
182
183 /* translate? */
184 if (drive->forced_geom)
185 transl = 0;
186
187 /* does ptheads look reasonable? */
188 if (ptheads == 32 || ptheads == 64 || ptheads == 128 ||
189 ptheads == 240 || ptheads == 255)
190 heads = ptheads;
191
192 if (xparm == 2) {
193 if (!heads ||
194 (drive->bios_head >= heads && drive->bios_sect == 63))
195 transl = 0;
196 }
197 if (xparm == -1) {
198 if (drive->bios_head > 16)
199 transl = 0; /* we already have a translation */
200 }
201
202 if (transl) {
203 ontrack(drive, heads, &c, &h, &s);
204 drive->bios_cyl = c;
205 drive->bios_head = h;
206 drive->bios_sect = s;
207 ret = 1;
208 }
209
210 drive->part[0].nr_sects = current_capacity(drive);
211
212 if (ret)
213 printk("%s%s [%d/%d/%d]", msg, msg1,
214 drive->bios_cyl, drive->bios_head, drive->bios_sect);
215 return ret;
216 }
217 #endif /* CONFIG_BLK_DEV_IDE */
218
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.