ATA/ATAPI using DMA problem with the PRD Table

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
Freddy
Posts: 8
Joined: Sat May 15, 2010 9:52 am

ATA/ATAPI using DMA problem with the PRD Table

Post by Freddy »

Hi

I am trying to program an cd Driver who uses Dma to recieve datas from the CD. Therefore I tried to set up the prdt table with that code:

This is for the second ATA Channel

Code: Select all

  ..........
          unsigned long addrr_bar4 =  results[0].pci_device->bar4;
  ................
          else if((addrr_bar4 & 0x1) == 1)

         {

            //Save start port in an var  and add the offset (Secondary ATA bus)

            int port = (addrr_bar4 & 0xFFFFFFFC) + 8; 

            //Go to the port to which we have to send the ptr table address

            port+=7;

            //make sure it is an DWORD and store the address into the var address

            unsigned long address_of_ptr = (int)ptr_table &  0xFFFFFFFF;

            //Send the first byte of the address 

            outportb(port, address_of_ptr & 0xFF);

            port--;

            //Send the second byte of the address

            outportb(port, (address_of_ptr >> 8)& 0xFF);

            port--;

            outportb(port, (address_of_ptr >> 16)& 0xFF);

            port--;

            //Send the last byte

            outportb(port,(address_of_ptr >>24) & 0xFF); 
            //Set Command byte. To start and write        

            outportb((addrr_bar4 & 0xFFFFFFFC) + 8,  0x81 & 0xFF); 

          }

That code I used to set up the ptrd table

Code: Select all

void DMA::setup_ptr_table(uint8_t count, unsigned long memory_space)

{

        



     //set the value of the ptr table. Memory Space is the first DWORD. Count the next Word. Next word Reservt for MSB    

     //I was not sure if an unsigned char pointer can store an unsigned long var. So I wrote this. If he can only



     *(ptr_table+3) = (unsigned char)(memory_space & 0xFF);
     *(ptr_table+2) = (unsigned char)(memory_space >> 8);
     *(ptr_table+1) = (unsigned char) (memory_space >> 16);              

     *ptr_table     = (unsigned char) (memory_space >> 24);

     
     //Set the next DWORD. First 16 bit are 0 (reserver MSB). The next is the count. A count of 0 means 64 k 

     //I was not sure if an unsigned char pointer can store an unsigned long var. So I wrote this. If he can only

     *(ptr_table+5) = (unsigned char) (count & 0xff);
     *(ptr_table +4) = (unsigned char)(count >> 8);

     

     //Set MSB

     *(ptr_table+6) = 0x00;

     *(ptr_table+7) = 0x00;
     *(ptr_table+8) = '\0';  

    

}
The function which return false;

Code: Select all

bool DMA::check_fail(int ata_bus) 

{



     //Read the two words of the BAR4 register 

     unsigned long addrr_bar4 =  results[0].pci_device->bar4;

     unsigned char* status_address; 

     unsigned long base_port;

     if((addrr_bar4 & 0x1 ) == 0) {

       status_address = (unsigned char *)(addrr_bar4 & 0xFFFFFFF0); 

       if(ata_bus == 1) {

         if(status_address[2] & 0x2 == 2)

                return false;    

       }  

       else { 

         if(status_address[10] & 0x2 == 2) 

            return false;

       }  

     }    

     else {

       base_port =  (addrr_bar4 & 0xFFFFFFFC);

       if (ata_bus == 1)  

       	 base_port += 2;

       else 

         base_port += 10;

                

       unsigned char staus_register = inportb(base_port);

       if(staus_register & 0x2 == 2)

         return false;  

                   

     }

     return true;

}
Does anyone know why the transfer fail ??
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: ATA/ATAPI using DMA problem with the PRD Table

Post by pcmattman »

Are you using virtual memory at all? If so, you need to use a physical address when talking to the device, and a virtual address when manipulating the data. DMA doesn't go through the MMU - it hits the memory directly.
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: ATA/ATAPI using DMA problem with the PRD Table

Post by bewing »

Did you get the basic driver running in PIO mode before you tried using DMA? Is this on real hardware, or in an emulator?
Freddy
Posts: 8
Joined: Sat May 15, 2010 9:52 am

Re: ATA/ATAPI using DMA problem with the PRD Table

Post by Freddy »

Thanks for the response
bewing wrote:Is this on real hardware, or in an emulator?
It is on an emulator:
QEMU PC emulator version 0.12.3 (qemu-kvm-0.12.3), Copyright (c) 2003-2008 Fabrice Bellard
bewing wrote:Did you get the basic driver running in PIO mode before you tried using DMA?
I will try today to get the Driver to work in PIO mode. I will post then the result.
pcmattman wrote:Are you using virtual memory at all?
No Virtuall Memory. Paging is disable
Freddy
Posts: 8
Joined: Sat May 15, 2010 9:52 am

