Saturday, 27 June 2009

SATA AHCI mode on systems without BIOS option

Background:
I've got a Dell Poweredge SC430 I bought a couple of years back.
I recently put 4 new WD 1TB drives in it which support native command queuing and installed the latest Ubuntu 9.04 whilst I was rebuilding my server.
Anyway, I noticed linux was only using the ata_piix module for my onboard SATA ICH7 family controller (integrated in the Intel Chipset). As some background, many SATA controllers offer a legacy mode (ATA/IDE emulation mode) and native mode (AHCI or RAID). Normally you can change which mode the controller is in via the BIOS hoever for whatever reason Dell chose not to include this option in my system.

Problem: The hardware ID that the controller reports to the system is dependant on which mode the controller is in. This means that the OS can load the appropriate driver depending on the mode of the controller. For Windows users the solution is aparently easy, you can force Windows to use the AHCI driver when the controller is still in the legacy mode. I presume the driver then detects that the controller is in legacy mode and instructs it to change to AHCI mode on the fly.

Unfortunately for linux this isn't exactly easy to do. To force linux to use a particular module with hardware that it doesn't have it must have it's hardware ID listed in the driver when the module is built. This means compiling the kernel from source. This also means re-compiling the kernel from source whenever you want to update your kernel, not something I want to have to deal with.

Fortunately some clever Mac Pro users have found another way. Instead of modifying the linux kernel, they edited the stage1 part of the grub bootloader to add some assembly commands to instruct the controller to switch modes. This is a fantastic hack for several reasons:
  1. As grub can boot virtually any OS, this hack will ensure AHCI mode is available for any OS, not just linux
  2. Grub, and especially the stage1 file, is relatively static and doesn't get updated too often, so no need to worry about patching new versions continually
  3. No need to worry about kernel updates clobbering the patch and no need to compile the kernel from source every time there is an update
Solution: Note, at the time of writing this, I used grub 0.97, you might need to change some directory paths appropriately if you use a different version.

This patch, whilst originally written for a Mac Pro with an Intel 631xESB/632xESB Controller just happens to work perfectly on my Dell with an ICH7 Controller. Note that I did indeed verify that the commands to switch SATA mode were identical by comparing the Intel documentation here: http://www.intel.com/Assets/PDF/datasheet/313082.pdf Port Mapping Register (SATA–D31:F2) on page 764 and here: http://www.intel.com/Assets/PDF/datasheet/307013.pdf Sub Class Code Register (SATA–D31:F2) on page 495.

You should verify at least two things before trying this patch:
  • ensure your chipset supports AHCI (not all ICH7 variants do)
  • ensure your chipset has the same format command at the same offset to switch modes (if it is an Intel, I'd hope that they're consistent, they seem to be so far)
If you're happy to try this out, here's how you do it:
  1. Get the source of grub, in ubuntu:
    sudo apt-get source grub
  2. If you're using and x64 OS you'll need the 32bit libc dev files:
    sudo apt-get install libc6-dev-i386
  3. Get the patch:
    http://boeglin.org/static/macpro/grub-0.97_macpro_esb2_ahci_stage1_new.patch
  4. Apply the patch
    patch grub-0.97/stage1/stage1.S grub-0.97_macpro_esb2_ahci_stage1_new.patch
  5. Configure grub
    cd grub-0.97; ./configure
  6. Build grub:
    make all
  7. Find your grub installed libraries. eg:
    cd /usr/lib/grub/x86_64-pc
  8. Backup your grub existing grub stage1 file
  9. Copy the compiled stage1 to your grub library directory
  10. Update your grub bootloader. eg:
    grub-install hd0
  11. Note: grub-install will overwrite /boot/grub/stage1 with the stage1 from your library directory so you'll need to make sure you're putting the patched stage1 in the library directory NOT the /boot/grub or equivalent directory
  12. Reboot and verify your controller is now using the ahci module!

12 comments:

Albator said...

Excellent trick, I've been looking forward this kind of info for a long time.

Alas, it does not work on my laptop Dell XPS M1210 with ICH7 (8086:27c4) under Mandriva 2009.1 64 bits. Grub hangs immediatly and it just writes the word "GRUB" on top left of the screen, with a blinking cursor :'-(

