Updated the build files to use $(xCP), allows use of mcopy to a mtools disk
[tpg/acess2.git] / Kernel / drv / ata_x86.c
index e64c65f..8d9e2e8 100644 (file)
@@ -2,14 +2,17 @@
  * Acess2 IDE Harddisk Driver
  * drv/ide.c
  */
-#define DEBUG  0
+#define DEBUG  1
 #include <common.h>
 #include <modules.h>
 #include <vfs.h>
 #include <fs_devfs.h>
 #include <drv_pci.h>
 #include <tpl_drv_common.h>
-#include <drvutil.h>
+#include <tpl_drv_disk.h>
+
+// --- Flags ---
+#define START_BEFORE_CMD       0
 
 // === CONSTANTS ===
 #define        MAX_ATA_DISKS   4
@@ -105,10 +108,12 @@ tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name);
 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
  int   ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
-// Disk Read
+// Read/Write Interface/Quantiser
 Uint   ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
+Uint   ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
+// Read/Write DMA
  int   ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
-// Disk Write
+ int   ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
 // IRQs
 void   ATA_IRQHandlerPri(int unused);
 void   ATA_IRQHandlerSec(int unused);
@@ -118,7 +123,7 @@ void        ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
 void   ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
 
 // === GLOBALS ===
-MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL);
+MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, NULL);
 tDevFS_Driver  gATA_DriverInfo = {
        NULL, "ata",
        {
@@ -173,15 +178,14 @@ int ATA_Install()
 int ATA_SetupIO()
 {
         int    ent;
-       Uint    addr;
+       tPAddr  addr;
        
        ENTER("");
        
        // Get IDE Controller's PCI Entry
        ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1);
-       LOG("ent = %i\n", ent);
+       LOG("ent = %i", ent);
        gATA_BusMasterBase = PCI_GetBAR4( ent );
-       LOG("gATA_BusMasterBase = 0x%x\n", gATA_BusMasterBase);
        if( gATA_BusMasterBase == 0 ) {
                Warning("It seems that there is no Bus Master Controller on this machine, get one");
                LEAVE('i', 0);
@@ -193,6 +197,11 @@ int ATA_SetupIO()
                        gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase);
                else
                        gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
+               LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr);
+       }
+       else {
+               // Bit 0 is left set as a flag to other functions
+               LOG("gATA_BusMasterBase = 0x%x", gATA_BusMasterBase & ~1);
        }
        
        IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
@@ -201,13 +210,18 @@ int ATA_SetupIO()
        gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] );
        gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] );
        
-       LOG("gATA_PRDTs = {0x%x, 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
+       LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
        
        addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] );
+       LOG("addr = 0x%x", addr);
        ATA_int_BusMasterWriteDWord(4, addr);
        addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] );
+       LOG("addr = 0x%x", addr);
        ATA_int_BusMasterWriteDWord(12, addr);
        
+       outb(IDE_PRI_BASE+1, 1);
+       outb(IDE_SEC_BASE+1, 1);
+       
        LEAVE('i', 1);
        return 1;
 }
@@ -273,8 +287,12 @@ int ATA_ScanDisk(int Disk)
         int    i;
        tVFS_Node       *node;
        
+       ENTER("iDisk", Disk);
+       
        base = ATA_GetBasePort( Disk );
        
+       LOG("base = 0x%x", base);
+       
        // Send Disk Selector
        if(Disk == 1 || Disk == 3)
                outb(base+6, 0xB0);
@@ -284,12 +302,18 @@ int ATA_ScanDisk(int Disk)
        // Send IDENTIFY
        outb(base+7, 0xEC);
        val = inb(base+7);      // Read status
-       if(val == 0)    return 0;       // Disk does not exist
+       if(val == 0) {
+               LEAVE('i', 0);
+               return 0;       // Disk does not exist
+       }
        
        // Poll until BSY clears and DRQ sets or ERR is set
        while( ((val & 0x80) || !(val & 0x08)) && !(val & 1))   val = inb(base+7);
        
-       if(val & 1)     return 0;       // Error occured, so return false
+       if(val & 1) {
+               LEAVE('i', 0);
+               return 0;       // Error occured, so return false
+       }
        
        // Read Data
        for(i=0;i<256;i++)      buf[i] = inw(base);
@@ -301,6 +325,8 @@ int ATA_ScanDisk(int Disk)
                gATA_Disks[ Disk ].Sectors = identify->Sectors28;
        
        
+       LOG("gATA_Disks[ Disk ].Sectors = 0x%x", gATA_Disks[ Disk ].Sectors);
+       
        if( gATA_Disks[ Disk ].Sectors / (2048*1024) )
                Log("Disk %i: 0x%llx Sectors (%i GiB)", Disk,
                        gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / (2048*1024));
@@ -326,11 +352,12 @@ int ATA_ScanDisk(int Disk)
                = node->CTime = now();
        
        node->Read = ATA_ReadFS;