Re: ATA/ATAPI using DMA problem with the PRD Table

Post by Freddy »

Only to make sure that I have the table with the I/O Ports understand right and the progam only does not work because I wrote to the wrong ports :(:

Bar4: 4-Byte Aligned Base Address of Bar 4 register. (Bar 4 & 0xFFFFFFFC)

Primary IDE channel
Bar4 | is the command port
Bar 4 + 0x2 | is the Status Port
Bar 4 + 0x4 |Port to send the first Byte of the PRDT Address
Bar 4 + 0x5 | Port to send the second Byte of the PRDT Address
.......................................
Second IDE channel
Bar4 + 0x8 | is the Command I/o port
Bar4 + 0xA | is the I/O port form which I can read the Status
Bar 0xC | Port to send the first byte of the PRDT Address

.....

http://wiki.osdev.org/ATA/ATAPI_using_DMA

That is right or ?

Update: bar4 is: c001
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: ATA/ATAPI using DMA problem with the PRD Table

Post by Combuster »

Freddy wrote:Update: bar4 is: c001
I sure hope you use the actual base address of 0xc000 (see PCI)
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Freddy
Posts: 8
Joined: Sat May 15, 2010 9:52 am

Re: ATA/ATAPI using DMA problem with the PRD Table

Post by Freddy »

Combuster wrote:
Freddy wrote:Update: bar4 is: c001
I sure hope you use the actual base address of 0xc000 (see PCI)
Thanks for the response
At first I check with

Code: Select all

 if(addrr_bar4 & 0x1 == 1) 
if it is an Memory Space BAR Layout or I/O Space BAR Layout. If it is an I/O space layout I calculate addrr_bar4 & 0xFFFFFFFC to get the base port. Othercase I would calculate Bar & 0xFFFFFFF0 to get the base address .

But if bar4 has the value c001 it should be an I/O Space BAR Layout

Right ?
User avatar
thepowersgang
Member
Member
Posts: 734
Joined: Tue Dec 25, 2007 6:03 am
Libera.chat IRC: thePowersGang
Location: Perth, Western Australia
Contact:

Re: ATA/ATAPI using DMA problem with the PRD Table

Post by thepowersgang »

yes it should be (also, that C code is wrong, the & operator has a lower precedence than == for some reason, so the correct code is (addrr_bar4 & 0x1) == 1
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
User avatar
Owen
Member
Member
Posts: 1700
Joined: Fri Jun 13, 2008 3:21 pm
Location: Cambridge, United Kingdom
Contact:

Re: ATA/ATAPI using DMA problem with the PRD Table

Post by Owen »

The reason is quite obvious when one looks at history: BCPL had no && operator, so bitwise and was abused as a logical and.

Of course, we are now stuck with the stupidity, as changing that would break code.
Freddy
Posts: 8
Joined: Sat May 15, 2010 9:52 am

Re: ATA/ATAPI using DMA problem with the PRD Table

Post by Freddy »

thepowersgang wrote:yes it should be (also, that C code is wrong, the & operator has a lower precedence than == for some reason, so the correct code is (addrr_bar4 & 0x1) == 1
I uses it right for checking if it is Memory Mapt or an I/O port but for the function which check for an error in DMA I forgot the () . Thx did not know that :(.

There was some other errors in the code and I make it easier (I use union now). I did not get the cd Driver to work right now but no function which check if with DMA everything work right "return false" (I hope there are no errors in these functions) :D. So I think with DMA is now everything right. If I get other problems with DMA I will repost. THX to all
Freddy
Posts: 8
Joined: Sat May 15, 2010 9:52 am

Re: ATA/ATAPI using DMA problem with the PRD Table

Post by Freddy »

Hi
i did not get an IRQ after I send the atapi read command(0xA8). I think the reason for that is that the 0x3C PCI register has the value 0xffffff.. So no conection with the Interrupt Line. But also the Bit 0 of the Status register did not change to 0, which means last entry of prdt table is read.

Can someone pls check if my error methods are so far right so that I really know that with DMA is all right. And I have to search the error in Atapi :(
Bit 1 (value = 2) is set if any DMA memory transfer failed for any reason in this PRDT.

Code: Select all

..................
       base_port =  (addrr_bar4 & 0xFFFFFFFC);

       if (ata_bus == 1)  

       	 base_port += 2;

       else 

         base_port += 10;

                

       unsigned char staus_register = (inportb(base_port)  & 0x2);

       if(staus_register == 2)

         return false;  

Bit 0 (value = 1) is set when the bus goes into DMA mode. It is cleared when the last PRD in the table has been used up.

Code: Select all

 if((staus_register & 0x1) != 1)
Or does the transfer fail because it is not conected with the IRQ line and therefore also the first bit of the status registe will not be cleared?
Post Reply