1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
* Sun Feb 24 23:13:03 CET 2002: Patch by Andries Brouwer to remove the
* confused CMOS probe applied. This is solving more problems than it may
* (unexpectedly) introduce.
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/ide.h>
#include <linux/mc146818rtc.h>
#include <asm/io.h>
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
extern struct ata_device * get_info_ptr(kdev_t);
/*
* If heads is nonzero: find a translation with this many heads and S=63.
* Otherwise: find out how OnTrack Disk Manager would translate the disk.
*/
static void
ontrack(struct ata_device *drive, int heads, unsigned int *c, int *h, int *s)
{
static const u8 dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
const u8 *headp = dm_head_vals;
unsigned long total;
/*
* The specs say: take geometry as obtained from Identify, compute
* total capacity C*H*S from that, and truncate to 1024*255*63. Now
* take S=63, H the first in the sequence 4, 8, 16, 32, 64, 128, 255
* such that 63*H*1024 >= total. [Please tell aeb@cwi.nl in case this
* computes a geometry different from what OnTrack uses.]
*/
total = ata_capacity(drive);
*s = 63;
if (heads) {
*h = heads;
*c = total / (63 * heads);
return;
}
while (63 * headp[0] * 1024 < total && headp[1] != 0)
headp++;
*h = headp[0];
*c = total / (63 * headp[0]);
}
/*
* This routine is called from the partition-table code in pt/msdos.c.
* It has two tasks:
* (i) to handle Ontrack DiskManager by offsetting everything by 63 sectors,
* or to handle EZdrive by remapping sector 0 to sector 1.
* (ii) to invent a translated geometry.
* Part (i) is suppressed if the user specifies the "noremap" option
* on the command line.
* Part (ii) is suppressed if the user specifies an explicit geometry.
*
* The ptheads parameter is either 0 or tells about the number of
* heads shown by the end of the first nonempty partition.
* If this is either 16, 32, 64, 128, 240 or 255 we'll believe it.
*
* The xparm parameter has the following meaning:
* 0 = convert to CHS with fewer than 1024 cyls
* using the same method as Ontrack DiskManager.
* 1 = same as "0", plus offset everything by 63 sectors.
* -1 = similar to "0", plus redirect sector 0 to sector 1.
* 2 = convert to a CHS geometry with "ptheads" heads.
*
* Returns 0 if the translation was not possible, if the device was not
* an IDE disk drive, or if a geometry was "forced" on the commandline.
* Returns 1 if the geometry translation was successful.
*/
int ide_xlate_1024(kdev_t i_rdev, int xparm, int ptheads, const char *msg)
{
struct ata_device *drive;
const char *msg1 = "";
int heads = 0;
int c, h, s;
int transl = 1; /* try translation */
int ret = 0;
drive = get_info_ptr(i_rdev);
if (!drive)
return 0;
/* remap? */
if (drive->remap_0_to_1 != 2) {
if (xparm == 1) { /* DM */
drive->sect0 = 63;
msg1 = " [remap +63]";
ret = 1;
} else if (xparm == -1) { /* EZ-Drive */
if (drive->remap_0_to_1 == 0) {
drive->remap_0_to_1 = 1;
msg1 = " [remap 0->1]";
ret = 1;
}
}
}
/* There used to be code here that assigned drive->id->CHS
to drive->CHS and that to drive->bios_CHS. However,
some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB.
In such cases that code was wrong. Moreover,
there seems to be no reason to do any of these things. */
/* translate? */
if (drive->forced_geom)
transl = 0;
/* does ptheads look reasonable? */
if (ptheads == 32 || ptheads == 64 || ptheads == 128 ||
ptheads == 240 || ptheads == 255)
heads = ptheads;
if (xparm == 2) {
if (!heads ||
(drive->bios_head >= heads && drive->bios_sect == 63))
transl = 0;
}
if (xparm == -1) {
if (drive->bios_head > 16)
transl = 0; /* we already have a translation */
}
if (transl) {
ontrack(drive, heads, &c, &h, &s);
drive->bios_cyl = c;
drive->bios_head = h;
drive->bios_sect = s;
ret = 1;
}
drive->part[0].nr_sects = ata_capacity(drive);
if (ret)
printk("%s%s [%d/%d/%d]", msg, msg1,
drive->bios_cyl, drive->bios_head, drive->bios_sect);
return ret;
}
#endif