Unable to get ATA driver working :(
Posted: Sat Jun 11, 2011 11:41 am
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
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;
}