-       //node->Write = ATA_WriteFS;
+       node->Write = ATA_WriteFS;
        node->IOCtl = ATA_IOCtl;
 
 
        // --- Scan Partitions ---
+       LOG("Reading MBR");
        // Read Boot Sector
        ATA_ReadDMA( Disk, 0, 1, mbr );
        
@@ -340,6 +367,7 @@ int ATA_ScanDisk(int Disk)
        else    // No? Just parse the MBR
                ATA_ParseMBR(Disk);
        
+       LEAVE('i', 0);
        return 1;
 }
 
@@ -362,6 +390,8 @@ void ATA_ParseMBR(int Disk)
        tMBR    mbr;
        Uint64  extendedLBA;
        
+       ENTER("iDisk", Disk);
+       
        // Read Boot Sector
        ATA_ReadDMA( Disk, 0, 1, &mbr );
        
@@ -377,6 +407,7 @@ void ATA_ParseMBR(int Disk)
                        )
                {
                        if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
+                               LOG("Extended Partition");
                                if(extendedLBA != 0) {
                                        Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
                                        continue;
@@ -384,6 +415,7 @@ void ATA_ParseMBR(int Disk)
                                extendedLBA = mbr.Parts[i].LBAStart;
                                continue;
                        }
+                       LOG("Primary Partition");
                        
                        gATA_Disks[Disk].NumPartitions ++;
                        continue;
@@ -431,6 +463,7 @@ void ATA_ParseMBR(int Disk)
                        }
                }
        }
+       LOG("gATA_Disks[Disk].NumPartitions = %i", gATA_Disks[Disk].NumPartitions);
        
        // Create patition array
        gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
@@ -439,6 +472,7 @@ void ATA_ParseMBR(int Disk)
        extendedLBA = 0;
        for( i = 0; i < 4; i ++ )
        {
+               Log("mbr.Parts[%i].SystemID = 0x%02x", i, mbr.Parts[i].SystemID);
                if( mbr.Parts[i].SystemID == 0 )        continue;
                if(     mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) // LBA 28
                {
@@ -565,6 +599,8 @@ void ATA_ParseMBR(int Disk)
                        }
                }
        }
+       
+       LEAVE('-');
 }
 
 /**
@@ -590,6 +626,7 @@ void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start
        Part->Node.ImplPtr = Part->Name;
        
        Part->Node.Read = ATA_ReadFS;
+       Part->Node.Write = ATA_WriteFS;
        Part->Node.IOCtl = ATA_IOCtl;
        LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
        LEAVE('-');
@@ -628,7 +665,11 @@ tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
        if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
                return NULL;
        // Raw Disk
-       if(Name[1] == '\0')     return &gATA_Disks[Name[0]-'A'].Node;
+       if(Name[1] == '\0') {
+               if( gATA_Disks[Name[0]-'A'].Sectors == 0 )
+                       return NULL;
+               return &gATA_Disks[Name[0]-'A'].Node;
+       }
        
        // Partitions
        if(Name[1] < '0' || '9' < Name[1])      return NULL;
@@ -683,7 +724,30 @@ Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
  */
 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
 {
-       return 0;
+        int    disk = Node->Inode >> 8;
+        int    part = Node->Inode & 0xFF;
+       
+       // Raw Disk Access
+       if(part == 0xFF)
+       {
+               if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
+                       return 0;
+               if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
+                       Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
+       }
+       // Partition
+       else
+       {
+               if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
+                       return 0;
+               if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
+                       Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
+               Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
+       }
+       
+       Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
+       Debug_HexDump("ATA_WriteFS", Buffer, Length);
+       return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
 }
 
 /**
@@ -736,7 +800,42 @@ Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
 }
 
 /**
- * \fn int ATA_ReadDMAPage(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+ * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+ */
+Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
+{
+        int    ret;
+       Uint    offset;
+       Uint    done = 0;
+        
+       // Pass straight on to ATA_WriteDMA if we can
+       if(Count <= MAX_DMA_SECTORS)
+       {
+               ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
+               if(ret == 0)    return 0;
+               return Count;
+       }
+       
+       // Else we will have to break up the transfer
+       offset = 0;
+       while(Count > MAX_DMA_SECTORS)
+       {
+               ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
+               // Check for errors
+               if(ret != 1)    return done;
+               // Change Position
+               done += MAX_DMA_SECTORS;
+               Count -= MAX_DMA_SECTORS;
+               offset += MAX_DMA_SECTORS*SECTOR_SIZE;
+       }
+       
+       ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
+       if(ret != 1)    return 0;
+       return done+Count;
+}
+
+/**
+ * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
  */
 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
 {
@@ -744,8 +843,15 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
         int    disk = Disk & 1;
        Uint16  base;
        
+       ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer);
+       
        // Check if the count is small enough
