From: John Hodge Date: Tue, 17 Aug 2010 01:34:22 +0000 (+0800) Subject: Added timeout support to the ATA driver (timeout is 2 seconds) X-Git-Tag: rel0.06~60 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=e6b37dbe81b4492796fd262f95fc94e06cb67966;p=tpg%2Facess2.git Added timeout support to the ATA driver (timeout is 2 seconds) --- diff --git a/Modules/Storage/ATA/common.h b/Modules/Storage/ATA/common.h index 242827c0..891d2bbe 100644 --- a/Modules/Storage/ATA/common.h +++ b/Modules/Storage/ATA/common.h @@ -10,29 +10,11 @@ // === CONSTANTS === #define MAX_ATA_DISKS 4 -#define SECTOR_SIZE 512 +#define SECTOR_SIZE 512 +#define ATA_TIMEOUT 2000 // 2s timeout +// Needed out of io.c because it's the max for Read/WriteDMA #define MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE) -#define IDE_PRI_BASE 0x1F0 -#define IDE_SEC_BASE 0x170 - -#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 -}; - // === STRUCTURES === typedef struct { diff --git a/Modules/Storage/ATA/io.c b/Modules/Storage/ATA/io.c index e9e141a3..89fcdb9f 100644 --- a/Modules/Storage/ATA/io.c +++ b/Modules/Storage/ATA/io.c @@ -13,6 +13,27 @@ // === MACROS === #define IO_DELAY() do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0) +// === Constants === +#define IDE_PRI_BASE 0x1F0 +#define IDE_SEC_BASE 0x170 + +#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 @@ -198,9 +219,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) { @@ -235,22 +262,24 @@ 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; } // Get exclusive access to the disk controller @@ -301,7 +330,9 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) ATA_int_BusMasterWriteByte( cont << 3, 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) + Threads_Yield(); // Complete Transfer ATA_int_BusMasterWriteByte( cont << 3, 8 ); // Read and stop @@ -312,14 +343,25 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) 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 ) { + // Release controller lock + RELEASE( &giaATA_ControllerLock[ cont ] ); + Log_Warning("ATA", + "Read timeout on disk %i (Reading sector 0x%llx)\n", + Disk, Address); + // Return error + LEAVE('i', 1); + return 1; + } + else { + // Copy to destination buffer + memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE ); + // Release controller lock + RELEASE( &giaATA_ControllerLock[ cont ] ); - LEAVE('i', 1); - return 1; + LEAVE('i', 0); + return 0; + } } /** @@ -329,15 +371,17 @@ 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 ] ); @@ -348,6 +392,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 +420,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 +427,23 @@ 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(); // 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 + RELEASE( &giaATA_ControllerLock[ cont ] ); + return 1; // Error + } + else { + RELEASE( &giaATA_ControllerLock[ cont ] ); + return 0; + } } /** diff --git a/Modules/Storage/ATA/main.c b/Modules/Storage/ATA/main.c index 05caaab0..9c71a901 100644 --- a/Modules/Storage/ATA/main.c +++ b/Modules/Storage/ATA/main.c @@ -179,7 +179,11 @@ int ATA_ScanDisk(int Disk) // --- Scan Partitions --- LOG("Reading MBR"); // Read Boot Sector - ATA_ReadDMA( Disk, 0, 1, &mbr ); + if( ATA_ReadDMA( Disk, 0, 1, &mbr ) != 0 ) { + Log_Warning("ATA", "Error in reading MBR on %i", Disk); + LEAVE('i', 0); + return 0; + } // Check for a GPT table if(mbr.Parts[0].SystemID == 0xEE) @@ -192,7 +196,7 @@ int ATA_ScanDisk(int Disk) Debug_HexDump("ATA_ScanDisk", &mbr, 512); #endif - LEAVE('i', 0); + LEAVE('i', 1); return 1; }