Modules/ATA - (minor) Updated commenting
[tpg/acess2.git] / KernelLand / Modules / Storage / ATA / io.c
index 0ed5e37..8b2d1b7 100644 (file)
@@ -9,6 +9,8 @@
 #include <modules.h>   // Needed for error codes
 #include <drv_pci.h>
 #include "common.h"
+#include <events.h>
+#include <timers.h>
 
 // === MACROS ===
 #define IO_DELAY()     do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0)
@@ -95,10 +97,11 @@ Uint8       *gATA_BusMasterBasePtr; //!< Paging Mapped MMIO (If needed)
  int   gATA_IRQPri = 14;
  int   gATA_IRQSec = 15;
 volatile int   gaATA_IRQs[2] = {0};
+tThread        *gATA_WaitingThreads[2];
 // - Locks to avoid tripping
 tMutex glaATA_ControllerLock[2];
 // - Buffers!
-Uint8  gATA_Buffers[2][(MAX_DMA_SECTORS+0xFFF)&~0xFFF] __attribute__ ((section(".padata")));
+void   *gATA_Buffers[2];
 // - PRDTs
 tPRDT_Ent      gATA_PRDTs[2] = {
        {0, 512, IDE_PRDT_LAST},
@@ -121,7 +124,7 @@ int ATA_SetupIO(void)
        LOG("ent = %i", ent);
        gATA_BusMasterBase = PCI_GetBAR(ent, 4);
        if( gATA_BusMasterBase == 0 ) {
-               Log_Warning("ATA", "It seems that there is no Bus Master Controller on this machine. Get one");
+               Log_Warning("ATA", "Unable to find a Bus Master DMA controller");
                // TODO: Use PIO mode instead
                LEAVE('i', MODULE_ERR_NOTNEEDED);
                return MODULE_ERR_NOTNEEDED;
@@ -129,36 +132,70 @@ int ATA_SetupIO(void)
        
        LOG("BAR5 = 0x%x", PCI_GetBAR(ent, 5));
        LOG("IRQ = %i", PCI_GetIRQ(ent));
+
+       // Ensure controllers are present where we think they should be
+       for( int i = 0; i < 2; i ++ )
+       {
+               Uint16  base = ATA_GetBasePort( i*2 );
+               // Send Disk Selector
+               outb(base+6, 0xA0);
+               IO_DELAY();
+               // Check for a floating bus
+               if( 0xFF == inb(base+7) ) {
+                       Log_Error("ATA", "Floating bus at address 0x%x", base+7);
+                       LEAVE('i', MODULE_ERR_MISC);
+                       return MODULE_ERR_MISC;
+               }
+       
+               // Check for the controller
+               // - Write to two RW ports and attempt to read back
+               outb(base+0x02, 0x66);
+               outb(base+0x03, 0xFF);
+               if(inb(base+0x02) != 0x66 || inb(base+0x03) != 0xFF) {
+                       Log_Error("ATA", "Unable to write to 0x%x/0x%x", base+2, base+3);
+                       LEAVE('i', MODULE_ERR_MISC);
+                       return MODULE_ERR_MISC;
+               }
+       }
        
        // Map memory
-       if( !(gATA_BusMasterBase & 1) )
+       if( gATA_BusMasterBase & 1 )
        {
-               if( gATA_BusMasterBase < 0x100000 )
-                       gATA_BusMasterBasePtr = (void*)(KERNEL_BASE | (tVAddr)gATA_BusMasterBase);
-               else
-                       gATA_BusMasterBasePtr = (void*)( MM_MapHWPages( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
-               LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr);
+               gATA_BusMasterBase &= ~1;
+               LOG("gATA_BusMasterBase = IO 0x%x", gATA_BusMasterBase);
        }
-       else {
-               // Bit 0 is left set as a flag to other functions
-               LOG("gATA_BusMasterBase = IO 0x%x", gATA_BusMasterBase & ~1);
+       else
+       {
+               // MMIO
+               gATA_BusMasterBasePtr = MM_MapHWPages( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF);
+               LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr);
        }
 
        // Register IRQs and get Buffers
        IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri, NULL );
        IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec, NULL );
 
-       gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( &gATA_Buffers[0] );
-       gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( &gATA_Buffers[1] );
+       tPAddr  paddr;
+       gATA_Buffers[0] = (void*)MM_AllocDMA(1, 32, &paddr);
+       gATA_PRDTs[0].PBufAddr = paddr;
+       gATA_Buffers[1] = (void*)MM_AllocDMA(1, 32, &paddr);
+       gATA_PRDTs[1].PBufAddr = paddr;
 
        LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
 
        gaATA_PRDT_PAddrs[0] = MM_GetPhysAddr( &gATA_PRDTs[0] );
-       LOG("gaATA_PRDT_PAddrs[0] = 0x%x", gaATA_PRDT_PAddrs[0]);
-       ATA_int_BusMasterWriteDWord(4, gaATA_PRDT_PAddrs[0]);
-       
        gaATA_PRDT_PAddrs[1] = MM_GetPhysAddr( &gATA_PRDTs[1] );
-       LOG("gaATA_PRDT_PAddrs[1] = 0x%x", gaATA_PRDT_PAddrs[1]);
+       LOG("gaATA_PRDT_PAddrs = {0x%P, 0x%P}", gaATA_PRDT_PAddrs[0], gaATA_PRDT_PAddrs[1]);
+       #if PHYS_BITS > 32
+       // Ensure that this is within 32-bits
+       if( gaATA_PRDT_PAddrs[0] >> 32 || gaATA_PRDT_PAddrs[1] >> 32 ) {
+               Log_Error("ATA", "Physical addresses of PRDTs are not in 32-bits (%P and %P)",
+                       gaATA_PRDT_PAddrs[0], gaATA_PRDT_PAddrs[1]);
+               LEAVE('i', MODULE_ERR_MISC);
+               return MODULE_ERR_MISC;
+       }
+       #endif
+       ATA_int_BusMasterWriteDWord(4, gaATA_PRDT_PAddrs[0]);
        ATA_int_BusMasterWriteDWord(12, gaATA_PRDT_PAddrs[1]);
 
        // Enable controllers
@@ -191,35 +228,16 @@ Uint64 ATA_GetDiskSize(int Disk)
        }       data;
        Uint16  base;
        Uint8   val;
