IDE 드라이버는 구조정보를 다섯가지 다른 방법으로 얻을 수 있다. 첫번째(G_user)는 명령 라인상에서 사용자에 의한 명시 방법이다. 두번째(G_bios)는 32 bit 모드로 전환 이전, 시스템 시작시에 읽혀지는 첫째, 두번째 디스크에 대한 BIOS상의 고정된 디스크 항목 테이블이다. 세번째(G_phys)와 네번째(G_log)는 IDENTIFY 명령에 대해 IDE 컨트롤러가 의해서 반환하는 것으로, 이것은 `물리적'이거나 `현재의 논리적' 구조정보이다.
반면에, 드라이버는 구조정보에 관한 두개의 값을 필요로 한다.
한가지는 HDIO_GETGEO ioctl에 의해 반환되는 G_fdisk이고, 다른 하나는
실제적인 입출력에 사용되는 G_used이다.
G_fdisk 와 G_used 는 G_user 가 주어진 경우, G_user로 초기화 되고, CMOS에
의해 G_bios값이 제공되면 G_bios 값으로 설정된다. 마지막으로 위의 경우에
해당되지 않는 경우 G_phys로 초기화 된다.
만약 G_log가 적당한 값으로 판단되면, G_used는 이 값으로 설정된다.
그렇지 않고 G_used는 부정당해 보이며, G_phys는 적당해 보이면
G_used는 G_phys 값으로 설정된다.
여기에서 적당하다는 것은 헤드의 수가 1-16인 경우를 의미한다.
달리 말하면: 명령 라인 정보가 BIOS 정보를 덮어 씌우고
fdisk가 어떤 것을 참조할 지 결정한다. 그러나 만약 이것이 16개 헤드이상을
갖는 변환된 구조정보로 구체화 되면, 커널 입출력에 대해, IDENTIFY 명령의
출력 값에 의해 덮어 씌워진다.
G_bios는 다소 신뢰할 만하지 못하다는 것을 기억하기 바란다. : SCSI 로 부터 부팅하는 시스템의 경우 첫번째나 두번째 디스크는 SCSI 디스크일 것이다. 그리고 sda에 대해 BIOS가 제공하는 구조정보는 커널 내부에서 hda를 위해 사용된다. 게다가 BIOS 설정 단계에서 언급되는 않는 디스크들은 BIOS에 의해 보이지 않는다. 이것은 예를들어 IDE 만을 사용하는 시스템에서 hdb가 셋업 단계에서 주어지지 않은 경우 BIOS 에 의해 제공되는 첫째, 둘째 디스크의 구조정보가 hda와 hdc 에 적용된다는 것을 의미한다.
SCSI의 경우는 약간 차이가 있다. SCSI 명령이 이미 논리적인 블럭 번호를
사용하기 때문에 구조정보(Geometry)는 실제 입출력과 무관하다.
그렇지만 파티션 테이블의 유형은 여전히 동일하다. 그러므로 fdisk는 일부
구조정보를 조작해야 하며, HDIO_GETGEO 명령을 사용한다.
대신에 fdisk는 IDE와 SCSI 디스크사이에 구분을 두지 않는다.
아래의 상세한 정보로 부터 볼수 있듯이 다양한 드라이버들은 각각 조금씩
다른 구조정보를 만들어 낸다. 실제로 하나의 큰 혼합체이다.
만약 여러분이 DOS나 비슷한 유형의 운영체제를 사용하고 있지 않다면, 모든 확장 변환 설정을 피하고 가능하다면, 64개의 헤드와 트랙당 32개의 섹터 (완전하고, 편리한 설정을 위해 실린더당 1 MiB의 크기로, 64*32*512 = 1 MiB)를 사용하여라. 그러므로 디스크를 다른 컨트롤러로 이동시에도 이러한 문제가 발생하지 않도록 하여라. 몇몇 SCSI 디스크 드라이버(aha152x, pas16, ppa, qlogicfas, qlogicisp)는 DOS 호환성에 대해 매우 예민하여 8 GiB이상을 사용하는 리눅스 시스템을 허용하지 않는다. 버그다.
실제 구조정보는 무엇인가 ? 먼저 얘기하면 실제적인(real) 구조정보는
없다는 것이다.
그리고 만약이 있었더라도 여러분은 결코 알고자 하지 않았을 것이고
결코 fdisk나 LILO 또는 kernel에 그러한 정보를 전달하지 않을 것이다.
이것은 엄밀히 말해 SCSI 컨트롤러와 디스크간의 사업과 같다.
다시 얘기하면, 단지 어리석은 사용자만이 여전히 fdisk/LILO/kernel>에
SCSI 디스크의 실제 구조정보를 전달할 것이다.
그러나 여전히 호기심이 생긴다면, 디스크 자체에 정보를 요구할 수 있다. 전체 디스크의 크기 정보를 반환하는 READ CAPACITY라는 쓸만한 명령이 존재하고 Rigid Disk Driver Geometry Page에서 실린더의 수와 헤드의 수를 알려주는 Format Page에서 섹터당 바이트 크기와 트랙당 섹터의 수를 알려 주는 MODE SENSE 명령이 존재한다.
마지막 번호는 일반적으로 notch에 의존한다. 그리고 트랙당 섹터의 수는
유동적이다. 바깥쪽의 트랙은 안쪽 트랙보다 많은 수의 섹터를 갖는다.
리눅스에서 제공되는 scsiinfo 프로그램은 이러한 정보를 제공한다.
이 프로그램에는 어느 누구도 사용하길 원치 않는 복잡하고도 세부적인 내용이
들어 있다. (아마 심지어 운영체제 까지도)
게다가 우리가 fdisk나 LILO에 관심을 갖는다면, 파티션 테이블이 C/H/S를
위해 단지 각각 10, 8, 6 비트를 예약해 두었기 때문에 fdisk에서는 사용될 수
없는 C/H/S=4476/27/171과 같은 하나의 예를 찾을 수 있다.
그러면 커널의 HDIO_GETGEO는 이러한 정보를 어디에서 얻는가 ?
아마도, SCSI 컨트롤러나 입력된 논리에 의한 추측을 통해 얻을 것이다.
몇몇 드라이버는 우리가 실제값을 알고자 하는 것으로 간주하는 듯 싶지만,
우리는 단지 DOS 나 OS/2 FDISK(또는 Adaptec AFDISK나 기타 등등)가
무엇을 사용할 것인지 알고자 한다.
리눅스의 fdisk프로그램은 LBA 섹터번호를 c/h/s 주소로 변경하기 위해
트랙당 헤더(H)와 섹터의 수(S)를 필요로 한다는 것을 기억하라.
그러나 실린더의 수(C)는 위의 변환 과정에서 아무런 역할도 하지 않는다.
몇몇 드라이버들은 드라이브의 크기가 적어도 1023*255*63 sector 이상 이라는
것을 알리기 위해 (C,H,S) = (1023,255,63)을 사용한다.
이러한 방법은 실제 크기를 밝히지 않기 때문에 유감스러운 일이다.
그리고 대부분의 fdisk 프로그램은 사용자들을 약 8GiB 의 크기로 제한시킨다.
아래의 기술에서, M 은 전체 디스크 공간을 표시하며, C, H, S는 실린더,
헤드 그리고 트랙당 섹터의 수를 나타낸다.
C 값을 M / (H*S)로 정의하면, H, S 값을 할당하기에 충분하다.
기본적으로 H = 64, S = 32이다.
H=64, S=32.
C <= 1024 이고 H=64, S=32이면,
H=255, S=63이고 C 값은 1023과 M/(H*S)에서 작은 값을 택한다.
(그러므로 C 값은 절삭되고, H*S*C는 디스크 크기 M에 대한
근사값이 아니다. 이것은 대부분의 fdisk 프로그램을 혼돈스럽게 한다.)
ppa.c 코드는 M 대신에 M+1값을 사용하고, sd.c에서의 버그 때문에 M 값을
1 만큼 크게 설정한다고 얘기한다.
C <= 1024 이고 H=64, S=32 이며, BIOS 상에서 `> 1 GB' 옵션이 설정되면, H=255, S=63이 된다.
컨트롤러에서 두가지 가능한 변환방법중 어떤 방법을 사용하고 있는지 요구한다. 그리고 H=255, S=63 으로 설정하거나 H=64, S=32로 사용한다. 전자의 경우, "aha1542.c: Using extended bios translation"이라는 부팅 메세지가 나타난다.
C <= 1024, H=64, S=32이고, "extended" 부팅 파라메터가 주어지거나, SEEPROM 이나 BIOS에 `extended' 비트가 설정되는 경우 H=255, S=63을 갖는다.
C < 1024, 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를 만족하는 한가지 값이 사용된다. 그리고 부팅 메세지는 "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를 사용한다.
C <= 1024를 만족하는 첫번째 쌍을 다음에서 찾아서 사용한다. (H,S) = (64,32), (64,63), (128,63), (255,63) 마지막 경우, 1023으로 절단된다.
디스크로 부터 C,H,S 값을 읽어 들인다. (소름끼는 일이죠!)
만약 C 또는 S 가 매우 큰 경우, S=17, H=2로 설정하고
C <= 1024 일때 까지 H를 배수로 만든다.
이것은 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 에 *ensSendH+1 을 S 에 endS 를 대입한다.
이 과정이 실패하면, 실제로 파티션이 존재하지 않거나, 그들이 상이한 크기값을 갖기 때문이며, 이 경우 디스크의 용량 M 값을 확인하라.
Algorithm: H = M/(62*1024) (rounded up), S = M/(1024*H)
(rounded up), C = M/(H*S) (rounded down). 이것은 실린더가 최대 1024값을
갖고 섹터의 경우 62개를 갖는 범위내의 값으로 하는 (C, H, S)를 만들어 내는
결과를 갖는다.