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