Page 1 of 1

Unable to get ATA driver working :(

Posted: Sat Jun 11, 2011 11:41 am
by pranjas
Hi Guys,

I've been trying and losing... on writing ata driver. I've specs ATA-7 from t13 and i'm using bochs emulator. I've tried IDENTIFY Command which works well. HOWEVER....

Word 83, bit 10 specifies that 48 bit LBA supported or not. I get the bit as set, but now Word 100 through 103 are all zero indicating no 48 bit LBA support... how come?

And then i tried to use read sector command 0x20h only and it returns some weird results and DRQ/DRDY are never set. So i continue to loop and it doesn't work jst doesn't work. Help me guys what am i missing!

My Read_sectors code looks like below

Code: Select all

#define PRIMARY_DATA_PORT			0x1F0
#define PRIMARY_ERROR_PORT			PRIMARY_DATA_PORT+1
#define PRIMARY_SECTOR_COUNT_PORT		PRIMARY_DATA_PORT+2 /*Number of sectors to read/write*/
#define PRIMARY_SECTOR_LBA_LOW_PORT			PRIMARY_DATA_PORT+3 /*LBA28/CHS/LBA48 specific.*/
#define PRIMARY_CYLLOW_LBA_MID_PORT		PRIMARY_DATA_PORT+4 /*Either Cylinder low for CHS or LBA mid bits*/
#define PRIMARY_CYLHIGH_LBA_HIGH_PORT		PRIMARY_DATA_PORT+5 /*High bits for cylinder/lba address*/
#define PRIMARY_DRIVE_SELECT_PORT		PRIMARY_DATA_PORT+6 /*drive/head select*/
#define PRIMARY_COMMAND_PORT			PRIMARY_DATA_PORT+7 /*May also be used to read in status*/
#define PRIMARY_STATUS_PORT			0x3F6		   /*Will read Alternate status register instead.Good*/

#define PRIMARY_STATUS_DATA_READY		(1<<6)

#define PRIMARY_STATUS_DRIVE_BUSY		(1<<7)

 
int read_sectors (struct dev_geo* dev,unsigned int first_block,unsigned char howmany,void *buffer)
{
	unsigned short* buff=(unsigned short*)buffer;
	unsigned char drive_select=0xE0;
	if(IS_BIT_SET(dev->drive_mode,5)) /*This is for my dev_geo structure nothing to do with ATA*/
	{
		drive_select|=1<<4;
	}

	volatile unsigned char status;
/*I was trying maybe interrupt disabling works, well it doesnt for me :(*/
	outb(PRIMARY_DRIVE_SELECT_PORT,drive_select);
	outb(PRIMARY_STATUS_PORT,0x02); /*We don't want interrupts yet, otherwise set it to 0x04*/

	drive_select|=(unsigned char)(first_block>>24 & 0x0f);
	howmany=howmany<dev->max_sectors?howmany:dev->max_sectors-1;

read_again:
	while( inb(PRIMARY_COMMAND_PORT) & PRIMARY_STATUS_DRIVE_BUSY) printk("here\n");
	/*Currently only works for primary BUS*/
	outb(PRIMARY_DRIVE_SELECT_PORT,drive_select);
	outb(PRIMARY_ERROR_PORT,0);/*0x1f1 needs to sent a NULL byte so.. */
	outb(PRIMARY_SECTOR_COUNT_PORT,howmany);
	outb(PRIMARY_SECTOR_LBA_LOW_PORT,(unsigned char)first_block);
	outb(PRIMARY_CYLLOW_LBA_MID_PORT,(unsigned char)(first_block>>8 & 0xff));
	outb(PRIMARY_CYLHIGH_LBA_HIGH_PORT,(unsigned char)(first_block>>16 &0xff));


	/*send the read sector command*/
	outb(PRIMARY_COMMAND_PORT,COMMAND_READ_SECTORS);
	printk("reading %d sectors\n",howmany);
	int i=0;
	while(i!=howmany)
	{	
		printk("l\n");

		while(!((status=inb(PRIMARY_COMMAND_PORT)) & PRIMARY_STATUS_DATA_READY))
		{
			printk("status is %x\n",status);/*This prints 0 always :(*/
			if(status & 0x01){
			outb(PRIMARY_DRIVE_SELECT_PORT,drive_select);
			outb(PRIMARY_STATUS_PORT,0x06);/*We don't want interrupts yet, otherwise set it to 0x40*/
			goto read_again;			
			}
		}
		if(status & PRIMARY_STATUS_DATA_READY)
		{			
			int j=0;
			for(;j<256;j++)
			{
				buff[256*i+j]=ins(PRIMARY_DATA_PORT);
			}
		}
		else if(status & PRIMARY_STATUS_DRIVE_FAULT)
		{
				return -1;
		}
		else if(status & PRIMARY_STATUS_ERROR)
		{
			/*send a SOFTWARE RESET*/

			/* Device Control Register primary at 3f6 and secondary at 3f7
			-----------------------------------------------------------------
			|Bit7	|Bit6	|Bit5	|Bit4	|Bit3	|Bit2	|Bit1	|Bit0	|
			|---------------------------------------------------------------|
			|HOB	|0	|0	|0	|0	|SRST	|nIEN	|0	|
			|-------|-------|-------|-------|-------|-------|-------|-------|

			SRST is the software reset bit.
			nIEN is the interrupt request for this drive when CLEARED.

			*/			
			outb(PRIMARY_DRIVE_SELECT_PORT,drive_select);
			outb(PRIMARY_STATUS_PORT,0x06);/*We don't want interrupts yet, otherwise set it to 0x04*/
		}
		i++;
	}
return howmany;
}