Page 1 of 1

VirtualBox ATA DMA Read timing out (Primary Channel Only)

Posted: Fri Feb 25, 2011 7:23 pm
by thepowersgang
This is a bug that's been bothering me for a while.

My ATA DMA driver works seemingly perfectly on Bochs and Qemu (real hardware needs to be tested sometime), but on VirtualBox (Using the PIIX4 controller), reads on the first channel (disks 0 and 1) time out (I have a 2 second timeout), while for the same code on the secondary channel, it works.

Here is my ATA driver code, with the debugging prints removed to keep the length down, the original source is avaliable at http://www.mutabah.net/source/acess2/Mo ... /io.c.html

Code: Select all

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;

	// Check if the count is small enough
	if(Count > MAX_DMA_SECTORS) {
		Log_Warning("ATA", "Passed too many sectors for a bulk DMA read (%i > %i)",
			Count, MAX_DMA_SECTORS);
		return 1;
	}

	// Get exclusive access to the disk controller
	Mutex_Acquire( &glaATA_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
	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+0x4, Address >> 28);	// Mid 2 Addr
		outb(base+0x5, Address >> 32);	// High 2 Addr
	}
	else
	{
		// Magic, Disk, High Address nibble
		outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F));
	}

	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
	
	// HACK: Ensure the PRDT is reset
	ATA_int_BusMasterWriteDWord(cont*8+4, gaATA_PRDT_PAddrs[cont]);
	
	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 * 8, 9 );	// Read and start

	// Wait for transfer to complete
	timeoutTime = now() + ATA_TIMEOUT;
	while( gaATA_IRQs[cont] == 0 && now() < timeoutTime)	HALT();

	// Complete Transfer
	ATA_int_BusMasterWriteByte( cont * 8, 8 );	// Read and stop

	val = inb(base+0x7);

	if( gaATA_IRQs[cont] == 0 ) {
		// Release controller lock
		Mutex_Release( &glaATA_ControllerLock[ cont ] );
		Log_Warning("ATA",
			"Read timeout on disk %i (Reading sector 0x%llx)",
			Disk, Address);
		// Return error
		return 1;
	}
	else {
		// Copy to destination buffer
		memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
		// Release controller lock
		Mutex_Release( &glaATA_ControllerLock[ cont ] );

		return 0;
	}
}
Does anyone know of caveats when working with the VBox driver?

Re: VirtualBox ATA DMA Read timing out (Primary Channel Only

Posted: Sat Feb 26, 2011 7:34 am
by thepowersgang
:) You had to ask that, yes I do have disks mounted.

I have tested with four different disks with sizes from 2GB up to 20GB on all four ports.
The disks are identified OK (using the ATA IDENTIFY command), but the ones on the first channel do not complete the read (well, I never get an IRQ that they do)