-       if(Count > MAX_DMA_SECTORS)     return 0;
+       if(Count > MAX_DMA_SECTORS) {
+               Warning("Passed too many sectors for a bulk DMA read (%i > %i)",
+                       Count, MAX_DMA_SECTORS);
+               LEAVE('i');
+               return 0;
+       }
        
        // Get exclusive access to the disk controller
        LOCK( &giaATA_ControllerLock[ cont ] );
@@ -756,6 +862,9 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
        // 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
@@ -775,16 +884,100 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
        outb(base+0x03, (Uint8) Address);               // Low Addr
        outb(base+0x04, (Uint8) (Address >> 8));        // Middle Addr
        outb(base+0x05, (Uint8) (Address >> 16));       // High Addr
+       
+       LOG("Starting Transfer");
+       #if START_BEFORE_CMD
+       // Start transfer
+       ATA_int_BusMasterWriteByte( cont << 3, 9 );     // Read and start
        if( Address > 0x0FFFFFFF )
                outb(base+0x07, HDD_DMA_R48);   // Read Command (LBA48)
        else
                outb(base+0x07, HDD_DMA_R28);   // Read Command (LBA28)
+       #else
+       if( Address > 0x0FFFFFFF )
+               outb(base+0x07, HDD_DMA_R48);   // Read Command (LBA48)
+       else
+               outb(base+0x07, HDD_DMA_R28);   // Read Command (LBA28)
+       // Start transfer
+       ATA_int_BusMasterWriteByte( cont << 3, 9 );     // Read and start
+       #endif
+       
+       // Wait for transfer to complete
+       //ATA_int_BusMasterWriteByte( (cont << 3) + 2, 0x4 );
+       while( gaATA_IRQs[cont] == 0 ) {
+               //Uint8 val = ATA_int_BusMasterReadByte( (cont << 3) + 2, 0x4 );
+               //LOG("val = 0x%02x", val);
+               Threads_Yield();
+       }
+       
+       // Complete Transfer
+       ATA_int_BusMasterWriteByte( cont << 3, 0 );     // Write and stop
+       
+       LOG("Transfer Completed & Acknowledged");
+       
+       // Copy to destination buffer
+       memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
+       
+       // Release controller lock
+       RELEASE( &giaATA_ControllerLock[ cont ] );
+       
+       LEAVE('i', 1);
+       return 1;
+}
+
+/**
+ * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+ */
+int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+{
+        int    cont = (Disk>>1)&1;     // Controller ID
+        int    disk = Disk & 1;
+       Uint16  base;
+       
+       // Check if the count is small enough
+       if(Count > MAX_DMA_SECTORS)     return 0;
+       
+       // Get exclusive access to the disk controller
+       LOCK( &giaATA_ControllerLock[ cont ] );
+       
+       // Set Size
+       gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
+       
+       // Get Port Base
+       base = ATA_GetBasePort(Disk);
+       
+       // 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
+       {
+               outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
+       }
+       
+       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)
        
        // Reset IRQ Flag
        gaATA_IRQs[cont] = 0;
        
+       // Copy to output buffer
+       memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE );
+       
        // Start transfer
-       ATA_int_BusMasterWriteByte( cont << 3, 9 );     // Read and start
+       ATA_int_BusMasterWriteByte( cont << 3, 1 );     // Write and start
        
        // Wait for transfer to complete
        while( gaATA_IRQs[cont] == 0 )  Threads_Yield();
@@ -792,9 +985,6 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
        // Complete Transfer
        ATA_int_BusMasterWriteByte( cont << 3, 0 );     // Write and stop
        
-       // Copy to destination buffer
-       memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
-       
        // Release controller lock
        RELEASE( &giaATA_ControllerLock[ cont ] );
        
@@ -810,8 +1000,9 @@ void ATA_IRQHandlerPri(int unused)
        
        // IRQ bit set for Primary Controller
        val = ATA_int_BusMasterReadByte( 0x2 );
+       LOG("IRQ val = 0x%x", val);
        if(val & 4) {
-               //Log(" ATA_IRQHandlerPri: IRQ hit (val = 0x%x)", val);
+               LOG("IRQ hit (val = 0x%x)", val);
                ATA_int_BusMasterWriteByte( 0x2, 4 );
                gaATA_IRQs[0] = 1;
                return ;
@@ -827,7 +1018,7 @@ void ATA_IRQHandlerSec(int unused)
        // IRQ bit set for Secondary Controller
        val = ATA_int_BusMasterReadByte( 0xA );
        if(val & 4) {
-               //Log(" ATA_IRQHandlerSec: IRQ hit (val = 0x%x)", val);
+               LOG("IRQ hit (val = 0x%x)", val);
                ATA_int_BusMasterWriteByte( 0xA, 4 );
                gaATA_IRQs[1] = 1;
                return ;

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