-        int    i;
+
        ENTER("iDisk", Disk);
 
        base = ATA_GetBasePort( Disk );
 
        // Send Disk Selector
-       if(Disk & 1)    // Slave
-               outb(base+6, 0xB0);
-       else    // Master
-               outb(base+6, 0xA0);
+       // - Slave / Master
+       outb(base+6, 0xA0 | (Disk & 1) << 4);
        IO_DELAY();
        
-       // Check for a floating bus
-       if( 0xFF == inb(base+7) ) {
-               LOG("Floating bus");
-               LEAVE('i', 0);
-               return 0;
-       }
-       
-       // Check for the controller
-       // - Write to two RW ports and attempt to read back
-       outb(base+0x02, 0x66);
-       outb(base+0x03, 0xFF);
-       if(inb(base+0x02) != 0x66 || inb(base+0x03) != 0xFF) {
-               LOG("No controller");
-               LEAVE('i', 0);
-               return 0;
-       }
-
        // Send ATA IDENTIFY
        outb(base+7, HDD_IDENTIFY);
        IO_DELAY();
@@ -231,15 +249,22 @@ Uint64 ATA_GetDiskSize(int Disk)
        }
 
        // Poll until BSY clears or ERR is set
+       tTime   endtime = now() + 2*1000;       // 2 second timeout
        // TODO: Timeout?
-       while( (val & 0x80) && !(val & 1) )
+       while( (val & 0x80) && !(val & 1) && now() < endtime )
                val = inb(base+7);
        LOG("BSY unset (0x%x)", val);
        // and, wait for DRQ to set
-       while( !(val & 0x08) && !(val & 1))
+       while( !(val & 0x08) && !(val & 1) && now() < endtime )
                val = inb(base+7);
        LOG("DRQ set (0x%x)", val);
 
+       if(now() >= endtime) {
+               Log_Warning("ATA", "Timeout on ATA IDENTIFY (Disk %i)", Disk);
+               LEAVE('i', 0);
+               return 0;
+       }
+
        // Check for an error
        if(val & 1) {
                LEAVE('i', 0);
@@ -247,7 +272,7 @@ Uint64 ATA_GetDiskSize(int Disk)
        }
 
        // Read Data
