Detecting ATAPI drives

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
AUsername
Member
Member
Posts: 54
Joined: Sun Feb 01, 2009 9:07 pm

Detecting ATAPI drives

Post by AUsername »

Hey again, I have a simple script that grabs if a drive is active or not but it doesn't grab if it's an HDD or an ODD. I can't find anything on how to detect that other than checking the vendor string which I won't do for obvious reasons.

This is my current code:

Code: Select all

uint8_t odd_find_drive(uint32_t bus, uint32_t drive){
	uint8_t status;

	//Select the drive
	//Channel = bus, device = drive
	outportb(ATA_DRIVE_SELECT(bus),drive & (1 << 4));

	status = inportb(ATA_COMMAND(bus));
	if ((!status) || status == 0xFF)
		return 0;

	printf("features = 0x%x\n",status);

	return 1;
}
It always returns 0x50 (http://i45.tinypic.com/25r18i8.png , please ignore the ugly debugging messages :P)
Any ideas how I'm SUPPOSED to grab it because I'm pretty sure what I'm doing only returns if the drive exists or not (since that works).

Also here's my bochsrc.txt:
#Boot from HDD -------------------------------------------------------
ata0-master: type=disk, path="C:\Coras\coras_slim.img", mode=flat, cylinders=65, heads=16, spt=63
ata1-slave: type=disk, path="C:\Coras\hd1.img", mode=flat, cylinders=65, heads=16, spt=63
ata1-master: type=cdrom, mode=flat, path="C:\Coras\od0.iso"
ata0-slave: type=cdrom, mode=flat, path="C:\Coras\od1.iso"
Thanks in advance. :)
User avatar
-m32
Member
Member
Posts: 120
Joined: Thu Feb 21, 2008 5:59 am
Location: Ottawa, Canada

Re: Detecting ATAPI drives

Post by -m32 »

Do an ATA IDENTIFY, then check if the high-order bit of word 0 is set to one. If so, it's a packet (ATAPI) device. If it's set to 0, it's an ATA device.
AUsername
Member
Member
Posts: 54
Joined: Sun Feb 01, 2009 9:07 pm

Re: Detecting ATAPI drives

Post by AUsername »

Awesome, thanks, it worked. =D
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Re: Detecting ATAPI drives

Post by ~ »

Some time ago I posted a method for reliably detecting ATA/ATAPI devices. Actually, there are several required tests that must always work together for being able to detect the drives across differently behaved chipsets and drives.

That is a lot of little theoric and practical details, and you must be aware that it can be very frustrating being able to detect correctly in a computer but not in other, but it should help greatly:

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

I also attached a compiled DOS COM file and its sample source code.

-------------------------------

Note that SATA drives in AHCI controllers can be programmed in this way as well, and the only thing you need to do is scan the PCI bus for a Class/Subclass/Interface controller with corresponding 01/06/01 values. Then look for its base address registers (BARs) of type I/O. But this is only if that controller actually has these I/O spaces, because it looks like the AHCI specification states that they are optional.

The interesting thing is that if the range of that I/O base address register is 8 (meaning 8 ports in this case) you can be more than sure that those are the first eight ATA registers, as listed in the standards. (By the way, does anybody know if a SATA controller of this kind has the 9th, Alternate Status//Device Control Register in I/O space and where?)

This can work if the controller is in ATA mode, and in the computer I have, it also works in SATA mode using these non-standard 8-register ranges.
Attachments
atadetec.rar
(8.43 KiB) Downloaded 69 times
AUsername
Member
Member
Posts: 54
Joined: Sun Feb 01, 2009 9:07 pm

Re: Detecting ATAPI drives

Post by AUsername »

Thanks for the help ~, but now I have another... annoying problem.
In Bochs I can read sectors off of the CD drive but it doesn't work in VBox or VPC (meaning it won't work on real hardware).

I believe it's timing but I've made it wait for a second each sector read so it can't be. I have NO idea what I'm missing and nothing I'm looking at is helping. The documentation on ATA/ATAPI is really bad...
Code based off of tutorial found at http://wiki.osdev.org/ATAPI

Code: Select all

drvextern uint8_t* odd_read_sector(uint32_t lba){
	uint8_t status;
	int size;

	if (!bus || !drive)
		return 0;

	printf("ReadSector[");

	//Select drive
	outportb(ATA_DRIVE_SELECT(bus),drive & (1 << 4));

	tvga_putc('1');

	//wait 400ns
	for(int i = 0; i < 4; i++)
		inportb(ATA_DCR(bus));

	outportb(ATA_FEATURES(bus),0x0);
	outportb(ATA_ADDRESS2(bus),SECTOR_SIZE & 0xFF);
	outportb(ATA_ADDRESS3(bus),SECTOR_SIZE >> 8);
	outportb(ATA_COMMAND(bus),ATA_CMD_PACKET);

	while((status = inportb(ATA_COMMAND(bus))) & 0x80);
	while(!((status = inportb(ATA_COMMAND(bus))) & 0x8) && !(status & 0x1));

	tvga_putc('4');
	if ((status & 0x1))
		return 0x0;

	ata_packet[0] = ATAPI_CMD_READ;
	//ata_packet[1] = ata_packet[6] = ata_packet[7] = ata_packet[8] = 0;
	ata_packet[9] = 1;
	ata_packet[2] = (lba >> 0x18) & 0xFF;
	ata_packet[3] = (lba >> 0x10) & 0xFF;
	ata_packet[4] = (lba >> 0x8) & 0xFF;
	ata_packet[5] = lba & 0xFF;

	tvga_putc('5');

	outsw(ATA_DATA(bus),(uint16_t*)ata_packet,6);

	irq_wait();

	tvga_putc('6');

	size = (((int)inportb(ATA_ADDRESS3(bus))) << 8) | (int)(inportb(ATA_ADDRESS2(bus)));
	insw(ATA_DATA(bus),(uint16_t*)buffer,size / 2);

	printf("9]\n");

	return buffer;
}
See anything wrong there? Cause I've been going in circles for about 2 hours now and it's starting to get on my nerves.
Post Reply