Page 1 of 2

ATA_IDENTIFY

Posted: Wed Mar 30, 2016 7:21 am
by ahmedfme
Hi,
i am trying to use some codes from other OSes to get ATA working in my code.
i am using below code to send IDENTIFY command

Code: Select all

outportb(io + ATA_REG_SECCOUNT0, 0);
	outportb(io + ATA_REG_LBA0, 0);
	outportb(io + ATA_REG_LBA1, 0);
	outportb(io + ATA_REG_LBA2, 0);
	/* Now, send IDENTIFY */
	Printf("Sending IDENTIFY to port 0x%X\n",io);
	outportb(io + ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
	Printf("Sent IDENTIFY\n");
	/* Now, read status port */
	uint8_t status = inportb(io + ATA_REG_STATUS);
	Printf("\nThe status right now is %d", status);
	if (status)
	{
		Printf("\nNow Polling... _IRQP = %d , _IRQS= %d",_IRQP,_IRQS);
		/* Now, poll untill BSY is clear. */
		while (inportb(io + ATA_REG_STATUS) & ATA_SR_BSY != 0);
		//while (!_IRQP || !_IRQS){}
		Printf("\nFinished Polling... _IRQP = %d , _IRQS= %d", _IRQP, _IRQ
when running this code it always hang up after sending the command.
some times it writes on screen "Sen" without completing the word and hang up.
there is no panic catched ..
any isea why it is hanging up?

Re: ATA_IDENTIFY

Posted: Wed Mar 30, 2016 8:12 am
by BrightLight
I don't see any code for selecting a device. Every ATA channel can have two devices.

Re: ATA_IDENTIFY

Posted: Wed Mar 30, 2016 8:43 am
by ahmedfme
here is the full function code

Code: Select all

uint8_t ide_identify(uint8_t bus, uint8_t drive)
{
	uint16_t io = 0;
	ide_select_drive(bus, drive);
	if (bus == ATA_PRIMARY) io = ATA_PRIMARY_IO;
	else io = ATA_SECONDARY_IO;
	/* ATA specs say these values must be zero before sending IDENTIFY */
	outportb(io + ATA_REG_SECCOUNT0, 0);
	outportb(io + ATA_REG_LBA0, 0);
	outportb(io + ATA_REG_LBA1, 0);
	outportb(io + ATA_REG_LBA2, 0);
	/* Now, send IDENTIFY */
	Printf("Sending IDENTIFY to port 0x%X\n",io);
	outportb(io + ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
	Printf("Sent IDENTIFY\n");
	/* Now, read status port */
	uint8_t status = inportb(io + ATA_REG_STATUS);
	Printf("\nThe status right now is %d", status);
	if (status)
	{
		Printf("\nNow Polling... _IRQP = %d , _IRQS= %d",_IRQP,_IRQS);
		/* Now, poll untill BSY is clear. */
		while (inportb(io + ATA_REG_STATUS) & ATA_SR_BSY != 0);
		//while (!_IRQP || !_IRQS){}
		Printf("\nFinished Polling... _IRQP = %d , _IRQS= %d", _IRQP, _IRQS);
		if (_IRQP)	{_IRQP = false;	}
		if (_IRQS)	{ _IRQS = false; }
		
	pm_stat_read:		status = inportb(io + ATA_REG_STATUS);
		if (status & ATA_SR_ERR)
		{
			Printf("\n%s%s has ERR set. Disabled.\n", bus == ATA_PRIMARY ? "Primary" : "Secondary", drive == ATA_PRIMARY ? " master" : " slave");
			return 0;
		}
		while (!(status & ATA_SR_DRQ)) goto pm_stat_read;
		Printf("\n%s%s is online.\n", bus == ATA_PRIMARY ? "Primary" : "Secondary", drive == ATA_PRIMARY ? " master" : " slave");
		/* Now, actually read the data */
		
		for (int i = 0; i<256; i++)
		{
			*(uint16_t *)(ide_buf + i * 2) = inportw(io + ATA_REG_DATA);
		}
		
	}
}

Re: ATA_IDENTIFY

Posted: Wed Mar 30, 2016 8:44 am
by ahmedfme
and drive select function code is here

Code: Select all

void ide_select_drive(uint8_t bus, uint8_t i)
{
	if (bus == ATA_PRIMARY)
		if (i == ATA_MASTER)
			outportb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xA0);
		else outportb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xB0);
	else
		if (i == ATA_MASTER)
			outportb(ATA_SECONDARY_IO + ATA_REG_HDDEVSEL, 0xA0);
		else outportb(ATA_SECONDARY_IO + ATA_REG_HDDEVSEL, 0xB0);
}

Re: ATA_IDENTIFY

Posted: Wed Mar 30, 2016 10:23 am
by BrightLight
It doesn't really look like something is wrong. Run it in Bochs and check the log messages.

Re: ATA_IDENTIFY

Posted: Wed Mar 30, 2016 3:53 pm
by ahmedfme
I have tried but unfortunately Bochs can't loade my bootloader "Neptune" because it doesn't support int 15h Function AX=0088

Re: ATA_IDENTIFY

Posted: Wed Mar 30, 2016 5:46 pm
by Octocontrabass
Why are you using INT 0x15 AH=0x00? That function doesn't do anything useful on modern PCs.

Maybe what you really want is INT 0x15 AH=0x88.

Re: ATA_IDENTIFY

Posted: Thu Mar 31, 2016 9:11 am
by BrightLight
Octocontrabass wrote:Maybe what you really want is INT 0x15 AH=0x88.
Even so, INT 0x15 EAX = 0xE820 should be used for detecting memory. It is supported on almost all real hardware and all emulators.

Re: ATA_IDENTIFY

Posted: Tue Apr 05, 2016 9:29 am
by alexg
ahmedfme wrote:and drive select function code is here

Code: Select all

void ide_select_drive(uint8_t bus, uint8_t i)
{
	if (bus == ATA_PRIMARY)
		if (i == ATA_MASTER)
			outportb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xA0);
		else outportb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xB0);
	else
		if (i == ATA_MASTER)
			outportb(ATA_SECONDARY_IO + ATA_REG_HDDEVSEL, 0xA0);
		else outportb(ATA_SECONDARY_IO + ATA_REG_HDDEVSEL, 0xB0);
}
You are setting bits 7 and 5 (which are undefined => you should not touch them) besides the device select, I think you want to set bit 6 (which sets LBA addressing mode).

