Page 1 of 1

[Solved]Problem with IDE Detection via PIO

Posted: Thu Oct 14, 2010 7:03 am
by Almamu
Im working on LBA28/48 support. Im trying to detect how many drivers are connected at the moment you run the SO. I have no problem to detect all of them in the real Hardware, but when i'm trying to test it in a Virtual Machine(VirtualBox)i get: No drives detected and i have one connected to the Master...
This is my code:

Code: Select all

int HDD_find_drives(){
	outb(0x1F3, 0x88);//Write some data to see if there are any drive
	unsigned short status = inb(0x1F3);//Read the data
	if(status & 0x88){//Compare with the data we write
		printf("Drives detected");
		outb(0x1F6, 0xA0);//Find primary Master
		sleep(1);//Wait the device to be ready
		unsigned short word = inb(0x1F7);//Read the data
		if(word & 0x40){//If drive is present
			printf("Primary Master detected\n");
		}
		outb(0x176, 0xB0);//Find primary Slave
		sleep(1);//Whait the device to be ready
		word = inb(0x177);//Read the data
		if(word & 0x40){//If drive is present
			printf("Primary Slave detected\n");
		}
		printf("LBA test completed\n");
	}else{//No drives detected
		printf("No drives detected\n");
	}
	return 1;
}
If i set a Slave primary device in the virtual machine it reports: Drives detected, but it doesnt seem to detect any Master and/or Slave, any help ?

Re: Problem with IDE Detection via PIO

Posted: Thu Oct 14, 2010 11:51 am
by ~
You can see this topic. Maybe or maybe not you'll need to read some further details in the ATA manuals:

http://forum.osdev.org/viewtopic.php?f=1&t=20690

If you can use DOS, you can use the following .COM program as a proof of concept of the topic above to see if it detects properly the devices, and the source code of it against yours:

http://126.sytes.net/tmp/atadiskdetect.zip
Image

Remember that all machines have subtle differences in this aspect, and to accurately detect all combinations attached ATA/ATAPI devices you have to take those differences into account.

Re: Problem with IDE Detection via PIO

Posted: Thu Oct 14, 2010 1:13 pm
by Almamu
Im using the "write & read data to the port" method, as it's supossed to work with most of the drives. It seems to be the most "universal" way to detect them, maybe my code is wrong...

EDIT: I've been doing some test and if I connect two drives to the first IDE it only detects the Master, and not the Slave.

Re: Problem with IDE Detection via PIO

Posted: Thu Oct 14, 2010 1:42 pm
by ~
You might try the DOS .COM program I included in the previous post and see if it works as expected. It uses 2 or 3 different detection methods. It's because different methods of detection are successful in some machines, or are unstable, or just fail to detect drives properly. If one fails, the other will succeed.

Note that this program still seems to have a small bug with an old 24X Creative CD-ROM in an HP Vectra, which is something that needs to be fixed, but in all other cases has worked flawless for me so far.

The biggest problem aren't the drives, although they don't all return signatures exactly as stated by the standards or set/clear status bits straightforwardly; but the motherboard ATA controllers themselves also differ in behavior.

Re: Problem with IDE Detection via PIO

Posted: Thu Oct 14, 2010 2:05 pm
by Almamu
Ive tested the .com file in DOS 6.22 and it detects the two HDD's. Image of the output:

Dont care about the CDROM drive, its only for start DOS,

Re: Problem with IDE Detection via PIO

Posted: Thu Oct 14, 2010 5:35 pm
by ~
Well, if it's what your machine/emulator actually has connected, you can compare results and study your sources and the forum explanations for corrections to be integrated.

If you need some help, make sure you read the explanations, the standard and whatever you need, and see what you are able to fix, and if there's something unclear, ask and maybe I'll try to clarify, but it all should be already in the explanation of the algorithm.

Keep in mind that the actual sources are crafted to be specific to display the results of this program, so they would need some rewriting for generalizing them (and fix the HP Vectra bug).

The more actual tests and combinations you do will give you more certainty that you won't be losing work with bogus sources, to integrate this method.

Re: Problem with IDE Detection via PIO

Posted: Fri Oct 15, 2010 7:34 am
by Almamu
Ok, i've been doing some more test and if i read the Regular Status port(1F7h)i can determine if there is any Master drive(as the post says), but, atm i'm a bit confused. How can i know if there is any Slave in the first/second port? I've been able to read the First Master and Second Master, and determine if it is connected or not. But atm i don't know how to detect the slave from both ports...
This is my actual code:

Code: Select all

    outb(0x1F3, 0x88);
    unsigned short status = inb(0x1F3);
    unsigned short bus = inb(0x1F7);
    unsigned short word;
    if((status & 0x88) || ((bus == 0xFF) || (bus == 0x00) || (bus == 0x7F))){
        printf("Drives detected\nExtra test begin now\n");
        outb(0x1F6, 0xA0);
        sleep(1);
        word = inb(0x1F7);
        if(word & 0x40){
            d_hdd_info->primary.master = 1;
            printf("Primary Master detected\n");
        }
    }
    outb(0x173, 0x88);
    status = inb(0x173);
    bus = inb(0x177);
    if((status & 0x88) || ((bus == 0xFF) || (bus == 0x00) || (bus == 0x7F))){
        outb(0x176, 0xB0);
        sleep(1);
        word = inb(0x177);
        if(word & 0x40){
            d_hdd_info->secondary.master = 1;
            printf("Secondary Master detected\n");
        }
    }
    printf("LBA Test completed\n");
    return 1;
}

Re: Problem with IDE Detection via PIO

Posted: Fri Oct 15, 2010 8:41 am
by ~
Almamu wrote:Ok, i've been doing some more test and if i read the Regular Status port(1F7h)i can determine if there is any Master drive(as the post says), but, atm i'm a bit confused.
What part of the explanation are you quoting? Is it the part that says that just reading the status port for a "valid" value is enough? If that's the part, then you must know that detection will work in some drive/machines combinations but not in others.

Almamu wrote:How can i know if there is any Slave in the first/second port? I've been able to read the First Master and Second Master, and determine if it is connected or not. But atm i don't know how to detect the slave from both ports...
Try encapsulating the snippet that allows you to detect the Primary Master with the testings, and try to pass the base I/O port (170h, 1F0h) and alternate register port and the DEV bit as parameters (3 parameters in total). In this way you only need to add from 0 to 7 to the base port parameter for the different registers of the Task File.

The DEV bit is located at bit 4 of register #6 (e.g, 1F6h or 176h). You clear it to reach the Master (00000000b) and set it to reach the slave (00010000b). You should always write/AND/OR either 0 or 16 for Slave to that port to be sure which device is selected, and you should be set. Then more tests should be done.

The Alternate Status register is located at 3F6h, 376h, 3E6h and 366h, for the Primary, Secondary, 3rd and 4th IDE channels.

Re: Problem with IDE Detection via PIO

Posted: Fri Oct 15, 2010 9:10 am
by Almamu
Ok, now the code seems to work correctly. Here is the code if anyone need it:

Code: Select all

/* You need the functions: printf, inb, outb*/
typedef struct{
	int master, slave;
}_HDD_DRIVE_INFO;

typedef struct{
	_HDD_DRIVE_INFO primary;
	_HDD_DRIVE_INFO secondary;
}_HDD_SYSTEM_INFO;

_HDD_SYSTEM_INFO* d_hdd_info;

int HDD_find_drives(){
	outb(0x1F3, 0x88);
	unsigned short status = inb(0x1F3);
	unsigned short bus = inb(0x1F7);
	unsigned short word;
	if((status & 0x88) || ((bus == 0xFF) || (bus == 0x00) || (bus == 0x7F))){
                //Test for primary master
		printf("Drives detected\nExtra test begins now\n");
		outb(0x1F6, 0xA0);
		sleep(1);
		word = inb(0x1F7);
		if(word & 0x40){
			d_hdd_info->primary.master = 1;
			printf("Primary master detected\n");
		}
                //Test for primary slave
		outb(0x1F6, 0xB0);
		sleep(1);
		word = inb(0x1F7);
		if(word & 0x40){
			d_hdd_info->primary.slave = 1;
			printf("Primary slave detected\n");
		}
	}
	outb(0x173, 0x88);
	status = inb(0x173);
	bus = inb(0x177);
	if((status & 0x88) || ((bus == 0xFF) || (bus == 0x00) || (bus == 0x7F))){
                //Test for secondary master
		outb(0x176, 0xA0);
		sleep(1);
		word = inb(0x177);
		if(word & 0x40){
			d_hdd_info->secondary.master = 1;
			printf("Secondary master detected\n");
		}
                //Test for secondary slave
		outb(0x176, 0xB0);
		sleep(1);
		word = inb(0x177);
		if(word & 0x40){
			d_hdd_info->secondary.slave = 1;
			printf("Secondary slave detected\n");
		}
	}
	printf("LBA Test completed\n");
	return 1;
}
It works correctly for HDD.
Thanks for the help.

P.D: I write 0xA0 in 0x1F6 to let the hardware know that i want to get data from primary master and 0xB0 to get data from primary slave as the doc i have says.