I have tested the same "stage1" with the same Distro running under Virtualbox (emulating an ICH8M 8086:2829), and it works correctly, meaning my compilation is correct.

I will try tommorrow on a desktop Dell Optiplex 745 with a real ICH8 inside.

Alan Murray said...

Hi Albator,

I would suspect that your XPS M1210 might not support AHCI mode. Not all ICH7 chipsets support it. Do you know if you can force Windows to load the Intel AHCI driver?

You might have better luck with your Optiplex.

Good luck.

Albator said...

Hello again,
I have no more success on Dell Optiplex 745. The ICH8 is 8086:2820 .

When using the modified stage1 (my own OR the one found on the Mac forum), the Optiplex boots fine but the ICH8 is still detected as normal, non-ahci controller.
At least it doesnt crash the system like it does on the XPS M1210 ... but the patch is useless.

Looking into the source code of the grub patch, I understand how it works, but I am wondering where the memory adress 0x8000fa90 comes from.

I have done other tests. Under both computers, I manage to switch mode of ICH controller while running Linux (8086:27c4 becomes 8086:27c5, and 8086:2820 becomes 8086:2824), causing a crash soon after (the hard disks becoming inaccessible ...), so it is possible to switch mode.
But why doesn't it work inside Grub ? I suspect the memory address given in the grub patch may differ depending on the PC configuration.

Alex said...

Hi,

The address is actually:
0x80000000 | (pci_bus << 16) | (pci_device << 11) | (pci_function << 8) | (offset & 0xfc)

And according to the spec, 0x90 is the offset that is used to specify the mode (Legacy IDE, AHCI or RAID), and the controller should be on bus 0, device 0x1f, function 2.

Regards,
Alex

Alexandru said...

Hi, Alan! Could you, please, tell me if your Dell Poweredge had an AHCI Option BIOS? As far as I could see, one needs an option BIOS in order to manage the AHCI feature of the chipset and to be able to boot from that chpset. This option BIOS is separated from the main setup BIOS. It is loaded only if the AHCI (or RAID) mode has been enabled in the setup BIOS. One may consider this option BIOS like the BIOS stored in the flash memory of an add-on SCSI/SATA card.

Alan Murray said...

Hi Alexandru,
I don't think my Dell has an option BIOS. I'm guessing you're referring to the ability to put the controller in RAID mode and then set up RAID? Otherwise I'm not really sure what options you can configure in AHCI mode anyway.

If you're trying to set up pseudo-hardware raid, may I suggest you do some googling and compare pseudo-hardware raid to linux software raid. I'm saying pseudo-hardware raid as these controllers get your CPU to do all the hard work.

In my opinion its a loose-loose option to use it (if anything it's slower than linux software raid and you still get the problem of it being a proprietary lock in option that isn't easily manageable on a live system).

Tim Small said...

I have written a Linux PCI quirk which puts my ICH8 box (abit ib9) into AHCI mode. Might be able to test on an Optiplex 745 soon...

I aim to get this working on some Dell poweredges (r200 / r300) soon - as these have no bios ahci support either...

If anyone would like to be a tester, please let me know - I'd like to get this patch (when it's finished) into the mainline kernel....

Tim.

Alan Murray said...

Hi Tim, how did you go with your quirk patch?
I'd be happy to test it out for you!
Making sure grub updates don't clobber this work around is getting a bit tiresome.

Tim Small said...

I got it to the point where it worked on the Poweredge R300 which I had to test it on.

Then I discovered Matthew Garrett had also written one using a similar but probably better approach.

The immediate reason I had to complete that work went away, but it's on my TODO list to ask on the linux-pci list which is best approach, and then try and push it into the mainline...

Tim.

Bryan Smith said...

sorry to revive this but does this leave the controller in ahci mode?

Bryan Smith said...

sorry to revive this but does this leave the controller in ahci mode

Scott Rhee said...

To confirm that ICH7-M has the same way to enable AHCI, I checked the latest datasheet here:

http://www.intel.com.au/content/dam/doc/datasheet/i-o-controller-hub-7-datasheet.pdf

On p509, I found offset 90h at section 12.1.33 as you described. So now what I have to do is to write the byte of AHCI + non-Combined mode on that address, using GRUB. And after some research, I found that (probably) GRUB can load Windows.

Thanks for this interesting tip!

Regards,
Scott