small problem with ATA

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Pyrofan1
Member
Member
Posts: 234
Joined: Sun Apr 29, 2007 1:13 am

small problem with ATA

Post by Pyrofan1 »

new problem, see next post
Pyrofan1
Member
Member
Posts: 234
Joined: Sun Apr 29, 2007 1:13 am

Post by Pyrofan1 »

okay, i fixed the last problem, but now i got another
my readATAsector code

Code: Select all

#define ATA_DATA_REGISTER 0x1F0
#define ATA_ERROR_REGISTER 0x1F1
#define ATA_SECTORS_REGISTER 0x1F2
#define ATA_SECTOR_NUMBER 0x1F3
#define ATA_CYLINDERS_LOW 0x1F4
#define ATA_CYLINDERS_HIGH 0x1F5
#define ATA_DRIVE_HEAD 0x1F6
#define ATA_STATUS_REGISTER 0x1F7
#define ATA_COMMAND_REGISTER 0x1F7

#define ATA_FORMAT_TRACK 0x50
#define ATA_READ_SECTOR_RETRY 0x20
#define ATA_READ_SECTOR 0x21
#define ATA_READ_LONG_RETRY 0x22
#define ATA_READ_LONG 0x23
#define ATA_WRITE_SECTOR_RETRY 0x30
#define ATA_WRITE_SECTOR 0x31
#define ATA_WRITE_LONG_RETRY 0x32
#define ATA_WRITE_LONG 0x33

#define ATA_DRIVE_BUSY 0x80
#define ATA_DRIVE_READY 0x40
#define ATA_WRITE_FAULT 0x20
#define ATA_SEEK_COMPLETE 0x10
#define ATA_BUFFER_SECTOR 0x08
#define ATA_DATA_CORRECTION 0x04
#define ATA_INDEX 0x02
#define ATA_ERROR 0x01

struct ATA_SECTOR get_sector(void);
struct ATA_SECTOR readATAsector(unsigned char drive,unsigned char head,unsigned char cylinders_low,unsigned char cylinders_high,unsigned char sector)
{
	unsigned char drive_head;
	struct ATA_SECTOR s;

	if(drive==0)
	{
		drive_head=0xA0;
	}
	else
	{
		drive_head=0xB0;
	}

	while(1)
	{
		if((inportb(ATA_STATUS_REGISTER)&ATA_DRIVE_BUSY)!=ATA_DRIVE_BUSY) break;
	}

	drive_head=drive_head|head;
	outportb(ATA_DRIVE_HEAD,drive_head);

	outportb(ATA_SECTORS_REGISTER,1);
	outportb(ATA_SECTOR_NUMBER,sector);
	outportb(ATA_CYLINDERS_LOW,cylinders_low);
	outportb(ATA_CYLINDERS_HIGH,cylinders_high);
	outportb(ATA_COMMAND_REGISTER,ATA_READ_SECTOR_RETRY);


	s=get_sector();
	s.drive=drive;
	s.head=head;
	s.cylinders_high=cylinders_high;
	s.cylinders_low=cylinders_low;
	s.sector=sector;
	return s;
}
my get_sector function

Code: Select all

struct ATA_SECTOR get_sector(void)
{
	while(sector.read==0);
	sector.read=0;
	return sector;
}
my ATA_SECTOR struct

Code: Select all

struct ATA_SECTOR
{
	unsigned char data;
	unsigned char sector;
	unsigned char cylinders_high;
	unsigned char cylinders_low;
	unsigned char drive;
	unsigned char head;
	unsigned char read;
};
my code to handle IRQ 14

Code: Select all

sector.data=inportb(0x1F0);
sector.read=1;

if((inportb(0x1F7)&0x01)==0x01) sector.data=-1;
and my main

Code: Select all