-       for( i = 0; i < 256; i++ )
+       for( int i = 0; i < 256; i++ )
                data.buf[i] = inw(base);
 
        // Return the disk size
@@ -275,22 +300,18 @@ Uint16 ATA_GetBasePort(int Disk)
        return 0;
 }
 
-/**
- * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
- * \return Boolean Failure
- */
-int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+int ATA_DoDMA(Uint8 Disk, Uint64 Address, Uint Count, int bWrite, void *Buffer)
 {
         int    cont = (Disk>>1)&1;     // Controller ID
         int    disk = Disk & 1;
        Uint16  base;
-       Sint64  timeoutTime;
+        int    bUseBounceBuffer = 0;
 
-       ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer);
+       ENTER("iDisk XAddress iCount bbWrite pBuffer", Disk, Address, Count, bWrite, Buffer);
 
        // Check if the count is small enough
        if(Count > MAX_DMA_SECTORS) {
-               Log_Warning("ATA", "Passed too many sectors for a bulk DMA read (%i > %i)",
+               Log_Warning("ATA", "Passed too many sectors for a bulk DMA (%i > %i)",
                        Count, MAX_DMA_SECTORS);
                LEAVE('i');
                return 1;
@@ -306,6 +327,35 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
 
        // Set Size
        gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
+       
+       // Detemine if the transfer can be done directly
+       tPAddr  buf_ps = MM_GetPhysAddr(Buffer);
+       tPAddr  buf_pe = MM_GetPhysAddr((char*)Buffer + Count * SECTOR_SIZE - 1);
+       if( buf_pe == buf_ps + Count * SECTOR_SIZE - 1 ) {
+               // Contiguous, nice
+               #if PHYS_BITS > 32
+               if( buf_pe >> 32 ) {
+                       // Over 32-bits, need to copy anyway
+                       bUseBounceBuffer = 1;
+                       LOG("%P over 32-bit, using bounce buffer", buf_pe);
+               }
+               #endif
+       }
+       else {
+               // TODO: Handle splitting the read into two?
+               bUseBounceBuffer = 1;
+               LOG("%P + 0x%x != %P, using bounce buffer", buf_ps, Count * SECTOR_SIZE, buf_pe);
+       }
+
+       // Set up destination / source buffers
+       if( bUseBounceBuffer ) {
+               gATA_PRDTs[cont].PBufAddr = MM_GetPhysAddr(gATA_Buffers[cont]);
+               if( bWrite )
+                       memcpy(gATA_Buffers[cont], Buffer, Count * SECTOR_SIZE);
+       }
+       else {
+               gATA_PRDTs[cont].PBufAddr = MM_GetPhysAddr(Buffer);
+       }
 
        // Get Port Base
        base = ATA_GetBasePort(Disk);
@@ -313,6 +363,8 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
        // Reset IRQ Flag
        gaATA_IRQs[cont] = 0;
 
+       
+       // TODO: What the ____ does this do?
        #if 1
        if( cont == 0 ) {
                outb(IDE_PRI_CTRL, 4);
@@ -358,26 +410,29 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
        
        LOG("gATA_PRDTs[%i].Bytes = %i", cont, gATA_PRDTs[cont].Bytes);
        if( Address > 0x0FFFFFFF )
-               outb(base+0x07, HDD_DMA_R48);   // Read Command (LBA48)
+               outb(base+0x07, bWrite ? HDD_DMA_W48 : HDD_DMA_R48);    // Command (LBA48)
        else
-               outb(base+0x07, HDD_DMA_R28);   // Read Command (LBA28)
+               outb(base+0x07, bWrite ? HDD_DMA_W28 : HDD_DMA_R28);    // Command (LBA28)
 
+       // Intialise timeout timer
+       Threads_ClearEvent(THREAD_EVENT_SHORTWAIT|THREAD_EVENT_TIMER);
+       tTimer *timeout = Time_AllocateTimer(NULL, NULL);
+       Time_ScheduleTimer(timeout, ATA_TIMEOUT);
+       gATA_WaitingThreads[cont] = Proc_GetCurThread();
+       
        // Start transfer
-       ATA_int_BusMasterWriteByte( cont * 8, 9 );      // Read and start
+       ATA_int_BusMasterWriteByte( cont * 8, (bWrite ? 0 : 8) | 1 );   // Write(0)/Read(8) and start
 
        // Wait for transfer to complete
-       timeoutTime = now() + ATA_TIMEOUT;
-       while( gaATA_IRQs[cont] == 0 && now() < timeoutTime)
-       {
-               HALT();
-       }
-       
-       if( now() >= timeoutTime ) {
+       Uint32 ev = Threads_WaitEvents(THREAD_EVENT_SHORTWAIT|THREAD_EVENT_TIMER);
+       Time_FreeTimer(timeout);
+
+       if( ev & THREAD_EVENT_TIMER ) {
                Log_Notice("ATA", "Timeout of %i ms exceeded", ATA_TIMEOUT);
        }
 
        // Complete Transfer
-       ATA_int_BusMasterWriteByte( cont * 8, 8 );      // Read and stop
+       ATA_int_BusMasterWriteByte( cont * 8, (bWrite ? 0 : 8) );       // Write/Read and stop
 
        #if DEBUG
        {
@@ -394,10 +449,7 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
                if( ATA_int_BusMasterReadByte(cont * 8 + 2) & 0x4 ) {
                        Log_Error("ATA", "BM Status reports an interrupt, but none recieved");
                        ATA_int_BusMasterWriteByte(cont*8 + 2, 4);      // Clear interrupt
-                       memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
-                       Mutex_Release( &glaATA_ControllerLock[ cont ] );
-                       LEAVE('i', 0);
-                       return 0;
+                       goto _success;
                }
 
                #if 1
@@ -407,24 +459,35 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
                // Release controller lock
                Mutex_Release( &glaATA_ControllerLock[ cont ] );
                Log_Warning("ATA",
-                       "Read timeout on disk %i (Reading sector 0x%llx)",
-                       Disk, Address);
+                       "Timeout on disk %i (%s sector 0x%llx)",
+                       Disk, bWrite ? "Writing" : "Reading", Address);
                // Return error
                LEAVE('i', 1);
                return 1;
        }
-       else {
-               LOG("Transfer Completed & Acknowledged");
-               // Copy to destination buffer
+       
+       LOG("Transfer Completed & Acknowledged");
+_success:
+       // Copy to destination buffer (if bounce was used and it was a read)
+       if( bUseBounceBuffer && !bWrite )
                memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
-               // Release controller lock
-               Mutex_Release( &glaATA_ControllerLock[ cont ] );
+       // Release controller lock
+       Mutex_Release( &glaATA_ControllerLock[ cont ] );
 
-               LEAVE('i', 0);
-               return 0;
-       }
+       LEAVE('i', 0);
+       return 0;
 }
 
+/**
+ * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+ * \return Boolean Failure
+ */
+int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+{
+       return ATA_DoDMA(Disk, Address, Count, 0, Buffer);
+}
+
+
 /**
  * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
  * \brief Write up to \a MAX_DMA_SECTORS to a disk
@@ -436,77 +499,7 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
  */
 int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer)
 {
-        int    cont = (Disk>>1)&1;     // Controller ID
-        int    disk = Disk & 1;
-       Uint16  base;
-       Sint64  timeoutTime;
-
-       // Check if the count is small enough
-       if(Count > MAX_DMA_SECTORS)     return 1;
-
-       // Get exclusive access to the disk controller
-       Mutex_Acquire( &glaATA_ControllerLock[ cont ] );
-
-       // Set Size
-       gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
-
-       // Get Port Base
-       base = ATA_GetBasePort(Disk);
-
-       // Reset IRQ Flag
-       gaATA_IRQs[cont] = 0;
-       
-       // Set up transfer
-       outb(base+0x01, 0x00);
-       if( Address > 0x0FFFFFFF )      // Use LBA48
-       {
-               outb(base+0x6, 0x40 | (disk << 4));
-               outb(base+0x2, 0 >> 8); // Upper Sector Count
-               outb(base+0x3, Address >> 24);  // Low 2 Addr
-               outb(base+0x3, Address >> 28);  // Mid 2 Addr
-               outb(base+0x3, Address >> 32);  // High 2 Addr
-       }
-       else
-       {
-               // Magic, Disk, High Address nibble
-               outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F));
-       }
-
-       outb(base+0x02, (Uint8) Count);         // Sector Count
-       outb(base+0x03, (Uint8) Address);               // Low Addr
-       outb(base+0x04, (Uint8) (Address >> 8));        // Middle Addr
-       outb(base+0x05, (Uint8) (Address >> 16));       // High Addr
-       if( Address > 0x0FFFFFFF )
-               outb(base+0x07, HDD_DMA_W48);   // Write Command (LBA48)
-       else
-               outb(base+0x07, HDD_DMA_W28);   // Write Command (LBA28)
-
-       // Copy to output buffer
-       memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE );
-
-       // Start transfer
-       ATA_int_BusMasterWriteByte( cont << 3, 1 );     // Write and start
-
-       // Wait for transfer to complete
-       timeoutTime = now() + ATA_TIMEOUT;
-       while( gaATA_IRQs[cont] == 0 && now() < timeoutTime)
-       {
-               HALT();
-       }
-
-       // Complete Transfer
-       ATA_int_BusMasterWriteByte( cont << 3, 0 );     // Write and stop
-
-       // If the IRQ is unset, return error
-       if( gaATA_IRQs[cont] == 0 ) {
-               // Release controller lock
-               Mutex_Release( &glaATA_ControllerLock[ cont ] );
-               return 1;       // Error
-       }
-       else {
-               Mutex_Release( &glaATA_ControllerLock[ cont ] );
-               return 0;
-       }
+       return ATA_DoDMA(Disk, Address, Count, 1, (void*)Buffer);
 }
 
 /**
@@ -519,10 +512,12 @@ void ATA_IRQHandlerPri(int UNUSED(IRQ), void *UNUSED(Ptr))
        // IRQ bit set for Primary Controller
        val = ATA_int_BusMasterReadByte( 0x2 );
        LOG("IRQ val = 0x%x", val);
-       if(val & 4) {
+       if(val & 4)
+       {
                LOG("IRQ hit (val = 0x%x)", val);
                ATA_int_BusMasterWriteByte( 0x2, 4 );
                gaATA_IRQs[0] = 1;
+               Threads_PostEvent(gATA_WaitingThreads[0], THREAD_EVENT_SHORTWAIT);
                return ;
        }
 }
@@ -540,6 +535,7 @@ void ATA_IRQHandlerSec(int UNUSED(IRQ), void *UNUSED(Ptr))
                LOG("IRQ hit (val = 0x%x)", val);
                ATA_int_BusMasterWriteByte( 0xA, 4 );
                gaATA_IRQs[1] = 1;
+               Threads_PostEvent(gATA_WaitingThreads[1], THREAD_EVENT_SHORTWAIT);
                return ;
        }
 }
@@ -550,10 +546,10 @@ void ATA_IRQHandlerSec(int UNUSED(IRQ), void *UNUSED(Ptr))
  */
 Uint8 ATA_int_BusMasterReadByte(int Ofs)
 {
-       if( gATA_BusMasterBase & 1 )
-               return inb( (gATA_BusMasterBase & ~1) + Ofs );
-       else
+       if( gATA_BusMasterBasePtr )
                return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
+       else
+               return inb( gATA_BusMasterBase + Ofs );
 }
 
 /**
@@ -562,10 +558,10 @@ Uint8 ATA_int_BusMasterReadByte(int Ofs)
  */
 Uint32 ATA_int_BusMasterReadDWord(int Ofs)
 {
-       if( gATA_BusMasterBase & 1 )
-               return ind( (gATA_BusMasterBase & ~1) + Ofs );
-       else
+       if( gATA_BusMasterBasePtr )
                return *(Uint32*)(gATA_BusMasterBasePtr + Ofs);
+       else
+               return ind( gATA_BusMasterBase + Ofs );
 }
 
 /**
@@ -575,10 +571,10 @@ Uint32 ATA_int_BusMasterReadDWord(int Ofs)
  */
 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
 {
-       if( gATA_BusMasterBase & 1 )
-               outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
-       else
+       if( gATA_BusMasterBasePtr )
                *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
+       else
+               outb( gATA_BusMasterBase + Ofs, Value );
 }
 
 /**
@@ -588,8 +584,8 @@ void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
  */
 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
 {
-       if( gATA_BusMasterBase & 1 )
-               outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
-       else
+       if( gATA_BusMasterBasePtr )
                *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value;
+       else
+               outd( gATA_BusMasterBase + Ofs, Value );
 }

UCC git Repository :: git.ucc.asn.au