IDE 驱动程序有五个关于几何结构的信息来源。第一个 (G_user) 是用户在命令行中指定的。第二个 (G_bios) 是 BIOS 固定磁盘参数表(仅适用于第一和第二个磁盘),它在系统启动时,切换到 32 位模式之前读取。第三个 (G_phys) 和第四个 (G_log) 是 IDE 控制器响应 IDENTIFY 命令 返回的 - 它们是“物理”和“当前逻辑”几何结构。
另一方面,驱动程序需要两个几何结构的值:一方面是由 HDIO_GETGEO
ioctl 返回的 G_fdisk,另一方面是实际用于执行 I/O 的 G_used。如果给定 G_user,则 G_fdisk 和 G_used 都初始化为 G_user;如果 CMOS 中存在此信息,则初始化为 G_bios;否则初始化为 G_phys。如果 G_log 看起来合理,则将 G_used 设置为 G_log。否则,如果 G_used 不合理且 G_phys 看起来合理,则将 G_used 设置为 G_phys。这里“合理”意味着磁头数在 1-16 范围内。
换句话说:命令行会覆盖 BIOS,并将决定 fdisk
看到的内容,但如果它指定了一个转换后的几何结构(磁头数超过 16 个),那么对于内核 I/O,它将被 IDENTIFY 命令的输出覆盖。
请注意,G_bios 是相当不可靠的:对于从 SCSI 启动的系统,第一和第二个磁盘很可能是 SCSI 磁盘,而 BIOS 为 sda 报告的几何结构被内核用于 hda。此外,BIOS 设置中未提及的磁盘不会被 BIOS 看到。这意味着,例如,在仅 IDE 系统中,如果 hdb 未在设置中给出,则 BIOS 为第一和第二个磁盘报告的几何结构将应用于 hda 和 hdc。
为了避免这种混淆,自 Linux 2.5.51 起,不再使用 G_bios。
当向 IDE 驱动器发送 IDENTIFY DRIVE (0xec) 命令时,它将返回 256 个字(512 字节)的信息。这包含大量技术内容。这里我们只描述在几何结构问题中起作用的内容。这些字编号为 0-255。
我们在这里找到四个信息片段:DefaultCHS(字 1,3,6)、CurrentCHS(字 54-58)和 LBAcapacity(字 60-61)以及 48 位容量(字 100-103)。
| 描述 | 示例 |
0 | 位字段:位 6:固定磁盘,位 7:可移动介质 | 0x0040 |
1 | 默认柱面数 | 16383 |
3 | 默认磁头数 | 16 |
6 | 每个磁道的默认扇区数 | 63 |
10-19 | 序列号(ASCII 码) | G8067TME |
23-26 | 固件版本(ASCII 码) | GAK&1B0 |
27-46 | 型号名称(ASCII 码) | Maxtor 4G160J8 |
49 | 位字段:位 9:支持 LBA | 0x2f00 |
53 | 位字段:位 0:字 54-58 有效 | 0x0007 |
54 | 当前柱面数 | 16383 |
55 | 当前磁头数 | 16 |
56 | 每个磁道的当前扇区数 | 63 |
57-58 | 当前 LBA 容量 | 16514064 |
60-61 | 默认 LBA 容量 | 268435455 |
82-83 | 支持的命令集 | 7c69 4f09 |
85-86 | 启用的命令集 | 7c68 0e01 |
100-103 | 48 位寻址的最大用户 LBA | 320173056 |
255 | 校验和和签名 (0xa5) | 0x44a5 |
在 ASCII 字符串中,每个字包含两个字符,高位字节在前,低位字节在后。32 位值以低位字优先给出。字 54-58 由 INITIALIZE DRIVE PARAMETERS (0x91) 命令设置。它们仅在使用 CHS 寻址时才重要,但如果磁盘将 DefaultCHS 设置为 4092/16/63 以避免 BIOS 问题,则可能有助于查找实际磁盘大小。
有时,当跳线导致大容量驱动器错误报告 LBAcapacity(通常为 66055248 扇区,以保持在 33.8 GB 限制以下)时,需要第四个信息片段来查找实际磁盘大小,即 READ NATIVE MAX ADDRESS (0xf8) 命令的结果。
SCSI 的情况略有不同,因为 SCSI 命令已经使用逻辑块号,因此“几何结构”对于实际 I/O 完全无关紧要。但是,分区表的格式仍然相同,因此 fdisk
必须发明一些几何结构,并且也在此处使用 HDIO_GETGEO
- 实际上,fdisk
不区分 IDE 和 SCSI 磁盘。从下面的详细描述可以看出,各种驱动程序各自发明了略有不同的几何结构。确实是一团糟。
如果您不使用 DOS 或类似系统,那么请避免所有扩展转换设置,并且尽可能只使用 64 个磁头,每个磁道 32 个扇区(为了方便的每个柱面 1 MiB),这样当您将磁盘从一个控制器移动到另一个控制器时就不会出现问题。一些 SCSI 磁盘驱动程序 (aha152x, pas16, ppa, qlogicfas, qlogicisp) 对 DOS 兼容性过于紧张,以至于它们不允许仅 Linux 系统使用超过约 8 GiB 的空间。这是一个错误。
真实的几何结构是什么?最简单的答案是没有这样的东西。即使有,您也不想知道,并且绝对、永远不要告诉 fdisk
或 LILO 或内核关于它的信息。这完全是 SCSI 控制器和磁盘之间的事情。让我重复一遍:只有傻瓜才会告诉 fdisk
/LILO/内核关于真实的 SCSI 磁盘几何结构。
但如果您好奇并坚持,您可以询问磁盘本身。有一个重要的命令 READ CAPACITY,它将给出磁盘的总大小,还有一个 MODE SENSE 命令,它在 Rigid Disk Drive Geometry Page(第 04 页)中给出柱面数和磁头数(这是无法更改的信息),在 Format Page(第 03 页)中给出每扇区字节数和每磁道扇区数。后一个数字通常取决于刻槽,并且每磁道扇区数是变化的 - 外磁道比内磁道具有更多的扇区。Linux 程序 scsiinfo
将提供此信息。有很多细节和复杂性,很明显没有人(可能甚至操作系统)想要使用此信息。此外,只要我们只关心 fdisk
和 LILO,通常会得到像 C/H/S=4476/27/171 这样的答案 - fdisk
无法使用这些值,因为分区表仅为 C/H/S 保留 10 位、8 位和 6 位。
那么内核 HDIO_GETGEO
从哪里获取其信息呢?嗯,要么来自 SCSI 控制器,要么通过做出有根据的猜测。一些驱动程序似乎认为我们想知道“现实”,但当然我们只想知道 DOS 或 OS/2 FDISK(或 Adaptec AFDISK 等)将使用什么。
请注意,Linux fdisk
需要磁头数 H 和每磁道扇区数 S,才能将 LBA 扇区号转换为 c/h/s 地址,但柱面数 C 在此转换中不起作用。一些驱动程序使用 (C,H,S) = (1023,255,63) 来表示驱动器容量至少为 1023*
255*
63 个扇区。这是不幸的,因为它没有揭示实际大小,并将大多数 fdisk
版本的用户限制为大约 8 GiB 的磁盘空间 - 在今天这是一个真正的限制。
在下面的描述中,M 表示总磁盘容量,C、H、S 分别表示柱面数、磁头数和每磁道扇区数。如果我们认为 C 由 M / (H*
S) 定义,则给出 H、S 就足够了。
默认情况下,H=64,S=32。
H=64,S=32。
H=64,S=32,除非 C > 1024,在这种情况下 H=255,S=63,C = min(1023, M/(H*
S))。(因此 C 被截断,并且 H*
S*
C 不是磁盘容量 M 的近似值。这将使大多数版本的 fdisk
感到困惑。)ppa.c
代码使用 M+1 而不是 M,并表示由于 sd.c
中的错误,M 偏移了 1。
H=64,S=32,除非 C > 1024,并且 BIOS 中启用了“> 1 GB”选项,在这种情况下 H=255,S=63。
询问控制器正在使用哪种可能的转换方案,并使用 H=255,S=63 或 H=64,S=32。在前一种情况下,会有一条启动消息“aha1542.c: Using extended bios translation”。
H=64,S=32,除非 C > 1024,并且给出了“extended”启动参数,或者在 SEEPROM 或 BIOS 中设置了“extended”位,在这种情况下 H=255,S=63。在 Linux 2.0.36 中,如果未找到 SEEPROM,则始终会设置此扩展转换,但在 Linux 2.2.6 中,如果未找到 SEEPROM,则仅当用户使用此启动参数要求时才设置扩展转换(而当找到 SEEPROM 时,启动参数将被忽略)。这意味着在 2.0.36 下工作的设置可能无法在 2.2.6 下启动(并且需要 LILO 的 linear
关键字,或 aic7xxx=extended
内核启动参数)。
H=64,S=32,除非 C >= 1024,并且在控制器上启用了扩展转换,在这种情况下,如果 M < 2^22,则 H=128,S=32;否则 H=255,S=63。但是,在为此 (C,H,S) 做出选择后,将读取分区表,如果对于三种可能性 (H,S) = (64,32)、(128,32)、(255,63) 之一,在某处看到值 endH=H-1,则使用该对 (H,S),并打印启动消息“Adopting Geometry from Partition Table”。
在 BIOS 驱动器参数表中查找几何结构信息,或读取分区表并对第一个分区使用 H=endH+1,S=endS(如果它非空),或者对于 M < 2^21 (1 GiB) 使用 H=64,S=32,对于 M < 63*
2^17 (3.9 GiB) 使用 H=128,S=63,否则使用 H=255,S=63。
使用 (H,S) = (64,32)、(64,63)、(128,63)、(255,63) 中的第一个,这将使 C <= 1024。在最后一种情况下,将 C 截断为 1023。
从磁盘读取 C、H、S。(恐怖!)如果 C 或 S 太大,则设置 S=17,H=2 并将 H 加倍,直到 C <= 1024。这意味着如果 M > 128*
1024*
17 (1.1 GiB),则 H 将设置为 0。这是一个错误。
根据控制器映射模式,使用三种映射之一 ((H,S) = (16,63)、(64,32)、(64,63))。
查看分区表。由于按照惯例,分区在柱面边界处结束,因此,给定任何分区的 end = (endC,endH,endS)
,我们可以直接设置 H = endH+1
和 S = endS
。(回想一下,扇区从 1 开始计数。)更准确地说,执行以下操作。如果存在非空分区,则选择具有最大 beginC
的分区。对于该分区,查看 end+1
,通过添加 start
和 length
计算,以及通过假设此分区在柱面边界处结束来计算。如果两个值一致,或者如果 endC
= 1023 并且 start+length
是 (endH+1)
的整数倍,则假设此分区确实与柱面边界对齐,并将 H = *
endSendH+1
和 S = endS
。如果这失败,要么是因为没有分区,要么是因为它们具有奇怪的大小,则仅查看磁盘容量 M。算法:设置 H = M/(62*
1024)(向上舍入),S = M/(1024*
H)(向上舍入),C = M/(H*
S)(向下舍入)。这具有产生 (C,H,S) 的效果,其中 C 最大为 1024,S 最大为 62。