* Acess2 IDE Harddisk Driver
* - main.c
*/
-#define DEBUG 0
+#define DEBUG 1
#include <acess.h>
#include <modules.h>
#include <vfs.h>
#include <tpl_drv_disk.h>
#include "common.h"
-// --- Flags ---
-#define START_BEFORE_CMD 0
-
// === STRUCTURES ===
typedef struct
{
} __attribute__ ((packed)) tIdentify;
// === IMPORTS ===
-extern void ATA_ParseMBR(int Disk);
+extern void ATA_ParseMBR(int Disk, tMBR *MBR);
// === PROTOTYPES ===
int ATA_Install();
void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
// === GLOBALS ===
-MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, NULL);
+MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, "PCI", NULL);
tDevFS_Driver gATA_DriverInfo = {
NULL, "ata",
{
int gATA_IRQPri = 14;
int gATA_IRQSec = 15;
int giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller
-Uint8 gATA_Buffers[2][4096] __attribute__ ((section(".padata")));
- int gaATA_IRQs[2] = {0};
+Uint8 gATA_Buffers[2][(MAX_DMA_SECTORS+0xFFF)&~0xFFF] __attribute__ ((section(".padata")));
+volatile int gaATA_IRQs[2] = {0};
tPRDT_Ent gATA_PRDTs[2] = {
{0, 512, IDE_PRDT_LAST},
{0, 512, IDE_PRDT_LAST}
int ATA_Install()
{
int ret;
-
+
ret = ATA_SetupIO();
- if(ret != 1) return ret;
-
+ if(ret) return ret;
+
ATA_SetupPartitions();
-
+
ATA_SetupVFS();
-
+
if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
- return MODULE_INIT_FAILURE;
-
- return MODULE_INIT_SUCCESS;
+ return MODULE_ERR_MISC;
+
+ return MODULE_ERR_OK;
}
/**
{
int ent;
tPAddr addr;
-
+
ENTER("");
-
+
// Get IDE Controller's PCI Entry
ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1);
LOG("ent = %i", ent);
gATA_BusMasterBase = PCI_GetBAR4( ent );
if( gATA_BusMasterBase == 0 ) {
- Warning("It seems that there is no Bus Master Controller on this machine. Get one");
- LEAVE('i', MODULE_INIT_FAILURE);
- return MODULE_INIT_FAILURE;
+ Log_Warning("ATA", "It seems that there is no Bus Master Controller on this machine. Get one");
+ // TODO: Use PIO mode instead
+ LEAVE('i', MODULE_ERR_NOTNEEDED);
+ return MODULE_ERR_NOTNEEDED;
}
+
+ // Map memory
if( !(gATA_BusMasterBase & 1) )
{
if( gATA_BusMasterBase < 0x100000 )
- gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase);
+ gATA_BusMasterBasePtr = (void*)(KERNEL_BASE | (tVAddr)gATA_BusMasterBase);
else
- gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
+ gATA_BusMasterBasePtr = (void*)( MM_MapHWPages( 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);
}
-
+
+ // Register IRQs and get Buffers
IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec );
-
- gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] );
- gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] );
-
+
+ gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[0] );
+ gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[1] );
+
LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
-
- addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] );
+
+ addr = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[0] );
LOG("addr = 0x%x", addr);
ATA_int_BusMasterWriteDWord(4, addr);
- addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] );
+ addr = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[1] );
LOG("addr = 0x%x", addr);
ATA_int_BusMasterWriteDWord(12, addr);
-
+
+ // Enable controllers
outb(IDE_PRI_BASE+1, 1);
outb(IDE_SEC_BASE+1, 1);
-
- LEAVE('i', MODULE_INIT_SUCCESS);
- return MODULE_INIT_SUCCESS;
+
+ // return
+ LEAVE('i', MODULE_ERR_OK);
+ return MODULE_ERR_OK;
}
/**
void ATA_SetupVFS()
{
int i, j, k;
-
+
// Count number of nodes needed
giATA_NumNodes = 0;
for( i = 0; i < MAX_ATA_DISKS; i++ )
giATA_NumNodes ++;
giATA_NumNodes += gATA_Disks[i].NumPartitions;
}
-
+
// Allocate Node space
gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
-
+
// Set nodes
k = 0;
for( i = 0; i < MAX_ATA_DISKS; i++ )
for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
}
-
+
gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
}
*/
int ATA_ScanDisk(int Disk)
{
- Uint16 buf[256];
- tIdentify *identify = (void*)buf;
- tMBR *mbr = (void*)buf;
+ union {
+ Uint16 buf[256];
+ tIdentify identify;
+ tMBR mbr;
+ } data;
Uint16 base;
Uint8 val;
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);
else
outb(base+6, 0xA0);
-
+
// Send IDENTIFY
outb(base+7, 0xEC);
val = inb(base+7); // Read status
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) {
LEAVE('i', 0);
return 0; // Error occured, so return false
}
-
+
// Read Data
- for(i=0;i<256;i++) buf[i] = inw(base);
-
+ for(i=0;i<256;i++) data.buf[i] = inw(base);
+
// Populate Disk Structure
- if(identify->Sectors48 != 0)
- gATA_Disks[ Disk ].Sectors = identify->Sectors48;
+ if(data.identify.Sectors48 != 0)
+ gATA_Disks[ Disk ].Sectors = data.identify.Sectors48;
else
- gATA_Disks[ Disk ].Sectors = identify->Sectors28;
-
-
+ gATA_Disks[ Disk ].Sectors = data.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));
- else if( gATA_Disks[ Disk ].Sectors / 2048 )
- Log("Disk %i: 0x%llx Sectors (%i MiB)", Disk,
- gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2048);
- else
- Log("Disk %i: 0x%llx Sectors (%i KiB)", Disk,
- gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2);
-
+
+ {
+ Uint64 val = gATA_Disks[ Disk ].Sectors / 2;
+ char *units = "KiB";
+ if( val > 4*1024 ) {
+ val /= 1024;
+ units = "MiB";
+ }
+ else if( val > 4*1024 ) {
+ val /= 1024;
+ units = "GiB";
+ }
+ else if( val > 4*1024 ) {
+ val /= 1024;
+ units = "TiB";
+ }
+ Log_Log("ATA", "Disk %i: 0x%llx Sectors (%i %s)", Disk,
+ gATA_Disks[ Disk ].Sectors, val, units);
+ }
+
// Create Name
gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
gATA_Disks[ Disk ].Name[1] = '\0';
-
+
// Get pointer to vfs node and populate it
node = &gATA_Disks[ Disk ].Node;
node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
node->NumACLs = 0; // Means Superuser only can access it
node->Inode = (Disk << 8) | 0xFF;
node->ImplPtr = gATA_Disks[ Disk ].Name;
-
+
node->ATime = node->MTime
= node->CTime = now();
-
+
node->Read = ATA_ReadFS;
node->Write = ATA_WriteFS;
node->IOCtl = ATA_IOCtl;
-
// --- Scan Partitions ---
LOG("Reading MBR");
// Read Boot Sector
- ATA_ReadDMA( Disk, 0, 1, mbr );
-
+ ATA_ReadDMA( Disk, 0, 1, &data.mbr );
+
// Check for a GPT table
- if(mbr->Parts[0].SystemID == 0xEE)
+ if(data.mbr.Parts[0].SystemID == 0xEE)
ATA_ParseGPT(Disk);
else // No? Just parse the MBR
- ATA_ParseMBR(Disk);
+ ATA_ParseMBR(Disk, &data.mbr);
+ ATA_ReadDMA( Disk, 1, 1, &data );
+ Debug_HexDump("ATA_ScanDisk", &data, 512);
+
LEAVE('i', 0);
return 1;
}
Part->Node.NumACLs = 0; // Only root can read/write raw block devices
Part->Node.Inode = (Disk << 8) | Num;
Part->Node.ImplPtr = Part->Name;
-
+
Part->Node.Read = ATA_ReadFS;
Part->Node.Write = ATA_WriteFS;
Part->Node.IOCtl = ATA_IOCtl;
+ Log_Notice("ATA", "Note '%s' at 0x%llx, 0x%llx long", Part->Name, Part->Start, Part->Length);
LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
LEAVE('-');
}
tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
{
int part;
+ tATA_Disk *disk;
+
// Check first character
if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
return NULL;
+ disk = &gATA_Disks[Name[0]-'A'];
// Raw Disk
if(Name[1] == '\0') {
- if( gATA_Disks[Name[0]-'A'].Sectors == 0 )
+ if( disk->Sectors == 0 && disk->Name[0] == '\0')
return NULL;
- return &gATA_Disks[Name[0]-'A'].Node;
+ return &disk->Node;
}
-
+
// Partitions
if(Name[1] < '0' || '9' < Name[1]) return NULL;
if(Name[2] == '\0') { // <= 9
part = Name[1] - '0';
part --;
- return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
+ return &disk->Partitions[part].Node;
}
// > 9
if('0' > Name[2] || '9' < Name[2]) return NULL;
if(Name[3] != '\0') return NULL;
-
+
part = (Name[1] - '0') * 10;
part += Name[2] - '0';
part --;
- return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
-
+ return &disk->Partitions[part].Node;
+
}
/**
{
int disk = Node->Inode >> 8;
int part = Node->Inode & 0xFF;
-
+
+ ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+
// Raw Disk Access
if(part == 0xFF)
{
- if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
+ if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) {
+ LEAVE('i', 0);
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 )
+ if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) {
+ LEAVE('i', 0);
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_ReadFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
- return DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
+
+ {
+ int ret = DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
+ Debug_HexDump("ATA_ReadFS", Buffer, Length);
+ LEAVE('i', ret);
+ return ret;
+ }
}
/**
{
int disk = Node->Inode >> 8;
int part = Node->Inode & 0xFF;
-
+
// Raw Disk Access
if(part == 0xFF)
{
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);
int ret;
Uint offset;
Uint done = 0;
-
+
// Pass straight on to ATA_ReadDMAPage if we can
if(Count <= MAX_DMA_SECTORS)
{
if(ret == 0) return 0;
return Count;
}
-
+
// Else we will have to break up the transfer
offset = 0;
while(Count > MAX_DMA_SECTORS)
Count -= MAX_DMA_SECTORS;
offset += MAX_DMA_SECTORS*SECTOR_SIZE;
}
-
+
ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
if(ret != 1) return 0;
return done+Count;
int ret;
Uint offset;
Uint done = 0;
-
- // Pass straight on to ATA_WriteDMA if we can
+
+ // 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)
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;
int cont = (Disk>>1)&1; // Controller ID
int disk = Disk & 1;
Uint16 base;
-
+ Uint8 val;
+
ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer);
-
+
// Check if the count is small enough
if(Count > MAX_DMA_SECTORS) {
Warning("Passed too many sectors for a bulk DMA read (%i > %i)",
LEAVE('i');
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);
-
+
// 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
+ outb(base+0x4, Address >> 28); // Mid 2 Addr
+ outb(base+0x5, Address >> 32); // High 2 Addr
}
else
{
- outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
+ outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); // Magic, Disk, 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
-
+
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 );
+ val = 0;
+ while( gaATA_IRQs[cont] == 0 && !(val & 0x4) ) {
+ val = ATA_int_BusMasterReadByte( (cont << 3) + 2 );
//LOG("val = 0x%02x", val);
Threads_Yield();
}
-
+
// Complete Transfer
- ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
-
+ ATA_int_BusMasterWriteByte( cont << 3, 8 ); // Read and stop
+
+ val = inb(base+0x7);
+ LOG("Status byte = 0x%02x", val);
+
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;
}
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+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+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, 1 ); // Write and start
-
+
// Wait for transfer to complete
while( gaATA_IRQs[cont] == 0 ) Threads_Yield();
-
+
// Complete Transfer
ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
-
+
// Release controller lock
RELEASE( &giaATA_ControllerLock[ cont ] );
-
+
return 1;
}
void ATA_IRQHandlerPri(int unused)
{
Uint8 val;
-
+
// IRQ bit set for Primary Controller
val = ATA_int_BusMasterReadByte( 0x2 );
LOG("IRQ val = 0x%x", val);
Uint8 val;
// IRQ bit set for Secondary Controller
val = ATA_int_BusMasterReadByte( 0xA );
+ LOG("IRQ val = 0x%x", val);
if(val & 4) {
LOG("IRQ hit (val = 0x%x)", val);
ATA_int_BusMasterWriteByte( 0xA, 4 );
*/
void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
{
-
+
if( gATA_BusMasterBase & 1 )
outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
else