Bug #3797

AHCI: Support for ASMedia ASM106x

Added by Marcel Telka over 3 years ago. Updated over 3 years ago.

Status:ResolvedStart date:2013-05-29
Priority:NormalDue date:
Assignee:Marcel Telka% Done:

100%

Category:driver - device drivers
Target version:-
Difficulty:Medium Tags:

Description

AHCI driver is unable to do port reset properly on this SATA AHCI Controller:

  • ASMedia Technology Inc. ASM1062 Serial ATA Controller
# cfgadm -y -x sata_reset_port sata1/0
cfgadm: Hardware specific failure: Driver ioctl failed I/O error
#

Several other SATA AHCI Controllers were tested and all of them are able to properly do the port reset (cfgadm completed without an error). These controllers were tested:

  • Intel Corporation 6 Series/C200 Series Chipset Family SATA AHCI Controller
  • NVIDIA Corporation MCP78S [GeForce 8200] AHCI Controller
  • Intel Corporation 82801HM/HEM (ICH8M/ICH8M-E) SATA Controller [AHCI mode]
  • Advanced Micro Devices [AMD] nee ATI SB7x0/SB8x0/SB9x0 SATA Controller [AHCI mode]
  • Intel Corporation C600/X79 series chipset 6-Port SATA AHCI Controller
  • Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode] (rev 02)

The difference seems to be that the ASM1062 offers "staggered spin-up" support via CAP.SSS = 1 (see AHCI specification), while all other tested AHCI controllers does not (CAP.SSS = 0 for them).

This issue could be easily tested/reproduced using this:

1. Identify your SATA HBAs:

  • run `scanpci`
  • run `cfgadm | grep sata./0`

2. Run this dtrace script:

# dtrace -n 'ahci_port_reset:entry {trace((1&((ahci_port_t *)arg1)->ahciport_flags) ? "SSS" : "no SSS")}' &

3. Reset first SATA port for all SATA HBA you have.

# cfgadm -y -x sata_reset_port sata0/0
# cfgadm -y -x sata_reset_port sata1/0
# ... etc

For example:

Step 1:

# scanpci | grep -i ata
 Intel Corporation 6 Series/C200 Series Chipset Family SATA AHCI Controller
 ASMedia Technology Inc. ASM1062 Serial ATA Controller
# cfgadm | grep sata./0
sata0/0::dsk/c6t0d0            disk         connected    configured   ok
sata1/0                        sata-port    disconnected unconfigured failed
#

Okay, I have two SATA HBA: sata0 and sata1.

Step 2:

# dtrace -n 'ahci_port_reset:entry {trace((1&((ahci_port_t *)arg1)->ahciport_flags) ? "SSS" : "no SSS")}' &
dtrace: description 'ahci_port_reset:entry ' matched 1 probe

Step 3:

# cfgadm -y -x sata_reset_port sata0/0
#   3  48644            ahci_port_reset:entry   no SSS

# cfgadm -y -x sata_reset_port sata1/0
cfgadm: Hardware specific failure: Driver ioctl failed I/O error

#   3  48644            ahci_port_reset:entry   SSS

The ahci_port_reset function is failing at line 5355 here:

5345    /*
5346     * A COMINIT signal is supposed to be received
5347     * PxSERR.DIAG.X or PxIS.PCS should be set
5348     */
5349    if (!(port_intr_status & AHCI_INTR_STATUS_PCS) &&
5350        !(port_serror & SERROR_EXCHANGED_ERR)) {
5351        cmn_err(CE_WARN, "!ahci%d: ahci_port_reset port %d " 
5352            "COMINIT signal from the device not received",
5353            instance, port);
5354        AHCIPORT_SET_STATE(ahci_portp, addrp, SATA_PSTATE_FAILED);
5355        return (AHCI_FAILURE);
5356    }

Related issues

Related to illumos gate - Bug #3815: AHCI: Support for Marvell 88SE9128 Resolved 2013-06-14
Duplicated by illumos gate - Bug #3099: AMD hudson D3 AHCI support Closed 2012-08-20

History

#1 Updated by Marcel Telka over 3 years ago

  • Subject changed from AHCI: Staggered spin-up does not work with ASM106x to AHCI: Support for ASMedia ASM106x

Several issues were found (most of them are not directly related to the ASM1062 issue; they are fixed here to make the ahci driver more robust):

  • 64-bit access sometimes fail for ASM1062

PxCLB, PxCLBU, PxFB, and PxFBU are written using ddi_put64(). According the AHCI spec (first paragraph in chapter 3) this should work. But it sometimes does not work properly for ASM1062 (looks like a bug in ASM1062).

This caused the wrong addresses were programmed for DMA engines, so the HBA wrote and/or read to/from random address in RAM. Result: SATA Command timeouts, machine hangs.

This is fixed/workarounded in ahci_setup_port_base_addresses().

  • Base addresses should be programmed when the port is idle

When the PxCLB, PxCLBU, PxFB, and PxFBU are programmed both DMA engines must be idle (AHCI spec, chapter 10.3). The original code had no such check.

Now the ahci_setup_port_base_addresses() contains code to turn off the DMA engines before PxCLB, PxCLBU, PxFB, and PxFBU registers are written.

  • Staggered spin-up is always tried in ahci_port_reset(), even the device is already spun-up

Once the AHCI_PORT_FLAG_SPINUP is set for a port, it is never cleared. In a case the drive is already spun-up (PxCMD.SUD is 1) the port reset should be performed using the same steps as it is done on a controller without the staggered spin-up support. Instead, the ahci driver ignores the PxCMD.SUD in a case the CAP.SSS is 1 and tries to do the staggered spin-up by clearing PxCMD.SUD and setting it back to 1 after a while. The PxCMD.SUD clearing is explicitly forbidden by the AHCI spec (chapter 10.10.1):

Software must only clear PxCMD.SUD if it believes that no device is attached.

The fix removes the staggered spin-up code from ahci_port_reset(). Such code is now in ahci_initialize_port() and ahci_hba_reset().

  • GHC.AE should be set first

According to the AHCI spec (chapter 5.3.2.3), the GHC.AE shall be set to 1 before any other AHCI register is accessed.

The GHC.AE initialization was moved from ahci_initialize_controller() to ahci_attach() to achieve this.

  • CAP2 dump

ahci_attach() now dumps value of CAP2 register for AHCI version 1.2+ (chapter 3.1.10).

  • ahcictl_num_ports initialization

The ahcictl_num_ports initialization in ahci_attach() assumed the CAP.NP should contain max. number of supported port by the HBA. This is not specified in the AHCI spec (see chapter 3.1.4 for details).

  • ahci_watchdog_tick is set after the mod_install() call in _init()

This could lead to uninitialized ahci_watchdog_tick when ahci_attach() is called. See mod_install(9f).

#2 Updated by Marcel Telka over 3 years ago

  • Status changed from New to In Progress

#3 Updated by Robert Mustacchi over 3 years ago

  • Tags deleted (needs-triage)
  • % Done changed from 0 to 100
  • Status changed from In Progress to Resolved

Resolved in 2ac302890e472bf0c11db192dd18f12ded6043f6.

Also available in: Atom