How to reduce the SATA link speed of drive in CentOS?

How do I make CentOS run SATA drives at 3Gb/s at boot?

Background:

I'm having an issue with a motherboard that claims to support 6Gb/s SATA transfer speeds, but when using 4 drives on it, in a software RAID 10 with heavy disk IO, some of the SATA links start throwing kernel errors, ie. ata1.00: failed command: WRITE FPDMA QUEUED. But it's a different drive each time, not always ata1, and running extended test on each disk individually produces no errors.

When the errors occur, the Kernel/OS (CentOS 6.2) eventually resets the link several times, and when it continues to fail, then it changes the link speed to 3Gb/s. Once that happens, the errors stop for that drive for the remainder of the session.

What I'd like to do is tell the OS to set the SATA links to 3Gb/s to start with on boot, since I don't think the motherboard's SATA bus can handle all 4 drives at 6Gb/s. I couldn't find an option in the Motherboard's BIOS to change the link speed.

Questions:

  1. How would I go about doing that? ie. a config file?

  2. Can it be done while the system is running with the RAID array assembled and root partition mounted, or do I need to boot from a rescue CD?

  3. Will this result in any data loss? I have backups of course, but reinstalling/restoring is several hours of work that I'd like to avoid if possible.


Solution 1:

There is nothing at runtime unfortunately (there is /sys/class/ata_link which contains read only infomation).

However at boot it seems you can setup parameters forcing values that you want. The documentation for this is here: https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html

Specifically 
    libata.force=   [LIBATA] Force configurations.  The format is comma
            separated list of "[ID:]VAL" where ID is
            PORT[.DEVICE].  PORT and DEVICE are decimal numbers
            matching port, link or device.  Basically, it matches
            the ATA ID string printed on console by libata.  If
            the whole ID part is omitted, the last PORT and DEVICE
            values are used.  If ID hasn't been specified yet, the
            configuration applies to all ports, links and devices.

            If only DEVICE is omitted, the parameter applies to
            the port and all links and devices behind it.  DEVICE
            number of 0 either selects the first device or the
            first fan-out link behind PMP device.  It does not
            select the host link.  DEVICE number of 15 selects the
            host link and device attached to it.

            The VAL specifies the configuration to force.  As long
            as there's no ambiguity shortcut notation is allowed.
            For example, both 1.5 and 1.5G would work for 1.5Gbps.
            The following configurations can be forced.

            * Cable type: 40c, 80c, short40c, unk, ign or sata.
              Any ID with matching PORT is used.

            * SATA link speed limit: 1.5Gbps or 3.0Gbps.

            * Transfer mode: pio[0-7], mwdma[0-4] and udma[0-7].
              udma[/][16,25,33,44,66,100,133] notation is also
              allowed.

            * [no]ncq: Turn on or off NCQ.

            * nohrst, nosrst, norst: suppress hard, soft
                          and both resets.

            * dump_id: dump IDENTIFY data.

            If there are multiple matching configurations changing
            the same attribute, the last one is used.

From the looks of things the kernel parameter libata.force=3.0G should work..

With regards to data loss, probably not -- but frankly since the SATA vendors clearly haven't honored the SATA spec correctly (or its buggy or whatever) then who knows.

Solution 2:

MIfe's answer here was a good clue (+1 for helpful reference), but not entirely complete.

To set the SATA links to 3Gb/s:

  1. Edit /boot/grub/grub.conf

  2. Find the line that starts with kernel. On mine, it was:

    kernel /vmlinuz-2.6.32-220.17.1.el6.x86_64 ro root=/dev/mapper/vg_lago-host rd_NO_LUKS LANG=en_US.UTF-8...

  3. Add libata.force=3.0 into that kernel line somewhere.

  4. Reboot

After doing the above, I am now able to run IO intensive operations like copying virtual machine images from one part of the disk to another without getting any more WRITE FPDMA QUEUED errors.