X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FStorage%2FATA%2Fio.c;h=c8f4fa97b679c8da3425c28cc3061dea243b9519;hb=c6b68cc230c9b6564e2809aca3119ec8118e72ac;hp=e9e141a3b91f155e0a5deb1d7a856c319b22b480;hpb=930fbc7181e9e19c64a4c7f87d20efeb3755b5f6;p=tpg%2Facess2.git diff --git a/Modules/Storage/ATA/io.c b/Modules/Storage/ATA/io.c index e9e141a3..c8f4fa97 100644 --- a/Modules/Storage/ATA/io.c +++ b/Modules/Storage/ATA/io.c @@ -4,7 +4,7 @@ * * Disk Input/Output control */ -#define DEBUG 0 +#define DEBUG 1 #include #include // Needed for error codes #include @@ -13,6 +13,29 @@ // === MACROS === #define IO_DELAY() do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0) +// === Constants === +#define IDE_PRI_BASE 0x1F0 +#define IDE_PRI_CTRL 0x3F6 +#define IDE_SEC_BASE 0x170 +#define IDE_SEC_CTRL 0x376 + +#define IDE_PRDT_LAST 0x8000 +/** + \enum HddControls + \brief Commands to be sent to HDD_CMD +*/ +enum HddControls { + HDD_PIO_R28 = 0x20, + HDD_PIO_R48 = 0x24, + HDD_DMA_R48 = 0x25, + HDD_PIO_W28 = 0x30, + HDD_PIO_W48 = 0x34, + HDD_DMA_W48 = 0x35, + HDD_DMA_R28 = 0xC8, + HDD_DMA_W28 = 0xCA, + HDD_IDENTIFY = 0xEC +}; + // === TYPES === /** * \brief PRDT Entry @@ -73,7 +96,7 @@ Uint8 *gATA_BusMasterBasePtr; //!< Paging Mapped MMIO (If needed) int gATA_IRQSec = 15; volatile int gaATA_IRQs[2] = {0}; // - Locks to avoid tripping -tSpinlock giaATA_ControllerLock[2]; +tMutex glaATA_ControllerLock[2]; // - Buffers! Uint8 gATA_Buffers[2][(MAX_DMA_SECTORS+0xFFF)&~0xFFF] __attribute__ ((section(".padata"))); // - PRDTs @@ -104,6 +127,9 @@ int ATA_SetupIO(void) return MODULE_ERR_NOTNEEDED; } + LOG("BAR5 = 0x%x", PCI_GetBAR5( ent )); + LOG("IRQ = %i", PCI_GetIRQ( ent )); + // Map memory if( !(gATA_BusMasterBase & 1) ) { @@ -138,6 +164,10 @@ int ATA_SetupIO(void) // Enable controllers outb(IDE_PRI_BASE+1, 1); outb(IDE_SEC_BASE+1, 1); + + // Make sure interrupts are ACKed + ATA_int_BusMasterWriteByte(2, 0x4); + ATA_int_BusMasterWriteByte(10, 0x4); // return LEAVE('i', MODULE_ERR_OK); @@ -198,9 +228,15 @@ Uint64 ATA_GetDiskSize(int Disk) return 0; // Disk does not exist } - // Poll until BSY clears and DRQ sets or ERR is set - while( ((val & 0x80) || !(val & 0x08)) && !(val & 1)) + // Poll until BSY clears or ERR is set + // TODO: Timeout? + while( (val & 0x80) && !(val & 1) ) val = inb(base+7); + LOG("BSY unset (0x%x)", val); + // and, wait for DRQ to set + while( !(val & 0x08) && !(val & 1)) + val = inb(base+7); + LOG("DRQ set (0x%x)", val); // Check for an error if(val & 1) { @@ -213,10 +249,14 @@ Uint64 ATA_GetDiskSize(int Disk) data.buf[i] = inw(base); // Return the disk size - if(data.identify.Sectors48 != 0) + if(data.identify.Sectors48 != 0) { + LEAVE('X', data.identify.Sectors48); return data.identify.Sectors48; - else + } + else { + LEAVE('x', data.identify.Sectors28); return data.identify.Sectors28; + } } /** @@ -235,26 +275,33 @@ Uint16 ATA_GetBasePort(int Disk) /** * \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 cont = (Disk>>1)&1; // Controller ID int disk = Disk & 1; Uint16 base; + Sint64 timeoutTime; 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)", + Log_Warning("ATA", "Passed too many sectors for a bulk DMA read (%i > %i)", Count, MAX_DMA_SECTORS); LEAVE('i'); - return 0; + return 1; } + + // Hack to make debug hexdump noticable + #if 1 + memset(Buffer, 0xFF, Count*SECTOR_SIZE); + #endif // Get exclusive access to the disk controller - LOCK( &giaATA_ControllerLock[ cont ] ); + Mutex_Acquire( &glaATA_ControllerLock[ cont ] ); // Set Size gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE; @@ -265,10 +312,24 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) // Reset IRQ Flag gaATA_IRQs[cont] = 0; + #if 1 + if( cont == 0 ) { + outb(base+IDE_PRI_CTRL, 4); + IO_DELAY(); + outb(base+IDE_PRI_CTRL, 0); + } + else { + outb(base+IDE_SEC_CTRL, 4); + IO_DELAY(); + outb(base+IDE_SEC_CTRL, 0); + } + #endif + // Set up transfer if( Address > 0x0FFFFFFF ) // Use LBA48 { outb(base+0x6, 0x40 | (disk << 4)); + IO_DELAY(); outb(base+0x2, 0 >> 8); // Upper Sector Count outb(base+0x3, Address >> 24); // Low 2 Addr outb(base+0x4, Address >> 28); // Mid 2 Addr @@ -278,13 +339,15 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) { // Magic, Disk, High Address nibble outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); + //outb(base+0x06, 0xA0 | (disk << 4) | ((Address >> 24) & 0x0F)); + IO_DELAY(); } - outb(base+0x01, 0x01); //? - 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 + //outb(base+0x01, 0x01); //? + outb(base+0x02, Count & 0xFF); // Sector Count + outb(base+0x03, Address & 0xFF); // Low Addr + outb(base+0x04, (Address >> 8) & 0xFF); // Middle Addr + outb(base+0x05, (Address >> 16) & 0xFF); // High Addr LOG("Starting Transfer"); @@ -298,28 +361,48 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28) // Start transfer - ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start + ATA_int_BusMasterWriteByte( cont * 8, 9 ); // Read and start // Wait for transfer to complete - while( gaATA_IRQs[cont] == 0 ) Threads_Yield(); + timeoutTime = now() + ATA_TIMEOUT; + while( gaATA_IRQs[cont] == 0 && now() < timeoutTime) + { + HALT(); +// Threads_Yield(); + } // Complete Transfer - ATA_int_BusMasterWriteByte( cont << 3, 8 ); // Read and stop + ATA_int_BusMasterWriteByte( cont * 8, 8 ); // Read and stop val = inb(base+0x7); - LOG("Status byte = 0x%02x", val); + LOG("Status byte = 0x%02x, Controller Status = 0x%02x", + val, ATA_int_BusMasterReadByte(cont * 8 + 2)); - LOG("gATA_PRDTs[%i].Bytes = %i", cont, gATA_PRDTs[cont].Bytes); - LOG("Transfer Completed & Acknowledged"); - - // Copy to destination buffer - memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE ); - - // Release controller lock - RELEASE( &giaATA_ControllerLock[ cont ] ); + if( gaATA_IRQs[cont] == 0 ) { + + #if 1 + Debug_HexDump("ATA", Buffer, 512); + #endif + + // Release controller lock + Mutex_Release( &glaATA_ControllerLock[ cont ] ); + Log_Warning("ATA", + "Read timeout on disk %i (Reading sector 0x%llx)", + Disk, Address); + // Return error + LEAVE('i', 1); + return 1; + } + else { + LOG("Transfer Completed & Acknowledged"); + // Copy to destination buffer + memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE ); + // Release controller lock + Mutex_Release( &glaATA_ControllerLock[ cont ] ); - LEAVE('i', 1); - return 1; + LEAVE('i', 0); + return 0; + } } /** @@ -329,18 +412,20 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) * \param Address LBA of first sector * \param Count Number of sectors to write (must be >= \a MAX_DMA_SECTORS) * \param Buffer Source buffer for data + * \return Boolean Failure */ 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 0; + if(Count > MAX_DMA_SECTORS) return 1; // Get exclusive access to the disk controller - LOCK( &giaATA_ControllerLock[ cont ] ); + Mutex_Acquire( &glaATA_ControllerLock[ cont ] ); // Set Size gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE; @@ -348,6 +433,9 @@ int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const 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 @@ -373,9 +461,6 @@ int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer) 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 ); @@ -383,15 +468,26 @@ int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer) ATA_int_BusMasterWriteByte( cont << 3, 1 ); // Write and start // Wait for transfer to complete - while( gaATA_IRQs[cont] == 0 ) Threads_Yield(); + timeoutTime = now() + ATA_TIMEOUT; + while( gaATA_IRQs[cont] == 0 && now() < timeoutTime) + { +// Threads_Yield(); + HALT(); + } // Complete Transfer ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop - // Release controller lock - RELEASE( &giaATA_ControllerLock[ cont ] ); - - return 1; + // 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; + } } /**