SATA and AHCI on real Hardware

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
User avatar
Ch4ozz
Member
Member
Posts: 170
Joined: Mon Jul 18, 2016 2:46 pm
Libera.chat IRC: esi

SATA and AHCI on real Hardware

Post by Ch4ozz »

Hello guys!
I bought a cheap laptop online to test my OS on it, and it works pretty good.
Im currently adjusting / coding new drivers to support the hardware.

With the help of the AHCI article in the wiki I coded a driver for the SATA controller and it works fine on VBox, VMWare and QEMU.
Unfortunately it doesnt work on the real hardware :(

I've got a Lenovo T400, it has a ICH9 chipset and the SATA controller PCI id is: 1.6.0 -> 0x2929 @ 0x8086

I logged some variables and read this data sheet:
http://www.intel.com/content/dam/www/pu ... v1-3-1.pdf

CAP.SAM is on all VMs 1 but on my laptop it is 0
GHC is completely 0 (therefore GHC.AE is not set either) on the laptop

The data sheet says:
The implementation of this bit is dependent upon the value of the CAP.SAM bit.
If CAP.SAM is '0', then GHC.AE shall be read-write and shall have a reset value of '0'.
If CAP.SAM is '1', then AE shall be read-only and shall have a reset value of '1'.
Which means I should activate GHC.AE manually.

If I do that, all the flags in the port.ssts are 0 (and not DET_PRESENT, IPM_ACTIVE) therefore I cant rebase them.
If I dont activate AHCI mode by writing the bit, I can rebase the ports but reading from them times out.

My code:

Code: Select all

if(pci_info->class.sub_class == 6) //AHCI
{
	printf("Device is AHCI ready!\n");
	
	abar = (HBA_MEM*)(pci_info->address5 & 0xFFFFE000);
	malloc_mark_used_adr((void*)abar);
	
	//Needed to be set for a full reset
	abar->ghc |= 0x80000000;

	Sleep(100);

	//Resetting HBA
	abar->ghc |= 1;
	while(abar->ghc & 1)
		Sleep(10);
	
	Sleep(100);
	
	//Enable AHCI if not enabled yet
	if (!(abar->ghc & 0x80000000))
		abar->ghc |= 0x80000000;
	
	int i;
	for(i = 0; i < 32; i++)
	{
		//Check for drive status
		if(!(abar->pi & (1 << i)))
			continue;
		if((abar->ports[i].ssts & 0x0F) != HBA_PORT_DET_PRESENT || ((abar->ports[i].ssts >> 8) & 0x0F) != HBA_PORT_IPM_ACTIVE)
			continue;
		
		port_rebase(&abar->ports[i], i);
		
		malloc_mark_used_adr(*(void**)&abar->ports[i]);
		
		ahci_devices[i].available = true;
		ahci_devices[i].type = abar->ports[i].sig;
		ahci_devices[i].has_data = false;
		
		device_count++;
	}
}
Im really lost and hope someone can give me a hint into the right direction.
Thanks in advance!
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: SATA and AHCI on real Hardware

Post by SpyderTL »

Complete shot in the dark here, but did you check the BIOS configuration to make sure it wasn't in IDE compatibility mode?
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: SATA and AHCI on real Hardware

Post by BrightLight »

SpyderTL wrote:Complete shot in the dark here, but did you check the BIOS configuration to make sure it wasn't in IDE compatibility mode?
In IDE compatibility mode, the AHCI controller doesn't even appear in the PCI configuration space, being replaced by an IDE controller with I/O ports in BAR0 and BAR1, and thus AHCI code would fail to detect anything. At least it's like this on my two test PCs.
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
Ch4ozz
Member
Member
Posts: 170
Joined: Mon Jul 18, 2016 2:46 pm
Libera.chat IRC: esi

Re: SATA and AHCI on real Hardware

Post by Ch4ozz »

Yes its in AHCI mode, I checked that.
I read the data sheet up and down and tried alot of stuff but I cant get this to work.
I also already checked the linux source but it wont help either :(

For some reason when I go into AHCI mode by setting AE all the status flags are 0 and when using ACPI I cant shut down the PC anymore
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: SATA and AHCI on real Hardware

Post by SpyderTL »

Have you tried booting Linux, and does it seem to have any problems with that AHCI controller?

Exactly how old is that machine?
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
User avatar
Kazinsal
Member
Member
Posts: 559
Joined: Wed Jul 13, 2011 7:38 pm
Libera.chat IRC: Kazinsal
Location: Vancouver
Contact:

Re: SATA and AHCI on real Hardware

Post by Kazinsal »

Perhaps the BIOS isn't releasing control of the HBA. Are you properly handling BIOS/OS Handoff Control (HBA memory offset 0x28)?
User avatar
Ch4ozz
Member
Member
Posts: 170
Joined: Mon Jul 18, 2016 2:46 pm
Libera.chat IRC: esi

Re: SATA and AHCI on real Hardware

Post by Ch4ozz »

SpyderTL wrote:Have you tried booting Linux, and does it seem to have any problems with that AHCI controller?

Exactly how old is that machine?
It should be from arround 2009
Booting up with windows works fine when its set to AHCI mode, it detects cdrom and hdd
Kazinsal wrote:Perhaps the BIOS isn't releasing control of the HBA. Are you properly handling BIOS/OS Handoff Control (HBA memory offset 0x28)?
Checking this right now, the cap2 tells me it supports it atleast.

EDIT: I added the following code and I get control but it doesnt change anything sadly:

Code: Select all

printf("Handoff: %X\n", abar->cap2 & 1);
		
abar->bohc |= 2;
		
while(!(abar->bohc & 2) || (abar->bohc & 1))
	Sleep(10);
		
printf("Got access to HBA!\n");


Im not sure if I have to do a specific task the BIOS did before, but actually the code should run...
Theres not much more I can do before setting the AHCI Enabled bit :(
Should I update the BIOS? Not sure ...
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: SATA and AHCI on real Hardware

Post by BenLunt »

Since the HBA (AHCI controller card) will have an optional ROM BIOS present, it most likely has already reset the HBA for you. It knows exactly how to do it, so I would allow it to. Therefore, skip the HBA reset until you actually need it.

However, I would do a Port Reset on each implemented port causing a COMRESET to be sent.
Write a 1 to PxSCTL.DET, wait a minimum of 1 mS, then clear PxSCTL.DET. Then wait for (with timeout) PxSSTS.DET == 3.

Also, within your code, you do

Code: Select all

while(abar->ghc & 1)
      Sleep(10);
Depending on the compiler and its options, the compiler could completely skip that whole block of code since it can't see any reason abar->ghc would ever change. Is abar set as volatile?

I suggest that you create two functions, one to read a dword from the controller and one to write a dword to the controller.

The compiler might change the read of 'abar->ghc' above to a byte read, where as the HBA might not like that byte read.

Ben
http://www.fysnet.net/media_storage_devices.htm
User avatar
Ch4ozz
Member
Member
Posts: 170
Joined: Mon Jul 18, 2016 2:46 pm
Libera.chat IRC: esi

Re: SATA and AHCI on real Hardware

Post by Ch4ozz »

BenLunt wrote:Since the HBA (AHCI controller card) will have an optional ROM BIOS present, it most likely has already reset the HBA for you. It knows exactly how to do it, so I would allow it to. Therefore, skip the HBA reset until you actually need it.

However, I would do a Port Reset on each implemented port causing a COMRESET to be sent.
Write a 1 to PxSCTL.DET, wait a minimum of 1 mS, then clear PxSCTL.DET. Then wait for (with timeout) PxSSTS.DET == 3.

Also, within your code, you do

Code: Select all

while(abar->ghc & 1)
      Sleep(10);
Depending on the compiler and its options, the compiler could completely skip that whole block of code since it can't see any reason abar->ghc would ever change. Is abar set as volatile?

I suggest that you create two functions, one to read a dword from the controller and one to write a dword to the controller.

The compiler might change the read of 'abar->ghc' above to a byte read, where as the HBA might not like that byte read.

Ben
http://www.fysnet.net/media_storage_devices.htm
Thanks, I will try a port reset.
I decleared the struct itself and the variable abar as volatile and disabled optimization for testing (-O0) so I should be fine here.
Nevertheless I will take a peek with IDA and check if everything is alright!

EDIT: The complete reset seems to work fine, but I will remove it for now and add the port reset
Also took a look at my kernel with IDA and it looks perfectly right

So I tested a portreset using this code:

Code: Select all

//Port reset
abar->ports[i].cmd &= ~HBA_PxCMD_ST;

while(abar->ports[i].cmd & HBA_PxCMD_CR)
	Sleep(10);

Sleep(1000);

uint32_t val = (abar->ports[i].sctl & 0xFFFFFFF0) | 1;
abar->ports[i].sctl = val; 

Sleep(1000);

abar->ports[i].sctl &= 0xFFFFFFF0;

while((abar->ports[i].sctl & 0xF) != 3)
{
	printf("sctl: %X\n", (abar->ports[i].sctl & 0xF));
	Sleep(1000);
}

Sleep(1000);

abar->ports[i].serr = 0xFFFFFFFF;
Everything works fine until I hit the sctl printf.
I always get 0 and not 3 as expected :(

Aso checked the BIOS version, its from 10/17/2012
User avatar
Ch4ozz
Member
Member
Posts: 170
Joined: Mon Jul 18, 2016 2:46 pm
Libera.chat IRC: esi

Re: SATA and AHCI on real Hardware

Post by Ch4ozz »

I rechecked my port reset code and also found interesting stuff about SSS supporting devices.
I added this code before checking DET and it finally works!

Code: Select all

//Check for drive status
if(!(abar->pi & (1 << i)))
	continue;

//If port is not idle force it to be idle
if(abar->ports[i].cmd & (HBA_PxCMD_ST | HBA_PxCMD_CR | HBA_PxCMD_FRE | HBA_PxCMD_FR))
	stop_cmd(&abar->ports[i]);

port_rebase(&abar->ports[i], i);

//Reset port, disable slumber and partial state
abar->ports[i].sctl = 0x301;
Sleep(50);
abar->ports[i].sctl = 0x300;

if(abar->cap & HBA_MEM_CAP_SSS)
{
	abar->ports[i].cmd |= (HBA_PxCMD_SUD | HBA_PxCMD_POD | HBA_PxCMD_ICC);
	Sleep(10);
}

//Clear interrupt status and error status
abar->ports[i].serr = 0xFFFFFFFF;
abar->ports[i].is = 0xFFFFFFFF;
Thanks alot guys!
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: SATA and AHCI on real Hardware

Post by SpyderTL »

The staggered spin up flag isn't mentioned on the AHCI wiki page. If you feel like you understand it well enough, can you add a quick section about what it is, and how it affects your driver code?

Thanks.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
User avatar
Ch4ozz
Member
Member
Posts: 170
Joined: Mon Jul 18, 2016 2:46 pm
Libera.chat IRC: esi

Re: SATA and AHCI on real Hardware

Post by Ch4ozz »

SpyderTL wrote:The staggered spin up flag isn't mentioned on the AHCI wiki page. If you feel like you understand it well enough, can you add a quick section about what it is, and how it affects your driver code?

Thanks.
I wont say that I completely understood everything it does.
As far as I understood, it supports spinning up all devices with a different level of power usage.
All I did was setting 2 more flags in order to get the device into running state:
During initial system power-on in a system that supports staggered spin-up, software needs to spin up
each attached device. In addition, when the system transitions from the S3 or greater system power
management state back to S0, the attached drives will also need to be spun up. In order to spin up the
devices attached to the HBA, software should perform the procedure outlined in section 10.1.1 for
staggered spin-up.

Power On Device (POD): This bit is read/write for HBAs that support cold presence
detection on this port as indicated by PxCMD.CPD set to ‘1’. This bit is read only ‘1’ for
HBAs that do not support cold presence detect. When set, the HBA sets the state of a
pin on the HBA to ‘1’ so that it may be used to provide power to a cold-presence
detectable port.
This has barely anything to do with staggered spin-up other then its initialization :D
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: SATA and AHCI on real Hardware

Post by SpyderTL »

Understood. I will eventually get around to working on my AHCI driver, and if it hasn't been done by then, I'll try to clarify these flags on the wiki page.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
Post Reply