void _main(void* mbd,unsigned int magic)
{
	struct ATA_SECTOR s;
	struct ATA_SECTOR a;

	kinit();

	Printf("hello world!\n");
	s=readATAsector(0,0,69,69,1);
	if(s.data!=-1)
	{
		putchar(s.data);
	}
	else
	{
		Printf("\nATA error\n");
	}

	a=readATAsector(0,0,69,69,1);
	if(a.data!=-1)
	{
		putchar(a.data);
	}
	else
	{
		Printf("\nATA error\n");
	}	
	for(;;);
}
now my problem is that only the first readATAsector function returns anything. I can't figure out why.
User avatar
XCHG
Member
Member
Posts: 416
Joined: Sat Nov 25, 2006 3:55 am
Location: Wisconsin
Contact:

Post by XCHG »

Pyrofan1,

I am not a C programmer but I can tell you that if you don't negate the INTRQ in IDE, you will not be able to read any sectors other than the first sector. The INTRQ (Interrupt Request) can be negated when you use the Status Register of the selected IDE Controller or its Alternate Status Register. When you read a sector using the Read Sector(s) command, read the status register (right before reading one sector) and ignore the results. Reading the Alternate Status Register is also recommended (as stated in ATA-4 specifications).

I have coded many ATA codes and one of them is called [__ATA4IDEReadFromPortsLBA28]. I will put the part that reads the requested sectors below so you can get the idea:

Code: Select all

    .StartReadingData:


      ; When the device is ready to transfer the data, it will clear BSY and set DRQ
      MOV     EDX , EBX
      ADD     EDX , IDE_PORT_OFFSET_STATUS
      MOV     ECX , IDE_TYPICAL_TIMEOUT
      XOR     EAX , EAX
      .WaitForBSYAndDRQ:
        NOP
        IN      AL , DX
        AND     EAX , (IDE_STATUSREG_BSY | IDE_STATUSREG_DRQ)
        XOR     EAX , IDE_STATUSREG_DRQ
        JZ      .PrepareToSenseInterrupt
        DEC     ECX
        JNZ     .WaitForBSYAndDRQ
        JMP     .Failure



      .PrepareToSenseInterrupt:
        MOV     EAX , IRQ_PULSE_IRQ14
        CMP     EBX , PIDEC_PORT_BASE
        JE      .SenseInterrupt
        MOV     EAX , IRQ_PULSE_IRQ15
        .SenseInterrupt:
          INVOKE  __WaitForIRQPulse, EAX



      .CheckStatusRegister1:
        ; EDX = Status Register's port address
        IN      AL , DX


      .ReadData:
        ; EDI = [Buffer]
        CLD
        MOV     EDX , EBX
        ADD     EDX , IDE_PORT_OFFSET_DATA
        MOV     ECX , 512 / 2 ; We are reading 2 bytes at a time and one sector after the other
        REP     INSW




      DEC     ESI
      JNZ     .StartReadingData




    ; Now that the data is read, we should first read the Alternate Status Register and ignore the result
    ; EBX = The base port address of the selected controller
    .ReadAlternateStatusRegister:
      MOV     EDX , IDEC_PORT_ALTERNATESTATUS
      IN      AL , DX
      TIMES   0x04 NOP




    ; Reading the Status Register is also recommended by ATA-4 specifications
    .ReadStatusRegister:
      ; EBX = The base port address of the selected controller
      MOV     EDX , EBX
      ADD     EDX , IDE_PORT_OFFSET_STATUS
      IN      AL , DX
      TIMES   0x04 NOP

Before reading any sectors, do these:

• Make sure BSY is is 0 (in the Status Register).
• Make sure the DRQ bit is 1 (in the Status Register).
• If the nIEN bit is cleared in the Device Control Register, sense the interrupt (wait for the interrupt).
• Read the Status Register and ignore the result.
• Read one sector from the Data Register.
• If there are more sectors left to be read, repeat the above steps from the beginning.
• Once you are done reading the sectors, read the Status Register and the Alternate Status Register and ignore the results.


And one more thing, make sure the nIEN bit in the Device Control Register is cleared as it will allow you to receive interrupts when they are fired.

Good luck.
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
Post Reply