X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FStorage%2FATA%2Fio.c;h=c8f4fa97b679c8da3425c28cc3061dea243b9519;hb=c6b68cc230c9b6564e2809aca3119ec8118e72ac;hp=4193377020d5bc1de36bf8602ef5ad300df41381;hpb=87f2bb07687054bcc230e38fe4bc9f8198cc3668;p=tpg%2Facess2.git diff --git a/Modules/Storage/ATA/io.c b/Modules/Storage/ATA/io.c index 41933770..c8f4fa97 100644 --- a/Modules/Storage/ATA/io.c +++ b/Modules/Storage/ATA/io.c @@ -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 @@ -42,9 +65,9 @@ typedef struct Uint16 ValidExtData; // 54 Uint16 Unused5[5]; // 59 Uint16 SizeOfRWMultiple; // 60 - Uint32 Sectors28; // 62 + Uint32 Sectors28; // LBA 28 Sector Count Uint16 Unused6[100-62]; - Uint64 Sectors48; + Uint64 Sectors48; // LBA 48 Sector Count Uint16 Unused7[256-104]; } __attribute__ ((packed)) tIdentify; @@ -60,21 +83,28 @@ void ATA_IRQHandlerPri(int UNUSED(IRQ)); void ATA_IRQHandlerSec(int UNUSED(IRQ)); // Controller IO Uint8 ATA_int_BusMasterReadByte(int Ofs); +Uint32 ATA_int_BusMasterReadDWord(int Ofs); void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value); void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value); // === GLOBALS === -Uint32 gATA_BusMasterBase = 0; -Uint8 *gATA_BusMasterBasePtr = 0; +// - BusMaster IO Addresses +Uint32 gATA_BusMasterBase; //!< True Address (IO/MMIO) +Uint8 *gATA_BusMasterBasePtr; //!< Paging Mapped MMIO (If needed) +// - IRQs int gATA_IRQPri = 14; int gATA_IRQSec = 15; - int giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller -Uint8 gATA_Buffers[2][(MAX_DMA_SECTORS+0xFFF)&~0xFFF] __attribute__ ((section(".padata"))); volatile int gaATA_IRQs[2] = {0}; +// - Locks to avoid tripping +tMutex glaATA_ControllerLock[2]; +// - Buffers! +Uint8 gATA_Buffers[2][(MAX_DMA_SECTORS+0xFFF)&~0xFFF] __attribute__ ((section(".padata"))); +// - PRDTs tPRDT_Ent gATA_PRDTs[2] = { {0, 512, IDE_PRDT_LAST}, {0, 512, IDE_PRDT_LAST} }; +tPAddr gaATA_PRDT_PAddrs[2]; // === CODE === /** @@ -83,7 +113,6 @@ tPRDT_Ent gATA_PRDTs[2] = { int ATA_SetupIO(void) { int ent; - tPAddr addr; ENTER(""); @@ -98,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) ) { @@ -121,22 +153,34 @@ int ATA_SetupIO(void) LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr); - addr = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[0] ); - LOG("addr = 0x%x", addr); - ATA_int_BusMasterWriteDWord(4, addr); - addr = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[1] ); - LOG("addr = 0x%x", addr); - ATA_int_BusMasterWriteDWord(12, addr); + gaATA_PRDT_PAddrs[0] = MM_GetPhysAddr( (tVAddr)&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( (tVAddr)&gATA_PRDTs[1] ); + LOG("gaATA_PRDT_PAddrs[1] = 0x%x", gaATA_PRDT_PAddrs[1]); + ATA_int_BusMasterWriteDWord(12, gaATA_PRDT_PAddrs[1]); // 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); return MODULE_ERR_OK; } +/** + * \brief Get the size (in sectors) of a disk + * \param Disk Disk to get size of + * \return Number of sectors reported + * + * Does an ATA IDENTIFY + */ Uint64 ATA_GetDiskSize(int Disk) { union { @@ -151,9 +195,9 @@ Uint64 ATA_GetDiskSize(int Disk) base = ATA_GetBasePort( Disk ); // Send Disk Selector - if(Disk == 1 || Disk == 3) + if(Disk & 1) // Slave outb(base+6, 0xB0); - else + else // Master outb(base+6, 0xA0); IO_DELAY(); @@ -165,6 +209,7 @@ Uint64 ATA_GetDiskSize(int Disk) } // 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) { @@ -173,8 +218,8 @@ Uint64 ATA_GetDiskSize(int Disk) return 0; } - // Send IDENTIFY - outb(base+7, 0xEC); + // Send ATA IDENTIFY + outb(base+7, HDD_IDENTIFY); IO_DELAY(); val = inb(base+7); // Read status LOG("val = 0x%02x", val); @@ -183,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) { @@ -198,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; + } } /** @@ -220,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; @@ -250,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 @@ -261,16 +337,23 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) } else { - outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); // Magic, Disk, High addr + // 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"); + + // HACK: Ensure the PRDT is reset + ATA_int_BusMasterWriteDWord(cont*8+4, gaATA_PRDT_PAddrs[cont]); + LOG("gATA_PRDTs[%i].Bytes = %i", cont, gATA_PRDTs[cont].Bytes); if( Address > 0x0FFFFFFF ) outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48) @@ -278,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("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 ] ); + LOG("Status byte = 0x%02x, Controller Status = 0x%02x", + val, ATA_int_BusMasterReadByte(cont * 8 + 2)); + + 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; + } } /** @@ -309,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; @@ -328,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 @@ -340,7 +448,8 @@ int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer) } else { - outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr + // Magic, Disk, High Address nibble + outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); } outb(base+0x02, (Uint8) Count); // Sector Count @@ -352,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 ); @@ -362,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; + } } /** @@ -420,6 +537,18 @@ Uint8 ATA_int_BusMasterReadByte(int Ofs) return *(Uint8*)(gATA_BusMasterBasePtr + Ofs); } +/** + * \brief Read an 32-bit value from a Bus Master register + * \param Ofs Register offset + */ +Uint32 ATA_int_BusMasterReadDWord(int Ofs) +{ + if( gATA_BusMasterBase & 1 ) + return ind( (gATA_BusMasterBase & ~1) + Ofs ); + else + return *(Uint32*)(gATA_BusMasterBasePtr + Ofs); +} + /** * \brief Writes a byte to a Bus Master Register * \param Ofs Register Offset