Programming ATA

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
purevoid

Programming ATA

Post by purevoid »

Hi,

We're having a few problems trying to get ATA to work.

My code is in O'Caml, so it might not be so clear to read, but I hope people can help me figure out what is wrong. I've followed the instructions in http://www.geocities.com/SiliconValley/2072/atapi.htm to implement an identify_drive command.

One thing I'm not clear on is what happens when there's no drive attached?

Anyways, it gets stuck in an infinite loop =/ Here's my code (a little big...):

Code: Select all

type controller = Primary | Secondary;;
type device = Master | Slave;;

let primary_base_address = 0x1F0
and secondary_base_address = 0x170;;

module Register = struct
   let data = 0x0
   let error = 0x1
   let features = 0x1
   let sector_count = 0x2
   let lba_low = 0x3
   let lba_mid = 0x4
   let lba_high = 0x5
   let device_head = 0x6
   let status = 0x7
   let command = 0x7
   let alt_status = 0x206
   let device_control = 0x206
end;;

module Status = struct
   let busy v = v land 1 <> 0
   let ready v = v land 2 <> 0
   let fault v = v land 4 <> 0
   let seek_complete v = v land 8 <> 0
   let transfer_req v = v land 16 <> 0
   let data_corrected v = v land 32 <> 0
   let index_mark v = v land 64 <> 0
   let error v = v land 128 <> 0
end;;

module Error = struct
   let bad_block v = v land 1 <> 0
   let uncorrectable_data v = v land 2 <> 0
   let media_changed v = v land 4 <> 0
   let id_mark_not_found v = v land 8 <> 0
   let media_change_req v = v land 16 <> 0
   let aborted v = v land 32 <> 0
   let track_0_not_found v = v land 64 <> 0
   let address_mark_not_found v = v land 128 <> 0
end;;

let rec poll f = if f () then () else poll f;;

let controller = function
| Primary -> primary_base_address
| Secondary -> secondary_base_address;;

let device = function
| Master -> 0x00
| Slave -> 0x10;;

let issue_command c command =
   poll (fun () -> not (Status.busy (Asm.in8 (controller c + Register.status))));
   Asm.cli ();
   poll (fun () -> Status.ready (Asm.in8 (controller c + Register.status)));
   let result = command () in
   Asm.sti ();
   result;;

let identify_drive c d =
   let action = (fun () ->
      Asm.out8 (controller c + Register.device_head) (device d);
      Asm.out8 (controller c + Register.command) 0x0EC; (* identify drive *)
      poll (fun () -> Status.ready (Asm.in8 (controller c + Register.status)));
      Asm.insw (controller c + Register.data) 256
   ) in
   issue_command c action;;
And my test is simply:

Code: Select all

Console.printf "IDE 0:0: %s\n" (IDE.identify_drive IDE.Primary IDE.Master);;
I've tried in Virtual PC (with a hard disk image present), and qemu -fda floppy.img -hda hda.img -boot a.

What is it that I'm doing wrong?

Jonathan
purevoid

Re:Programming ATA

Post by purevoid »

It seems the fault is in waiting for the device to be ready...

Code: Select all

poll (fun () -> Status.ready (Asm.in8 (controller c + Register.status)));
Using Register.alt_status doesn't work either.

Is my function for polling for ready flag not correct?
;If the second bit of the status register (DRDY) isn't 1, the device isn't
;ready, so keep looping until it is.
Status.ready does basically: return (v && 0x2) != 0. So, if v:2 is 0, then 0 != 0 == false...

So it should keep polling correctly. So, device is never ready? Is that meant to happen? I have to be doing something wrong =(
pradeep

Re:Programming ATA

Post by pradeep »

your code is not clear to me. But the ata atapi document you have used assumes that you are in real mode. For protected mode some changes are to be done anyway.
* After waiting for BSY flag to be cleared, put the right bit in DEVICE/head register and then issue wait for DRDY to be set.
* After writing the command you have to wait for DRQ to be set. It seems you are waiting for DRDY to be set.
Post Reply