Re: ATA_IDENTIFY

Posted: Tue Apr 05, 2016 12:22 pm
by BrightLight
alexg wrote:You are setting bits 7 and 5 (which are undefined => you should not touch them) besides the device select, I think you want to set bit 6 (which sets LBA addressing mode).
No. That code is correct.
OSDev Wiki wrote:To use the IDENTIFY command, select a target drive by sending 0xA0 for the master drive, or 0xB0 for the slave, to the "drive select" IO port.

Re: ATA_IDENTIFY

Posted: Fri Apr 08, 2016 11:56 am
by alexg
omarrx024 wrote:
alexg wrote:You are setting bits 7 and 5 (which are undefined => you should not touch them) besides the device select, I think you want to set bit 6 (which sets LBA addressing mode).
No. That code is correct.
OSDev Wiki wrote:To use the IDENTIFY command, select a target drive by sending 0xA0 for the master drive, or 0xB0 for the slave, to the "drive select" IO port.
I'm sorry, when I posted the reply I was pretty much in a hurry and I saw the fact that the ide_select_drive function specifies CHS addressing, but you're right, it's irrelevant for the IDENTIFY command. However, if LBA addressing will be used, the function should be modified to also set bit 6.

Regarding the quote from OSDev Wiki, I would appreciate you'd use an official specification when contradicting someone - http://www.t13.org/documents/uploadeddo ... lume_1.pdf ( see 6.17 IDENTIFY DEVICE bits 7 and 5 are obsolete, so it is enough to write 0x10 for the slave and 0x0 for the master ).

Re: ATA_IDENTIFY

Posted: Fri Apr 08, 2016 1:12 pm
by BrightLight
Well, writing 0xA0 and 0xB0 for the master and slave respectively works on Bochs, QEMU, VMware, VirtualBox, one real ATA hard drive and a SATA hard drive with IDE emulation.

Re: ATA_IDENTIFY

Posted: Fri Apr 08, 2016 2:24 pm
by Octocontrabass
alexg wrote:Regarding the quote from OSDev Wiki, I would appreciate you'd use an official specification when contradicting someone - http://www.t13.org/documents/uploadeddo ... lume_1.pdf ( see 6.17 IDENTIFY DEVICE bits 7 and 5 are obsolete, so it is enough to write 0x10 for the slave and 0x0 for the master ).
This version of the ATA specification (section 5.2.8) says bits 7 and 5 should be set for backwards compatibility.

Re: ATA_IDENTIFY

Posted: Sat Apr 09, 2016 6:32 am
by alexg
You said you are not running your OS on Bochs, what are you running it on?

I've just ran my OS on a real machine and the ATA registers are not exposed by the IDE controller at the standard locations and I have to read the values from the PCI IDE Controller bars (see http://wiki.osdev.org/PCI_IDE_Controller).

Edit: also make sure from your BIOS that the SATA configuration mode is set to IDE and not ACHI.

Re: ATA_IDENTIFY

Posted: Sun Apr 10, 2016 10:06 pm
by neon
Hello,
I have tried but unfortunately Bochs can't loade my bootloader "Neptune" because it doesn't support int 15h Function AX=0088
It should be noted that this was a copy of our old boot loader, which used int 15h function 88h to calculate the mem_lower and mem_upper fields of the multiboot information structure. The boot loader uses int 15h function e820h for the memory map fields which is what you really want. So, if you want to suppress the error, clear bit 0 of the multiboot header flags field. This will tell the boot loader to ignore the mem_* fields. In any case though, the software should still continue to run despite the error.