aboutsummaryrefslogtreecommitdiff
path: root/drivers/ata
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/Kconfig736
-rw-r--r--drivers/ata/Makefile100
-rw-r--r--drivers/ata/acard-ahci.c511
-rw-r--r--drivers/ata/ahci.c2716
-rw-r--r--drivers/ata/ahci.h410
-rw-r--r--drivers/ata/ahci_da850.c115
-rw-r--r--drivers/ata/ahci_imx.c527
-rw-r--r--drivers/ata/ahci_mvebu.c128
-rw-r--r--drivers/ata/ahci_platform.c105
-rw-r--r--drivers/ata/ahci_st.c245
-rw-r--r--drivers/ata/ahci_sunxi.c252
-rw-r--r--drivers/ata/ahci_xgene.c523
-rw-r--r--drivers/ata/ata_generic.c124
-rw-r--r--drivers/ata/ata_piix.c1142
-rw-r--r--drivers/ata/libahci.c2482
-rw-r--r--drivers/ata/libahci_platform.c549
-rw-r--r--drivers/ata/libata-acpi.c563
-rw-r--r--drivers/ata/libata-core.c2755
-rw-r--r--drivers/ata/libata-eh.c1861
-rw-r--r--drivers/ata/libata-pmp.c334
-rw-r--r--drivers/ata/libata-scsi.c1871
-rw-r--r--drivers/ata/libata-sff.c2332
-rw-r--r--drivers/ata/libata-transport.c785
-rw-r--r--drivers/ata/libata-transport.h18
-rw-r--r--drivers/ata/libata-zpodd.c283
-rw-r--r--drivers/ata/libata.h144
-rw-r--r--drivers/ata/pata_acpi.c69
-rw-r--r--drivers/ata/pata_ali.c199
-rw-r--r--drivers/ata/pata_amd.c198
-rw-r--r--drivers/ata/pata_arasan_cf.c976
-rw-r--r--drivers/ata/pata_artop.c180
-rw-r--r--drivers/ata/pata_at32.c31
-rw-r--r--drivers/ata/pata_at91.c457
-rw-r--r--drivers/ata/pata_atiixp.c125
-rw-r--r--drivers/ata/pata_atp867x.c573
-rw-r--r--drivers/ata/pata_bf54x.c468
-rw-r--r--drivers/ata/pata_cmd640.c51
-rw-r--r--drivers/ata/pata_cmd64x.c285
-rw-r--r--drivers/ata/pata_cs5520.c81
-rw-r--r--drivers/ata/pata_cs5530.c43
-rw-r--r--drivers/ata/pata_cs5535.c48
-rw-r--r--drivers/ata/pata_cs5536.c172
-rw-r--r--drivers/ata/pata_cypress.c36
-rw-r--r--drivers/ata/pata_efar.c90
-rw-r--r--drivers/ata/pata_ep93xx.c1037
-rw-r--r--drivers/ata/pata_hpt366.c251
-rw-r--r--drivers/ata/pata_hpt37x.c597
-rw-r--r--drivers/ata/pata_hpt3x2n.c369
-rw-r--r--drivers/ata/pata_hpt3x3.c94
-rw-r--r--drivers/ata/pata_icside.c58
-rw-r--r--drivers/ata/pata_imx.c258
-rw-r--r--drivers/ata/pata_isapnp.c18
-rw-r--r--drivers/ata/pata_it8213.c72
-rw-r--r--drivers/ata/pata_it821x.c373
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c58
-rw-r--r--drivers/ata/pata_jmicron.c24
-rw-r--r--drivers/ata/pata_legacy.c268
-rw-r--r--drivers/ata/pata_macio.c1421
-rw-r--r--drivers/ata/pata_marvell.c83
-rw-r--r--drivers/ata/pata_mpc52xx.c636
-rw-r--r--drivers/ata/pata_mpiix.c29
-rw-r--r--drivers/ata/pata_netcell.c43
-rw-r--r--drivers/ata/pata_ninja32.c70
-rw-r--r--drivers/ata/pata_ns87410.c29
-rw-r--r--drivers/ata/pata_ns87415.c71
-rw-r--r--drivers/ata/pata_octeon_cf.c1080
-rw-r--r--drivers/ata/pata_of_platform.c53
-rw-r--r--drivers/ata/pata_oldpiix.c35
-rw-r--r--drivers/ata/pata_opti.c26
-rw-r--r--drivers/ata/pata_optidma.c33
-rw-r--r--drivers/ata/pata_palmld.c138
-rw-r--r--drivers/ata/pata_pcmcia.c268
-rw-r--r--drivers/ata/pata_pdc2027x.c106
-rw-r--r--drivers/ata/pata_pdc202xx_old.c76
-rw-r--r--drivers/ata/pata_piccolo.c125
-rw-r--r--drivers/ata/pata_platform.c76
-rw-r--r--drivers/ata/pata_pxa.c398
-rw-r--r--drivers/ata/pata_qdi.c366
-rw-r--r--drivers/ata/pata_radisys.c39
-rw-r--r--drivers/ata/pata_rb532_cf.c (renamed from drivers/ata/pata_rb500_cf.c)137
-rw-r--r--drivers/ata/pata_rdc.c398
-rw-r--r--drivers/ata/pata_rz1000.c56
-rw-r--r--drivers/ata/pata_samsung_cf.c684
-rw-r--r--drivers/ata/pata_sc1200.c80
-rw-r--r--drivers/ata/pata_scc.c153
-rw-r--r--drivers/ata/pata_sch.c180
-rw-r--r--drivers/ata/pata_serverworks.c182
-rw-r--r--drivers/ata/pata_sil680.c193
-rw-r--r--drivers/ata/pata_sis.c238
-rw-r--r--drivers/ata/pata_sl82c105.c79
-rw-r--r--drivers/ata/pata_triflex.c53
-rw-r--r--drivers/ata/pata_via.c494
-rw-r--r--drivers/ata/pata_winbond.c282
-rw-r--r--drivers/ata/pdc_adma.c113
-rw-r--r--drivers/ata/sata_dwc_460ex.c1822
-rw-r--r--drivers/ata/sata_dwc_pmp.c3041
-rw-r--r--drivers/ata/sata_fsl.c729
-rw-r--r--drivers/ata/sata_highbank.c650
-rw-r--r--drivers/ata/sata_inic162x.c743
-rw-r--r--drivers/ata/sata_mv.c2915
-rw-r--r--drivers/ata/sata_nv.c636
-rw-r--r--drivers/ata/sata_promise.c435
-rw-r--r--drivers/ata/sata_qstor.c160
-rw-r--r--drivers/ata/sata_rcar.c1004
-rw-r--r--drivers/ata/sata_sil.c241
-rw-r--r--drivers/ata/sata_sil24.c207
-rw-r--r--drivers/ata/sata_sis.c155
-rw-r--r--drivers/ata/sata_svw.c162
-rw-r--r--drivers/ata/sata_sx4.c255
-rw-r--r--drivers/ata/sata_uli.c56
-rw-r--r--drivers/ata/sata_via.c351
-rw-r--r--drivers/ata/sata_vsc.c68
112 files changed, 38941 insertions, 12382 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 292aa9a0f02..2664da32d9d 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -2,15 +2,22 @@
# SATA/PATA driver configuration
#
+config HAVE_PATA_PLATFORM
+ bool
+ help
+ This is an internal configuration node for any machine that
+ uses pata-platform driver to enable the relevant driver in the
+ configuration structure without having to submit endless patches
+ to update the PATA_PLATFORM entry.
+
menuconfig ATA
- tristate "Serial ATA (prod) and Parallel ATA (experimental) drivers"
+ tristate "Serial ATA and Parallel ATA drivers (libata)"
depends on HAS_IOMEM
depends on BLOCK
- depends on !(M32R || M68K) || BROKEN
- depends on !SUN4 || BROKEN
+ depends on !(M32R || M68K || S390) || BROKEN
select SCSI
---help---
- If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
+ If you want to use an ATA hard disk, ATA tape drive, ATA CD-ROM or
any other ATA device under Linux, say Y and make sure that you know
the name of your ATA host adapter (the card inside your computer
that "speaks" the ATA protocol, also called ATA controller),
@@ -27,10 +34,20 @@ config ATA_NONSTANDARD
bool
default n
+config ATA_VERBOSE_ERROR
+ bool "Verbose ATA error reporting"
+ default y
+ help
+ This option adds parsing of ATA command descriptions and error bits
+ in libata kernel output, making it easier to interpret.
+ This option will enlarge the kernel by approx. 6KB. Disable it only
+ if kernel size is more important than ease of debugging.
+
+ If unsure, say Y.
+
config ATA_ACPI
bool "ATA ACPI Support"
depends on ACPI && PCI
- select ACPI_DOCK
default y
help
This option adds support for ATA-related ACPI objects.
@@ -41,6 +58,20 @@ config ATA_ACPI
You can disable this at kernel boot time by using the
option libata.noacpi=1
+config SATA_ZPODD
+ bool "SATA Zero Power Optical Disc Drive (ZPODD) support"
+ depends on ATA_ACPI && PM_RUNTIME
+ default n
+ help
+ This option adds support for SATA Zero Power Optical Disc
+ Drive (ZPODD). It requires both the ODD and the platform
+ support, and if enabled, will automatically power on/off the
+ ODD when certain condition is satisfied. This does not impact
+ end user's experience of the ODD, only power is saved when
+ the ODD is not in use (i.e. no disc inside).
+
+ If unsure, say N.
+
config SATA_PMP
bool "SATA Port Multiplier support"
default y
@@ -48,6 +79,8 @@ config SATA_PMP
This option adds support for SATA Port Multipliers
(the SATA version of an ethernet hub, or SAS expander).
+comment "Controllers with non-SFF native interface"
+
config SATA_AHCI
tristate "AHCI SATA support"
depends on PCI
@@ -56,14 +89,64 @@ config SATA_AHCI
If unsure, say N.
-config SATA_SIL24
- tristate "Silicon Image 3124/3132 SATA support"
- depends on PCI
+config SATA_AHCI_PLATFORM
+ tristate "Platform AHCI SATA support"
help
- This option enables support for Silicon Image 3124/3132 Serial ATA.
+ This option enables support for Platform AHCI Serial ATA
+ controllers.
+
+ If unsure, say N.
+
+config AHCI_DA850
+ tristate "DaVinci DA850 AHCI SATA support"
+ depends on ARCH_DAVINCI_DA850
+ help
+ This option enables support for the DaVinci DA850 SoC's
+ onboard AHCI SATA.
+
+ If unsure, say N.
+
+config AHCI_ST
+ tristate "ST AHCI SATA support"
+ depends on ARCH_STI
+ help
+ This option enables support for ST AHCI SATA controller.
+
+ If unsure, say N.
+
+config AHCI_IMX
+ tristate "Freescale i.MX AHCI SATA support"
+ depends on MFD_SYSCON && (ARCH_MXC || COMPILE_TEST)
+ help
+ This option enables support for the Freescale i.MX SoC's
+ onboard AHCI SATA.
+
+ If unsure, say N.
+
+config AHCI_MVEBU
+ tristate "Marvell EBU AHCI SATA support"
+ depends on ARCH_MVEBU
+ help
+ This option enables support for the Marvebu EBU SoC's
+ onboard AHCI SATA.
+
+ If unsure, say N.
+
+config AHCI_SUNXI
+ tristate "Allwinner sunxi AHCI SATA support"
+ depends on ARCH_SUNXI
+ help
+ This option enables support for the Allwinner sunxi SoC's
+ onboard AHCI SATA.
If unsure, say N.
+config AHCI_XGENE
+ tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support"
+ depends on PHY_XGENE
+ help
+ This option enables support for APM X-Gene SoC SATA host controller.
+
config SATA_FSL
tristate "Freescale 3.0Gbps SATA support"
depends on FSL_SOC
@@ -73,8 +156,30 @@ config SATA_FSL
If unsure, say N.
+config SATA_INIC162X
+ tristate "Initio 162x SATA support (Very Experimental)"
+ depends on PCI
+ help
+ This option enables support for Initio 162x Serial ATA.
+
+config SATA_ACARD_AHCI
+ tristate "ACard AHCI variant (ATP 8620)"
+ depends on PCI
+ help
+ This option enables support for Acard.
+
+ If unsure, say N.
+
+config SATA_SIL24
+ tristate "Silicon Image 3124/3132 SATA support"
+ depends on PCI
+ help
+ This option enables support for Silicon Image 3124/3132 Serial ATA.
+
+ If unsure, say N.
+
config ATA_SFF
- bool "ATA SFF support"
+ bool "ATA SFF support (for legacy IDE and PATA)"
default y
help
This option adds support for ATA controllers with SFF
@@ -87,21 +192,61 @@ config ATA_SFF
For users with exclusively modern controllers like AHCI,
Silicon Image 3124, or Marvell 6440, you may choose to
- disable this uneeded SFF support.
+ disable this unneeded SFF support.
If unsure, say Y.
if ATA_SFF
-config SATA_SVW
- tristate "ServerWorks Frodo / Apple K2 SATA support"
+comment "SFF controllers with custom DMA interface"
+
+config PDC_ADMA
+ tristate "Pacific Digital ADMA support"
depends on PCI
help
- This option enables support for Broadcom/Serverworks/Apple K2
- SATA support.
+ This option enables support for Pacific Digital ADMA controllers
If unsure, say N.
+config PATA_OCTEON_CF
+ tristate "OCTEON Boot Bus Compact Flash support"
+ depends on CAVIUM_OCTEON_SOC
+ help
+ This option enables a polled compact flash driver for use with
+ compact flash cards attached to the OCTEON boot bus.
+
+ If unsure, say N.
+
+config SATA_QSTOR
+ tristate "Pacific Digital SATA QStor support"
+ depends on PCI
+ help
+ This option enables support for Pacific Digital Serial ATA QStor.
+
+ If unsure, say N.
+
+config SATA_SX4
+ tristate "Promise SATA SX4 support (Experimental)"
+ depends on PCI
+ help
+ This option enables support for Promise Serial ATA SX4.
+
+ If unsure, say N.
+
+config ATA_BMDMA
+ bool "ATA BMDMA support"
+ default y
+ help
+ This option adds support for SFF ATA controllers with BMDMA
+ capability. BMDMA stands for bus-master DMA and is the
+ de facto DMA interface for SFF controllers.
+
+ If unsure, say Y.
+
+if ATA_BMDMA
+
+comment "SATA SFF controllers with BMDMA"
+
config ATA_PIIX
tristate "Intel ESB, ICH, PIIX3, PIIX4 PATA/SATA support"
depends on PCI
@@ -112,36 +257,62 @@ config ATA_PIIX
If unsure, say N.
-config SATA_MV
- tristate "Marvell SATA support (HIGHLY EXPERIMENTAL)"
- depends on EXPERIMENTAL
+config SATA_DWC
+ tristate "DesignWare Cores SATA support"
+ depends on 460EX
help
- This option enables support for the Marvell Serial ATA family.
- Currently supports 88SX[56]0[48][01] chips.
+ This option enables support for the on-chip SATA controller of the
+ AppliedMicro processor 460EX.
If unsure, say N.
-config SATA_NV
- tristate "NVIDIA SATA support"
- depends on PCI
+config SATA_DWC_DEBUG
+ bool "Debugging driver version"
+ depends on SATA_DWC
help
- This option enables support for NVIDIA Serial ATA.
+ This option enables debugging output in the driver.
+
+config SATA_DWC_VDEBUG
+ bool "Verbose debug output"
+ depends on SATA_DWC_DEBUG
+ help
+ This option enables the taskfile dumping and NCQ debugging.
+
+config SATA_DWC_PMP
+ tristate "DesignWare Cores SATA with PMP support"
+ depends on 460EX
+ help
+ This option enables support for the on-chip SATA controller of the
+ AppliedMicro processor 460EX with PMP support.
If unsure, say N.
-config PDC_ADMA
- tristate "Pacific Digital ADMA support"
- depends on PCI
+config SATA_HIGHBANK
+ tristate "Calxeda Highbank SATA support"
+ depends on ARCH_HIGHBANK || COMPILE_TEST
help
- This option enables support for Pacific Digital ADMA controllers
+ This option enables support for the Calxeda Highbank SoC's
+ onboard SATA.
If unsure, say N.
-config SATA_QSTOR
- tristate "Pacific Digital SATA QStor support"
+config SATA_MV
+ tristate "Marvell SATA support"
+ depends on PCI || ARCH_DOVE || ARCH_KIRKWOOD || ARCH_MV78XX0 || \
+ ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST
+ select GENERIC_PHY
+ help
+ This option enables support for the Marvell Serial ATA family.
+ Currently supports 88SX[56]0[48][01] PCI(-X) chips,
+ as well as the newer [67]042 PCI-X/PCIe and SOC devices.
+
+ If unsure, say N.
+
+config SATA_NV
+ tristate "NVIDIA SATA support"
depends on PCI
help
- This option enables support for Pacific Digital Serial ATA QStor.
+ This option enables support for NVIDIA Serial ATA.
If unsure, say N.
@@ -153,11 +324,11 @@ config SATA_PROMISE
If unsure, say N.
-config SATA_SX4
- tristate "Promise SATA SX4 support"
- depends on PCI && EXPERIMENTAL
+config SATA_RCAR
+ tristate "Renesas R-Car SATA support"
+ depends on ARCH_SHMOBILE || COMPILE_TEST
help
- This option enables support for Promise Serial ATA SX4.
+ This option enables support for Renesas R-Car Serial ATA.
If unsure, say N.
@@ -180,6 +351,15 @@ config SATA_SIS
enable the PATA_SIS driver in the config.
If unsure, say N.
+config SATA_SVW
+ tristate "ServerWorks Frodo / Apple K2 SATA support"
+ depends on PCI
+ help
+ This option enables support for Broadcom/Serverworks/Apple K2
+ SATA support.
+
+ If unsure, say N.
+
config SATA_ULI
tristate "ULi Electronics SATA support"
depends on PCI
@@ -204,24 +384,11 @@ config SATA_VITESSE
If unsure, say N.
-config SATA_INIC162X
- tristate "Initio 162x SATA support (HIGHLY EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
- help
- This option enables support for Initio 162x Serial ATA.
-
-config PATA_ACPI
- tristate "ACPI firmware driver for PATA"
- depends on ATA_ACPI
- help
- This option enables an ACPI method driver which drives
- motherboard PATA controller interfaces through the ACPI
- firmware in the BIOS. This driver can sometimes handle
- otherwise unsupported hardware.
+comment "PATA SFF controllers with BMDMA"
config PATA_ALI
- tristate "ALi PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "ALi PATA support"
+ depends on PCI
help
This option enables support for the ALi ATA interfaces
found on the many ALi chipsets.
@@ -237,6 +404,14 @@ config PATA_AMD
If unsure, say N.
+config PATA_ARASAN_CF
+ tristate "ARASAN CompactFlash PATA Controller Support"
+ depends on ARCH_SPEAR13XX || COMPILE_TEST
+ depends on DMADEVICES
+ select DMA_ENGINE
+ help
+ Say Y here to support the ARASAN CompactFlash PATA controller
+
config PATA_ARTOP
tristate "ARTOP 6210/6260 PATA support"
depends on PCI
@@ -245,15 +420,6 @@ config PATA_ARTOP
If unsure, say N.
-config PATA_AT32
- tristate "Atmel AVR32 PATA support (Experimental)"
- depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL
- help
- This option enables support for the IDE devices on the
- Atmel AT32AP platform.
-
- If unsure, say N.
-
config PATA_ATIIXP
tristate "ATI PATA support"
depends on PCI
@@ -263,13 +429,21 @@ config PATA_ATIIXP
If unsure, say N.
-config PATA_CMD640_PCI
- tristate "CMD640 PCI PATA support (Very Experimental)"
- depends on PCI && EXPERIMENTAL
+config PATA_ATP867X
+ tristate "ARTOP/Acard ATP867X PATA support"
+ depends on PCI
help
- This option enables support for the CMD640 PCI IDE
- interface chip. Only the primary channel is currently
- supported.
+ This option enables support for ARTOP/Acard ATP867X PATA
+ controllers.
+
+ If unsure, say N.
+
+config PATA_BF54X
+ tristate "Blackfin 54x ATAPI support"
+ depends on BF542 || BF548 || BF549
+ help
+ This option enables support for the built-in ATAPI controller on
+ Blackfin 54x family chips.
If unsure, say N.
@@ -284,7 +458,7 @@ config PATA_CMD64X
config PATA_CS5520
tristate "CS5510/5520 PATA support"
- depends on PCI
+ depends on PCI && (X86_32 || COMPILE_TEST)
help
This option enables support for the Cyrix 5510/5520
companion chip used with the MediaGX/Geode processor family.
@@ -292,8 +466,8 @@ config PATA_CS5520
If unsure, say N.
config PATA_CS5530
- tristate "CS5530 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "CS5530 PATA support"
+ depends on PCI && (X86_32 || COMPILE_TEST)
help
This option enables support for the Cyrix/NatSemi/AMD CS5530
companion chip used with the MediaGX/Geode processor family.
@@ -302,7 +476,7 @@ config PATA_CS5530
config PATA_CS5535
tristate "CS5535 PATA support (Experimental)"
- depends on PCI && X86 && !X86_64 && EXPERIMENTAL
+ depends on PCI && X86_32
help
This option enables support for the NatSemi/AMD CS5535
companion chip used with the Geode processor family.
@@ -310,8 +484,8 @@ config PATA_CS5535
If unsure, say N.
config PATA_CS5536
- tristate "CS5536 PATA support (Experimental)"
- depends on PCI && X86 && !X86_64 && EXPERIMENTAL
+ tristate "CS5536 PATA support"
+ depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
help
This option enables support for the AMD CS5536
companion chip used with the Geode LX processor family.
@@ -320,7 +494,7 @@ config PATA_CS5536
config PATA_CYPRESS
tristate "Cypress CY82C693 PATA support (Very Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables support for the Cypress/Contaq CY82C693
chipset found in some Alpha systems
@@ -336,12 +510,12 @@ config PATA_EFAR
If unsure, say N.
-config ATA_GENERIC
- tristate "Generic ATA support"
- depends on PCI
+config PATA_EP93XX
+ tristate "Cirrus Logic EP93xx PATA support"
+ depends on ARCH_EP93XX
help
- This option enables support for generic BIOS configured
- ATA controllers via the new ATA layer
+ This option enables support for the PATA controller in
+ the Cirrus Logic EP9312 and EP9315 ARM CPU.
If unsure, say N.
@@ -355,8 +529,8 @@ config PATA_HPT366
If unsure, say N.
config PATA_HPT37X
- tristate "HPT 370/370A/371/372/374/302 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "HPT 370/370A/371/372/374/302 PATA support"
+ depends on PCI
help
This option enables support for the majority of the later HPT
PATA controllers via the new ATA layer.
@@ -364,11 +538,11 @@ config PATA_HPT37X
If unsure, say N.
config PATA_HPT3X2N
- tristate "HPT 372N/302N PATA support (Very Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "HPT 371N/372N/302N PATA support"
+ depends on PCI
help
This option enables support for the N variant HPT PATA
- controllers via the new ATA layer
+ controllers via the new ATA layer.
If unsure, say N.
@@ -382,102 +556,88 @@ config PATA_HPT3X3
If unsure, say N.
config PATA_HPT3X3_DMA
- bool "HPT 343/363 DMA support (Experimental)"
+ bool "HPT 343/363 DMA support"
depends on PATA_HPT3X3
help
This option enables DMA support for the HPT343/363
controllers. Enable with care as there are still some
problems with DMA on this chipset.
-config PATA_ISAPNP
- tristate "ISA Plug and Play PATA support (Experimental)"
- depends on EXPERIMENTAL && ISAPNP
+config PATA_ICSIDE
+ tristate "Acorn ICS PATA support"
+ depends on ARM && ARCH_ACORN
help
- This option enables support for ISA plug & play ATA
- controllers such as those found on old soundcards.
-
- If unsure, say N.
+ On Acorn systems, say Y here if you wish to use the ICS PATA
+ interface card. This is not required for ICS partition support.
+ If you are unsure, say N to this.
-config PATA_IT821X
- tristate "IT8211/2 PATA support"
- depends on PCI
+config PATA_IMX
+ tristate "PATA support for Freescale iMX"
+ depends on ARCH_MXC
help
- This option enables support for the ITE 8211 and 8212
- PATA controllers via the new ATA layer, including RAID
- mode.
+ This option enables support for the PATA host available on Freescale
+ iMX SoCs.
If unsure, say N.
config PATA_IT8213
tristate "IT8213 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables support for the ITE 821 PATA
controllers via the new ATA layer.
If unsure, say N.
-config PATA_JMICRON
- tristate "JMicron PATA support"
+config PATA_IT821X
+ tristate "IT8211/2 PATA support"
depends on PCI
help
- Enable support for the JMicron IDE controller, via the new
- ATA layer.
+ This option enables support for the ITE 8211 and 8212
+ PATA controllers via the new ATA layer, including RAID
+ mode.
If unsure, say N.
-config PATA_LEGACY
- tristate "Legacy ISA PATA support (Experimental)"
- depends on ISA && EXPERIMENTAL
+config PATA_JMICRON
+ tristate "JMicron PATA support"
+ depends on PCI
help
- This option enables support for ISA/VLB bus legacy PATA
- ports and allows them to be accessed via the new ATA layer.
+ Enable support for the JMicron IDE controller, via the new
+ ATA layer.
If unsure, say N.
-config PATA_TRIFLEX
- tristate "Compaq Triflex PATA support"
- depends on PCI
+config PATA_MACIO
+ tristate "Apple PowerMac/PowerBook internal 'MacIO' IDE"
+ depends on PPC_PMAC
help
- Enable support for the Compaq 'Triflex' IDE controller as found
- on many Compaq Pentium-Pro systems, via the new ATA layer.
-
- If unsure, say N.
+ Most IDE capable PowerMacs have IDE busses driven by a variant
+ of this controller which is part of the Apple chipset used on
+ most PowerMac models. Some models have multiple busses using
+ different chipsets, though generally, MacIO is one of them.
config PATA_MARVELL
tristate "Marvell PATA support via legacy mode"
depends on PCI
help
- This option enables limited support for the Marvell 88SE6145 ATA
- controller.
+ This option enables limited support for the Marvell 88SE61xx ATA
+ controllers. If you wish to use only the SATA ports then select
+ the AHCI driver alone. If you wish to the use the PATA port or
+ both SATA and PATA include this driver.
If unsure, say N.
config PATA_MPC52xx
tristate "Freescale MPC52xx SoC internal IDE"
- depends on PPC_MPC52xx
+ depends on PPC_MPC52xx && PPC_BESTCOMM
+ select PPC_BESTCOMM_ATA
help
This option enables support for integrated IDE controller
of the Freescale MPC52xx SoC.
If unsure, say N.
-config PATA_MPIIX
- tristate "Intel PATA MPIIX support"
- depends on PCI
- help
- This option enables support for MPIIX PATA support.
-
- If unsure, say N.
-
-config PATA_OLDPIIX
- tristate "Intel PATA old PIIX support"
- depends on PCI
- help
- This option enables support for early PIIX PATA support.
-
- If unsure, say N.
-
config PATA_NETCELL
tristate "NETCELL Revolution RAID support"
depends on PCI
@@ -488,44 +648,34 @@ config PATA_NETCELL
If unsure, say N.
config PATA_NINJA32
- tristate "Ninja32/Delkin Cardbus ATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "Ninja32/Delkin Cardbus ATA support"
+ depends on PCI
help
This option enables support for the Ninja32, Delkin and
possibly other brands of Cardbus ATA adapter
If unsure, say N.
-config PATA_NS87410
- tristate "Nat Semi NS87410 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
- help
- This option enables support for the National Semiconductor
- NS87410 PCI-IDE controller.
-
- If unsure, say N.
-
config PATA_NS87415
- tristate "Nat Semi NS87415 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "Nat Semi NS87415 PATA support"
+ depends on PCI
help
This option enables support for the National Semiconductor
NS87415 PCI-IDE controller.
If unsure, say N.
-config PATA_OPTI
- tristate "OPTI621/6215 PATA support (Very Experimental)"
- depends on PCI && EXPERIMENTAL
+config PATA_OLDPIIX
+ tristate "Intel PATA old PIIX support"
+ depends on PCI
help
- This option enables full PIO support for the early Opti ATA
- controllers found on some old motherboards.
+ This option enables support for early PIIX PATA support.
If unsure, say N.
config PATA_OPTIDMA
tristate "OPTI FireStar PATA support (Very Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables DMA/PIO support for the later OPTi
controllers found on some old motherboards and in some
@@ -533,80 +683,75 @@ config PATA_OPTIDMA
If unsure, say N.
-config PATA_PCMCIA
- tristate "PCMCIA PATA support"
- depends on PCMCIA
+config PATA_PDC2027X
+ tristate "Promise PATA 2027x support"
+ depends on PCI
help
- This option enables support for PCMCIA ATA interfaces, including
- compact flash card adapters via the new ATA layer.
+ This option enables support for Promise PATA pdc20268 to pdc20277 host adapters.
If unsure, say N.
config PATA_PDC_OLD
- tristate "Older Promise PATA controller support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "Older Promise PATA controller support"
+ depends on PCI
help
This option enables support for the Promise 20246, 20262, 20263,
20265 and 20267 adapters.
If unsure, say N.
-config PATA_QDI
- tristate "QDI VLB PATA support"
- depends on ISA
- help
- Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
-
config PATA_RADISYS
- tristate "RADISYS 82600 PATA support (Very Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "RADISYS 82600 PATA support (Experimental)"
+ depends on PCI
help
This option enables support for the RADISYS 82600
PATA controllers via the new ATA layer
If unsure, say N.
-config PATA_RB500
- tristate "RouterBoard 500 PATA CompactFlash support"
- depends on MIKROTIK_RB500
- help
- This option enables support for the RouterBoard 500
- PATA CompactFlash controller.
-
- If unsure, say N.
-
-config PATA_RZ1000
- tristate "PC Tech RZ1000 PATA support"
+config PATA_RDC
+ tristate "RDC PATA support"
depends on PCI
help
- This option enables basic support for the PC Tech RZ1000/1
- PATA controllers via the new ATA layer
+ This option enables basic support for the later RDC PATA controllers
+ controllers via the new ATA layer. For the RDC 1010, you need to
+ enable the IT821X driver instead.
If unsure, say N.
config PATA_SC1200
- tristate "SC1200 PATA support (Very Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "SC1200 PATA support"
+ depends on PCI && (X86_32 || COMPILE_TEST)
help
This option enables support for the NatSemi/AMD SC1200 SoC
companion chip used with the Geode processor family.
If unsure, say N.
-config PATA_SERVERWORKS
- tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support"
+config PATA_SCC
+ tristate "Toshiba's Cell Reference Set IDE support"
+ depends on PCI && PPC_CELLEB
+ help
+ This option enables support for the built-in IDE controller on
+ Toshiba Cell Reference Board.
+
+ If unsure, say N.
+
+config PATA_SCH
+ tristate "Intel SCH PATA support"
depends on PCI
help
- This option enables support for the Serverworks OSB4/CSB5/CSB6 and
- HT1000 PATA controllers, via the new ATA layer.
+ This option enables support for Intel SCH PATA on the Intel
+ SCH (US15W, US15L, UL11L) series host controllers.
If unsure, say N.
-config PATA_PDC2027X
- tristate "Promise PATA 2027x support"
+config PATA_SERVERWORKS
+ tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support"
depends on PCI
help
- This option enables support for Promise PATA pdc20268 to pdc20277 host adapters.
+ This option enables support for the Serverworks OSB4/CSB5/CSB6 and
+ HT1000 PATA controllers, via the new ATA layer.
If unsure, say N.
@@ -619,13 +764,31 @@ config PATA_SIL680
If unsure, say N.
config PATA_SIS
- tristate "SiS PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "SiS PATA support"
+ depends on PCI
help
This option enables support for SiS PATA controllers
If unsure, say N.
+config PATA_TOSHIBA
+ tristate "Toshiba Piccolo support (Experimental)"
+ depends on PCI
+ help
+ Support for the Toshiba Piccolo controllers. Currently only the
+ primary channel is supported by this driver.
+
+ If unsure, say N.
+
+config PATA_TRIFLEX
+ tristate "Compaq Triflex PATA support"
+ depends on PCI
+ help
+ Enable support for the Compaq 'Triflex' IDE controller as found
+ on many Compaq Pentium-Pro systems, via the new ATA layer.
+
+ If unsure, say N.
+
config PATA_VIA
tristate "VIA PATA support"
depends on PCI
@@ -635,6 +798,17 @@ config PATA_VIA
If unsure, say N.
+config PATA_PXA
+ tristate "PXA DMA-capable PATA support"
+ depends on ARCH_PXA
+ help
+ This option enables support for harddrive attached to PXA CPU's bus.
+
+ NOTE: This driver utilizes PXA DMA controller, in case your hardware
+ is not capable of doing MWDMA, use pata_platform instead.
+
+ If unsure, say N.
+
config PATA_WINBOND
tristate "Winbond SL82C105 PATA support"
depends on PCI
@@ -644,16 +818,103 @@ config PATA_WINBOND
If unsure, say N.
-config PATA_WINBOND_VLB
- tristate "Winbond W83759A VLB PATA support (Experimental)"
- depends on ISA && EXPERIMENTAL
+endif # ATA_BMDMA
+
+comment "PIO-only SFF controllers"
+
+config PATA_AT32
+ tristate "Atmel AVR32 PATA support (Experimental)"
+ depends on AVR32 && PLATFORM_AT32AP
help
- Support for the Winbond W83759A controller on Vesa Local Bus
- systems.
+ This option enables support for the IDE devices on the
+ Atmel AT32AP platform.
+
+ If unsure, say N.
+
+config PATA_AT91
+ tristate "PATA support for AT91SAM9260"
+ depends on ARM && SOC_AT91SAM9
+ help
+ This option enables support for IDE devices on the Atmel AT91SAM9260 SoC.
+
+ If unsure, say N.
+
+config PATA_CMD640_PCI
+ tristate "CMD640 PCI PATA support (Experimental)"
+ depends on PCI
+ help
+ This option enables support for the CMD640 PCI IDE
+ interface chip. Only the primary channel is currently
+ supported.
+
+ If unsure, say N.
+
+config PATA_ISAPNP
+ tristate "ISA Plug and Play PATA support"
+ depends on ISAPNP
+ help
+ This option enables support for ISA plug & play ATA
+ controllers such as those found on old soundcards.
+
+ If unsure, say N.
+
+config PATA_IXP4XX_CF
+ tristate "IXP4XX Compact Flash support"
+ depends on ARCH_IXP4XX
+ help
+ This option enables support for a Compact Flash connected on
+ the ixp4xx expansion bus. This driver had been written for
+ Loft/Avila boards in mind but can work with others.
+
+ If unsure, say N.
+
+config PATA_MPIIX
+ tristate "Intel PATA MPIIX support"
+ depends on PCI
+ help
+ This option enables support for MPIIX PATA support.
+
+ If unsure, say N.
+
+config PATA_NS87410
+ tristate "Nat Semi NS87410 PATA support"
+ depends on PCI
+ help
+ This option enables support for the National Semiconductor
+ NS87410 PCI-IDE controller.
+
+ If unsure, say N.
+
+config PATA_OPTI
+ tristate "OPTI621/6215 PATA support (Very Experimental)"
+ depends on PCI
+ help
+ This option enables full PIO support for the early Opti ATA
+ controllers found on some old motherboards.
+
+ If unsure, say N.
+
+config PATA_PALMLD
+ tristate "Palm LifeDrive PATA support"
+ depends on MACH_PALMLD
+ help
+ This option enables support for Palm LifeDrive's internal ATA
+ port via the new ATA layer.
+
+ If unsure, say N.
+
+config PATA_PCMCIA
+ tristate "PCMCIA PATA support"
+ depends on PCMCIA
+ help
+ This option enables support for PCMCIA ATA interfaces, including
+ compact flash card adapters via the new ATA layer.
+
+ If unsure, say N.
config PATA_PLATFORM
tristate "Generic platform device PATA support"
- depends on EMBEDDED || ARCH_RPC || PPC
+ depends on EXPERT || PPC || HAVE_PATA_PLATFORM
help
This option enables support for generic directly connected ATA
devices commonly found on embedded systems.
@@ -662,7 +923,7 @@ config PATA_PLATFORM
config PATA_OF_PLATFORM
tristate "OpenFirmware platform device PATA support"
- depends on PATA_PLATFORM && PPC_OF
+ depends on PATA_PLATFORM && OF
help
This option enables support for generic directly connected ATA
devices commonly found on embedded systems with OpenFirmware
@@ -670,39 +931,74 @@ config PATA_OF_PLATFORM
If unsure, say N.
-config PATA_ICSIDE
- tristate "Acorn ICS PATA support"
- depends on ARM && ARCH_ACORN
+config PATA_QDI
+ tristate "QDI VLB PATA support"
+ depends on ISA
+ select PATA_LEGACY
help
- On Acorn systems, say Y here if you wish to use the ICS PATA
- interface card. This is not required for ICS partition support.
- If you are unsure, say N to this.
+ Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
-config PATA_IXP4XX_CF
- tristate "IXP4XX Compact Flash support"
- depends on ARCH_IXP4XX
+config PATA_RB532
+ tristate "RouterBoard 532 PATA CompactFlash support"
+ depends on MIKROTIK_RB532
help
- This option enables support for a Compact Flash connected on
- the ixp4xx expansion bus. This driver had been written for
- Loft/Avila boards in mind but can work with others.
+ This option enables support for the RouterBoard 532
+ PATA CompactFlash controller.
If unsure, say N.
-config PATA_SCC
- tristate "Toshiba's Cell Reference Set IDE support"
- depends on PCI && PPC_CELLEB
+config PATA_RZ1000
+ tristate "PC Tech RZ1000 PATA support"
+ depends on PCI
help
- This option enables support for the built-in IDE controller on
- Toshiba Cell Reference Board.
+ This option enables basic support for the PC Tech RZ1000/1
+ PATA controllers via the new ATA layer
If unsure, say N.
-config PATA_BF54X
- tristate "Blackfin 54x ATAPI support"
- depends on BF542 || BF548 || BF549
+config PATA_SAMSUNG_CF
+ tristate "Samsung SoC PATA support"
+ depends on SAMSUNG_DEV_IDE
help
- This option enables support for the built-in ATAPI controller on
- Blackfin 54x family chips.
+ This option enables basic support for Samsung's S3C/S5P board
+ PATA controllers via the new ATA layer
+
+ If unsure, say N.
+
+config PATA_WINBOND_VLB
+ tristate "Winbond W83759A VLB PATA support (Experimental)"
+ depends on ISA
+ select PATA_LEGACY
+ help
+ Support for the Winbond W83759A controller on Vesa Local Bus
+ systems.
+
+comment "Generic fallback / legacy drivers"
+
+config PATA_ACPI
+ tristate "ACPI firmware driver for PATA"
+ depends on ATA_ACPI && ATA_BMDMA
+ help
+ This option enables an ACPI method driver which drives
+ motherboard PATA controller interfaces through the ACPI
+ firmware in the BIOS. This driver can sometimes handle
+ otherwise unsupported hardware.
+
+config ATA_GENERIC
+ tristate "Generic ATA support"
+ depends on PCI && ATA_BMDMA
+ help
+ This option enables support for generic BIOS configured
+ ATA controllers via the new ATA layer
+
+ If unsure, say N.
+
+config PATA_LEGACY
+ tristate "Legacy ISA PATA support (Experimental)"
+ depends on (ISA || PCI)
+ help
+ This option enables support for ISA/VLB/PCI bus legacy PATA
+ ports and allows them to be accessed via the new ATA layer.
If unsure, say N.
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 1fbc2aa648b..7e7a77de757 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -1,30 +1,50 @@
obj-$(CONFIG_ATA) += libata.o
-obj-$(CONFIG_SATA_AHCI) += ahci.o
-obj-$(CONFIG_SATA_SVW) += sata_svw.o
+# non-SFF interface
+obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
+obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o
+obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o libahci_platform.o
+obj-$(CONFIG_SATA_FSL) += sata_fsl.o
+obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
+obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
+obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
+obj-$(CONFIG_SATA_DWC_PMP) += sata_dwc_pmp.o
+obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
+obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o
+
+# SFF w/ custom DMA
+obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
+obj-$(CONFIG_PATA_ARASAN_CF) += pata_arasan_cf.o
+obj-$(CONFIG_PATA_OCTEON_CF) += pata_octeon_cf.o
+obj-$(CONFIG_SATA_QSTOR) += sata_qstor.o
+obj-$(CONFIG_SATA_SX4) += sata_sx4.o
+
+# SFF SATA w/ BMDMA
obj-$(CONFIG_ATA_PIIX) += ata_piix.o
+obj-$(CONFIG_SATA_MV) += sata_mv.o
+obj-$(CONFIG_SATA_NV) += sata_nv.o
obj-$(CONFIG_SATA_PROMISE) += sata_promise.o
-obj-$(CONFIG_SATA_QSTOR) += sata_qstor.o
+obj-$(CONFIG_SATA_RCAR) += sata_rcar.o
obj-$(CONFIG_SATA_SIL) += sata_sil.o
-obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
-obj-$(CONFIG_SATA_VIA) += sata_via.o
-obj-$(CONFIG_SATA_VITESSE) += sata_vsc.o
obj-$(CONFIG_SATA_SIS) += sata_sis.o
-obj-$(CONFIG_SATA_SX4) += sata_sx4.o
-obj-$(CONFIG_SATA_NV) += sata_nv.o
+obj-$(CONFIG_SATA_SVW) += sata_svw.o
obj-$(CONFIG_SATA_ULI) += sata_uli.o
-obj-$(CONFIG_SATA_MV) += sata_mv.o
-obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
-obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
-obj-$(CONFIG_SATA_FSL) += sata_fsl.o
+obj-$(CONFIG_SATA_VIA) += sata_via.o
+obj-$(CONFIG_SATA_VITESSE) += sata_vsc.o
+# SFF PATA w/ BMDMA
obj-$(CONFIG_PATA_ALI) += pata_ali.o
obj-$(CONFIG_PATA_AMD) += pata_amd.o
obj-$(CONFIG_PATA_ARTOP) += pata_artop.o
-obj-$(CONFIG_PATA_AT32) += pata_at32.o
obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o
-obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o
+obj-$(CONFIG_PATA_ATP867X) += pata_atp867x.o
+obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o
obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o
obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o
obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o
@@ -32,45 +52,58 @@ obj-$(CONFIG_PATA_CS5535) += pata_cs5535.o
obj-$(CONFIG_PATA_CS5536) += pata_cs5536.o
obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o
obj-$(CONFIG_PATA_EFAR) += pata_efar.o
+obj-$(CONFIG_PATA_EP93XX) += pata_ep93xx.o
obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o
obj-$(CONFIG_PATA_HPT37X) += pata_hpt37x.o
obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o
obj-$(CONFIG_PATA_HPT3X3) += pata_hpt3x3.o
-obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o
-obj-$(CONFIG_PATA_IT821X) += pata_it821x.o
+obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o
+obj-$(CONFIG_PATA_IMX) += pata_imx.o
obj-$(CONFIG_PATA_IT8213) += pata_it8213.o
+obj-$(CONFIG_PATA_IT821X) += pata_it821x.o
obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
+obj-$(CONFIG_PATA_MACIO) += pata_macio.o
+obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o
+obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o
obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
obj-$(CONFIG_PATA_NINJA32) += pata_ninja32.o
-obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o
obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o
-obj-$(CONFIG_PATA_OPTI) += pata_opti.o
-obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o
-obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o
-obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o
-obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o
obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o
-obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o
+obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o
obj-$(CONFIG_PATA_PDC2027X) += pata_pdc2027x.o
obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o
-obj-$(CONFIG_PATA_QDI) += pata_qdi.o
obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o
-obj-$(CONFIG_PATA_RB500) += pata_rb500_cf.o
-obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o
+obj-$(CONFIG_PATA_RDC) += pata_rdc.o
obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o
+obj-$(CONFIG_PATA_SCC) += pata_scc.o
+obj-$(CONFIG_PATA_SCH) += pata_sch.o
obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
obj-$(CONFIG_PATA_SIL680) += pata_sil680.o
-obj-$(CONFIG_PATA_VIA) += pata_via.o
-obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o
-obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o
obj-$(CONFIG_PATA_SIS) += pata_sis.o
+obj-$(CONFIG_PATA_TOSHIBA) += pata_piccolo.o
obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
+obj-$(CONFIG_PATA_VIA) += pata_via.o
+obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o
+
+# SFF PIO only
+obj-$(CONFIG_PATA_AT32) += pata_at32.o
+obj-$(CONFIG_PATA_AT91) += pata_at91.o
+obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o
+obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o
obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
-obj-$(CONFIG_PATA_SCC) += pata_scc.o
-obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o
+obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o
+obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o
+obj-$(CONFIG_PATA_OPTI) += pata_opti.o
+obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o
+obj-$(CONFIG_PATA_PALMLD) += pata_palmld.o
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
-obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o
+obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o
+obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o
+obj-$(CONFIG_PATA_SAMSUNG_CF) += pata_samsung_cf.o
+
+obj-$(CONFIG_PATA_PXA) += pata_pxa.o
+
# Should be last but two libata driver
obj-$(CONFIG_PATA_ACPI) += pata_acpi.o
# Should be last but one libata driver
@@ -78,7 +111,8 @@ obj-$(CONFIG_ATA_GENERIC) += ata_generic.o
# Should be last libata driver
obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o
-libata-objs := libata-core.o libata-scsi.o libata-eh.o
+libata-y := libata-core.o libata-scsi.o libata-eh.o libata-transport.o
libata-$(CONFIG_ATA_SFF) += libata-sff.o
libata-$(CONFIG_SATA_PMP) += libata-pmp.o
libata-$(CONFIG_ATA_ACPI) += libata-acpi.o
+libata-$(CONFIG_SATA_ZPODD) += libata-zpodd.o
diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c
new file mode 100644
index 00000000000..0cd7c7a39e5
--- /dev/null
+++ b/drivers/ata/acard-ahci.c
@@ -0,0 +1,511 @@
+
+/*
+ * acard-ahci.c - ACard AHCI SATA support
+ *
+ * Maintained by: Tejun Heo <tj@kernel.org>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2010 Red Hat, Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * AHCI hardware documentation:
+ * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
+ * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/gfp.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <linux/libata.h>
+#include "ahci.h"
+
+#define DRV_NAME "acard-ahci"
+#define DRV_VERSION "1.0"
+
+/*
+ Received FIS structure limited to 80h.
+*/
+
+#define ACARD_AHCI_RX_FIS_SZ 128
+
+enum {
+ AHCI_PCI_BAR = 5,
+};
+
+enum board_ids {
+ board_acard_ahci,
+};
+
+struct acard_sg {
+ __le32 addr;
+ __le32 addr_hi;
+ __le32 reserved;
+ __le32 size; /* bit 31 (EOT) max==0x10000 (64k) */
+};
+
+static void acard_ahci_qc_prep(struct ata_queued_cmd *qc);
+static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
+static int acard_ahci_port_start(struct ata_port *ap);
+static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+
+#ifdef CONFIG_PM_SLEEP
+static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
+static int acard_ahci_pci_device_resume(struct pci_dev *pdev);
+#endif
+
+static struct scsi_host_template acard_ahci_sht = {
+ AHCI_SHT("acard-ahci"),
+};
+
+static struct ata_port_operations acard_ops = {
+ .inherits = &ahci_ops,
+ .qc_prep = acard_ahci_qc_prep,
+ .qc_fill_rtf = acard_ahci_qc_fill_rtf,
+ .port_start = acard_ahci_port_start,
+};
+
+#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
+
+static const struct ata_port_info acard_ahci_port_info[] = {
+ [board_acard_ahci] =
+ {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &acard_ops,
+ },
+};
+
+static const struct pci_device_id acard_ahci_pci_tbl[] = {
+ /* ACard */
+ { PCI_VDEVICE(ARTOP, 0x000d), board_acard_ahci }, /* ATP8620 */
+
+ { } /* terminate list */
+};
+
+static struct pci_driver acard_ahci_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = acard_ahci_pci_tbl,
+ .probe = acard_ahci_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = acard_ahci_pci_device_suspend,
+ .resume = acard_ahci_pci_device_resume,
+#endif
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ u32 ctl;
+
+ if (mesg.event & PM_EVENT_SUSPEND &&
+ hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
+ dev_err(&pdev->dev,
+ "BIOS update required for suspend/resume\n");
+ return -EIO;
+ }
+
+ if (mesg.event & PM_EVENT_SLEEP) {
+ /* AHCI spec rev1.1 section 8.3.3:
+ * Software must disable interrupts prior to requesting a
+ * transition of the HBA to D3 state.
+ */
+ ctl = readl(mmio + HOST_CTL);
+ ctl &= ~HOST_IRQ_EN;
+ writel(ctl, mmio + HOST_CTL);
+ readl(mmio + HOST_CTL); /* flush */
+ }
+
+ return ata_pci_device_suspend(pdev, mesg);
+}
+
+static int acard_ahci_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(host);
+ }
+
+ ata_host_resume(host);
+
+ return 0;
+}
+#endif
+
+static int acard_ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
+{
+ int rc;
+
+ if (using_dac &&
+ !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (rc) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc) {
+ dev_err(&pdev->dev,
+ "64-bit DMA enable failed\n");
+ return rc;
+ }
+ }
+ } else {
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc) {
+ dev_err(&pdev->dev, "32-bit DMA enable failed\n");
+ return rc;
+ }
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc) {
+ dev_err(&pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ return rc;
+ }
+ }
+ return 0;
+}
+
+static void acard_ahci_pci_print_info(struct ata_host *host)
+{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ u16 cc;
+ const char *scc_s;
+
+ pci_read_config_word(pdev, 0x0a, &cc);
+ if (cc == PCI_CLASS_STORAGE_IDE)
+ scc_s = "IDE";
+ else if (cc == PCI_CLASS_STORAGE_SATA)
+ scc_s = "SATA";
+ else if (cc == PCI_CLASS_STORAGE_RAID)
+ scc_s = "RAID";
+ else
+ scc_s = "unknown";
+
+ ahci_print_info(host, scc_s);
+}
+
+static unsigned int acard_ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
+{
+ struct scatterlist *sg;
+ struct acard_sg *acard_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
+ unsigned int si, last_si = 0;
+
+ VPRINTK("ENTER\n");
+
+ /*
+ * Next, the S/G list.
+ */
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ dma_addr_t addr = sg_dma_address(sg);
+ u32 sg_len = sg_dma_len(sg);
+
+ /*
+ * ACard note:
+ * We must set an end-of-table (EOT) bit,
+ * and the segment cannot exceed 64k (0x10000)
+ */
+ acard_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
+ acard_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
+ acard_sg[si].size = cpu_to_le32(sg_len);
+ last_si = si;
+ }
+
+ acard_sg[last_si].size |= cpu_to_le32(1 << 31); /* set EOT */
+
+ return si;
+}
+
+static void acard_ahci_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+ int is_atapi = ata_is_atapi(qc->tf.protocol);
+ void *cmd_tbl;
+ u32 opts;
+ const u32 cmd_fis_len = 5; /* five dwords */
+ unsigned int n_elem;
+
+ /*
+ * Fill in command table information. First, the header,
+ * a SATA Register - Host to Device command FIS.
+ */
+ cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
+
+ ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
+ if (is_atapi) {
+ memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
+ memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
+ }
+
+ n_elem = 0;
+ if (qc->flags & ATA_QCFLAG_DMAMAP)
+ n_elem = acard_ahci_fill_sg(qc, cmd_tbl);
+
+ /*
+ * Fill in command slot information.
+ *
+ * ACard note: prd table length not filled in
+ */
+ opts = cmd_fis_len | (qc->dev->link->pmp << 12);
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ opts |= AHCI_CMD_WRITE;
+ if (is_atapi)
+ opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
+
+ ahci_fill_cmd_slot(pp, qc->tag, opts);
+}
+
+static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
+{
+ struct ahci_port_priv *pp = qc->ap->private_data;
+ u8 *rx_fis = pp->rx_fis;
+
+ if (pp->fbs_enabled)
+ rx_fis += qc->dev->link->pmp * ACARD_AHCI_RX_FIS_SZ;
+
+ /*
+ * After a successful execution of an ATA PIO data-in command,
+ * the device doesn't send D2H Reg FIS to update the TF and
+ * the host should take TF and E_Status from the preceding PIO
+ * Setup FIS.
+ */
+ if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE &&
+ !(qc->flags & ATA_QCFLAG_FAILED)) {
+ ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
+ qc->result_tf.command = (rx_fis + RX_FIS_PIO_SETUP)[15];
+ } else
+ ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
+
+ return true;
+}
+
+static int acard_ahci_port_start(struct ata_port *ap)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct device *dev = ap->host->dev;
+ struct ahci_port_priv *pp;
+ void *mem;
+ dma_addr_t mem_dma;
+ size_t dma_sz, rx_fis_sz;
+
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+
+ /* check FBS capability */
+ if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) {
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 cmd = readl(port_mmio + PORT_CMD);
+ if (cmd & PORT_CMD_FBSCP)
+ pp->fbs_supported = true;
+ else if (hpriv->flags & AHCI_HFLAG_YES_FBS) {
+ dev_info(dev, "port %d can do FBS, forcing FBSCP\n",
+ ap->port_no);
+ pp->fbs_supported = true;
+ } else
+ dev_warn(dev, "port %d is not capable of FBS\n",
+ ap->port_no);
+ }
+
+ if (pp->fbs_supported) {
+ dma_sz = AHCI_PORT_PRIV_FBS_DMA_SZ;
+ rx_fis_sz = ACARD_AHCI_RX_FIS_SZ * 16;
+ } else {
+ dma_sz = AHCI_PORT_PRIV_DMA_SZ;
+ rx_fis_sz = ACARD_AHCI_RX_FIS_SZ;
+ }
+
+ mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
+ memset(mem, 0, dma_sz);
+
+ /*
+ * First item in chunk of DMA memory: 32-slot command table,
+ * 32 bytes each in size
+ */
+ pp->cmd_slot = mem;
+ pp->cmd_slot_dma = mem_dma;
+
+ mem += AHCI_CMD_SLOT_SZ;
+ mem_dma += AHCI_CMD_SLOT_SZ;
+
+ /*
+ * Second item: Received-FIS area
+ */
+ pp->rx_fis = mem;
+ pp->rx_fis_dma = mem_dma;
+
+ mem += rx_fis_sz;
+ mem_dma += rx_fis_sz;
+
+ /*
+ * Third item: data area for storing a single command
+ * and its scatter-gather table
+ */
+ pp->cmd_tbl = mem;
+ pp->cmd_tbl_dma = mem_dma;
+
+ /*
+ * Save off initial list of interrupts to be enabled.
+ * This could be changed later
+ */
+ pp->intr_mask = DEF_PORT_IRQ;
+
+ ap->private_data = pp;
+
+ /* engage engines, captain */
+ return ahci_port_resume(ap);
+}
+
+static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ unsigned int board_id = ent->driver_data;
+ struct ata_port_info pi = acard_ahci_port_info[board_id];
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct ata_host *host;
+ int n_ports, i, rc;
+
+ VPRINTK("ENTER\n");
+
+ WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS);
+
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
+
+ /* acquire resources */
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ /* AHCI controllers often implement SFF compatible interface.
+ * Grab all PCI BARs just in case.
+ */
+ rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
+
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
+ hpriv->flags |= (unsigned long)pi.private_data;
+
+ if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
+ pci_enable_msi(pdev);
+
+ hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
+
+ /* save initial config */
+ ahci_save_initial_config(&pdev->dev, hpriv, 0, 0);
+
+ /* prepare host */
+ if (hpriv->cap & HOST_CAP_NCQ)
+ pi.flags |= ATA_FLAG_NCQ;
+
+ if (hpriv->cap & HOST_CAP_PMP)
+ pi.flags |= ATA_FLAG_PMP;
+
+ ahci_set_em_messages(hpriv, &pi);
+
+ /* CAP.NP sometimes indicate the index of the last enabled
+ * port, at other times, that of the last possible port, so
+ * determining the maximum port number requires looking at
+ * both CAP.NP and port_map.
+ */
+ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+ if (!host)
+ return -ENOMEM;
+ host->private_data = hpriv;
+
+ if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+ else
+ printk(KERN_INFO "ahci: SSS flag set, parallel bus scan disabled\n");
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
+ ata_port_pbar_desc(ap, AHCI_PCI_BAR,
+ 0x100 + ap->port_no * 0x80, "port");
+
+ /* set initial link pm policy */
+ /*
+ ap->pm_policy = NOT_AVAILABLE;
+ */
+ /* disabled/not-implemented port */
+ if (!(hpriv->port_map & (1 << i)))
+ ap->ops = &ata_dummy_port_ops;
+ }
+
+ /* initialize adapter */
+ rc = acard_ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
+ if (rc)
+ return rc;
+
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(host);
+ acard_ahci_pci_print_info(host);
+
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
+ &acard_ahci_sht);
+}
+
+module_pci_driver(acard_ahci_pci_driver);
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("ACard AHCI SATA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, acard_ahci_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 986e3324e30..4cd52a4541a 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1,7 +1,7 @@
/*
* ahci.c - AHCI SATA support
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -35,288 +35,65 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <linux/dmi.h>
+#include <linux/gfp.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
+#include "ahci.h"
#define DRV_NAME "ahci"
#define DRV_VERSION "3.0"
-static int ahci_skip_host_reset;
-module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444);
-MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)");
-
-static int ahci_enable_alpm(struct ata_port *ap,
- enum link_pm policy);
-static void ahci_disable_alpm(struct ata_port *ap);
-
enum {
- AHCI_PCI_BAR = 5,
- AHCI_MAX_PORTS = 32,
- AHCI_MAX_SG = 168, /* hardware max is 64K */
- AHCI_DMA_BOUNDARY = 0xffffffff,
- AHCI_MAX_CMDS = 32,
- AHCI_CMD_SZ = 32,
- AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ,
- AHCI_RX_FIS_SZ = 256,
- AHCI_CMD_TBL_CDB = 0x40,
- AHCI_CMD_TBL_HDR_SZ = 0x80,
- AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
- AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
- AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
- AHCI_RX_FIS_SZ,
- AHCI_IRQ_ON_SG = (1 << 31),
- AHCI_CMD_ATAPI = (1 << 5),
- AHCI_CMD_WRITE = (1 << 6),
- AHCI_CMD_PREFETCH = (1 << 7),
- AHCI_CMD_RESET = (1 << 8),
- AHCI_CMD_CLR_BUSY = (1 << 10),
-
- RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
- RX_FIS_SDB = 0x58, /* offset of SDB FIS data */
- RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
-
- board_ahci = 0,
- board_ahci_vt8251 = 1,
- board_ahci_ign_iferr = 2,
- board_ahci_sb600 = 3,
- board_ahci_mv = 4,
- board_ahci_sb700 = 5,
-
- /* global controller registers */
- HOST_CAP = 0x00, /* host capabilities */
- HOST_CTL = 0x04, /* global host control */
- HOST_IRQ_STAT = 0x08, /* interrupt status */
- HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */
- HOST_VERSION = 0x10, /* AHCI spec. version compliancy */
-
- /* HOST_CTL bits */
- HOST_RESET = (1 << 0), /* reset controller; self-clear */
- HOST_IRQ_EN = (1 << 1), /* global IRQ enable */
- HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
-
- /* HOST_CAP bits */
- HOST_CAP_SSC = (1 << 14), /* Slumber capable */
- HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */
- HOST_CAP_CLO = (1 << 24), /* Command List Override support */
- HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */
- HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
- HOST_CAP_SNTF = (1 << 29), /* SNotification register */
- HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
- HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
-
- /* registers for each SATA port */
- PORT_LST_ADDR = 0x00, /* command list DMA addr */
- PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */
- PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */
- PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */
- PORT_IRQ_STAT = 0x10, /* interrupt status */
- PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */
- PORT_CMD = 0x18, /* port command */
- PORT_TFDATA = 0x20, /* taskfile data */
- PORT_SIG = 0x24, /* device TF signature */
- PORT_CMD_ISSUE = 0x38, /* command issue */
- PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */
- PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */
- PORT_SCR_ERR = 0x30, /* SATA phy register: SError */
- PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
- PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */
-
- /* PORT_IRQ_{STAT,MASK} bits */
- PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
- PORT_IRQ_TF_ERR = (1 << 30), /* task file error */
- PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */
- PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */
- PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */
- PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */
- PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */
- PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */
-
- PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */
- PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */
- PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */
- PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */
- PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */
- PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */
- PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */
- PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */
- PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */
-
- PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR |
- PORT_IRQ_IF_ERR |
- PORT_IRQ_CONNECT |
- PORT_IRQ_PHYRDY |
- PORT_IRQ_UNK_FIS |
- PORT_IRQ_BAD_PMP,
- PORT_IRQ_ERROR = PORT_IRQ_FREEZE |
- PORT_IRQ_TF_ERR |
- PORT_IRQ_HBUS_DATA_ERR,
- DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
- PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
- PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
-
- /* PORT_CMD bits */
- PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */
- PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */
- PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
- PORT_CMD_PMP = (1 << 17), /* PMP attached */
- PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
- PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
- PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */
- PORT_CMD_CLO = (1 << 3), /* Command list override */
- PORT_CMD_POWER_ON = (1 << 2), /* Power up device */
- PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */
- PORT_CMD_START = (1 << 0), /* Enable port DMA engine */
-
- PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */
- PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */
- PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
- PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
-
- /* hpriv->flags bits */
- AHCI_HFLAG_NO_NCQ = (1 << 0),
- AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */
- AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */
- AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */
- AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */
- AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */
- AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */
- AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */
- AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */
-
- /* ap->flags bits */
-
- AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
- ATA_FLAG_IPM,
-
- ICH_MAP = 0x90, /* ICH MAP register */
-};
-
-struct ahci_cmd_hdr {
- __le32 opts;
- __le32 status;
- __le32 tbl_addr;
- __le32 tbl_addr_hi;
- __le32 reserved[4];
+ AHCI_PCI_BAR_STA2X11 = 0,
+ AHCI_PCI_BAR_ENMOTUS = 2,
+ AHCI_PCI_BAR_STANDARD = 5,
};
-struct ahci_sg {
- __le32 addr;
- __le32 addr_hi;
- __le32 reserved;
- __le32 flags_size;
+enum board_ids {
+ /* board IDs by feature in alphabetical order */
+ board_ahci,
+ board_ahci_ign_iferr,
+ board_ahci_noncq,
+ board_ahci_nosntf,
+ board_ahci_yes_fbs,
+
+ /* board IDs for specific chipsets in alphabetical order */
+ board_ahci_mcp65,
+ board_ahci_mcp77,
+ board_ahci_mcp89,
+ board_ahci_mv,
+ board_ahci_sb600,
+ board_ahci_sb700, /* for SB700 and SB800 */
+ board_ahci_vt8251,
+
+ /* aliases */
+ board_ahci_mcp_linux = board_ahci_mcp65,
+ board_ahci_mcp67 = board_ahci_mcp65,
+ board_ahci_mcp73 = board_ahci_mcp65,
+ board_ahci_mcp79 = board_ahci_mcp77,
};
-struct ahci_host_priv {
- unsigned int flags; /* AHCI_HFLAG_* */
- u32 cap; /* cap to use */
- u32 port_map; /* port map to use */
- u32 saved_cap; /* saved initial cap */
- u32 saved_port_map; /* saved initial port_map */
-};
-
-struct ahci_port_priv {
- struct ata_link *active_link;
- struct ahci_cmd_hdr *cmd_slot;
- dma_addr_t cmd_slot_dma;
- void *cmd_tbl;
- dma_addr_t cmd_tbl_dma;
- void *rx_fis;
- dma_addr_t rx_fis_dma;
- /* for NCQ spurious interrupt analysis */
- unsigned int ncq_saw_d2h:1;
- unsigned int ncq_saw_dmas:1;
- unsigned int ncq_saw_sdb:1;
- u32 intr_mask; /* interrupts to enable */
-};
-
-static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
-static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
-static int ahci_port_start(struct ata_port *ap);
-static void ahci_port_stop(struct ata_port *ap);
-static void ahci_qc_prep(struct ata_queued_cmd *qc);
-static void ahci_freeze(struct ata_port *ap);
-static void ahci_thaw(struct ata_port *ap);
-static void ahci_pmp_attach(struct ata_port *ap);
-static void ahci_pmp_detach(struct ata_port *ap);
-static int ahci_softreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline);
-static int ahci_hardreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline);
static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
+static void ahci_mcp89_apple_enable(struct pci_dev *pdev);
+static bool is_mcp89_apple(struct pci_dev *pdev);
static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
-static void ahci_postreset(struct ata_link *link, unsigned int *class);
-static void ahci_error_handler(struct ata_port *ap);
-static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
-static int ahci_port_resume(struct ata_port *ap);
-static void ahci_dev_config(struct ata_device *dev);
-static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
-static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
- u32 opts);
#ifdef CONFIG_PM
-static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
static int ahci_pci_device_resume(struct pci_dev *pdev);
#endif
-static struct device_attribute *ahci_shost_attrs[] = {
- &dev_attr_link_power_management_policy,
- NULL
-};
-
static struct scsi_host_template ahci_sht = {
- ATA_NCQ_SHT(DRV_NAME),
- .can_queue = AHCI_MAX_CMDS - 1,
- .sg_tablesize = AHCI_MAX_SG,
- .dma_boundary = AHCI_DMA_BOUNDARY,
- .shost_attrs = ahci_shost_attrs,
-};
-
-static struct ata_port_operations ahci_ops = {
- .inherits = &sata_pmp_port_ops,
-
- .qc_defer = sata_pmp_qc_defer_cmd_switch,
- .qc_prep = ahci_qc_prep,
- .qc_issue = ahci_qc_issue,
- .qc_fill_rtf = ahci_qc_fill_rtf,
-
- .freeze = ahci_freeze,
- .thaw = ahci_thaw,
- .softreset = ahci_softreset,
- .hardreset = ahci_hardreset,
- .postreset = ahci_postreset,
- .pmp_softreset = ahci_softreset,
- .error_handler = ahci_error_handler,
- .post_internal_cmd = ahci_post_internal_cmd,
- .dev_config = ahci_dev_config,
-
- .scr_read = ahci_scr_read,
- .scr_write = ahci_scr_write,
- .pmp_attach = ahci_pmp_attach,
- .pmp_detach = ahci_pmp_detach,
-
- .enable_pm = ahci_enable_alpm,
- .disable_pm = ahci_disable_alpm,
-#ifdef CONFIG_PM
- .port_suspend = ahci_port_suspend,
- .port_resume = ahci_port_resume,
-#endif
- .port_start = ahci_port_start,
- .port_stop = ahci_port_stop,
+ AHCI_SHT("ahci"),
};
static struct ata_port_operations ahci_vt8251_ops = {
@@ -329,60 +106,95 @@ static struct ata_port_operations ahci_p5wdh_ops = {
.hardreset = ahci_p5wdh_hardreset,
};
-#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
-
static const struct ata_port_info ahci_port_info[] = {
- /* board_ahci */
- {
+ /* by features */
+ [board_ahci] = {
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
- /* board_ahci_vt8251 */
- {
- AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
+ [board_ahci_ign_iferr] = {
+ AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR),
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
- .port_ops = &ahci_vt8251_ops,
+ .port_ops = &ahci_ops,
},
- /* board_ahci_ign_iferr */
- {
- AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR),
+ [board_ahci_noncq] = {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ),
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
- /* board_ahci_sb600 */
- {
- AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
- AHCI_HFLAG_32BIT_ONLY |
- AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP),
+ [board_ahci_nosntf] = {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_SNTF),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
+ [board_ahci_yes_fbs] = {
+ AHCI_HFLAGS (AHCI_HFLAG_YES_FBS),
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
- /* board_ahci_mv */
- {
+ /* by chipsets */
+ [board_ahci_mcp65] = {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
+ AHCI_HFLAG_YES_NCQ),
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
+ [board_ahci_mcp77] = {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
+ [board_ahci_mcp89] = {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
+ [board_ahci_mv] = {
AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
- AHCI_HFLAG_MV_PATA),
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
- .pio_mask = 0x1f, /* pio0-4 */
+ AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
+ .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
- /* board_ahci_sb700 */
- {
+ [board_ahci_sb600] = {
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
- AHCI_HFLAG_NO_PMP),
+ AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 |
+ AHCI_HFLAG_32BIT_ONLY),
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
- .port_ops = &ahci_ops,
+ .port_ops = &ahci_pmp_retry_srst_ops,
+ },
+ [board_ahci_sb700] = { /* for SB700 and SB800 */
+ AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_pmp_retry_srst_ops,
+ },
+ [board_ahci_vt8251] = {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_vt8251_ops,
},
};
@@ -399,7 +211,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf }, /* ICH8 */
{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
@@ -418,11 +230,88 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
+ { PCI_VDEVICE(INTEL, 0x3a22), board_ahci }, /* ICH10 */
{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
+ { PCI_VDEVICE(INTEL, 0x3b22), board_ahci }, /* PCH AHCI */
+ { PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
+ { PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
+ { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
+ { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
+ { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
+ { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
+ { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */
+ { PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
+ { PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
+ { PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
+ { PCI_VDEVICE(INTEL, 0x1d04), board_ahci }, /* PBG RAID */
+ { PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */
+ { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */
+ { PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
+ { PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
+ { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */
+ { PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */
+ { PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
+ { PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
+ { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
+ { PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
+ { PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */
+ { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */
+ { PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */
+ { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */
+ { PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */
+ { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */
+ { PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
+ { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */
+ { PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */
+ { PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */
+ { PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x9c05), board_ahci }, /* Lynx Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x9c06), board_ahci }, /* Lynx Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x9c07), board_ahci }, /* Lynx Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x9c0e), board_ahci }, /* Lynx Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x9c0f), board_ahci }, /* Lynx Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x1f22), board_ahci }, /* Avoton AHCI */
+ { PCI_VDEVICE(INTEL, 0x1f23), board_ahci }, /* Avoton AHCI */
+ { PCI_VDEVICE(INTEL, 0x1f24), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f25), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f26), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f32), board_ahci }, /* Avoton AHCI */
+ { PCI_VDEVICE(INTEL, 0x1f33), board_ahci }, /* Avoton AHCI */
+ { PCI_VDEVICE(INTEL, 0x1f34), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f35), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f36), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f37), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci }, /* Avoton RAID */
+ { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
+ { PCI_VDEVICE(INTEL, 0x8d04), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x8d06), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x8d0e), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x8d62), board_ahci }, /* Wellsburg AHCI */
+ { PCI_VDEVICE(INTEL, 0x8d64), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x23a3), board_ahci }, /* Coleto Creek AHCI */
+ { PCI_VDEVICE(INTEL, 0x9c83), board_ahci }, /* Wildcat Point-LP AHCI */
+ { PCI_VDEVICE(INTEL, 0x9c85), board_ahci }, /* Wildcat Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
+ /* JMicron 362B and 362C have an AHCI function with IDE class code */
+ { PCI_VDEVICE(JMICRON, 0x2362), board_ahci_ign_iferr },
+ { PCI_VDEVICE(JMICRON, 0x236f), board_ahci_ign_iferr },
/* ATI */
{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
@@ -433,88 +322,156 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
+ /* AMD */
+ { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
+ { PCI_VDEVICE(AMD, 0x7900), board_ahci }, /* AMD CZ */
+ /* AMD is using RAID class only for ahci controllers */
+ { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
+
/* VIA */
{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
/* NVIDIA */
- { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci }, /* MCP67 */
- { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci }, /* MCP73 */
- { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci }, /* MCP77 */
- { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci }, /* MCP77 */
- { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci }, /* MCP77 */
- { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci }, /* MCP77 */
- { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci }, /* MCP77 */
- { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci }, /* MCP77 */
- { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci }, /* MCP77 */
- { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci }, /* MCP77 */
- { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci }, /* MCP77 */
- { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */
- { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */
- { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */
- { PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */
- { PCI_VDEVICE(NVIDIA, 0x0bc8), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bc9), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bca), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bcb), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bcc), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bd0), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bd1), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bd2), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bd3), board_ahci }, /* MCP7B */
+ { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_mcp67 }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_mcp67 }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_mcp67 }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_mcp67 }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_mcp67 }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_mcp67 }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_mcp67 }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_mcp67 }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_mcp67 }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_mcp67 }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_mcp67 }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_mcp67 }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0581), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0582), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0583), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0584), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0585), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0586), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0587), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0588), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x0589), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x058a), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x058b), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x058c), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x058d), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x058e), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x058f), board_ahci_mcp_linux }, /* Linux ID */
+ { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_mcp73 }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_mcp73 }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_mcp73 }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_mcp73 }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_mcp73 }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_mcp73 }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_mcp73 }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_mcp73 }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_mcp73 }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_mcp73 }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_mcp73 }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_mcp73 }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci_mcp77 }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci_mcp77 }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci_mcp77 }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci_mcp77 }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci_mcp77 }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci_mcp77 }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci_mcp77 }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci_mcp77 }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci_mcp77 }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci_mcp77 }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci_mcp77 }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci_mcp77 }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci_mcp79 }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci_mcp79 }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci_mcp79 }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci_mcp79 }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci_mcp79 }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci_mcp79 }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci_mcp79 }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci_mcp79 }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci_mcp79 }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci_mcp79 }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci_mcp79 }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci_mcp79 }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci_mcp89 }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci_mcp89 }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci_mcp89 }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci_mcp89 }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci_mcp89 }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci_mcp89 }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci_mcp89 }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci_mcp89 }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci_mcp89 }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci_mcp89 }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci_mcp89 }, /* MCP89 */
+ { PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci_mcp89 }, /* MCP89 */
/* SiS */
- { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
- { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
- { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
+ { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
+ { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 968 */
+ { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
+
+ /* ST Microelectronics */
+ { PCI_VDEVICE(STMICRO, 0xCC06), board_ahci }, /* ST ConneXt */
/* Marvell */
{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */
{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9123),
+ .class = PCI_CLASS_STORAGE_SATA_AHCI,
+ .class_mask = 0xffffff,
+ .driver_data = board_ahci_yes_fbs }, /* 88se9128 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9125),
+ .driver_data = board_ahci_yes_fbs }, /* 88se9125 */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_MARVELL_EXT, 0x9178,
+ PCI_VENDOR_ID_MARVELL_EXT, 0x9170),
+ .driver_data = board_ahci_yes_fbs }, /* 88se9170 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),
+ .driver_data = board_ahci_yes_fbs }, /* 88se9172 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172),
+ .driver_data = board_ahci_yes_fbs }, /* 88se9172 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9192),
+ .driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0),
+ .driver_data = board_ahci_yes_fbs },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),
+ .driver_data = board_ahci_yes_fbs },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230),
+ .driver_data = board_ahci_yes_fbs },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642),
+ .driver_data = board_ahci_yes_fbs },
+
+ /* Promise */
+ { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */
+ { PCI_VDEVICE(PROMISE, 0x3781), board_ahci }, /* FastTrak TX8660 ahci-mode */
+
+ /* Asmedia */
+ { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci }, /* ASM1060 */
+ { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci }, /* ASM1060 */
+ { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */
+ { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */
+
+ /*
+ * Samsung SSDs found on some macbooks. NCQ times out.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=60731
+ */
+ { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_noncq },
+
+ /* Enmotus */
+ { PCI_DEVICE(0x1c44, 0x8000), board_ahci },
/* Generic, PCI class code for AHCI */
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -535,88 +492,24 @@ static struct pci_driver ahci_pci_driver = {
#endif
};
+#if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
+static int marvell_enable;
+#else
+static int marvell_enable = 1;
+#endif
+module_param(marvell_enable, int, 0644);
+MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
-static inline int ahci_nr_ports(u32 cap)
-{
- return (cap & 0x1f) + 1;
-}
-
-static inline void __iomem *__ahci_port_base(struct ata_host *host,
- unsigned int port_no)
-{
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
-
- return mmio + 0x100 + (port_no * 0x80);
-}
-
-static inline void __iomem *ahci_port_base(struct ata_port *ap)
-{
- return __ahci_port_base(ap->host, ap->port_no);
-}
-
-static void ahci_enable_ahci(void __iomem *mmio)
-{
- u32 tmp;
-
- /* turn on AHCI_EN */
- tmp = readl(mmio + HOST_CTL);
- if (!(tmp & HOST_AHCI_EN)) {
- tmp |= HOST_AHCI_EN;
- writel(tmp, mmio + HOST_CTL);
- tmp = readl(mmio + HOST_CTL); /* flush && sanity check */
- WARN_ON(!(tmp & HOST_AHCI_EN));
- }
-}
-/**
- * ahci_save_initial_config - Save and fixup initial config values
- * @pdev: target PCI device
- * @hpriv: host private area to store config values
- *
- * Some registers containing configuration info might be setup by
- * BIOS and might be cleared on reset. This function saves the
- * initial values of those registers into @hpriv such that they
- * can be restored after controller reset.
- *
- * If inconsistent, config values are fixed up by this function.
- *
- * LOCKING:
- * None.
- */
-static void ahci_save_initial_config(struct pci_dev *pdev,
- struct ahci_host_priv *hpriv)
+static void ahci_pci_save_initial_config(struct pci_dev *pdev,
+ struct ahci_host_priv *hpriv)
{
- void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
- u32 cap, port_map;
- int i;
- int mv;
-
- /* make sure AHCI mode is enabled before accessing CAP */
- ahci_enable_ahci(mmio);
+ unsigned int force_port_map = 0;
+ unsigned int mask_port_map = 0;
- /* Values prefixed with saved_ are written back to host after
- * reset. Values without are used for driver operation.
- */
- hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
- hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
-
- /* some chips have errata preventing 64bit use */
- if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
- dev_printk(KERN_INFO, &pdev->dev,
- "controller can't do 64bit DMA, forcing 32bit\n");
- cap &= ~HOST_CAP_64;
- }
-
- if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
- dev_printk(KERN_INFO, &pdev->dev,
- "controller can't do NCQ, turning off CAP_NCQ\n");
- cap &= ~HOST_CAP_NCQ;
- }
-
- if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
- dev_printk(KERN_INFO, &pdev->dev,
- "controller can't do PMP, turning off CAP_PMP\n");
- cap &= ~HOST_CAP_PMP;
+ if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
+ dev_info(&pdev->dev, "JMB361 has only one port\n");
+ force_port_map = 1;
}
/*
@@ -626,432 +519,25 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
*/
if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
if (pdev->device == 0x6121)
- mv = 0x3;
+ mask_port_map = 0x3;
else
- mv = 0xf;
- dev_printk(KERN_ERR, &pdev->dev,
- "MV_AHCI HACK: port_map %x -> %x\n",
- port_map,
- port_map & mv);
-
- port_map &= mv;
- }
-
- /* cross check port_map and cap.n_ports */
- if (port_map) {
- int map_ports = 0;
-
- for (i = 0; i < AHCI_MAX_PORTS; i++)
- if (port_map & (1 << i))
- map_ports++;
-
- /* If PI has more ports than n_ports, whine, clear
- * port_map and let it be generated from n_ports.
- */
- if (map_ports > ahci_nr_ports(cap)) {
- dev_printk(KERN_WARNING, &pdev->dev,
- "implemented port map (0x%x) contains more "
- "ports than nr_ports (%u), using nr_ports\n",
- port_map, ahci_nr_ports(cap));
- port_map = 0;
- }
- }
-
- /* fabricate port_map from cap.nr_ports */
- if (!port_map) {
- port_map = (1 << ahci_nr_ports(cap)) - 1;
- dev_printk(KERN_WARNING, &pdev->dev,
- "forcing PORTS_IMPL to 0x%x\n", port_map);
-
- /* write the fixed up value to the PI register */
- hpriv->saved_port_map = port_map;
- }
-
- /* record values to use during operation */
- hpriv->cap = cap;
- hpriv->port_map = port_map;
-}
-
-/**
- * ahci_restore_initial_config - Restore initial config
- * @host: target ATA host
- *
- * Restore initial config stored by ahci_save_initial_config().
- *
- * LOCKING:
- * None.
- */
-static void ahci_restore_initial_config(struct ata_host *host)
-{
- struct ahci_host_priv *hpriv = host->private_data;
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
-
- writel(hpriv->saved_cap, mmio + HOST_CAP);
- writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
- (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
-}
-
-static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
-{
- static const int offset[] = {
- [SCR_STATUS] = PORT_SCR_STAT,
- [SCR_CONTROL] = PORT_SCR_CTL,
- [SCR_ERROR] = PORT_SCR_ERR,
- [SCR_ACTIVE] = PORT_SCR_ACT,
- [SCR_NOTIFICATION] = PORT_SCR_NTF,
- };
- struct ahci_host_priv *hpriv = ap->host->private_data;
-
- if (sc_reg < ARRAY_SIZE(offset) &&
- (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
- return offset[sc_reg];
- return 0;
-}
-
-static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- int offset = ahci_scr_offset(ap, sc_reg);
-
- if (offset) {
- *val = readl(port_mmio + offset);
- return 0;
- }
- return -EINVAL;
-}
-
-static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- int offset = ahci_scr_offset(ap, sc_reg);
-
- if (offset) {
- writel(val, port_mmio + offset);
- return 0;
- }
- return -EINVAL;
-}
-
-static void ahci_start_engine(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 tmp;
-
- /* start DMA */
- tmp = readl(port_mmio + PORT_CMD);
- tmp |= PORT_CMD_START;
- writel(tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
-}
-
-static int ahci_stop_engine(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 tmp;
-
- tmp = readl(port_mmio + PORT_CMD);
-
- /* check if the HBA is idle */
- if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
- return 0;
-
- /* setting HBA to idle */
- tmp &= ~PORT_CMD_START;
- writel(tmp, port_mmio + PORT_CMD);
-
- /* wait for engine to stop. This could be as long as 500 msec */
- tmp = ata_wait_register(port_mmio + PORT_CMD,
- PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
- if (tmp & PORT_CMD_LIST_ON)
- return -EIO;
-
- return 0;
-}
-
-static void ahci_start_fis_rx(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ahci_host_priv *hpriv = ap->host->private_data;
- struct ahci_port_priv *pp = ap->private_data;
- u32 tmp;
-
- /* set FIS registers */
- if (hpriv->cap & HOST_CAP_64)
- writel((pp->cmd_slot_dma >> 16) >> 16,
- port_mmio + PORT_LST_ADDR_HI);
- writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
-
- if (hpriv->cap & HOST_CAP_64)
- writel((pp->rx_fis_dma >> 16) >> 16,
- port_mmio + PORT_FIS_ADDR_HI);
- writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
-
- /* enable FIS reception */
- tmp = readl(port_mmio + PORT_CMD);
- tmp |= PORT_CMD_FIS_RX;
- writel(tmp, port_mmio + PORT_CMD);
-
- /* flush */
- readl(port_mmio + PORT_CMD);
-}
-
-static int ahci_stop_fis_rx(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 tmp;
-
- /* disable FIS reception */
- tmp = readl(port_mmio + PORT_CMD);
- tmp &= ~PORT_CMD_FIS_RX;
- writel(tmp, port_mmio + PORT_CMD);
-
- /* wait for completion, spec says 500ms, give it 1000 */
- tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
- PORT_CMD_FIS_ON, 10, 1000);
- if (tmp & PORT_CMD_FIS_ON)
- return -EBUSY;
-
- return 0;
-}
-
-static void ahci_power_up(struct ata_port *ap)
-{
- struct ahci_host_priv *hpriv = ap->host->private_data;
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 cmd;
-
- cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
-
- /* spin up device */
- if (hpriv->cap & HOST_CAP_SSS) {
- cmd |= PORT_CMD_SPIN_UP;
- writel(cmd, port_mmio + PORT_CMD);
- }
-
- /* wake up link */
- writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
-}
-
-static void ahci_disable_alpm(struct ata_port *ap)
-{
- struct ahci_host_priv *hpriv = ap->host->private_data;
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 cmd;
- struct ahci_port_priv *pp = ap->private_data;
-
- /* IPM bits should be disabled by libata-core */
- /* get the existing command bits */
- cmd = readl(port_mmio + PORT_CMD);
-
- /* disable ALPM and ASP */
- cmd &= ~PORT_CMD_ASP;
- cmd &= ~PORT_CMD_ALPE;
-
- /* force the interface back to active */
- cmd |= PORT_CMD_ICC_ACTIVE;
-
- /* write out new cmd value */
- writel(cmd, port_mmio + PORT_CMD);
- cmd = readl(port_mmio + PORT_CMD);
-
- /* wait 10ms to be sure we've come out of any low power state */
- msleep(10);
-
- /* clear out any PhyRdy stuff from interrupt status */
- writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
-
- /* go ahead and clean out PhyRdy Change from Serror too */
- ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
-
- /*
- * Clear flag to indicate that we should ignore all PhyRdy
- * state changes
- */
- hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
-
- /*
- * Enable interrupts on Phy Ready.
- */
- pp->intr_mask |= PORT_IRQ_PHYRDY;
- writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
-
- /*
- * don't change the link pm policy - we can be called
- * just to turn of link pm temporarily
- */
-}
-
-static int ahci_enable_alpm(struct ata_port *ap,
- enum link_pm policy)
-{
- struct ahci_host_priv *hpriv = ap->host->private_data;
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 cmd;
- struct ahci_port_priv *pp = ap->private_data;
- u32 asp;
-
- /* Make sure the host is capable of link power management */
- if (!(hpriv->cap & HOST_CAP_ALPM))
- return -EINVAL;
-
- switch (policy) {
- case MAX_PERFORMANCE:
- case NOT_AVAILABLE:
- /*
- * if we came here with NOT_AVAILABLE,
- * it just means this is the first time we
- * have tried to enable - default to max performance,
- * and let the user go to lower power modes on request.
- */
- ahci_disable_alpm(ap);
- return 0;
- case MIN_POWER:
- /* configure HBA to enter SLUMBER */
- asp = PORT_CMD_ASP;
- break;
- case MEDIUM_POWER:
- /* configure HBA to enter PARTIAL */
- asp = 0;
- break;
- default:
- return -EINVAL;
- }
-
- /*
- * Disable interrupts on Phy Ready. This keeps us from
- * getting woken up due to spurious phy ready interrupts
- * TBD - Hot plug should be done via polling now, is
- * that even supported?
- */
- pp->intr_mask &= ~PORT_IRQ_PHYRDY;
- writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
-
- /*
- * Set a flag to indicate that we should ignore all PhyRdy
- * state changes since these can happen now whenever we
- * change link state
- */
- hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
-
- /* get the existing command bits */
- cmd = readl(port_mmio + PORT_CMD);
-
- /*
- * Set ASP based on Policy
- */
- cmd |= asp;
-
- /*
- * Setting this bit will instruct the HBA to aggressively
- * enter a lower power link state when it's appropriate and
- * based on the value set above for ASP
- */
- cmd |= PORT_CMD_ALPE;
-
- /* write out new cmd value */
- writel(cmd, port_mmio + PORT_CMD);
- cmd = readl(port_mmio + PORT_CMD);
-
- /* IPM bits should be set by libata-core */
- return 0;
-}
-
-#ifdef CONFIG_PM
-static void ahci_power_down(struct ata_port *ap)
-{
- struct ahci_host_priv *hpriv = ap->host->private_data;
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 cmd, scontrol;
-
- if (!(hpriv->cap & HOST_CAP_SSS))
- return;
-
- /* put device into listen mode, first set PxSCTL.DET to 0 */
- scontrol = readl(port_mmio + PORT_SCR_CTL);
- scontrol &= ~0xf;
- writel(scontrol, port_mmio + PORT_SCR_CTL);
-
- /* then set PxCMD.SUD to 0 */
- cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
- cmd &= ~PORT_CMD_SPIN_UP;
- writel(cmd, port_mmio + PORT_CMD);
-}
-#endif
-
-static void ahci_start_port(struct ata_port *ap)
-{
- /* enable FIS reception */
- ahci_start_fis_rx(ap);
-
- /* enable DMA */
- ahci_start_engine(ap);
-}
-
-static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
-{
- int rc;
-
- /* disable DMA */
- rc = ahci_stop_engine(ap);
- if (rc) {
- *emsg = "failed to stop engine";
- return rc;
+ mask_port_map = 0xf;
+ dev_info(&pdev->dev,
+ "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
}
- /* disable FIS reception */
- rc = ahci_stop_fis_rx(ap);
- if (rc) {
- *emsg = "failed stop FIS RX";
- return rc;
- }
-
- return 0;
+ ahci_save_initial_config(&pdev->dev, hpriv, force_port_map,
+ mask_port_map);
}
-static int ahci_reset_controller(struct ata_host *host)
+static int ahci_pci_reset_controller(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
- struct ahci_host_priv *hpriv = host->private_data;
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
- u32 tmp;
-
- /* we must be in AHCI mode, before using anything
- * AHCI-specific, such as HOST_RESET.
- */
- ahci_enable_ahci(mmio);
-
- /* global controller reset */
- if (!ahci_skip_host_reset) {
- tmp = readl(mmio + HOST_CTL);
- if ((tmp & HOST_RESET) == 0) {
- writel(tmp | HOST_RESET, mmio + HOST_CTL);
- readl(mmio + HOST_CTL); /* flush */
- }
-
- /* reset must complete within 1 second, or
- * the hardware should be considered fried.
- */
- ssleep(1);
-
- tmp = readl(mmio + HOST_CTL);
- if (tmp & HOST_RESET) {
- dev_printk(KERN_ERR, host->dev,
- "controller reset failed (0x%x)\n", tmp);
- return -EIO;
- }
- /* turn on AHCI mode */
- ahci_enable_ahci(mmio);
-
- /* Some registers might be cleared on reset. Restore
- * initial values.
- */
- ahci_restore_initial_config(host);
- } else
- dev_printk(KERN_INFO, host->dev,
- "skipping global host reset\n");
+ ahci_reset_controller(host);
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+ struct ahci_host_priv *hpriv = host->private_data;
u16 tmp16;
/* configure PCS */
@@ -1065,40 +551,10 @@ static int ahci_reset_controller(struct ata_host *host)
return 0;
}
-static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
- int port_no, void __iomem *mmio,
- void __iomem *port_mmio)
-{
- const char *emsg = NULL;
- int rc;
- u32 tmp;
-
- /* make sure port is not active */
- rc = ahci_deinit_port(ap, &emsg);
- if (rc)
- dev_printk(KERN_WARNING, &pdev->dev,
- "%s (%d)\n", emsg, rc);
-
- /* clear SError */
- tmp = readl(port_mmio + PORT_SCR_ERR);
- VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
- writel(tmp, port_mmio + PORT_SCR_ERR);
-
- /* clear port IRQ */
- tmp = readl(port_mmio + PORT_IRQ_STAT);
- VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
- if (tmp)
- writel(tmp, port_mmio + PORT_IRQ_STAT);
-
- writel(1 << port_no, mmio + HOST_IRQ_STAT);
-}
-
-static void ahci_init_controller(struct ata_host *host)
+static void ahci_pci_init_controller(struct ata_host *host)
{
struct ahci_host_priv *hpriv = host->private_data;
struct pci_dev *pdev = to_pci_dev(host->dev);
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
- int i;
void __iomem *port_mmio;
u32 tmp;
int mv;
@@ -1119,242 +575,14 @@ static void ahci_init_controller(struct ata_host *host)
writel(tmp, port_mmio + PORT_IRQ_STAT);
}
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
-
- port_mmio = ahci_port_base(ap);
- if (ata_port_is_dummy(ap))
- continue;
-
- ahci_port_init(pdev, ap, i, mmio, port_mmio);
- }
-
- tmp = readl(mmio + HOST_CTL);
- VPRINTK("HOST_CTL 0x%x\n", tmp);
- writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
- tmp = readl(mmio + HOST_CTL);
- VPRINTK("HOST_CTL 0x%x\n", tmp);
-}
-
-static void ahci_dev_config(struct ata_device *dev)
-{
- struct ahci_host_priv *hpriv = dev->link->ap->host->private_data;
-
- if (hpriv->flags & AHCI_HFLAG_SECT255) {
- dev->max_sectors = 255;
- ata_dev_printk(dev, KERN_INFO,
- "SB600 AHCI: limiting to 255 sectors per cmd\n");
- }
-}
-
-static unsigned int ahci_dev_classify(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ata_taskfile tf;
- u32 tmp;
-
- tmp = readl(port_mmio + PORT_SIG);
- tf.lbah = (tmp >> 24) & 0xff;
- tf.lbam = (tmp >> 16) & 0xff;
- tf.lbal = (tmp >> 8) & 0xff;
- tf.nsect = (tmp) & 0xff;
-
- return ata_dev_classify(&tf);
-}
-
-static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
- u32 opts)
-{
- dma_addr_t cmd_tbl_dma;
-
- cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
-
- pp->cmd_slot[tag].opts = cpu_to_le32(opts);
- pp->cmd_slot[tag].status = 0;
- pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
- pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
-}
-
-static int ahci_kick_engine(struct ata_port *ap, int force_restart)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ahci_host_priv *hpriv = ap->host->private_data;
- u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
- u32 tmp;
- int busy, rc;
-
- /* do we need to kick the port? */
- busy = status & (ATA_BUSY | ATA_DRQ);
- if (!busy && !force_restart)
- return 0;
-
- /* stop engine */
- rc = ahci_stop_engine(ap);
- if (rc)
- goto out_restart;
-
- /* need to do CLO? */
- if (!busy) {
- rc = 0;
- goto out_restart;
- }
-
- if (!(hpriv->cap & HOST_CAP_CLO)) {
- rc = -EOPNOTSUPP;
- goto out_restart;
- }
-
- /* perform CLO */
- tmp = readl(port_mmio + PORT_CMD);
- tmp |= PORT_CMD_CLO;
- writel(tmp, port_mmio + PORT_CMD);
-
- rc = 0;
- tmp = ata_wait_register(port_mmio + PORT_CMD,
- PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
- if (tmp & PORT_CMD_CLO)
- rc = -EIO;
-
- /* restart engine */
- out_restart:
- ahci_start_engine(ap);
- return rc;
-}
-
-static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
- struct ata_taskfile *tf, int is_cmd, u16 flags,
- unsigned long timeout_msec)
-{
- const u32 cmd_fis_len = 5; /* five dwords */
- struct ahci_port_priv *pp = ap->private_data;
- void __iomem *port_mmio = ahci_port_base(ap);
- u8 *fis = pp->cmd_tbl;
- u32 tmp;
-
- /* prep the command */
- ata_tf_to_fis(tf, pmp, is_cmd, fis);
- ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
-
- /* issue & wait */
- writel(1, port_mmio + PORT_CMD_ISSUE);
-
- if (timeout_msec) {
- tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
- 1, timeout_msec);
- if (tmp & 0x1) {
- ahci_kick_engine(ap, 1);
- return -EBUSY;
- }
- } else
- readl(port_mmio + PORT_CMD_ISSUE); /* flush */
-
- return 0;
-}
-
-static int ahci_check_ready(struct ata_link *link)
-{
- void __iomem *port_mmio = ahci_port_base(link->ap);
- u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
-
- if (!(status & ATA_BUSY))
- return 1;
- return 0;
-}
-
-static int ahci_softreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
-{
- struct ata_port *ap = link->ap;
- int pmp = sata_srst_pmp(link);
- const char *reason = NULL;
- unsigned long now, msecs;
- struct ata_taskfile tf;
- int rc;
-
- DPRINTK("ENTER\n");
-
- /* prepare for SRST (AHCI-1.1 10.4.1) */
- rc = ahci_kick_engine(ap, 1);
- if (rc && rc != -EOPNOTSUPP)
- ata_link_printk(link, KERN_WARNING,
- "failed to reset engine (errno=%d)\n", rc);
-
- ata_tf_init(link->device, &tf);
-
- /* issue the first D2H Register FIS */
- msecs = 0;
- now = jiffies;
- if (time_after(now, deadline))
- msecs = jiffies_to_msecs(deadline - now);
-
- tf.ctl |= ATA_SRST;
- if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
- AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
- rc = -EIO;
- reason = "1st FIS failed";
- goto fail;
- }
-
- /* spec says at least 5us, but be generous and sleep for 1ms */
- msleep(1);
-
- /* issue the second D2H Register FIS */
- tf.ctl &= ~ATA_SRST;
- ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
-
- /* wait for link to become ready */
- rc = ata_wait_after_reset(link, deadline, ahci_check_ready);
- /* link occupied, -ENODEV too is an error */
- if (rc) {
- reason = "device not ready";
- goto fail;
- }
- *class = ahci_dev_classify(ap);
-
- DPRINTK("EXIT, class=%u\n", *class);
- return 0;
-
- fail:
- ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
- return rc;
-}
-
-static int ahci_hardreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
-{
- const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
- struct ata_port *ap = link->ap;
- struct ahci_port_priv *pp = ap->private_data;
- u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
- struct ata_taskfile tf;
- bool online;
- int rc;
-
- DPRINTK("ENTER\n");
-
- ahci_stop_engine(ap);
-
- /* clear D2H reception area to properly wait for D2H FIS */
- ata_tf_init(link->device, &tf);
- tf.command = 0x80;
- ata_tf_to_fis(&tf, 0, 0, d2h_fis);
-
- rc = sata_link_hardreset(link, timing, deadline, &online,
- ahci_check_ready);
-
- ahci_start_engine(ap);
-
- if (online)
- *class = ahci_dev_classify(ap);
-
- DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
- return rc;
+ ahci_init_controller(host);
}
static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
bool online;
int rc;
@@ -1365,7 +593,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline, &online, NULL);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
@@ -1380,6 +608,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
{
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
@@ -1389,13 +618,13 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(link->device, &tf);
- tf.command = 0x80;
+ tf.command = ATA_BUSY;
ata_tf_to_fis(&tf, 0, 0, d2h_fis);
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline, &online, NULL);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* The pseudo configuration device on SIMG4726 attached to
* ASUS P5W-DH Deluxe doesn't send signature FIS after
@@ -1414,446 +643,26 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
ahci_check_ready);
if (rc)
- ahci_kick_engine(ap, 0);
+ ahci_kick_engine(ap);
}
return rc;
}
-static void ahci_postreset(struct ata_link *link, unsigned int *class)
-{
- struct ata_port *ap = link->ap;
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 new_tmp, tmp;
-
- ata_std_postreset(link, class);
-
- /* Make sure port's ATAPI bit is set appropriately */
- new_tmp = tmp = readl(port_mmio + PORT_CMD);
- if (*class == ATA_DEV_ATAPI)
- new_tmp |= PORT_CMD_ATAPI;
- else
- new_tmp &= ~PORT_CMD_ATAPI;
- if (new_tmp != tmp) {
- writel(new_tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
- }
-}
-
-static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
-{
- struct scatterlist *sg;
- struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
- unsigned int si;
-
- VPRINTK("ENTER\n");
-
- /*
- * Next, the S/G list.
- */
- for_each_sg(qc->sg, sg, qc->n_elem, si) {
- dma_addr_t addr = sg_dma_address(sg);
- u32 sg_len = sg_dma_len(sg);
-
- ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
- ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
- ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
- }
-
- return si;
-}
-
-static void ahci_qc_prep(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct ahci_port_priv *pp = ap->private_data;
- int is_atapi = ata_is_atapi(qc->tf.protocol);
- void *cmd_tbl;
- u32 opts;
- const u32 cmd_fis_len = 5; /* five dwords */
- unsigned int n_elem;
-
- /*
- * Fill in command table information. First, the header,
- * a SATA Register - Host to Device command FIS.
- */
- cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
-
- ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
- if (is_atapi) {
- memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
- memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
- }
-
- n_elem = 0;
- if (qc->flags & ATA_QCFLAG_DMAMAP)
- n_elem = ahci_fill_sg(qc, cmd_tbl);
-
- /*
- * Fill in command slot information.
- */
- opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
- if (qc->tf.flags & ATA_TFLAG_WRITE)
- opts |= AHCI_CMD_WRITE;
- if (is_atapi)
- opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
-
- ahci_fill_cmd_slot(pp, qc->tag, opts);
-}
-
-static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
-{
- struct ahci_host_priv *hpriv = ap->host->private_data;
- struct ahci_port_priv *pp = ap->private_data;
- struct ata_eh_info *host_ehi = &ap->link.eh_info;
- struct ata_link *link = NULL;
- struct ata_queued_cmd *active_qc;
- struct ata_eh_info *active_ehi;
- u32 serror;
-
- /* determine active link */
- ata_port_for_each_link(link, ap)
- if (ata_link_active(link))
- break;
- if (!link)
- link = &ap->link;
-
- active_qc = ata_qc_from_tag(ap, link->active_tag);
- active_ehi = &link->eh_info;
-
- /* record irq stat */
- ata_ehi_clear_desc(host_ehi);
- ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
-
- /* AHCI needs SError cleared; otherwise, it might lock up */
- ahci_scr_read(ap, SCR_ERROR, &serror);
- ahci_scr_write(ap, SCR_ERROR, serror);
- host_ehi->serror |= serror;
-
- /* some controllers set IRQ_IF_ERR on device errors, ignore it */
- if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
- irq_stat &= ~PORT_IRQ_IF_ERR;
-
- if (irq_stat & PORT_IRQ_TF_ERR) {
- /* If qc is active, charge it; otherwise, the active
- * link. There's no active qc on NCQ errors. It will
- * be determined by EH by reading log page 10h.
- */
- if (active_qc)
- active_qc->err_mask |= AC_ERR_DEV;
- else
- active_ehi->err_mask |= AC_ERR_DEV;
-
- if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
- host_ehi->serror &= ~SERR_INTERNAL;
- }
-
- if (irq_stat & PORT_IRQ_UNK_FIS) {
- u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
-
- active_ehi->err_mask |= AC_ERR_HSM;
- active_ehi->action |= ATA_EH_RESET;
- ata_ehi_push_desc(active_ehi,
- "unknown FIS %08x %08x %08x %08x" ,
- unk[0], unk[1], unk[2], unk[3]);
- }
-
- if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
- active_ehi->err_mask |= AC_ERR_HSM;
- active_ehi->action |= ATA_EH_RESET;
- ata_ehi_push_desc(active_ehi, "incorrect PMP");
- }
-
- if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
- host_ehi->err_mask |= AC_ERR_HOST_BUS;
- host_ehi->action |= ATA_EH_RESET;
- ata_ehi_push_desc(host_ehi, "host bus error");
- }
-
- if (irq_stat & PORT_IRQ_IF_ERR) {
- host_ehi->err_mask |= AC_ERR_ATA_BUS;
- host_ehi->action |= ATA_EH_RESET;
- ata_ehi_push_desc(host_ehi, "interface fatal error");
- }
-
- if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
- ata_ehi_hotplugged(host_ehi);
- ata_ehi_push_desc(host_ehi, "%s",
- irq_stat & PORT_IRQ_CONNECT ?
- "connection status changed" : "PHY RDY changed");
- }
-
- /* okay, let's hand over to EH */
-
- if (irq_stat & PORT_IRQ_FREEZE)
- ata_port_freeze(ap);
- else
- ata_port_abort(ap);
-}
-
-static void ahci_port_intr(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ata_eh_info *ehi = &ap->link.eh_info;
- struct ahci_port_priv *pp = ap->private_data;
- struct ahci_host_priv *hpriv = ap->host->private_data;
- int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
- u32 status, qc_active;
- int rc;
-
- status = readl(port_mmio + PORT_IRQ_STAT);
- writel(status, port_mmio + PORT_IRQ_STAT);
-
- /* ignore BAD_PMP while resetting */
- if (unlikely(resetting))
- status &= ~PORT_IRQ_BAD_PMP;
-
- /* If we are getting PhyRdy, this is
- * just a power state change, we should
- * clear out this, plus the PhyRdy/Comm
- * Wake bits from Serror
- */
- if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
- (status & PORT_IRQ_PHYRDY)) {
- status &= ~PORT_IRQ_PHYRDY;
- ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
- }
-
- if (unlikely(status & PORT_IRQ_ERROR)) {
- ahci_error_intr(ap, status);
- return;
- }
-
- if (status & PORT_IRQ_SDB_FIS) {
- /* If SNotification is available, leave notification
- * handling to sata_async_notification(). If not,
- * emulate it by snooping SDB FIS RX area.
- *
- * Snooping FIS RX area is probably cheaper than
- * poking SNotification but some constrollers which
- * implement SNotification, ICH9 for example, don't
- * store AN SDB FIS into receive area.
- */
- if (hpriv->cap & HOST_CAP_SNTF)
- sata_async_notification(ap);
- else {
- /* If the 'N' bit in word 0 of the FIS is set,
- * we just received asynchronous notification.
- * Tell libata about it.
- */
- const __le32 *f = pp->rx_fis + RX_FIS_SDB;
- u32 f0 = le32_to_cpu(f[0]);
-
- if (f0 & (1 << 15))
- sata_async_notification(ap);
- }
- }
-
- /* pp->active_link is valid iff any command is in flight */
- if (ap->qc_active && pp->active_link->sactive)
- qc_active = readl(port_mmio + PORT_SCR_ACT);
- else
- qc_active = readl(port_mmio + PORT_CMD_ISSUE);
-
- rc = ata_qc_complete_multiple(ap, qc_active);
-
- /* while resetting, invalid completions are expected */
- if (unlikely(rc < 0 && !resetting)) {
- ehi->err_mask |= AC_ERR_HSM;
- ehi->action |= ATA_EH_RESET;
- ata_port_freeze(ap);
- }
-}
-
-static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
-{
- struct ata_host *host = dev_instance;
- struct ahci_host_priv *hpriv;
- unsigned int i, handled = 0;
- void __iomem *mmio;
- u32 irq_stat, irq_ack = 0;
-
- VPRINTK("ENTER\n");
-
- hpriv = host->private_data;
- mmio = host->iomap[AHCI_PCI_BAR];
-
- /* sigh. 0xffffffff is a valid return from h/w */
- irq_stat = readl(mmio + HOST_IRQ_STAT);
- irq_stat &= hpriv->port_map;
- if (!irq_stat)
- return IRQ_NONE;
-
- spin_lock(&host->lock);
-
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap;
-
- if (!(irq_stat & (1 << i)))
- continue;
-
- ap = host->ports[i];
- if (ap) {
- ahci_port_intr(ap);
- VPRINTK("port %u\n", i);
- } else {
- VPRINTK("port %u (no irq)\n", i);
- if (ata_ratelimit())
- dev_printk(KERN_WARNING, host->dev,
- "interrupt on disabled port %u\n", i);
- }
-
- irq_ack |= (1 << i);
- }
-
- if (irq_ack) {
- writel(irq_ack, mmio + HOST_IRQ_STAT);
- handled = 1;
- }
-
- spin_unlock(&host->lock);
-
- VPRINTK("EXIT\n");
-
- return IRQ_RETVAL(handled);
-}
-
-static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ahci_port_priv *pp = ap->private_data;
-
- /* Keep track of the currently active link. It will be used
- * in completion path to determine whether NCQ phase is in
- * progress.
- */
- pp->active_link = qc->dev->link;
-
- if (qc->tf.protocol == ATA_PROT_NCQ)
- writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
- writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
- readl(port_mmio + PORT_CMD_ISSUE); /* flush */
-
- return 0;
-}
-
-static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
-{
- struct ahci_port_priv *pp = qc->ap->private_data;
- u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
-
- ata_tf_from_fis(d2h_fis, &qc->result_tf);
- return true;
-}
-
-static void ahci_freeze(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
-
- /* turn IRQ off */
- writel(0, port_mmio + PORT_IRQ_MASK);
-}
-
-static void ahci_thaw(struct ata_port *ap)
-{
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 tmp;
- struct ahci_port_priv *pp = ap->private_data;
-
- /* clear IRQ */
- tmp = readl(port_mmio + PORT_IRQ_STAT);
- writel(tmp, port_mmio + PORT_IRQ_STAT);
- writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
-
- /* turn IRQ back on */
- writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
-}
-
-static void ahci_error_handler(struct ata_port *ap)
-{
- if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
- /* restart engine */
- ahci_stop_engine(ap);
- ahci_start_engine(ap);
- }
-
- sata_pmp_error_handler(ap);
-}
-
-static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
-
- /* make DMA engine forget about the failed command */
- if (qc->flags & ATA_QCFLAG_FAILED)
- ahci_kick_engine(ap, 1);
-}
-
-static void ahci_pmp_attach(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ahci_port_priv *pp = ap->private_data;
- u32 cmd;
-
- cmd = readl(port_mmio + PORT_CMD);
- cmd |= PORT_CMD_PMP;
- writel(cmd, port_mmio + PORT_CMD);
-
- pp->intr_mask |= PORT_IRQ_BAD_PMP;
- writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
-}
-
-static void ahci_pmp_detach(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ahci_port_priv *pp = ap->private_data;
- u32 cmd;
-
- cmd = readl(port_mmio + PORT_CMD);
- cmd &= ~PORT_CMD_PMP;
- writel(cmd, port_mmio + PORT_CMD);
-
- pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
- writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
-}
-
-static int ahci_port_resume(struct ata_port *ap)
-{
- ahci_power_up(ap);
- ahci_start_port(ap);
-
- if (sata_pmp_attached(ap))
- ahci_pmp_attach(ap);
- else
- ahci_pmp_detach(ap);
-
- return 0;
-}
-
#ifdef CONFIG_PM
-static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
-{
- const char *emsg = NULL;
- int rc;
-
- rc = ahci_deinit_port(ap, &emsg);
- if (rc == 0)
- ahci_power_down(ap);
- else {
- ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
- ahci_start_port(ap);
- }
-
- return rc;
-}
-
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
+ struct ata_host *host = pci_get_drvdata(pdev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
u32 ctl;
+ if (mesg.event & PM_EVENT_SUSPEND &&
+ hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
+ dev_err(&pdev->dev,
+ "BIOS update required for suspend/resume\n");
+ return -EIO;
+ }
+
if (mesg.event & PM_EVENT_SLEEP) {
/* AHCI spec rev1.1 section 8.3.3:
* Software must disable interrupts prior to requesting a
@@ -1870,19 +679,23 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
static int ahci_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
if (rc)
return rc;
+ /* Apple BIOS helpfully mangles the registers on resume */
+ if (is_mcp89_apple(pdev))
+ ahci_mcp89_apple_enable(pdev);
+
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
- rc = ahci_reset_controller(host);
+ rc = ahci_pci_reset_controller(host);
if (rc)
return rc;
- ahci_init_controller(host);
+ ahci_pci_init_controller(host);
}
ata_host_resume(host);
@@ -1891,126 +704,50 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
}
#endif
-static int ahci_port_start(struct ata_port *ap)
+static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
{
- struct device *dev = ap->host->dev;
- struct ahci_port_priv *pp;
- void *mem;
- dma_addr_t mem_dma;
-
- pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
- if (!pp)
- return -ENOMEM;
-
- mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
- GFP_KERNEL);
- if (!mem)
- return -ENOMEM;
- memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
-
- /*
- * First item in chunk of DMA memory: 32-slot command table,
- * 32 bytes each in size
- */
- pp->cmd_slot = mem;
- pp->cmd_slot_dma = mem_dma;
-
- mem += AHCI_CMD_SLOT_SZ;
- mem_dma += AHCI_CMD_SLOT_SZ;
-
- /*
- * Second item: Received-FIS area
- */
- pp->rx_fis = mem;
- pp->rx_fis_dma = mem_dma;
-
- mem += AHCI_RX_FIS_SZ;
- mem_dma += AHCI_RX_FIS_SZ;
-
- /*
- * Third item: data area for storing a single command
- * and its scatter-gather table
- */
- pp->cmd_tbl = mem;
- pp->cmd_tbl_dma = mem_dma;
+ int rc;
/*
- * Save off initial list of interrupts to be enabled.
- * This could be changed later
+ * If the device fixup already set the dma_mask to some non-standard
+ * value, don't extend it here. This happens on STA2X11, for example.
*/
- pp->intr_mask = DEF_PORT_IRQ;
-
- ap->private_data = pp;
-
- /* engage engines, captain */
- return ahci_port_resume(ap);
-}
-
-static void ahci_port_stop(struct ata_port *ap)
-{
- const char *emsg = NULL;
- int rc;
-
- /* de-initialize port */
- rc = ahci_deinit_port(ap, &emsg);
- if (rc)
- ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
-}
-
-static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
-{
- int rc;
+ if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32))
+ return 0;
if (using_dac &&
- !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
if (rc) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "64-bit DMA enable failed\n");
+ dev_err(&pdev->dev,
+ "64-bit DMA enable failed\n");
return rc;
}
}
} else {
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit DMA enable failed\n");
+ dev_err(&pdev->dev, "32-bit DMA enable failed\n");
return rc;
}
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit consistent DMA enable failed\n");
+ dev_err(&pdev->dev,
+ "32-bit consistent DMA enable failed\n");
return rc;
}
}
return 0;
}
-static void ahci_print_info(struct ata_host *host)
+static void ahci_pci_print_info(struct ata_host *host)
{
- struct ahci_host_priv *hpriv = host->private_data;
struct pci_dev *pdev = to_pci_dev(host->dev);
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
- u32 vers, cap, impl, speed;
- const char *speed_s;
u16 cc;
const char *scc_s;
- vers = readl(mmio + HOST_VERSION);
- cap = hpriv->cap;
- impl = hpriv->port_map;
-
- speed = (cap >> 20) & 0xf;
- if (speed == 1)
- speed_s = "1.5";
- else if (speed == 2)
- speed_s = "3";
- else
- speed_s = "?";
-
pci_read_config_word(pdev, 0x0a, &cc);
if (cc == PCI_CLASS_STORAGE_IDE)
scc_s = "IDE";
@@ -2021,44 +758,7 @@ static void ahci_print_info(struct ata_host *host)
else
scc_s = "unknown";
- dev_printk(KERN_INFO, &pdev->dev,
- "AHCI %02x%02x.%02x%02x "
- "%u slots %u ports %s Gbps 0x%x impl %s mode\n"
- ,
-
- (vers >> 24) & 0xff,
- (vers >> 16) & 0xff,
- (vers >> 8) & 0xff,
- vers & 0xff,
-
- ((cap >> 8) & 0x1f) + 1,
- (cap & 0x1f) + 1,
- speed_s,
- impl,
- scc_s);
-
- dev_printk(KERN_INFO, &pdev->dev,
- "flags: "
- "%s%s%s%s%s%s%s"
- "%s%s%s%s%s%s%s\n"
- ,
-
- cap & (1 << 31) ? "64bit " : "",
- cap & (1 << 30) ? "ncq " : "",
- cap & (1 << 29) ? "sntf " : "",
- cap & (1 << 28) ? "ilck " : "",
- cap & (1 << 27) ? "stag " : "",
- cap & (1 << 26) ? "pm " : "",
- cap & (1 << 25) ? "led " : "",
-
- cap & (1 << 24) ? "clo " : "",
- cap & (1 << 19) ? "nz " : "",
- cap & (1 << 18) ? "only " : "",
- cap & (1 << 17) ? "pmp " : "",
- cap & (1 << 15) ? "pio " : "",
- cap & (1 << 14) ? "slum " : "",
- cap & (1 << 13) ? "part " : ""
- );
+ ahci_print_info(host, scc_s);
}
/* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
@@ -2098,42 +798,540 @@ static void ahci_p5wdh_workaround(struct ata_host *host)
dmi_check_system(sysids)) {
struct ata_port *ap = host->ports[1];
- dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "
- "Deluxe on-board SIMG4726 workaround\n");
+ dev_info(&pdev->dev,
+ "enabling ASUS P5W DH Deluxe on-board SIMG4726 workaround\n");
ap->ops = &ahci_p5wdh_ops;
ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
}
}
+/*
+ * Macbook7,1 firmware forcibly disables MCP89 AHCI and changes PCI ID when
+ * booting in BIOS compatibility mode. We restore the registers but not ID.
+ */
+static void ahci_mcp89_apple_enable(struct pci_dev *pdev)
+{
+ u32 val;
+
+ printk(KERN_INFO "ahci: enabling MCP89 AHCI mode\n");
+
+ pci_read_config_dword(pdev, 0xf8, &val);
+ val |= 1 << 0x1b;
+ /* the following changes the device ID, but appears not to affect function */
+ /* val = (val & ~0xf0000000) | 0x80000000; */
+ pci_write_config_dword(pdev, 0xf8, val);
+
+ pci_read_config_dword(pdev, 0x54c, &val);
+ val |= 1 << 0xc;
+ pci_write_config_dword(pdev, 0x54c, val);
+
+ pci_read_config_dword(pdev, 0x4a4, &val);
+ val &= 0xff;
+ val |= 0x01060100;
+ pci_write_config_dword(pdev, 0x4a4, val);
+
+ pci_read_config_dword(pdev, 0x54c, &val);
+ val &= ~(1 << 0xc);
+ pci_write_config_dword(pdev, 0x54c, val);
+
+ pci_read_config_dword(pdev, 0xf8, &val);
+ val &= ~(1 << 0x1b);
+ pci_write_config_dword(pdev, 0xf8, val);
+}
+
+static bool is_mcp89_apple(struct pci_dev *pdev)
+{
+ return pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
+ pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA &&
+ pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
+ pdev->subsystem_device == 0xcb89;
+}
+
+/* only some SB600 ahci controllers can do 64bit DMA */
+static bool ahci_sb600_enable_64bit(struct pci_dev *pdev)
+{
+ static const struct dmi_system_id sysids[] = {
+ /*
+ * The oldest version known to be broken is 0901 and
+ * working is 1501 which was released on 2007-10-26.
+ * Enable 64bit DMA on 1501 and anything newer.
+ *
+ * Please read bko#9412 for more info.
+ */
+ {
+ .ident = "ASUS M2A-VM",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR,
+ "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"),
+ },
+ .driver_data = "20071026", /* yyyymmdd */
+ },
+ /*
+ * All BIOS versions for the MSI K9A2 Platinum (MS-7376)
+ * support 64bit DMA.
+ *
+ * BIOS versions earlier than 1.5 had the Manufacturer DMI
+ * fields as "MICRO-STAR INTERANTIONAL CO.,LTD".
+ * This spelling mistake was fixed in BIOS version 1.5, so
+ * 1.5 and later have the Manufacturer as
+ * "MICRO-STAR INTERNATIONAL CO.,LTD".
+ * So try to match on DMI_BOARD_VENDOR of "MICRO-STAR INTER".
+ *
+ * BIOS versions earlier than 1.9 had a Board Product Name
+ * DMI field of "MS-7376". This was changed to be
+ * "K9A2 Platinum (MS-7376)" in version 1.9, but we can still
+ * match on DMI_BOARD_NAME of "MS-7376".
+ */
+ {
+ .ident = "MSI K9A2 Platinum",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR,
+ "MICRO-STAR INTER"),
+ DMI_MATCH(DMI_BOARD_NAME, "MS-7376"),
+ },
+ },
+ /*
+ * All BIOS versions for the MSI K9AGM2 (MS-7327) support
+ * 64bit DMA.
+ *
+ * This board also had the typo mentioned above in the
+ * Manufacturer DMI field (fixed in BIOS version 1.5), so
+ * match on DMI_BOARD_VENDOR of "MICRO-STAR INTER" again.
+ */
+ {
+ .ident = "MSI K9AGM2",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR,
+ "MICRO-STAR INTER"),
+ DMI_MATCH(DMI_BOARD_NAME, "MS-7327"),
+ },
+ },
+ /*
+ * All BIOS versions for the Asus M3A support 64bit DMA.
+ * (all release versions from 0301 to 1206 were tested)
+ */
+ {
+ .ident = "ASUS M3A",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR,
+ "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "M3A"),
+ },
+ },
+ { }
+ };
+ const struct dmi_system_id *match;
+ int year, month, date;
+ char buf[9];
+
+ match = dmi_first_match(sysids);
+ if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
+ !match)
+ return false;
+
+ if (!match->driver_data)
+ goto enable_64bit;
+
+ dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
+ snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
+
+ if (strcmp(buf, match->driver_data) >= 0)
+ goto enable_64bit;
+ else {
+ dev_warn(&pdev->dev,
+ "%s: BIOS too old, forcing 32bit DMA, update BIOS\n",
+ match->ident);
+ return false;
+ }
+
+enable_64bit:
+ dev_warn(&pdev->dev, "%s: enabling 64bit DMA\n", match->ident);
+ return true;
+}
+
+static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
+{
+ static const struct dmi_system_id broken_systems[] = {
+ {
+ .ident = "HP Compaq nx6310",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6310"),
+ },
+ /* PCI slot number of the controller */
+ .driver_data = (void *)0x1FUL,
+ },
+ {
+ .ident = "HP Compaq 6720s",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6720s"),
+ },
+ /* PCI slot number of the controller */
+ .driver_data = (void *)0x1FUL,
+ },
+
+ { } /* terminate list */
+ };
+ const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
+
+ if (dmi) {
+ unsigned long slot = (unsigned long)dmi->driver_data;
+ /* apply the quirk only to on-board controllers */
+ return slot == PCI_SLOT(pdev->devfn);
+ }
+
+ return false;
+}
+
+static bool ahci_broken_suspend(struct pci_dev *pdev)
+{
+ static const struct dmi_system_id sysids[] = {
+ /*
+ * On HP dv[4-6] and HDX18 with earlier BIOSen, link
+ * to the harddisk doesn't become online after
+ * resuming from STR. Warn and fail suspend.
+ *
+ * http://bugzilla.kernel.org/show_bug.cgi?id=12276
+ *
+ * Use dates instead of versions to match as HP is
+ * apparently recycling both product and version
+ * strings.
+ *
+ * http://bugzilla.kernel.org/show_bug.cgi?id=15462
+ */
+ {
+ .ident = "dv4",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME,
+ "HP Pavilion dv4 Notebook PC"),
+ },
+ .driver_data = "20090105", /* F.30 */
+ },
+ {
+ .ident = "dv5",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME,
+ "HP Pavilion dv5 Notebook PC"),
+ },
+ .driver_data = "20090506", /* F.16 */
+ },
+ {
+ .ident = "dv6",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME,
+ "HP Pavilion dv6 Notebook PC"),
+ },
+ .driver_data = "20090423", /* F.21 */
+ },
+ {
+ .ident = "HDX18",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME,
+ "HP HDX18 Notebook PC"),
+ },
+ .driver_data = "20090430", /* F.23 */
+ },
+ /*
+ * Acer eMachines G725 has the same problem. BIOS
+ * V1.03 is known to be broken. V3.04 is known to
+ * work. Between, there are V1.06, V2.06 and V3.03
+ * that we don't have much idea about. For now,
+ * blacklist anything older than V3.04.
+ *
+ * http://bugzilla.kernel.org/show_bug.cgi?id=15104
+ */
+ {
+ .ident = "G725",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "eMachines"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "eMachines G725"),
+ },
+ .driver_data = "20091216", /* V3.04 */
+ },
+ { } /* terminate list */
+ };
+ const struct dmi_system_id *dmi = dmi_first_match(sysids);
+ int year, month, date;
+ char buf[9];
+
+ if (!dmi || pdev->bus->number || pdev->devfn != PCI_DEVFN(0x1f, 2))
+ return false;
+
+ dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
+ snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
+
+ return strcmp(buf, dmi->driver_data) < 0;
+}
+
+static bool ahci_broken_online(struct pci_dev *pdev)
+{
+#define ENCODE_BUSDEVFN(bus, slot, func) \
+ (void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func)))
+ static const struct dmi_system_id sysids[] = {
+ /*
+ * There are several gigabyte boards which use
+ * SIMG5723s configured as hardware RAID. Certain
+ * 5723 firmware revisions shipped there keep the link
+ * online but fail to answer properly to SRST or
+ * IDENTIFY when no device is attached downstream
+ * causing libata to retry quite a few times leading
+ * to excessive detection delay.
+ *
+ * As these firmwares respond to the second reset try
+ * with invalid device signature, considering unknown
+ * sig as offline works around the problem acceptably.
+ */
+ {
+ .ident = "EP45-DQ6",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR,
+ "Gigabyte Technology Co., Ltd."),
+ DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"),
+ },
+ .driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0),
+ },
+ {
+ .ident = "EP45-DS5",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR,
+ "Gigabyte Technology Co., Ltd."),
+ DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"),
+ },
+ .driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0),
+ },
+ { } /* terminate list */
+ };
+#undef ENCODE_BUSDEVFN
+ const struct dmi_system_id *dmi = dmi_first_match(sysids);
+ unsigned int val;
+
+ if (!dmi)
+ return false;
+
+ val = (unsigned long)dmi->driver_data;
+
+ return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
+}
+
+static bool ahci_broken_devslp(struct pci_dev *pdev)
+{
+ /* device with broken DEVSLP but still showing SDS capability */
+ static const struct pci_device_id ids[] = {
+ { PCI_VDEVICE(INTEL, 0x0f23)}, /* Valleyview SoC */
+ {}
+ };
+
+ return pci_match_id(ids, pdev);
+}
+
+#ifdef CONFIG_ATA_ACPI
+static void ahci_gtf_filter_workaround(struct ata_host *host)
+{
+ static const struct dmi_system_id sysids[] = {
+ /*
+ * Aspire 3810T issues a bunch of SATA enable commands
+ * via _GTF including an invalid one and one which is
+ * rejected by the device. Among the successful ones
+ * is FPDMA non-zero offset enable which when enabled
+ * only on the drive side leads to NCQ command
+ * failures. Filter it out.
+ */
+ {
+ .ident = "Aspire 3810T",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3810T"),
+ },
+ .driver_data = (void *)ATA_ACPI_FILTER_FPDMA_OFFSET,
+ },
+ { }
+ };
+ const struct dmi_system_id *dmi = dmi_first_match(sysids);
+ unsigned int filter;
+ int i;
+
+ if (!dmi)
+ return;
+
+ filter = (unsigned long)dmi->driver_data;
+ dev_info(host->dev, "applying extra ACPI _GTF filter 0x%x for %s\n",
+ filter, dmi->ident);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ struct ata_link *link;
+ struct ata_device *dev;
+
+ ata_for_each_link(link, ap, EDGE)
+ ata_for_each_dev(dev, link, ALL)
+ dev->gtf_filter |= filter;
+ }
+}
+#else
+static inline void ahci_gtf_filter_workaround(struct ata_host *host)
+{}
+#endif
+
+static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
+ struct ahci_host_priv *hpriv)
+{
+ int rc, nvec;
+
+ if (hpriv->flags & AHCI_HFLAG_NO_MSI)
+ goto intx;
+
+ nvec = pci_msi_vec_count(pdev);
+ if (nvec < 0)
+ goto intx;
+
+ /*
+ * If number of MSIs is less than number of ports then Sharing Last
+ * Message mode could be enforced. In this case assume that advantage
+ * of multipe MSIs is negated and use single MSI mode instead.
+ */
+ if (nvec < n_ports)
+ goto single_msi;
+
+ rc = pci_enable_msi_exact(pdev, nvec);
+ if (rc == -ENOSPC)
+ goto single_msi;
+ else if (rc < 0)
+ goto intx;
+
+ /* fallback to single MSI mode if the controller enforced MRSM mode */
+ if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) {
+ pci_disable_msi(pdev);
+ printk(KERN_INFO "ahci: MRSM is on, fallback to single MSI\n");
+ goto single_msi;
+ }
+
+ return nvec;
+
+single_msi:
+ if (pci_enable_msi(pdev))
+ goto intx;
+ return 1;
+
+intx:
+ pci_intx(pdev, 1);
+ return 0;
+}
+
+/**
+ * ahci_host_activate - start AHCI host, request IRQs and register it
+ * @host: target ATA host
+ * @irq: base IRQ number to request
+ * @n_msis: number of MSIs allocated for this host
+ * @irq_handler: irq_handler used when requesting IRQs
+ * @irq_flags: irq_flags used when requesting IRQs
+ *
+ * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1
+ * when multiple MSIs were allocated. That is one MSI per port, starting
+ * from @irq.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
+{
+ int i, rc;
+
+ /* Sharing Last Message among several ports is not supported */
+ if (n_msis < host->n_ports)
+ return -EINVAL;
+
+ rc = ata_host_start(host);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ahci_port_priv *pp = host->ports[i]->private_data;
+
+ /* Do not receive interrupts sent by dummy ports */
+ if (!pp) {
+ disable_irq(irq + i);
+ continue;
+ }
+
+ rc = devm_request_threaded_irq(host->dev, irq + i,
+ ahci_hw_interrupt,
+ ahci_thread_fn, IRQF_SHARED,
+ pp->irq_desc, host->ports[i]);
+ if (rc)
+ goto out_free_irqs;
+ }
+
+ for (i = 0; i < host->n_ports; i++)
+ ata_port_desc(host->ports[i], "irq %d", irq + i);
+
+ rc = ata_host_register(host, &ahci_sht);
+ if (rc)
+ goto out_free_all_irqs;
+
+ return 0;
+
+out_free_all_irqs:
+ i = host->n_ports;
+out_free_irqs:
+ for (i--; i >= 0; i--)
+ devm_free_irq(host->dev, irq + i, host->ports[i]);
+
+ return rc;
+}
+
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
- struct ata_port_info pi = ahci_port_info[ent->driver_data];
+ unsigned int board_id = ent->driver_data;
+ struct ata_port_info pi = ahci_port_info[board_id];
const struct ata_port_info *ppi[] = { &pi, NULL };
struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv;
struct ata_host *host;
- int n_ports, i, rc;
+ int n_ports, n_msis, i, rc;
+ int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
VPRINTK("ENTER\n");
- WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
+ WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS);
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
- /* acquire resources */
- rc = pcim_enable_device(pdev);
- if (rc)
- return rc;
+ /* The AHCI driver can only drive the SATA ports, the PATA driver
+ can drive them all so if both drivers are selected make sure
+ AHCI stays out of the way */
+ if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
+ return -ENODEV;
- /* AHCI controllers often implement SFF compatible interface.
- * Grab all PCI BARs just in case.
+ /* Apple BIOS on MCP89 prevents us using AHCI */
+ if (is_mcp89_apple(pdev))
+ ahci_mcp89_apple_enable(pdev);
+
+ /* Promise's PDC42819 is a SAS/SATA controller that has an AHCI mode.
+ * At the moment, we can only use the AHCI mode. Let the users know
+ * that for SAS drives they're out of luck.
*/
- rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
- if (rc == -EBUSY)
- pcim_pin_device(pdev);
+ if (pdev->vendor == PCI_VENDOR_ID_PROMISE)
+ dev_info(&pdev->dev,
+ "PDC42819 can only drive SATA devices with this driver\n");
+
+ /* Both Connext and Enmotus devices use non-standard BARs */
+ if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06)
+ ahci_pci_bar = AHCI_PCI_BAR_STA2X11;
+ else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000)
+ ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS;
+
+ /* acquire resources */
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -2147,30 +1345,92 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
pci_read_config_byte(pdev, ICH_MAP, &map);
if (map & 0x3) {
- dev_printk(KERN_INFO, &pdev->dev, "controller is in "
- "combined mode, can't enable AHCI mode\n");
+ dev_info(&pdev->dev,
+ "controller is in combined mode, can't enable AHCI mode\n");
return -ENODEV;
}
}
+ /* AHCI controllers often implement SFF compatible interface.
+ * Grab all PCI BARs just in case.
+ */
+ rc = pcim_iomap_regions_request_all(pdev, 1 << ahci_pci_bar, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
+
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
hpriv->flags |= (unsigned long)pi.private_data;
- if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
- pci_intx(pdev, 1);
+ /* MCP65 revision A1 and A2 can't do MSI */
+ if (board_id == board_ahci_mcp65 &&
+ (pdev->revision == 0xa1 || pdev->revision == 0xa2))
+ hpriv->flags |= AHCI_HFLAG_NO_MSI;
+
+ /* SB800 does NOT need the workaround to ignore SERR_INTERNAL */
+ if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
+ hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
+
+ /* only some SB600s can do 64bit DMA */
+ if (ahci_sb600_enable_64bit(pdev))
+ hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
+
+ hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
+
+ /* must set flag prior to save config in order to take effect */
+ if (ahci_broken_devslp(pdev))
+ hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
/* save initial config */
- ahci_save_initial_config(pdev, hpriv);
+ ahci_pci_save_initial_config(pdev, hpriv);
/* prepare host */
- if (hpriv->cap & HOST_CAP_NCQ)
+ if (hpriv->cap & HOST_CAP_NCQ) {
pi.flags |= ATA_FLAG_NCQ;
+ /*
+ * Auto-activate optimization is supposed to be
+ * supported on all AHCI controllers indicating NCQ
+ * capability, but it seems to be broken on some
+ * chipsets including NVIDIAs.
+ */
+ if (!(hpriv->flags & AHCI_HFLAG_NO_FPDMA_AA))
+ pi.flags |= ATA_FLAG_FPDMA_AA;
+
+ /*
+ * All AHCI controllers should be forward-compatible
+ * with the new auxiliary field. This code should be
+ * conditionalized if any buggy AHCI controllers are
+ * encountered.
+ */
+ pi.flags |= ATA_FLAG_FPDMA_AUX;
+ }
if (hpriv->cap & HOST_CAP_PMP)
pi.flags |= ATA_FLAG_PMP;
+ ahci_set_em_messages(hpriv, &pi);
+
+ if (ahci_broken_system_poweroff(pdev)) {
+ pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN;
+ dev_info(&pdev->dev,
+ "quirky BIOS, skipping spindown on poweroff\n");
+ }
+
+ if (ahci_broken_suspend(pdev)) {
+ hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
+ dev_warn(&pdev->dev,
+ "BIOS update required for suspend/resume\n");
+ }
+
+ if (ahci_broken_online(pdev)) {
+ hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE;
+ dev_info(&pdev->dev,
+ "online status unreliable, applying workaround\n");
+ }
+
/* CAP.NP sometimes indicate the index of the last enabled
* port, at other times, that of the last possible port, so
* determining the maximum port number requires looking at
@@ -2178,21 +1438,34 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+ n_msis = ahci_init_interrupts(pdev, n_ports, hpriv);
+ if (n_msis > 1)
+ hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
+
host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
if (!host)
return -ENOMEM;
- host->iomap = pcim_iomap_table(pdev);
host->private_data = hpriv;
+ if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+ else
+ dev_info(&pdev->dev, "SSS flag set, parallel bus scan disabled\n");
+
+ if (pi.flags & ATA_FLAG_EM)
+ ahci_reset_em(host);
+
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
- ata_port_pbar_desc(ap, AHCI_PCI_BAR,
+ ata_port_pbar_desc(ap, ahci_pci_bar, -1, "abar");
+ ata_port_pbar_desc(ap, ahci_pci_bar,
0x100 + ap->port_no * 0x80, "port");
- /* set initial link pm policy */
- ap->pm_policy = NOT_AVAILABLE;
+ /* set enclosure management message type */
+ if (ap->flags & ATA_FLAG_EM)
+ ap->em_message_type = hpriv->em_msg_type;
+
/* disabled/not-implemented port */
if (!(hpriv->port_map & (1 << i)))
@@ -2202,39 +1475,34 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* apply workaround for ASUS P5W DH Deluxe mainboard */
ahci_p5wdh_workaround(host);
+ /* apply gtf filter quirk */
+ ahci_gtf_filter_workaround(host);
+
/* initialize adapter */
rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
if (rc)
return rc;
- rc = ahci_reset_controller(host);
+ rc = ahci_pci_reset_controller(host);
if (rc)
return rc;
- ahci_init_controller(host);
- ahci_print_info(host);
+ ahci_pci_init_controller(host);
+ ahci_pci_print_info(host);
pci_set_master(pdev);
- return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
- &ahci_sht);
-}
-static int __init ahci_init(void)
-{
- return pci_register_driver(&ahci_pci_driver);
-}
+ if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
+ return ahci_host_activate(host, pdev->irq, n_msis);
-static void __exit ahci_exit(void)
-{
- pci_unregister_driver(&ahci_pci_driver);
+ return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
+ &ahci_sht);
}
+module_pci_driver(ahci_pci_driver);
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("AHCI SATA low-level driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
-module_init(ahci_init);
-module_exit(ahci_exit);
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
new file mode 100644
index 00000000000..5513296e5e2
--- /dev/null
+++ b/drivers/ata/ahci.h
@@ -0,0 +1,410 @@
+/*
+ * ahci.h - Common AHCI SATA definitions and declarations
+ *
+ * Maintained by: Tejun Heo <tj@kernel.org>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2004-2005 Red Hat, Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * AHCI hardware documentation:
+ * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
+ * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
+ *
+ */
+
+#ifndef _AHCI_H
+#define _AHCI_H
+
+#include <linux/clk.h>
+#include <linux/libata.h>
+#include <linux/phy/phy.h>
+#include <linux/regulator/consumer.h>
+
+/* Enclosure Management Control */
+#define EM_CTRL_MSG_TYPE 0x000f0000
+
+/* Enclosure Management LED Message Type */
+#define EM_MSG_LED_HBA_PORT 0x0000000f
+#define EM_MSG_LED_PMP_SLOT 0x0000ff00
+#define EM_MSG_LED_VALUE 0xffff0000
+#define EM_MSG_LED_VALUE_ACTIVITY 0x00070000
+#define EM_MSG_LED_VALUE_OFF 0xfff80000
+#define EM_MSG_LED_VALUE_ON 0x00010000
+
+enum {
+ AHCI_MAX_PORTS = 32,
+ AHCI_MAX_CLKS = 3,
+ AHCI_MAX_SG = 168, /* hardware max is 64K */
+ AHCI_DMA_BOUNDARY = 0xffffffff,
+ AHCI_MAX_CMDS = 32,
+ AHCI_CMD_SZ = 32,
+ AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ,
+ AHCI_RX_FIS_SZ = 256,
+ AHCI_CMD_TBL_CDB = 0x40,
+ AHCI_CMD_TBL_HDR_SZ = 0x80,
+ AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
+ AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
+ AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
+ AHCI_RX_FIS_SZ,
+ AHCI_PORT_PRIV_FBS_DMA_SZ = AHCI_CMD_SLOT_SZ +
+ AHCI_CMD_TBL_AR_SZ +
+ (AHCI_RX_FIS_SZ * 16),
+ AHCI_IRQ_ON_SG = (1 << 31),
+ AHCI_CMD_ATAPI = (1 << 5),
+ AHCI_CMD_WRITE = (1 << 6),
+ AHCI_CMD_PREFETCH = (1 << 7),
+ AHCI_CMD_RESET = (1 << 8),
+ AHCI_CMD_CLR_BUSY = (1 << 10),
+
+ RX_FIS_PIO_SETUP = 0x20, /* offset of PIO Setup FIS data */
+ RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
+ RX_FIS_SDB = 0x58, /* offset of SDB FIS data */
+ RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
+
+ /* global controller registers */
+ HOST_CAP = 0x00, /* host capabilities */
+ HOST_CTL = 0x04, /* global host control */
+ HOST_IRQ_STAT = 0x08, /* interrupt status */
+ HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */
+ HOST_VERSION = 0x10, /* AHCI spec. version compliancy */
+ HOST_EM_LOC = 0x1c, /* Enclosure Management location */
+ HOST_EM_CTL = 0x20, /* Enclosure Management Control */
+ HOST_CAP2 = 0x24, /* host capabilities, extended */
+
+ /* HOST_CTL bits */
+ HOST_RESET = (1 << 0), /* reset controller; self-clear */
+ HOST_IRQ_EN = (1 << 1), /* global IRQ enable */
+ HOST_MRSM = (1 << 2), /* MSI Revert to Single Message */
+ HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
+
+ /* HOST_CAP bits */
+ HOST_CAP_SXS = (1 << 5), /* Supports External SATA */
+ HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */
+ HOST_CAP_CCC = (1 << 7), /* Command Completion Coalescing */
+ HOST_CAP_PART = (1 << 13), /* Partial state capable */
+ HOST_CAP_SSC = (1 << 14), /* Slumber state capable */
+ HOST_CAP_PIO_MULTI = (1 << 15), /* PIO multiple DRQ support */
+ HOST_CAP_FBS = (1 << 16), /* FIS-based switching support */
+ HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */
+ HOST_CAP_ONLY = (1 << 18), /* Supports AHCI mode only */
+ HOST_CAP_CLO = (1 << 24), /* Command List Override support */
+ HOST_CAP_LED = (1 << 25), /* Supports activity LED */
+ HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */
+ HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
+ HOST_CAP_MPS = (1 << 28), /* Mechanical presence switch */
+ HOST_CAP_SNTF = (1 << 29), /* SNotification register */
+ HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
+ HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
+
+ /* HOST_CAP2 bits */
+ HOST_CAP2_BOH = (1 << 0), /* BIOS/OS handoff supported */
+ HOST_CAP2_NVMHCI = (1 << 1), /* NVMHCI supported */
+ HOST_CAP2_APST = (1 << 2), /* Automatic partial to slumber */
+ HOST_CAP2_SDS = (1 << 3), /* Support device sleep */
+ HOST_CAP2_SADM = (1 << 4), /* Support aggressive DevSlp */
+ HOST_CAP2_DESO = (1 << 5), /* DevSlp from slumber only */
+
+ /* registers for each SATA port */
+ PORT_LST_ADDR = 0x00, /* command list DMA addr */
+ PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */
+ PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */
+ PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */
+ PORT_IRQ_STAT = 0x10, /* interrupt status */
+ PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */
+ PORT_CMD = 0x18, /* port command */
+ PORT_TFDATA = 0x20, /* taskfile data */
+ PORT_SIG = 0x24, /* device TF signature */
+ PORT_CMD_ISSUE = 0x38, /* command issue */
+ PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */
+ PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */
+ PORT_SCR_ERR = 0x30, /* SATA phy register: SError */
+ PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
+ PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */
+ PORT_FBS = 0x40, /* FIS-based Switching */
+ PORT_DEVSLP = 0x44, /* device sleep */
+
+ /* PORT_IRQ_{STAT,MASK} bits */
+ PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
+ PORT_IRQ_TF_ERR = (1 << 30), /* task file error */
+ PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */
+ PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */
+ PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */
+ PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */
+ PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */
+ PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */
+
+ PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */
+ PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */
+ PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */
+ PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */
+ PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */
+ PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */
+ PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */
+ PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */
+ PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */
+
+ PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR |
+ PORT_IRQ_IF_ERR |
+ PORT_IRQ_CONNECT |
+ PORT_IRQ_PHYRDY |
+ PORT_IRQ_UNK_FIS |
+ PORT_IRQ_BAD_PMP,
+ PORT_IRQ_ERROR = PORT_IRQ_FREEZE |
+ PORT_IRQ_TF_ERR |
+ PORT_IRQ_HBUS_DATA_ERR,
+ DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
+ PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
+ PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
+
+ /* PORT_CMD bits */
+ PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */
+ PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */
+ PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
+ PORT_CMD_FBSCP = (1 << 22), /* FBS Capable Port */
+ PORT_CMD_PMP = (1 << 17), /* PMP attached */
+ PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
+ PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
+ PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */
+ PORT_CMD_CLO = (1 << 3), /* Command list override */
+ PORT_CMD_POWER_ON = (1 << 2), /* Power up device */
+ PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */
+ PORT_CMD_START = (1 << 0), /* Enable port DMA engine */
+
+ PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */
+ PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */
+ PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
+ PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
+
+ /* PORT_FBS bits */
+ PORT_FBS_DWE_OFFSET = 16, /* FBS device with error offset */
+ PORT_FBS_ADO_OFFSET = 12, /* FBS active dev optimization offset */
+ PORT_FBS_DEV_OFFSET = 8, /* FBS device to issue offset */
+ PORT_FBS_DEV_MASK = (0xf << PORT_FBS_DEV_OFFSET), /* FBS.DEV */
+ PORT_FBS_SDE = (1 << 2), /* FBS single device error */
+ PORT_FBS_DEC = (1 << 1), /* FBS device error clear */
+ PORT_FBS_EN = (1 << 0), /* Enable FBS */
+
+ /* PORT_DEVSLP bits */
+ PORT_DEVSLP_DM_OFFSET = 25, /* DITO multiplier offset */
+ PORT_DEVSLP_DM_MASK = (0xf << 25), /* DITO multiplier mask */
+ PORT_DEVSLP_DITO_OFFSET = 15, /* DITO offset */
+ PORT_DEVSLP_MDAT_OFFSET = 10, /* Minimum assertion time */
+ PORT_DEVSLP_DETO_OFFSET = 2, /* DevSlp exit timeout */
+ PORT_DEVSLP_DSP = (1 << 1), /* DevSlp present */
+ PORT_DEVSLP_ADSE = (1 << 0), /* Aggressive DevSlp enable */
+
+ /* hpriv->flags bits */
+
+#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
+
+ AHCI_HFLAG_NO_NCQ = (1 << 0),
+ AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */
+ AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */
+ AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */
+ AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */
+ AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */
+ AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */
+ AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */
+ AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */
+ AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */
+ AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as
+ link offline */
+ AHCI_HFLAG_NO_SNTF = (1 << 12), /* no sntf */
+ AHCI_HFLAG_NO_FPDMA_AA = (1 << 13), /* no FPDMA AA */
+ AHCI_HFLAG_YES_FBS = (1 << 14), /* force FBS cap on */
+ AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on
+ port start (wait until
+ error-handling stage) */
+ AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */
+ AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */
+ AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */
+
+ /* ap->flags bits */
+
+ AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_ACPI_SATA | ATA_FLAG_AN,
+
+ ICH_MAP = 0x90, /* ICH MAP register */
+
+ /* em constants */
+ EM_MAX_SLOTS = 8,
+ EM_MAX_RETRY = 5,
+
+ /* em_ctl bits */
+ EM_CTL_RST = (1 << 9), /* Reset */
+ EM_CTL_TM = (1 << 8), /* Transmit Message */
+ EM_CTL_MR = (1 << 0), /* Message Received */
+ EM_CTL_ALHD = (1 << 26), /* Activity LED */
+ EM_CTL_XMT = (1 << 25), /* Transmit Only */
+ EM_CTL_SMB = (1 << 24), /* Single Message Buffer */
+ EM_CTL_SGPIO = (1 << 19), /* SGPIO messages supported */
+ EM_CTL_SES = (1 << 18), /* SES-2 messages supported */
+ EM_CTL_SAFTE = (1 << 17), /* SAF-TE messages supported */
+ EM_CTL_LED = (1 << 16), /* LED messages supported */
+
+ /* em message type */
+ EM_MSG_TYPE_LED = (1 << 0), /* LED */
+ EM_MSG_TYPE_SAFTE = (1 << 1), /* SAF-TE */
+ EM_MSG_TYPE_SES2 = (1 << 2), /* SES-2 */
+ EM_MSG_TYPE_SGPIO = (1 << 3), /* SGPIO */
+};
+
+struct ahci_cmd_hdr {
+ __le32 opts;
+ __le32 status;
+ __le32 tbl_addr;
+ __le32 tbl_addr_hi;
+ __le32 reserved[4];
+};
+
+struct ahci_sg {
+ __le32 addr;
+ __le32 addr_hi;
+ __le32 reserved;
+ __le32 flags_size;
+};
+
+struct ahci_em_priv {
+ enum sw_activity blink_policy;
+ struct timer_list timer;
+ unsigned long saved_activity;
+ unsigned long activity;
+ unsigned long led_state;
+};
+
+struct ahci_port_priv {
+ struct ata_link *active_link;
+ struct ahci_cmd_hdr *cmd_slot;
+ dma_addr_t cmd_slot_dma;
+ void *cmd_tbl;
+ dma_addr_t cmd_tbl_dma;
+ void *rx_fis;
+ dma_addr_t rx_fis_dma;
+ /* for NCQ spurious interrupt analysis */
+ unsigned int ncq_saw_d2h:1;
+ unsigned int ncq_saw_dmas:1;
+ unsigned int ncq_saw_sdb:1;
+ u32 intr_status; /* interrupts to handle */
+ spinlock_t lock; /* protects parent ata_port */
+ u32 intr_mask; /* interrupts to enable */
+ bool fbs_supported; /* set iff FBS is supported */
+ bool fbs_enabled; /* set iff FBS is enabled */
+ int fbs_last_dev; /* save FBS.DEV of last FIS */
+ /* enclosure management info per PM slot */
+ struct ahci_em_priv em_priv[EM_MAX_SLOTS];
+ char *irq_desc; /* desc in /proc/interrupts */
+};
+
+struct ahci_host_priv {
+ void __iomem * mmio; /* bus-independent mem map */
+ unsigned int flags; /* AHCI_HFLAG_* */
+ u32 cap; /* cap to use */
+ u32 cap2; /* cap2 to use */
+ u32 port_map; /* port map to use */
+ u32 saved_cap; /* saved initial cap */
+ u32 saved_cap2; /* saved initial cap2 */
+ u32 saved_port_map; /* saved initial port_map */
+ u32 em_loc; /* enclosure management location */
+ u32 em_buf_sz; /* EM buffer size in byte */
+ u32 em_msg_type; /* EM message type */
+ bool got_runtime_pm; /* Did we do pm_runtime_get? */
+ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
+ struct regulator *target_pwr; /* Optional */
+ struct phy *phy; /* If platform uses phy */
+ void *plat_data; /* Other platform data */
+ /*
+ * Optional ahci_start_engine override, if not set this gets set to the
+ * default ahci_start_engine during ahci_save_initial_config, this can
+ * be overridden anytime before the host is activated.
+ */
+ void (*start_engine)(struct ata_port *ap);
+};
+
+extern int ahci_ignore_sss;
+
+extern struct device_attribute *ahci_shost_attrs[];
+extern struct device_attribute *ahci_sdev_attrs[];
+
+#define AHCI_SHT(drv_name) \
+ ATA_NCQ_SHT(drv_name), \
+ .can_queue = AHCI_MAX_CMDS - 1, \
+ .sg_tablesize = AHCI_MAX_SG, \
+ .dma_boundary = AHCI_DMA_BOUNDARY, \
+ .shost_attrs = ahci_shost_attrs, \
+ .sdev_attrs = ahci_sdev_attrs
+
+extern struct ata_port_operations ahci_ops;
+extern struct ata_port_operations ahci_platform_ops;
+extern struct ata_port_operations ahci_pmp_retry_srst_ops;
+
+unsigned int ahci_dev_classify(struct ata_port *ap);
+void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
+ u32 opts);
+void ahci_save_initial_config(struct device *dev,
+ struct ahci_host_priv *hpriv,
+ unsigned int force_port_map,
+ unsigned int mask_port_map);
+void ahci_init_controller(struct ata_host *host);
+int ahci_reset_controller(struct ata_host *host);
+
+int ahci_do_softreset(struct ata_link *link, unsigned int *class,
+ int pmp, unsigned long deadline,
+ int (*check_ready)(struct ata_link *link));
+
+unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
+int ahci_stop_engine(struct ata_port *ap);
+void ahci_start_fis_rx(struct ata_port *ap);
+void ahci_start_engine(struct ata_port *ap);
+int ahci_check_ready(struct ata_link *link);
+int ahci_kick_engine(struct ata_port *ap);
+int ahci_port_resume(struct ata_port *ap);
+void ahci_set_em_messages(struct ahci_host_priv *hpriv,
+ struct ata_port_info *pi);
+int ahci_reset_em(struct ata_host *host);
+irqreturn_t ahci_interrupt(int irq, void *dev_instance);
+irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance);
+irqreturn_t ahci_thread_fn(int irq, void *dev_instance);
+void ahci_print_info(struct ata_host *host, const char *scc_s);
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis);
+void ahci_error_handler(struct ata_port *ap);
+
+static inline void __iomem *__ahci_port_base(struct ata_host *host,
+ unsigned int port_no)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+
+ return mmio + 0x100 + (port_no * 0x80);
+}
+
+static inline void __iomem *ahci_port_base(struct ata_port *ap)
+{
+ return __ahci_port_base(ap->host, ap->port_no);
+}
+
+static inline int ahci_nr_ports(u32 cap)
+{
+ return (cap & 0x1f) + 1;
+}
+
+#endif /* _AHCI_H */
diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c
new file mode 100644
index 00000000000..2b77d53bccf
--- /dev/null
+++ b/drivers/ata/ahci_da850.c
@@ -0,0 +1,115 @@
+/*
+ * DaVinci DA850 AHCI SATA platform driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include "ahci.h"
+
+/* SATA PHY Control Register offset from AHCI base */
+#define SATA_P0PHYCR_REG 0x178
+
+#define SATA_PHY_MPY(x) ((x) << 0)
+#define SATA_PHY_LOS(x) ((x) << 6)
+#define SATA_PHY_RXCDR(x) ((x) << 10)
+#define SATA_PHY_RXEQ(x) ((x) << 13)
+#define SATA_PHY_TXSWING(x) ((x) << 19)
+#define SATA_PHY_ENPLL(x) ((x) << 31)
+
+/*
+ * The multiplier needed for 1.5GHz PLL output.
+ *
+ * NOTE: This is currently hardcoded to be suitable for 100MHz crystal
+ * frequency (which is used by DA850 EVM board) and may need to be changed
+ * if you would like to use this driver on some other board.
+ */
+#define DA850_SATA_CLK_MULTIPLIER 7
+
+static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg,
+ void __iomem *ahci_base)
+{
+ unsigned int val;
+
+ /* Enable SATA clock receiver */
+ val = readl(pwrdn_reg);
+ val &= ~BIT(0);
+ writel(val, pwrdn_reg);
+
+ val = SATA_PHY_MPY(DA850_SATA_CLK_MULTIPLIER + 1) | SATA_PHY_LOS(1) |
+ SATA_PHY_RXCDR(4) | SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) |
+ SATA_PHY_ENPLL(1);
+
+ writel(val, ahci_base + SATA_P0PHYCR_REG);
+}
+
+static const struct ata_port_info ahci_da850_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
+};
+
+static int ahci_da850_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct resource *res;
+ void __iomem *pwrdn_reg;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ goto disable_resources;
+
+ pwrdn_reg = devm_ioremap(dev, res->start, resource_size(res));
+ if (!pwrdn_reg)
+ goto disable_resources;
+
+ da850_sata_init(dev, pwrdn_reg, hpriv->mmio);
+
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info,
+ 0, 0, 0);
+ if (rc)
+ goto disable_resources;
+
+ return 0;
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+
+static SIMPLE_DEV_PM_OPS(ahci_da850_pm_ops, ahci_platform_suspend,
+ ahci_platform_resume);
+
+static struct platform_driver ahci_da850_driver = {
+ .probe = ahci_da850_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "ahci_da850",
+ .owner = THIS_MODULE,
+ .pm = &ahci_da850_pm_ops,
+ },
+};
+module_platform_driver(ahci_da850_driver);
+
+MODULE_DESCRIPTION("DaVinci DA850 AHCI SATA platform driver");
+MODULE_AUTHOR("Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
new file mode 100644
index 00000000000..cac4360f272
--- /dev/null
+++ b/drivers/ata/ahci_imx.c
@@ -0,0 +1,527 @@
+/*
+ * copyright (c) 2013 Freescale Semiconductor, Inc.
+ * Freescale IMX AHCI SATA platform driver
+ *
+ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/ahci_platform.h>
+#include <linux/of_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/libata.h>
+#include "ahci.h"
+
+enum {
+ /* Timer 1-ms Register */
+ IMX_TIMER1MS = 0x00e0,
+ /* Port0 PHY Control Register */
+ IMX_P0PHYCR = 0x0178,
+ IMX_P0PHYCR_TEST_PDDQ = 1 << 20,
+ IMX_P0PHYCR_CR_READ = 1 << 19,
+ IMX_P0PHYCR_CR_WRITE = 1 << 18,
+ IMX_P0PHYCR_CR_CAP_DATA = 1 << 17,
+ IMX_P0PHYCR_CR_CAP_ADDR = 1 << 16,
+ /* Port0 PHY Status Register */
+ IMX_P0PHYSR = 0x017c,
+ IMX_P0PHYSR_CR_ACK = 1 << 18,
+ IMX_P0PHYSR_CR_DATA_OUT = 0xffff << 0,
+ /* Lane0 Output Status Register */
+ IMX_LANE0_OUT_STAT = 0x2003,
+ IMX_LANE0_OUT_STAT_RX_PLL_STATE = 1 << 1,
+ /* Clock Reset Register */
+ IMX_CLOCK_RESET = 0x7f3f,
+ IMX_CLOCK_RESET_RESET = 1 << 0,
+};
+
+enum ahci_imx_type {
+ AHCI_IMX53,
+ AHCI_IMX6Q,
+};
+
+struct imx_ahci_priv {
+ struct platform_device *ahci_pdev;
+ enum ahci_imx_type type;
+ struct clk *sata_clk;
+ struct clk *sata_ref_clk;
+ struct clk *ahb_clk;
+ struct regmap *gpr;
+ bool no_device;
+ bool first_time;
+};
+
+static int ahci_imx_hotplug;
+module_param_named(hotplug, ahci_imx_hotplug, int, 0644);
+MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)");
+
+static void ahci_imx_host_stop(struct ata_host *host);
+
+static int imx_phy_crbit_assert(void __iomem *mmio, u32 bit, bool assert)
+{
+ int timeout = 10;
+ u32 crval;
+ u32 srval;
+
+ /* Assert or deassert the bit */
+ crval = readl(mmio + IMX_P0PHYCR);
+ if (assert)
+ crval |= bit;
+ else
+ crval &= ~bit;
+ writel(crval, mmio + IMX_P0PHYCR);
+
+ /* Wait for the cr_ack signal */
+ do {
+ srval = readl(mmio + IMX_P0PHYSR);
+ if ((assert ? srval : ~srval) & IMX_P0PHYSR_CR_ACK)
+ break;
+ usleep_range(100, 200);
+ } while (--timeout);
+
+ return timeout ? 0 : -ETIMEDOUT;
+}
+
+static int imx_phy_reg_addressing(u16 addr, void __iomem *mmio)
+{
+ u32 crval = addr;
+ int ret;
+
+ /* Supply the address on cr_data_in */
+ writel(crval, mmio + IMX_P0PHYCR);
+
+ /* Assert the cr_cap_addr signal */
+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, true);
+ if (ret)
+ return ret;
+
+ /* Deassert cr_cap_addr */
+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, false);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int imx_phy_reg_write(u16 val, void __iomem *mmio)
+{
+ u32 crval = val;
+ int ret;
+
+ /* Supply the data on cr_data_in */
+ writel(crval, mmio + IMX_P0PHYCR);
+
+ /* Assert the cr_cap_data signal */
+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, true);
+ if (ret)
+ return ret;
+
+ /* Deassert cr_cap_data */
+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, false);
+ if (ret)
+ return ret;
+
+ if (val & IMX_CLOCK_RESET_RESET) {
+ /*
+ * In case we're resetting the phy, it's unable to acknowledge,
+ * so we return immediately here.
+ */
+ crval |= IMX_P0PHYCR_CR_WRITE;
+ writel(crval, mmio + IMX_P0PHYCR);
+ goto out;
+ }
+
+ /* Assert the cr_write signal */
+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, true);
+ if (ret)
+ return ret;
+
+ /* Deassert cr_write */
+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, false);
+ if (ret)
+ return ret;
+
+out:
+ return 0;
+}
+
+static int imx_phy_reg_read(u16 *val, void __iomem *mmio)
+{
+ int ret;
+
+ /* Assert the cr_read signal */
+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, true);
+ if (ret)
+ return ret;
+
+ /* Capture the data from cr_data_out[] */
+ *val = readl(mmio + IMX_P0PHYSR) & IMX_P0PHYSR_CR_DATA_OUT;
+
+ /* Deassert cr_read */
+ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, false);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int imx_sata_phy_reset(struct ahci_host_priv *hpriv)
+{
+ void __iomem *mmio = hpriv->mmio;
+ int timeout = 10;
+ u16 val;
+ int ret;
+
+ /* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */
+ ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio);
+ if (ret)
+ return ret;
+ ret = imx_phy_reg_write(IMX_CLOCK_RESET_RESET, mmio);
+ if (ret)
+ return ret;
+
+ /* Wait for PHY RX_PLL to be stable */
+ do {
+ usleep_range(100, 200);
+ ret = imx_phy_reg_addressing(IMX_LANE0_OUT_STAT, mmio);
+ if (ret)
+ return ret;
+ ret = imx_phy_reg_read(&val, mmio);
+ if (ret)
+ return ret;
+ if (val & IMX_LANE0_OUT_STAT_RX_PLL_STATE)
+ break;
+ } while (--timeout);
+
+ return timeout ? 0 : -ETIMEDOUT;
+}
+
+static int imx_sata_enable(struct ahci_host_priv *hpriv)
+{
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+ struct device *dev = &imxpriv->ahci_pdev->dev;
+ int ret;
+
+ if (imxpriv->no_device)
+ return 0;
+
+ if (hpriv->target_pwr) {
+ ret = regulator_enable(hpriv->target_pwr);
+ if (ret)
+ return ret;
+ }
+
+ ret = clk_prepare_enable(imxpriv->sata_ref_clk);
+ if (ret < 0)
+ goto disable_regulator;
+
+ if (imxpriv->type == AHCI_IMX6Q) {
+ /*
+ * set PHY Paremeters, two steps to configure the GPR13,
+ * one write for rest of parameters, mask of first write
+ * is 0x07ffffff, and the other one write for setting
+ * the mpll_clk_en.
+ */
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+ IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK |
+ IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK |
+ IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK |
+ IMX6Q_GPR13_SATA_SPD_MODE_MASK |
+ IMX6Q_GPR13_SATA_MPLL_SS_EN |
+ IMX6Q_GPR13_SATA_TX_ATTEN_MASK |
+ IMX6Q_GPR13_SATA_TX_BOOST_MASK |
+ IMX6Q_GPR13_SATA_TX_LVL_MASK |
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN |
+ IMX6Q_GPR13_SATA_TX_EDGE_RATE,
+ IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
+ IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
+ IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
+ IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
+ IMX6Q_GPR13_SATA_MPLL_SS_EN |
+ IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
+ IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
+ IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN,
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+
+ usleep_range(100, 200);
+
+ ret = imx_sata_phy_reset(hpriv);
+ if (ret) {
+ dev_err(dev, "failed to reset phy: %d\n", ret);
+ goto disable_regulator;
+ }
+ }
+
+ usleep_range(1000, 2000);
+
+ return 0;
+
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+
+ return ret;
+}
+
+static void imx_sata_disable(struct ahci_host_priv *hpriv)
+{
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+
+ if (imxpriv->no_device)
+ return;
+
+ if (imxpriv->type == AHCI_IMX6Q) {
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN,
+ !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+ }
+
+ clk_disable_unprepare(imxpriv->sata_ref_clk);
+
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+}
+
+static void ahci_imx_error_handler(struct ata_port *ap)
+{
+ u32 reg_val;
+ struct ata_device *dev;
+ struct ata_host *host = dev_get_drvdata(ap->dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+
+ ahci_error_handler(ap);
+
+ if (!(imxpriv->first_time) || ahci_imx_hotplug)
+ return;
+
+ imxpriv->first_time = false;
+
+ ata_for_each_dev(dev, &ap->link, ENABLED)
+ return;
+ /*
+ * Disable link to save power. An imx ahci port can't be recovered
+ * without full reset once the pddq mode is enabled making it
+ * impossible to use as part of libata LPM.
+ */
+ reg_val = readl(mmio + IMX_P0PHYCR);
+ writel(reg_val | IMX_P0PHYCR_TEST_PDDQ, mmio + IMX_P0PHYCR);
+ imx_sata_disable(hpriv);
+ imxpriv->no_device = true;
+
+ dev_info(ap->dev, "no device found, disabling link.\n");
+ dev_info(ap->dev, "pass " MODULE_PARAM_PREFIX ".hotplug=1 to enable hotplug\n");
+}
+
+static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct ata_host *host = dev_get_drvdata(ap->dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+ int ret = -EIO;
+
+ if (imxpriv->type == AHCI_IMX53)
+ ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline);
+ else if (imxpriv->type == AHCI_IMX6Q)
+ ret = ahci_ops.softreset(link, class, deadline);
+
+ return ret;
+}
+
+static struct ata_port_operations ahci_imx_ops = {
+ .inherits = &ahci_ops,
+ .host_stop = ahci_imx_host_stop,
+ .error_handler = ahci_imx_error_handler,
+ .softreset = ahci_imx_softreset,
+};
+
+static const struct ata_port_info ahci_imx_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_imx_ops,
+};
+
+static const struct of_device_id imx_ahci_of_match[] = {
+ { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 },
+ { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q },
+ {},
+};
+MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
+
+static int imx_ahci_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id;
+ struct ahci_host_priv *hpriv;
+ struct imx_ahci_priv *imxpriv;
+ unsigned int reg_val;
+ int ret;
+
+ of_id = of_match_device(imx_ahci_of_match, dev);
+ if (!of_id)
+ return -EINVAL;
+
+ imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
+ if (!imxpriv)
+ return -ENOMEM;
+
+ imxpriv->ahci_pdev = pdev;
+ imxpriv->no_device = false;
+ imxpriv->first_time = true;
+ imxpriv->type = (enum ahci_imx_type)of_id->data;
+
+ imxpriv->sata_clk = devm_clk_get(dev, "sata");
+ if (IS_ERR(imxpriv->sata_clk)) {
+ dev_err(dev, "can't get sata clock.\n");
+ return PTR_ERR(imxpriv->sata_clk);
+ }
+
+ imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref");
+ if (IS_ERR(imxpriv->sata_ref_clk)) {
+ dev_err(dev, "can't get sata_ref clock.\n");
+ return PTR_ERR(imxpriv->sata_ref_clk);
+ }
+
+ imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
+ if (IS_ERR(imxpriv->ahb_clk)) {
+ dev_err(dev, "can't get ahb clock.\n");
+ return PTR_ERR(imxpriv->ahb_clk);
+ }
+
+ if (imxpriv->type == AHCI_IMX6Q) {
+ imxpriv->gpr = syscon_regmap_lookup_by_compatible(
+ "fsl,imx6q-iomuxc-gpr");
+ if (IS_ERR(imxpriv->gpr)) {
+ dev_err(dev,
+ "failed to find fsl,imx6q-iomux-gpr regmap\n");
+ return PTR_ERR(imxpriv->gpr);
+ }
+ }
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ hpriv->plat_data = imxpriv;
+
+ ret = clk_prepare_enable(imxpriv->sata_clk);
+ if (ret)
+ return ret;
+
+ ret = imx_sata_enable(hpriv);
+ if (ret)
+ goto disable_clk;
+
+ /*
+ * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
+ * and IP vendor specific register IMX_TIMER1MS.
+ * Configure CAP_SSS (support stagered spin up).
+ * Implement the port0.
+ * Get the ahb clock rate, and configure the TIMER1MS register.
+ */
+ reg_val = readl(hpriv->mmio + HOST_CAP);
+ if (!(reg_val & HOST_CAP_SSS)) {
+ reg_val |= HOST_CAP_SSS;
+ writel(reg_val, hpriv->mmio + HOST_CAP);
+ }
+ reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL);
+ if (!(reg_val & 0x1)) {
+ reg_val |= 0x1;
+ writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
+ }
+
+ reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
+ writel(reg_val, hpriv->mmio + IMX_TIMER1MS);
+
+ ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info,
+ 0, 0, 0);
+ if (ret)
+ goto disable_sata;
+
+ return 0;
+
+disable_sata:
+ imx_sata_disable(hpriv);
+disable_clk:
+ clk_disable_unprepare(imxpriv->sata_clk);
+ return ret;
+}
+
+static void ahci_imx_host_stop(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+
+ imx_sata_disable(hpriv);
+ clk_disable_unprepare(imxpriv->sata_clk);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int imx_ahci_suspend(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int ret;
+
+ ret = ahci_platform_suspend_host(dev);
+ if (ret)
+ return ret;
+
+ imx_sata_disable(hpriv);
+
+ return 0;
+}
+
+static int imx_ahci_resume(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int ret;
+
+ ret = imx_sata_enable(hpriv);
+ if (ret)
+ return ret;
+
+ return ahci_platform_resume_host(dev);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume);
+
+static struct platform_driver imx_ahci_driver = {
+ .probe = imx_ahci_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "ahci-imx",
+ .owner = THIS_MODULE,
+ .of_match_table = imx_ahci_of_match,
+ .pm = &ahci_imx_pm_ops,
+ },
+};
+module_platform_driver(imx_ahci_driver);
+
+MODULE_DESCRIPTION("Freescale i.MX AHCI SATA platform driver");
+MODULE_AUTHOR("Richard Zhu <Hong-Xing.Zhu@freescale.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ahci:imx");
diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c
new file mode 100644
index 00000000000..fd3dfd733b8
--- /dev/null
+++ b/drivers/ata/ahci_mvebu.c
@@ -0,0 +1,128 @@
+/*
+ * AHCI glue platform driver for Marvell EBU SOCs
+ *
+ * Copyright (C) 2014 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ * Marcin Wojtas <mw@semihalf.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/ahci_platform.h>
+#include <linux/kernel.h>
+#include <linux/mbus.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "ahci.h"
+
+#define AHCI_VENDOR_SPECIFIC_0_ADDR 0xa0
+#define AHCI_VENDOR_SPECIFIC_0_DATA 0xa4
+
+#define AHCI_WINDOW_CTRL(win) (0x60 + ((win) << 4))
+#define AHCI_WINDOW_BASE(win) (0x64 + ((win) << 4))
+#define AHCI_WINDOW_SIZE(win) (0x68 + ((win) << 4))
+
+static void ahci_mvebu_mbus_config(struct ahci_host_priv *hpriv,
+ const struct mbus_dram_target_info *dram)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ writel(0, hpriv->mmio + AHCI_WINDOW_CTRL(i));
+ writel(0, hpriv->mmio + AHCI_WINDOW_BASE(i));
+ writel(0, hpriv->mmio + AHCI_WINDOW_SIZE(i));
+ }
+
+ for (i = 0; i < dram->num_cs; i++) {
+ const struct mbus_dram_window *cs = dram->cs + i;
+
+ writel((cs->mbus_attr << 8) |
+ (dram->mbus_dram_target_id << 4) | 1,
+ hpriv->mmio + AHCI_WINDOW_CTRL(i));
+ writel(cs->base, hpriv->mmio + AHCI_WINDOW_BASE(i));
+ writel(((cs->size - 1) & 0xffff0000),
+ hpriv->mmio + AHCI_WINDOW_SIZE(i));
+ }
+}
+
+static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv)
+{
+ /*
+ * Enable the regret bit to allow the SATA unit to regret a
+ * request that didn't receive an acknowlegde and avoid a
+ * deadlock
+ */
+ writel(0x4, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_ADDR);
+ writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA);
+}
+
+static const struct ata_port_info ahci_mvebu_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
+};
+
+static int ahci_mvebu_probe(struct platform_device *pdev)
+{
+ struct ahci_host_priv *hpriv;
+ const struct mbus_dram_target_info *dram;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ dram = mv_mbus_dram_info();
+ if (!dram)
+ return -ENODEV;
+
+ ahci_mvebu_mbus_config(hpriv, dram);
+ ahci_mvebu_regret_option(hpriv);
+
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info,
+ 0, 0, 0);
+ if (rc)
+ goto disable_resources;
+
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+
+static const struct of_device_id ahci_mvebu_of_match[] = {
+ { .compatible = "marvell,armada-380-ahci", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match);
+
+/*
+ * We currently don't provide power management related operations,
+ * since there is no suspend/resume support at the platform level for
+ * Armada 38x for the moment.
+ */
+static struct platform_driver ahci_mvebu_driver = {
+ .probe = ahci_mvebu_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "ahci-mvebu",
+ .owner = THIS_MODULE,
+ .of_match_table = ahci_mvebu_of_match,
+ },
+};
+module_platform_driver(ahci_mvebu_driver);
+
+MODULE_DESCRIPTION("Marvell EBU AHCI SATA driver");
+MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>, Marcin Wojtas <mw@semihalf.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ahci_mvebu");
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
new file mode 100644
index 00000000000..b10d81ddb52
--- /dev/null
+++ b/drivers/ata/ahci_platform.c
@@ -0,0 +1,105 @@
+/*
+ * AHCI SATA platform driver
+ *
+ * Copyright 2004-2005 Red Hat, Inc.
+ * Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2010 MontaVista Software, LLC.
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include "ahci.h"
+
+static const struct ata_port_info ahci_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
+};
+
+static int ahci_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ struct ahci_host_priv *hpriv;
+ unsigned long hflags = 0;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ /*
+ * Some platforms might need to prepare for mmio region access,
+ * which could be done in the following init call. So, the mmio
+ * region shouldn't be accessed before init (if provided) has
+ * returned successfully.
+ */
+ if (pdata && pdata->init) {
+ rc = pdata->init(dev, hpriv->mmio);
+ if (rc)
+ goto disable_resources;
+ }
+
+ if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
+ hflags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
+
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info,
+ hflags, 0, 0);
+ if (rc)
+ goto pdata_exit;
+
+ return 0;
+pdata_exit:
+ if (pdata && pdata->exit)
+ pdata->exit(dev);
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+
+static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
+ ahci_platform_resume);
+
+static const struct of_device_id ahci_of_match[] = {
+ { .compatible = "snps,spear-ahci", },
+ { .compatible = "snps,exynos5440-ahci", },
+ { .compatible = "ibm,476gtr-ahci", },
+ { .compatible = "snps,dwc-ahci", },
+ { .compatible = "hisilicon,hisi-ahci", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ahci_of_match);
+
+static struct platform_driver ahci_driver = {
+ .probe = ahci_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "ahci",
+ .owner = THIS_MODULE,
+ .of_match_table = ahci_of_match,
+ .pm = &ahci_pm_ops,
+ },
+};
+module_platform_driver(ahci_driver);
+
+MODULE_DESCRIPTION("AHCI SATA platform driver");
+MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ahci");
diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c
new file mode 100644
index 00000000000..2595598df9c
--- /dev/null
+++ b/drivers/ata/ahci_st.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2012 STMicroelectronics Limited
+ *
+ * Authors: Francesco Virlinzi <francesco.virlinzi@st.com>
+ * Alexandre Torgue <alexandre.torgue@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/ahci_platform.h>
+#include <linux/libata.h>
+#include <linux/reset.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+
+#include "ahci.h"
+
+#define ST_AHCI_OOBR 0xbc
+#define ST_AHCI_OOBR_WE BIT(31)
+#define ST_AHCI_OOBR_CWMIN_SHIFT 24
+#define ST_AHCI_OOBR_CWMAX_SHIFT 16
+#define ST_AHCI_OOBR_CIMIN_SHIFT 8
+#define ST_AHCI_OOBR_CIMAX_SHIFT 0
+
+struct st_ahci_drv_data {
+ struct platform_device *ahci;
+ struct reset_control *pwr;
+ struct reset_control *sw_rst;
+ struct reset_control *pwr_rst;
+ struct ahci_host_priv *hpriv;
+};
+
+static void st_ahci_configure_oob(void __iomem *mmio)
+{
+ unsigned long old_val, new_val;
+
+ new_val = (0x02 << ST_AHCI_OOBR_CWMIN_SHIFT) |
+ (0x04 << ST_AHCI_OOBR_CWMAX_SHIFT) |
+ (0x08 << ST_AHCI_OOBR_CIMIN_SHIFT) |
+ (0x0C << ST_AHCI_OOBR_CIMAX_SHIFT);
+
+ old_val = readl(mmio + ST_AHCI_OOBR);
+ writel(old_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
+ writel(new_val | ST_AHCI_OOBR_WE, mmio + ST_AHCI_OOBR);
+ writel(new_val, mmio + ST_AHCI_OOBR);
+}
+
+static int st_ahci_deassert_resets(struct device *dev)
+{
+ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+ int err;
+
+ if (drv_data->pwr) {
+ err = reset_control_deassert(drv_data->pwr);
+ if (err) {
+ dev_err(dev, "unable to bring out of pwrdwn\n");
+ return err;
+ }
+ }
+
+ st_ahci_configure_oob(drv_data->hpriv->mmio);
+
+ if (drv_data->sw_rst) {
+ err = reset_control_deassert(drv_data->sw_rst);
+ if (err) {
+ dev_err(dev, "unable to bring out of sw-rst\n");
+ return err;
+ }
+ }
+
+ if (drv_data->pwr_rst) {
+ err = reset_control_deassert(drv_data->pwr_rst);
+ if (err) {
+ dev_err(dev, "unable to bring out of pwr-rst\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static void st_ahci_host_stop(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct device *dev = host->dev;
+ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+ int err;
+
+ if (drv_data->pwr) {
+ err = reset_control_assert(drv_data->pwr);
+ if (err)
+ dev_err(dev, "unable to pwrdwn\n");
+ }
+
+ ahci_platform_disable_resources(hpriv);
+}
+
+static int st_ahci_probe_resets(struct platform_device *pdev)
+{
+ struct st_ahci_drv_data *drv_data = platform_get_drvdata(pdev);
+
+ drv_data->pwr = devm_reset_control_get(&pdev->dev, "pwr-dwn");
+ if (IS_ERR(drv_data->pwr)) {
+ dev_info(&pdev->dev, "power reset control not defined\n");
+ drv_data->pwr = NULL;
+ }
+
+ drv_data->sw_rst = devm_reset_control_get(&pdev->dev, "sw-rst");
+ if (IS_ERR(drv_data->sw_rst)) {
+ dev_info(&pdev->dev, "soft reset control not defined\n");
+ drv_data->sw_rst = NULL;
+ }
+
+ drv_data->pwr_rst = devm_reset_control_get(&pdev->dev, "pwr-rst");
+ if (IS_ERR(drv_data->pwr_rst)) {
+ dev_dbg(&pdev->dev, "power soft reset control not defined\n");
+ drv_data->pwr_rst = NULL;
+ }
+
+ return st_ahci_deassert_resets(&pdev->dev);
+}
+
+static struct ata_port_operations st_ahci_port_ops = {
+ .inherits = &ahci_platform_ops,
+ .host_stop = st_ahci_host_stop,
+};
+
+static const struct ata_port_info st_ahci_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &st_ahci_port_ops,
+};
+
+static int st_ahci_probe(struct platform_device *pdev)
+{
+ struct st_ahci_drv_data *drv_data;
+ struct ahci_host_priv *hpriv;
+ int err;
+
+ drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
+ if (!drv_data)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, drv_data);
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ drv_data->hpriv = hpriv;
+
+ err = st_ahci_probe_resets(pdev);
+ if (err)
+ return err;
+
+ err = ahci_platform_enable_resources(hpriv);
+ if (err)
+ return err;
+
+ err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info, 0, 0, 0);
+ if (err) {
+ ahci_platform_disable_resources(hpriv);
+ return err;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int st_ahci_suspend(struct device *dev)
+{
+ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = drv_data->hpriv;
+ int err;
+
+ err = ahci_platform_suspend_host(dev);
+ if (err)
+ return err;
+
+ if (drv_data->pwr) {
+ err = reset_control_assert(drv_data->pwr);
+ if (err) {
+ dev_err(dev, "unable to pwrdwn");
+ return err;
+ }
+ }
+
+ ahci_platform_disable_resources(hpriv);
+
+ return 0;
+}
+
+static int st_ahci_resume(struct device *dev)
+{
+ struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = drv_data->hpriv;
+ int err;
+
+ err = ahci_platform_enable_resources(hpriv);
+ if (err)
+ return err;
+
+ err = st_ahci_deassert_resets(dev);
+ if (err) {
+ ahci_platform_disable_resources(hpriv);
+ return err;
+ }
+
+ return ahci_platform_resume_host(dev);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(st_ahci_pm_ops, st_ahci_suspend, st_ahci_resume);
+
+static struct of_device_id st_ahci_match[] = {
+ { .compatible = "st,ahci", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, st_ahci_match);
+
+static struct platform_driver st_ahci_driver = {
+ .driver = {
+ .name = "st_ahci",
+ .owner = THIS_MODULE,
+ .pm = &st_ahci_pm_ops,
+ .of_match_table = of_match_ptr(st_ahci_match),
+ },
+ .probe = st_ahci_probe,
+ .remove = ata_platform_remove_one,
+};
+module_platform_driver(st_ahci_driver);
+
+MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@st.com>");
+MODULE_AUTHOR("Francesco Virlinzi <francesco.virlinzi@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics SATA AHCI Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
new file mode 100644
index 00000000000..02002f125bd
--- /dev/null
+++ b/drivers/ata/ahci_sunxi.c
@@ -0,0 +1,252 @@
+/*
+ * Allwinner sunxi AHCI SATA platform driver
+ * Copyright 2013 Olliver Schinagl <oliver@schinagl.nl>
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
+ * Based on code from Allwinner Technology Co., Ltd. <www.allwinnertech.com>,
+ * Daniel Wang <danielwang@allwinnertech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/ahci_platform.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include "ahci.h"
+
+#define AHCI_BISTAFR 0x00a0
+#define AHCI_BISTCR 0x00a4
+#define AHCI_BISTFCTR 0x00a8
+#define AHCI_BISTSR 0x00ac
+#define AHCI_BISTDECR 0x00b0
+#define AHCI_DIAGNR0 0x00b4
+#define AHCI_DIAGNR1 0x00b8
+#define AHCI_OOBR 0x00bc
+#define AHCI_PHYCS0R 0x00c0
+#define AHCI_PHYCS1R 0x00c4
+#define AHCI_PHYCS2R 0x00c8
+#define AHCI_TIMER1MS 0x00e0
+#define AHCI_GPARAM1R 0x00e8
+#define AHCI_GPARAM2R 0x00ec
+#define AHCI_PPARAMR 0x00f0
+#define AHCI_TESTR 0x00f4
+#define AHCI_VERSIONR 0x00f8
+#define AHCI_IDR 0x00fc
+#define AHCI_RWCR 0x00fc
+#define AHCI_P0DMACR 0x0170
+#define AHCI_P0PHYCR 0x0178
+#define AHCI_P0PHYSR 0x017c
+
+static void sunxi_clrbits(void __iomem *reg, u32 clr_val)
+{
+ u32 reg_val;
+
+ reg_val = readl(reg);
+ reg_val &= ~(clr_val);
+ writel(reg_val, reg);
+}
+
+static void sunxi_setbits(void __iomem *reg, u32 set_val)
+{
+ u32 reg_val;
+
+ reg_val = readl(reg);
+ reg_val |= set_val;
+ writel(reg_val, reg);
+}
+
+static void sunxi_clrsetbits(void __iomem *reg, u32 clr_val, u32 set_val)
+{
+ u32 reg_val;
+
+ reg_val = readl(reg);
+ reg_val &= ~(clr_val);
+ reg_val |= set_val;
+ writel(reg_val, reg);
+}
+
+static u32 sunxi_getbits(void __iomem *reg, u8 mask, u8 shift)
+{
+ return (readl(reg) >> shift) & mask;
+}
+
+static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base)
+{
+ u32 reg_val;
+ int timeout;
+
+ /* This magic is from the original code */
+ writel(0, reg_base + AHCI_RWCR);
+ msleep(5);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
+ (0x7 << 24),
+ (0x5 << 24) | BIT(23) | BIT(18));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS1R,
+ (0x3 << 16) | (0x1f << 8) | (0x3 << 6),
+ (0x2 << 16) | (0x6 << 8) | (0x2 << 6));
+ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(28) | BIT(15));
+ sunxi_clrbits(reg_base + AHCI_PHYCS1R, BIT(19));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
+ (0x7 << 20), (0x3 << 20));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS2R,
+ (0x1f << 5), (0x19 << 5));
+ msleep(5);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19));
+
+ timeout = 250; /* Power up takes aprox 50 us */
+ do {
+ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28);
+ if (reg_val == 0x02)
+ break;
+
+ if (--timeout == 0) {
+ dev_err(dev, "PHY power up failed.\n");
+ return -EIO;
+ }
+ udelay(1);
+ } while (1);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS2R, (0x1 << 24));
+
+ timeout = 100; /* Calibration takes aprox 10 us */
+ do {
+ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24);
+ if (reg_val == 0x00)
+ break;
+
+ if (--timeout == 0) {
+ dev_err(dev, "PHY calibration failed.\n");
+ return -EIO;
+ }
+ udelay(1);
+ } while (1);
+
+ msleep(15);
+
+ writel(0x7, reg_base + AHCI_RWCR);
+
+ return 0;
+}
+
+static void ahci_sunxi_start_engine(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
+ /* Setup DMA before DMA start */
+ sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ff00, 0x00004400);
+
+ /* Start DMA */
+ sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START);
+}
+
+static const struct ata_port_info ahci_sunxi_port_info = {
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
+};
+
+static int ahci_sunxi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ unsigned long hflags;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ hpriv->start_engine = ahci_sunxi_start_engine;
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
+ if (rc)
+ goto disable_resources;
+
+ hflags = AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
+ AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ;
+
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info,
+ hflags, 0, 0);
+ if (rc)
+ goto disable_resources;
+
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ahci_sunxi_resume(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
+ if (rc)
+ goto disable_resources;
+
+ rc = ahci_platform_resume_host(dev);
+ if (rc)
+ goto disable_resources;
+
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend,
+ ahci_sunxi_resume);
+
+static const struct of_device_id ahci_sunxi_of_match[] = {
+ { .compatible = "allwinner,sun4i-a10-ahci", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match);
+
+static struct platform_driver ahci_sunxi_driver = {
+ .probe = ahci_sunxi_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "ahci-sunxi",
+ .owner = THIS_MODULE,
+ .of_match_table = ahci_sunxi_of_match,
+ .pm = &ahci_sunxi_pm_ops,
+ },
+};
+module_platform_driver(ahci_sunxi_driver);
+
+MODULE_DESCRIPTION("Allwinner sunxi AHCI SATA driver");
+MODULE_AUTHOR("Olliver Schinagl <oliver@schinagl.nl>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
new file mode 100644
index 00000000000..ee3a3659bd9
--- /dev/null
+++ b/drivers/ata/ahci_xgene.c
@@ -0,0 +1,523 @@
+/*
+ * AppliedMicro X-Gene SoC SATA Host Controller Driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Author: Loc Ho <lho@apm.com>
+ * Tuan Phan <tphan@apm.com>
+ * Suman Tripathi <stripathi@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * NOTE: PM support is not currently available.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/ahci_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/phy/phy.h>
+#include "ahci.h"
+
+/* Max # of disk per a controller */
+#define MAX_AHCI_CHN_PERCTR 2
+
+/* MUX CSR */
+#define SATA_ENET_CONFIG_REG 0x00000000
+#define CFG_SATA_ENET_SELECT_MASK 0x00000001
+
+/* SATA core host controller CSR */
+#define SLVRDERRATTRIBUTES 0x00000000
+#define SLVWRERRATTRIBUTES 0x00000004
+#define MSTRDERRATTRIBUTES 0x00000008
+#define MSTWRERRATTRIBUTES 0x0000000c
+#define BUSCTLREG 0x00000014
+#define IOFMSTRWAUX 0x00000018
+#define INTSTATUSMASK 0x0000002c
+#define ERRINTSTATUS 0x00000030
+#define ERRINTSTATUSMASK 0x00000034
+
+/* SATA host AHCI CSR */
+#define PORTCFG 0x000000a4
+#define PORTADDR_SET(dst, src) \
+ (((dst) & ~0x0000003f) | (((u32)(src)) & 0x0000003f))
+#define PORTPHY1CFG 0x000000a8
+#define PORTPHY1CFG_FRCPHYRDY_SET(dst, src) \
+ (((dst) & ~0x00100000) | (((u32)(src) << 0x14) & 0x00100000))
+#define PORTPHY2CFG 0x000000ac
+#define PORTPHY3CFG 0x000000b0
+#define PORTPHY4CFG 0x000000b4
+#define PORTPHY5CFG 0x000000b8
+#define SCTL0 0x0000012C
+#define PORTPHY5CFG_RTCHG_SET(dst, src) \
+ (((dst) & ~0xfff00000) | (((u32)(src) << 0x14) & 0xfff00000))
+#define PORTAXICFG_EN_CONTEXT_SET(dst, src) \
+ (((dst) & ~0x01000000) | (((u32)(src) << 0x18) & 0x01000000))
+#define PORTAXICFG 0x000000bc
+#define PORTAXICFG_OUTTRANS_SET(dst, src) \
+ (((dst) & ~0x00f00000) | (((u32)(src) << 0x14) & 0x00f00000))
+
+/* SATA host controller AXI CSR */
+#define INT_SLV_TMOMASK 0x00000010
+
+/* SATA diagnostic CSR */
+#define CFG_MEM_RAM_SHUTDOWN 0x00000070
+#define BLOCK_MEM_RDY 0x00000074
+
+struct xgene_ahci_context {
+ struct ahci_host_priv *hpriv;
+ struct device *dev;
+ u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/
+ void __iomem *csr_core; /* Core CSR address of IP */
+ void __iomem *csr_diag; /* Diag CSR address of IP */
+ void __iomem *csr_axi; /* AXI CSR address of IP */
+ void __iomem *csr_mux; /* MUX CSR address of IP */
+};
+
+static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx)
+{
+ dev_dbg(ctx->dev, "Release memory from shutdown\n");
+ writel(0x0, ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN);
+ readl(ctx->csr_diag + CFG_MEM_RAM_SHUTDOWN); /* Force a barrier */
+ msleep(1); /* reset may take up to 1ms */
+ if (readl(ctx->csr_diag + BLOCK_MEM_RDY) != 0xFFFFFFFF) {
+ dev_err(ctx->dev, "failed to release memory from shutdown\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/**
+ * xgene_ahci_restart_engine - Restart the dma engine.
+ * @ap : ATA port of interest
+ *
+ * Restarts the dma engine inside the controller.
+ */
+static int xgene_ahci_restart_engine(struct ata_port *ap)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
+ ahci_stop_engine(ap);
+ ahci_start_fis_rx(ap);
+ hpriv->start_engine(ap);
+
+ return 0;
+}
+
+/**
+ * xgene_ahci_qc_issue - Issue commands to the device
+ * @qc: Command to issue
+ *
+ * Due to Hardware errata for IDENTIFY DEVICE command, the controller cannot
+ * clear the BSY bit after receiving the PIO setup FIS. This results in the dma
+ * state machine goes into the CMFatalErrorUpdate state and locks up. By
+ * restarting the dma engine, it removes the controller out of lock up state.
+ */
+static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct xgene_ahci_context *ctx = hpriv->plat_data;
+ int rc = 0;
+
+ if (unlikely(ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA))
+ xgene_ahci_restart_engine(ap);
+
+ rc = ahci_qc_issue(qc);
+
+ /* Save the last command issued */
+ ctx->last_cmd[ap->port_no] = qc->tf.command;
+
+ return rc;
+}
+
+/**
+ * xgene_ahci_read_id - Read ID data from the specified device
+ * @dev: device
+ * @tf: proposed taskfile
+ * @id: data buffer
+ *
+ * This custom read ID function is required due to the fact that the HW
+ * does not support DEVSLP.
+ */
+static unsigned int xgene_ahci_read_id(struct ata_device *dev,
+ struct ata_taskfile *tf, u16 *id)
+{
+ u32 err_mask;
+
+ err_mask = ata_do_dev_read_id(dev, tf, id);
+ if (err_mask)
+ return err_mask;
+
+ /*
+ * Mask reserved area. Word78 spec of Link Power Management
+ * bit15-8: reserved
+ * bit7: NCQ autosence
+ * bit6: Software settings preservation supported
+ * bit5: reserved
+ * bit4: In-order sata delivery supported
+ * bit3: DIPM requests supported
+ * bit2: DMA Setup FIS Auto-Activate optimization supported
+ * bit1: DMA Setup FIX non-Zero buffer offsets supported
+ * bit0: Reserved
+ *
+ * Clear reserved bit 8 (DEVSLP bit) as we don't support DEVSLP
+ */
+ id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8);
+
+ return 0;
+}
+
+static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel)
+{
+ void __iomem *mmio = ctx->hpriv->mmio;
+ u32 val;
+
+ dev_dbg(ctx->dev, "port configure mmio 0x%p channel %d\n",
+ mmio, channel);
+ val = readl(mmio + PORTCFG);
+ val = PORTADDR_SET(val, channel == 0 ? 2 : 3);
+ writel(val, mmio + PORTCFG);
+ readl(mmio + PORTCFG); /* Force a barrier */
+ /* Disable fix rate */
+ writel(0x0001fffe, mmio + PORTPHY1CFG);
+ readl(mmio + PORTPHY1CFG); /* Force a barrier */
+ writel(0x5018461c, mmio + PORTPHY2CFG);
+ readl(mmio + PORTPHY2CFG); /* Force a barrier */
+ writel(0x1c081907, mmio + PORTPHY3CFG);
+ readl(mmio + PORTPHY3CFG); /* Force a barrier */
+ writel(0x1c080815, mmio + PORTPHY4CFG);
+ readl(mmio + PORTPHY4CFG); /* Force a barrier */
+ /* Set window negotiation */
+ val = readl(mmio + PORTPHY5CFG);
+ val = PORTPHY5CFG_RTCHG_SET(val, 0x300);
+ writel(val, mmio + PORTPHY5CFG);
+ readl(mmio + PORTPHY5CFG); /* Force a barrier */
+ val = readl(mmio + PORTAXICFG);
+ val = PORTAXICFG_EN_CONTEXT_SET(val, 0x1); /* Enable context mgmt */
+ val = PORTAXICFG_OUTTRANS_SET(val, 0xe); /* Set outstanding */
+ writel(val, mmio + PORTAXICFG);
+ readl(mmio + PORTAXICFG); /* Force a barrier */
+}
+
+/**
+ * xgene_ahci_do_hardreset - Issue the actual COMRESET
+ * @link: link to reset
+ * @deadline: deadline jiffies for the operation
+ * @online: Return value to indicate if device online
+ *
+ * Due to the limitation of the hardware PHY, a difference set of setting is
+ * required for each supported disk speed - Gen3 (6.0Gbps), Gen2 (3.0Gbps),
+ * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will
+ * report disparity error and etc. In addition, during COMRESET, there can
+ * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and
+ * SERR_10B_8B_ERR, the PHY receiver line must be reseted. The following
+ * algorithm is followed to proper configure the hardware PHY during COMRESET:
+ *
+ * Alg Part 1:
+ * 1. Start the PHY at Gen3 speed (default setting)
+ * 2. Issue the COMRESET
+ * 3. If no link, go to Alg Part 3
+ * 4. If link up, determine if the negotiated speed matches the PHY
+ * configured speed
+ * 5. If they matched, go to Alg Part 2
+ * 6. If they do not matched and first time, configure the PHY for the linked
+ * up disk speed and repeat step 2
+ * 7. Go to Alg Part 2
+ *
+ * Alg Part 2:
+ * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error
+ * reported in the register PORT_SCR_ERR, then reset the PHY receiver line
+ * 2. Go to Alg Part 3
+ *
+ * Alg Part 3:
+ * 1. Clear any pending from register PORT_SCR_ERR.
+ *
+ * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition
+ * and until the underlying PHY supports an method to reset the receiver
+ * line, on detection of SERR_DISPARITY or SERR_10B_8B_ERR errors,
+ * an warning message will be printed.
+ */
+static int xgene_ahci_do_hardreset(struct ata_link *link,
+ unsigned long deadline, bool *online)
+{
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+ struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct xgene_ahci_context *ctx = hpriv->plat_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ata_taskfile tf;
+ int rc;
+ u32 val;
+
+ /* clear D2H reception area to properly wait for D2H FIS */
+ ata_tf_init(link->device, &tf);
+ tf.command = ATA_BUSY;
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+ rc = sata_link_hardreset(link, timing, deadline, online,
+ ahci_check_ready);
+
+ val = readl(port_mmio + PORT_SCR_ERR);
+ if (val & (SERR_DISPARITY | SERR_10B_8B_ERR))
+ dev_warn(ctx->dev, "link has error\n");
+
+ /* clear all errors if any pending */
+ val = readl(port_mmio + PORT_SCR_ERR);
+ writel(val, port_mmio + PORT_SCR_ERR);
+
+ return rc;
+}
+
+static int xgene_ahci_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ bool online;
+ int rc;
+ u32 portcmd_saved;
+ u32 portclb_saved;
+ u32 portclbhi_saved;
+ u32 portrxfis_saved;
+ u32 portrxfishi_saved;
+
+ /* As hardreset resets these CSR, save it to restore later */
+ portcmd_saved = readl(port_mmio + PORT_CMD);
+ portclb_saved = readl(port_mmio + PORT_LST_ADDR);
+ portclbhi_saved = readl(port_mmio + PORT_LST_ADDR_HI);
+ portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR);
+ portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI);
+
+ ahci_stop_engine(ap);
+
+ rc = xgene_ahci_do_hardreset(link, deadline, &online);
+
+ /* As controller hardreset clears them, restore them */
+ writel(portcmd_saved, port_mmio + PORT_CMD);
+ writel(portclb_saved, port_mmio + PORT_LST_ADDR);
+ writel(portclbhi_saved, port_mmio + PORT_LST_ADDR_HI);
+ writel(portrxfis_saved, port_mmio + PORT_FIS_ADDR);
+ writel(portrxfishi_saved, port_mmio + PORT_FIS_ADDR_HI);
+
+ hpriv->start_engine(ap);
+
+ if (online)
+ *class = ahci_dev_classify(ap);
+
+ return rc;
+}
+
+static void xgene_ahci_host_stop(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+
+ ahci_platform_disable_resources(hpriv);
+}
+
+static struct ata_port_operations xgene_ahci_ops = {
+ .inherits = &ahci_ops,
+ .host_stop = xgene_ahci_host_stop,
+ .hardreset = xgene_ahci_hardreset,
+ .read_id = xgene_ahci_read_id,
+ .qc_issue = xgene_ahci_qc_issue,
+};
+
+static const struct ata_port_info xgene_ahci_port_info = {
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &xgene_ahci_ops,
+};
+
+static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv)
+{
+ struct xgene_ahci_context *ctx = hpriv->plat_data;
+ int i;
+ int rc;
+ u32 val;
+
+ /* Remove IP RAM out of shutdown */
+ rc = xgene_ahci_init_memram(ctx);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < MAX_AHCI_CHN_PERCTR; i++)
+ xgene_ahci_set_phy_cfg(ctx, i);
+
+ /* AXI disable Mask */
+ writel(0xffffffff, hpriv->mmio + HOST_IRQ_STAT);
+ readl(hpriv->mmio + HOST_IRQ_STAT); /* Force a barrier */
+ writel(0, ctx->csr_core + INTSTATUSMASK);
+ val = readl(ctx->csr_core + INTSTATUSMASK); /* Force a barrier */
+ dev_dbg(ctx->dev, "top level interrupt mask 0x%X value 0x%08X\n",
+ INTSTATUSMASK, val);
+
+ writel(0x0, ctx->csr_core + ERRINTSTATUSMASK);
+ readl(ctx->csr_core + ERRINTSTATUSMASK); /* Force a barrier */
+ writel(0x0, ctx->csr_axi + INT_SLV_TMOMASK);
+ readl(ctx->csr_axi + INT_SLV_TMOMASK);
+
+ /* Enable AXI Interrupt */
+ writel(0xffffffff, ctx->csr_core + SLVRDERRATTRIBUTES);
+ writel(0xffffffff, ctx->csr_core + SLVWRERRATTRIBUTES);
+ writel(0xffffffff, ctx->csr_core + MSTRDERRATTRIBUTES);
+ writel(0xffffffff, ctx->csr_core + MSTWRERRATTRIBUTES);
+
+ /* Enable coherency */
+ val = readl(ctx->csr_core + BUSCTLREG);
+ val &= ~0x00000002; /* Enable write coherency */
+ val &= ~0x00000001; /* Enable read coherency */
+ writel(val, ctx->csr_core + BUSCTLREG);
+
+ val = readl(ctx->csr_core + IOFMSTRWAUX);
+ val |= (1 << 3); /* Enable read coherency */
+ val |= (1 << 9); /* Enable write coherency */
+ writel(val, ctx->csr_core + IOFMSTRWAUX);
+ val = readl(ctx->csr_core + IOFMSTRWAUX);
+ dev_dbg(ctx->dev, "coherency 0x%X value 0x%08X\n",
+ IOFMSTRWAUX, val);
+
+ return rc;
+}
+
+static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx)
+{
+ u32 val;
+
+ /* Check for optional MUX resource */
+ if (IS_ERR(ctx->csr_mux))
+ return 0;
+
+ val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG);
+ val &= ~CFG_SATA_ENET_SELECT_MASK;
+ writel(val, ctx->csr_mux + SATA_ENET_CONFIG_REG);
+ val = readl(ctx->csr_mux + SATA_ENET_CONFIG_REG);
+ return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0;
+}
+
+static int xgene_ahci_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct xgene_ahci_context *ctx;
+ struct resource *res;
+ unsigned long hflags;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ hpriv->plat_data = ctx;
+ ctx->hpriv = hpriv;
+ ctx->dev = dev;
+
+ /* Retrieve the IP core resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ ctx->csr_core = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ctx->csr_core))
+ return PTR_ERR(ctx->csr_core);
+
+ /* Retrieve the IP diagnostic resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ ctx->csr_diag = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ctx->csr_diag))
+ return PTR_ERR(ctx->csr_diag);
+
+ /* Retrieve the IP AXI resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ ctx->csr_axi = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ctx->csr_axi))
+ return PTR_ERR(ctx->csr_axi);
+
+ /* Retrieve the optional IP mux resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+ ctx->csr_mux = devm_ioremap_resource(dev, res);
+
+ dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core,
+ hpriv->mmio);
+
+ /* Select ATA */
+ if ((rc = xgene_ahci_mux_select(ctx))) {
+ dev_err(dev, "SATA mux selection failed error %d\n", rc);
+ return -ENODEV;
+ }
+
+ /* Due to errata, HW requires full toggle transition */
+ rc = ahci_platform_enable_clks(hpriv);
+ if (rc)
+ goto disable_resources;
+ ahci_platform_disable_clks(hpriv);
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ goto disable_resources;
+
+ /* Configure the host controller */
+ xgene_ahci_hw_init(hpriv);
+
+ /*
+ * Setup DMA mask. This is preliminary until the DMA range is sorted
+ * out.
+ */
+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+ if (rc) {
+ dev_err(dev, "Unable to set dma mask\n");
+ goto disable_resources;
+ }
+
+ hflags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ;
+
+ rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info,
+ hflags, 0, 0);
+ if (rc)
+ goto disable_resources;
+
+ dev_dbg(dev, "X-Gene SATA host controller initialized\n");
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+
+static const struct of_device_id xgene_ahci_of_match[] = {
+ {.compatible = "apm,xgene-ahci"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, xgene_ahci_of_match);
+
+static struct platform_driver xgene_ahci_driver = {
+ .probe = xgene_ahci_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "xgene-ahci",
+ .owner = THIS_MODULE,
+ .of_match_table = xgene_ahci_of_match,
+ },
+};
+
+module_platform_driver(xgene_ahci_driver);
+
+MODULE_DESCRIPTION("APM X-Gene AHCI SATA driver");
+MODULE_AUTHOR("Loc Ho <lho@apm.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.4");
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 47aeccd52fa..9ff545ce8da 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -1,6 +1,6 @@
/*
* ata_generic.c - Generic PATA/SATA controller driver.
- * Copyright 2005 Red Hat Inc <alan@redhat.com>, all rights reserved.
+ * Copyright 2005 Red Hat Inc, all rights reserved.
*
* Elements from ide/pci/generic.c
* Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
@@ -32,6 +31,12 @@
* A generic parallel ATA driver using libata
*/
+enum {
+ ATA_GEN_CLASS_MATCH = (1 << 0),
+ ATA_GEN_FORCE_DMA = (1 << 1),
+ ATA_GEN_INTEL_IDER = (1 << 2),
+};
+
/**
* generic_set_mode - mode setting
* @link: link to set up
@@ -46,21 +51,18 @@
static int generic_set_mode(struct ata_link *link, struct ata_device **unused)
{
struct ata_port *ap = link->ap;
+ const struct pci_device_id *id = ap->host->private_data;
int dma_enabled = 0;
struct ata_device *dev;
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- /* Bits 5 and 6 indicate if DMA is active on master/slave */
- if (ap->ioaddr.bmdma_addr)
+ if (id->driver_data & ATA_GEN_FORCE_DMA) {
+ dma_enabled = 0xff;
+ } else if (ap->ioaddr.bmdma_addr) {
+ /* Bits 5 and 6 indicate if DMA is active on master/slave */
dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ }
- if (pdev->vendor == PCI_VENDOR_ID_CENATEK)
- dma_enabled = 0xFF;
-
- ata_link_for_each_dev(dev, link) {
- if (!ata_dev_enabled(dev))
- continue;
-
+ ata_for_each_dev(dev, link, ENABLED) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
dev->dma_mode = XFER_MW_DMA_0;
@@ -78,14 +80,13 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused)
xfer_mask |= ata_xfer_mode2mask(XFER_MW_DMA_0);
}
- ata_dev_printk(dev, KERN_INFO, "configured for %s\n",
- name);
+ ata_dev_info(dev, "configured for %s\n", name);
dev->xfer_mode = ata_xfer_mask2mode(xfer_mask);
dev->xfer_shift = ata_xfer_mode2shift(dev->xfer_mode);
dev->flags &= ~ATA_DFLAG_PIO;
} else {
- ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
+ ata_dev_info(dev, "configured for PIO\n");
dev->xfer_mode = XFER_PIO_0;
dev->xfer_shift = ATA_SHIFT_PIO;
dev->flags |= ATA_DFLAG_PIO;
@@ -107,6 +108,49 @@ static struct ata_port_operations generic_port_ops = {
static int all_generic_ide; /* Set to claim all devices */
/**
+ * is_intel_ider - identify intel IDE-R devices
+ * @dev: PCI device
+ *
+ * Distinguish Intel IDE-R controller devices from other Intel IDE
+ * devices. IDE-R devices have no timing registers and are in
+ * most respects virtual. They should be driven by the ata_generic
+ * driver.
+ *
+ * IDE-R devices have PCI offset 0xF8.L as zero, later Intel ATA has
+ * it non zero. All Intel ATA has 0x40 writable (timing), but it is
+ * not writable on IDE-R devices (this is guaranteed).
+ */
+
+static int is_intel_ider(struct pci_dev *dev)
+{
+ /* For Intel IDE the value at 0xF8 is only zero on IDE-R
+ interfaces */
+ u32 r;
+ u16 t;
+
+ /* Check the manufacturing ID, it will be zero for IDE-R */
+ pci_read_config_dword(dev, 0xF8, &r);
+ /* Not IDE-R: punt so that ata_(old)piix gets it */
+ if (r != 0)
+ return 0;
+ /* 0xF8 will also be zero on some early Intel IDE devices
+ but they will have a sane timing register */
+ pci_read_config_word(dev, 0x40, &t);
+ if (t != 0)
+ return 0;
+ /* Finally check if the timing register is writable so that
+ we eliminate any early devices hot-docked in a docking
+ station */
+ pci_write_config_word(dev, 0x40, 1);
+ pci_read_config_word(dev, 0x40, &t);
+ if (t) {
+ pci_write_config_word(dev, 0x40, 0);
+ return 0;
+ }
+ return 1;
+}
+
+/**
* ata_generic_init - attach generic IDE
* @dev: PCI device found
* @id: match entry
@@ -121,17 +165,21 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
u16 command;
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &generic_port_ops
};
const struct ata_port_info *ppi[] = { &info, NULL };
/* Don't use the generic entry unless instructed to do so */
- if (id->driver_data == 1 && all_generic_ide == 0)
+ if ((id->driver_data & ATA_GEN_CLASS_MATCH) && all_generic_ide == 0)
return -ENODEV;
+ if ((id->driver_data & ATA_GEN_INTEL_IDER) && !all_generic_ide)
+ if (!is_intel_ider(dev))
+ return -ENODEV;
+
/* Devices that need care */
if (dev->vendor == PCI_VENDOR_ID_UMC &&
dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
@@ -152,7 +200,13 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
if (dev->vendor == PCI_VENDOR_ID_AL)
ata_pci_bmdma_clear_simplex(dev);
- return ata_pci_sff_init_one(dev, ppi, &generic_sht, NULL);
+ if (dev->vendor == PCI_VENDOR_ID_ATI) {
+ int rc = pcim_enable_device(dev);
+ if (rc < 0)
+ return rc;
+ pcim_pin_device(dev);
+ }
+ return ata_pci_bmdma_init_one(dev, ppi, &generic_sht, (void *)id, 0);
}
static struct pci_device_id ata_generic[] = {
@@ -164,12 +218,21 @@ static struct pci_device_id ata_generic[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE), },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561), },
{ PCI_DEVICE(PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558), },
- { PCI_DEVICE(PCI_VENDOR_ID_CENATEK,PCI_DEVICE_ID_CENATEK_IDE), },
- { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO), },
+ { PCI_DEVICE(PCI_VENDOR_ID_CENATEK,PCI_DEVICE_ID_CENATEK_IDE),
+ .driver_data = ATA_GEN_FORCE_DMA },
+#if !defined(CONFIG_PATA_TOSHIBA) && !defined(CONFIG_PATA_TOSHIBA_MODULE)
{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), },
{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_3), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_5), },
+#endif
+ /* Intel, IDE class device */
+ { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL,
+ .driver_data = ATA_GEN_INTEL_IDER },
/* Must come last. If you add entries adjust this table appropriately */
- { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1},
+ { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL),
+ .driver_data = ATA_GEN_CLASS_MATCH },
{ 0, },
};
@@ -178,23 +241,13 @@ static struct pci_driver ata_generic_pci_driver = {
.id_table = ata_generic,
.probe = ata_generic_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init ata_generic_init(void)
-{
- return pci_register_driver(&ata_generic_pci_driver);
-}
-
-
-static void __exit ata_generic_exit(void)
-{
- pci_unregister_driver(&ata_generic_pci_driver);
-}
-
+module_pci_driver(ata_generic_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for generic ATA");
@@ -202,7 +255,4 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, ata_generic);
MODULE_VERSION(DRV_VERSION);
-module_init(ata_generic_init);
-module_exit(ata_generic_exit);
-
module_param(all_generic_ide, int, 0);
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index b7c38eeb498..893e30e9a9e 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -1,7 +1,7 @@
/*
* ata_piix.c - Intel PATA/SATA controllers
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -14,7 +14,7 @@
*
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
* Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
+ * Copyright (C) 2003 Red Hat Inc
*
*
* This program is free software; you can redistribute it and/or modify
@@ -38,16 +38,16 @@
* Hardware documentation available at http://developer.intel.com/
*
* Documentation
- * Publically available from Intel web site. Errata documentation
- * is also publically available. As an aide to anyone hacking on this
+ * Publicly available from Intel web site. Errata documentation
+ * is also publicly available. As an aide to anyone hacking on this
* driver the list of errata that are relevant is below, going back to
* PIIX4. Older device documentation is now a bit tricky to find.
*
- * The chipsets all follow very much the same design. The orginal Triton
- * series chipsets do _not_ support independant device timings, but this
+ * The chipsets all follow very much the same design. The original Triton
+ * series chipsets do _not_ support independent device timings, but this
* is fixed in Triton II. With the odd mobile exception the chips then
* change little except in gaining more modes until SATA arrives. This
- * driver supports only the chips with independant timing (that is those
+ * driver supports only the chips with independent timing (that is those
* with SITRE and the 0x44 timing register). See pata_oldpiix and pata_mpiix
* for the early chip drivers.
*
@@ -72,6 +72,7 @@
* ICH2 spec c #20 - IDE PRD must not cross a 64K boundary
* and must be dword aligned
* ICH2 spec c #24 - UDMA mode 4,5 t85/86 should be 6ns not 3.3
+ * ICH7 errata #16 - MWDMA1 timings are incorrect
*
* Should have been BIOS fixed:
* 450NX: errata #19 - DMA hangs on old 450NX
@@ -89,16 +90,17 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/gfp.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <linux/dmi.h>
#define DRV_NAME "ata_piix"
-#define DRV_VERSION "2.12"
+#define DRV_VERSION "2.13"
enum {
PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
- ICH5_PMR = 0x90, /* port mapping register */
+ ICH5_PMR = 0x90, /* address map register */
ICH5_PCS = 0x92, /* port control and status */
PIIX_SIDPR_BAR = 5,
PIIX_SIDPR_LEN = 16,
@@ -111,6 +113,8 @@ enum {
PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS,
PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR,
+ PIIX_FLAG_PIO16 = (1 << 30), /*support 16bit PIO only*/
+
PIIX_80C_PRI = (1 << 5) | (1 << 4),
PIIX_80C_SEC = (1 << 7) | (1 << 6),
@@ -120,7 +124,7 @@ enum {
P2 = 2, /* port 2 */
P3 = 3, /* port 3 */
IDE = -1, /* IDE */
- NA = -2, /* not avaliable */
+ NA = -2, /* not available */
RV = -3, /* reserved */
PIIX_AHCI_DEVICE = 6,
@@ -136,6 +140,7 @@ enum piix_controller_ids {
ich_pata_33, /* ICH up to UDMA 33 only */
ich_pata_66, /* ICH up to 66 Mhz */
ich_pata_100, /* ICH up to UDMA 100 */
+ ich_pata_100_nomwdma1, /* ICH up to UDMA 100 but with no MWDMA1*/
ich5_sata,
ich6_sata,
ich6m_sata,
@@ -144,6 +149,9 @@ enum piix_controller_ids {
ich8m_apple_sata, /* locks up on second port enable */
tolapai_sata,
piix_pata_vmw, /* PIIX4 for VMware, spurious DMA_ERR */
+ ich8_sata_snb,
+ ich8_2port_sata_snb,
+ ich8_2port_sata_byt,
};
struct piix_map_db {
@@ -154,24 +162,10 @@ struct piix_map_db {
struct piix_host_priv {
const int *map;
+ u32 saved_iocfg;
void __iomem *sidpr;
};
-static int piix_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent);
-static int piix_pata_prereset(struct ata_link *link, unsigned long deadline);
-static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev);
-static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev);
-static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev);
-static int ich_pata_cable_detect(struct ata_port *ap);
-static u8 piix_vmw_bmdma_status(struct ata_port *ap);
-static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val);
-static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val);
-#ifdef CONFIG_PM
-static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
-static int piix_pci_device_resume(struct pci_dev *pdev);
-#endif
-
static unsigned int in_module_init = 1;
static const struct pci_device_id piix_pci_tbl[] = {
@@ -200,6 +194,8 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* Intel ICH3 (E7500/1) UDMA 100 */
{ 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* Intel ICH4-L */
+ { 0x8086, 0x24C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */
{ 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
{ 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
@@ -212,14 +208,12 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* ICH6 (and 6) (i915) UDMA 100 */
{ 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* ICH7/7-R (i945, i975) UDMA 100*/
- { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
- { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100_nomwdma1 },
+ { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100_nomwdma1 },
/* ICH8 Mobile PATA Controller */
{ 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
- /* NOTE: The following PCI ids must be kept in sync with the
- * list in drivers/pci/quirks.c.
- */
+ /* SATA ports */
/* 82801EB (ICH5) */
{ 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
@@ -239,7 +233,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
PCI_CLASS_STORAGE_IDE << 8, 0xffff00, ich6m_sata },
/* 82801GB/GR/GH (ICH7, identical to ICH6) */
{ 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
- /* 2801GBM/GHM (ICH7M, identical to ICH6M) */
+ /* 82801GBM/GHM (ICH7M, identical to ICH6M) */
{ 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata },
/* Enterprise Southbridge 2 (631xESB/632xESB) */
{ 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
@@ -247,10 +241,12 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller 2 IDE (ICH8) */
{ 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
- /* Mobile SATA Controller IDE (ICH8M) */
- { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* Mobile SATA Controller IDE (ICH8M), Apple */
{ 0x8086, 0x2828, 0x106b, 0x00a0, 0, 0, ich8m_apple_sata },
+ { 0x8086, 0x2828, 0x106b, 0x00a1, 0, 0, ich8m_apple_sata },
+ { 0x8086, 0x2828, 0x106b, 0x00a3, 0, 0, ich8m_apple_sata },
+ /* Mobile SATA Controller IDE (ICH8M) */
+ { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller IDE (ICH9) */
{ 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller IDE (ICH9) */
@@ -273,55 +269,81 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x3a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller IDE (ICH10) */
{ 0x8086, 0x3a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (PCH) */
+ { 0x8086, 0x3b20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+ /* SATA Controller IDE (PCH) */
+ { 0x8086, 0x3b21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (PCH) */
+ { 0x8086, 0x3b26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (PCH) */
+ { 0x8086, 0x3b28, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+ /* SATA Controller IDE (PCH) */
+ { 0x8086, 0x3b2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (PCH) */
+ { 0x8086, 0x3b2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+ /* SATA Controller IDE (CPT) */
+ { 0x8086, 0x1c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (CPT) */
+ { 0x8086, 0x1c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (CPT) */
+ { 0x8086, 0x1c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (CPT) */
+ { 0x8086, 0x1c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (PBG) */
+ { 0x8086, 0x1d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (PBG) */
+ { 0x8086, 0x1d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (Panther Point) */
+ { 0x8086, 0x1e00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Panther Point) */
+ { 0x8086, 0x1e01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Panther Point) */
+ { 0x8086, 0x1e08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (Panther Point) */
+ { 0x8086, 0x1e09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (Lynx Point) */
+ { 0x8086, 0x8c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Lynx Point) */
+ { 0x8086, 0x8c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Lynx Point) */
+ { 0x8086, 0x8c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
+ /* SATA Controller IDE (Lynx Point) */
+ { 0x8086, 0x8c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (Lynx Point-LP) */
+ { 0x8086, 0x9c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Lynx Point-LP) */
+ { 0x8086, 0x9c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Lynx Point-LP) */
+ { 0x8086, 0x9c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (Lynx Point-LP) */
+ { 0x8086, 0x9c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (DH89xxCC) */
+ { 0x8086, 0x2326, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (Avoton) */
+ { 0x8086, 0x1f20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Avoton) */
+ { 0x8086, 0x1f21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Avoton) */
+ { 0x8086, 0x1f30, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (Avoton) */
+ { 0x8086, 0x1f31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (Wellsburg) */
+ { 0x8086, 0x8d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Wellsburg) */
+ { 0x8086, 0x8d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
+ /* SATA Controller IDE (Wellsburg) */
+ { 0x8086, 0x8d60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+ /* SATA Controller IDE (Wellsburg) */
+ { 0x8086, 0x8d68, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (BayTrail) */
+ { 0x8086, 0x0F20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt },
+ { 0x8086, 0x0F21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt },
+ /* SATA Controller IDE (Coleto Creek) */
+ { 0x8086, 0x23a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
{ } /* terminate list */
};
-static struct pci_driver piix_pci_driver = {
- .name = DRV_NAME,
- .id_table = piix_pci_tbl,
- .probe = piix_init_one,
- .remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
- .suspend = piix_pci_device_suspend,
- .resume = piix_pci_device_resume,
-#endif
-};
-
-static struct scsi_host_template piix_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
-};
-
-static struct ata_port_operations piix_pata_ops = {
- .inherits = &ata_bmdma_port_ops,
- .cable_detect = ata_cable_40wire,
- .set_piomode = piix_set_piomode,
- .set_dmamode = piix_set_dmamode,
- .prereset = piix_pata_prereset,
-};
-
-static struct ata_port_operations piix_vmw_ops = {
- .inherits = &piix_pata_ops,
- .bmdma_status = piix_vmw_bmdma_status,
-};
-
-static struct ata_port_operations ich_pata_ops = {
- .inherits = &piix_pata_ops,
- .cable_detect = ich_pata_cable_detect,
- .set_dmamode = ich_set_dmamode,
-};
-
-static struct ata_port_operations piix_sata_ops = {
- .inherits = &ata_bmdma_port_ops,
-};
-
-static struct ata_port_operations piix_sidpr_sata_ops = {
- .inherits = &piix_sata_ops,
- .hardreset = sata_std_hardreset,
- .scr_read = piix_sidpr_scr_read,
- .scr_write = piix_sidpr_scr_write,
-};
-
static const struct piix_map_db ich5_map_db = {
.mask = 0x7,
.port_enable = 0x3,
@@ -423,125 +445,9 @@ static const struct piix_map_db *piix_map_db_table[] = {
[ich8_2port_sata] = &ich8_2port_map_db,
[ich8m_apple_sata] = &ich8m_apple_map_db,
[tolapai_sata] = &tolapai_map_db,
-};
-
-static struct ata_port_info piix_port_info[] = {
- [piix_pata_mwdma] = /* PIIX3 MWDMA only */
- {
- .flags = PIIX_PATA_FLAGS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
- .port_ops = &piix_pata_ops,
- },
-
- [piix_pata_33] = /* PIIX4 at 33MHz */
- {
- .flags = PIIX_PATA_FLAGS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
- .udma_mask = ATA_UDMA_MASK_40C,
- .port_ops = &piix_pata_ops,
- },
-
- [ich_pata_33] = /* ICH0 - ICH at 33Mhz*/
- {
- .flags = PIIX_PATA_FLAGS,
- .pio_mask = 0x1f, /* pio 0-4 */
- .mwdma_mask = 0x06, /* Check: maybe 0x07 */
- .udma_mask = ATA_UDMA2, /* UDMA33 */
- .port_ops = &ich_pata_ops,
- },
-
- [ich_pata_66] = /* ICH controllers up to 66MHz */
- {
- .flags = PIIX_PATA_FLAGS,
- .pio_mask = 0x1f, /* pio 0-4 */
- .mwdma_mask = 0x06, /* MWDMA0 is broken on chip */
- .udma_mask = ATA_UDMA4,
- .port_ops = &ich_pata_ops,
- },
-
- [ich_pata_100] =
- {
- .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x06, /* mwdma1-2 */
- .udma_mask = ATA_UDMA5, /* udma0-5 */
- .port_ops = &ich_pata_ops,
- },
-
- [ich5_sata] =
- {
- .flags = PIIX_SATA_FLAGS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = ATA_UDMA6,
- .port_ops = &piix_sata_ops,
- },
-
- [ich6_sata] =
- {
- .flags = PIIX_SATA_FLAGS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = ATA_UDMA6,
- .port_ops = &piix_sata_ops,
- },
-
- [ich6m_sata] =
- {
- .flags = PIIX_SATA_FLAGS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = ATA_UDMA6,
- .port_ops = &piix_sata_ops,
- },
-
- [ich8_sata] =
- {
- .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = ATA_UDMA6,
- .port_ops = &piix_sata_ops,
- },
-
- [ich8_2port_sata] =
- {
- .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = ATA_UDMA6,
- .port_ops = &piix_sata_ops,
- },
-
- [tolapai_sata] =
- {
- .flags = PIIX_SATA_FLAGS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = ATA_UDMA6,
- .port_ops = &piix_sata_ops,
- },
-
- [ich8m_apple_sata] =
- {
- .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = ATA_UDMA6,
- .port_ops = &piix_sata_ops,
- },
-
- [piix_pata_vmw] =
- {
- .flags = PIIX_PATA_FLAGS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
- .udma_mask = ATA_UDMA_MASK_40C,
- .port_ops = &piix_vmw_ops,
- },
-
+ [ich8_sata_snb] = &ich8_map_db,
+ [ich8_2port_sata_snb] = &ich8_2port_map_db,
+ [ich8_2port_sata_byt] = &ich8_2port_map_db,
};
static struct pci_bits piix_enable_bits[] = {
@@ -570,13 +476,29 @@ static const struct ich_laptop ich_laptop[] = {
{ 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */
{ 0x27DF, 0x1025, 0x0102 }, /* ICH7 on Acer 5602aWLMi */
{ 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
+ { 0x27DF, 0x1028, 0x02b0 }, /* ICH7 on unknown Dell */
{ 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
{ 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
+ { 0x27DF, 0x103C, 0x361a }, /* ICH7 on unknown HP */
+ { 0x27DF, 0x1071, 0xD221 }, /* ICH7 on Hercules EC-900 */
+ { 0x27DF, 0x152D, 0x0778 }, /* ICH7 on unknown Intel */
{ 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */
+ { 0x24CA, 0x1025, 0x003d }, /* ICH4 on ACER TM290 */
+ { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */
+ { 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */
+ { 0x27df, 0x104d, 0x900e }, /* ICH7 on Sony TZ-90 */
/* end marker */
{ 0, }
};
+static int piix_port_start(struct ata_port *ap)
+{
+ if (!(ap->flags & PIIX_FLAG_PIO16))
+ ap->pflags |= ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE;
+
+ return ata_bmdma_port_start(ap);
+}
+
/**
* ich_pata_cable_detect - Probe host controller cable detect info
* @ap: Port for which cable detect info is desired
@@ -591,10 +513,11 @@ static const struct ich_laptop ich_laptop[] = {
static int ich_pata_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct piix_host_priv *hpriv = ap->host->private_data;
const struct ich_laptop *lap = &ich_laptop[0];
- u8 tmp, mask;
+ u8 mask;
- /* Check for specials - Acer Aspire 5602WLMi */
+ /* Check for specials */
while (lap->device) {
if (lap->device == pdev->device &&
lap->subvendor == pdev->subsystem_vendor &&
@@ -606,8 +529,7 @@ static int ich_pata_cable_detect(struct ata_port *ap)
/* check BIOS cable detect results */
mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
- pci_read_config_byte(pdev, PIIX_IOCFG, &tmp);
- if ((tmp & mask) == 0)
+ if ((hpriv->saved_iocfg & mask) == 0)
return ATA_CBL_PATA40;
return ATA_CBL_PATA80;
}
@@ -630,21 +552,13 @@ static int piix_pata_prereset(struct ata_link *link, unsigned long deadline)
return ata_sff_prereset(link, deadline);
}
-/**
- * piix_set_piomode - Initialize host controller PATA PIO timings
- * @ap: Port whose timings we are configuring
- * @adev: um
- *
- * Set PIO mode for device, in host controller PCI config space.
- *
- * LOCKING:
- * None (inherited from caller).
- */
+static DEFINE_SPINLOCK(piix_lock);
-static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void piix_set_timings(struct ata_port *ap, struct ata_device *adev,
+ u8 pio)
{
- unsigned int pio = adev->pio_mode - XFER_PIO_0;
struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned long flags;
unsigned int is_slave = (adev->devno != 0);
unsigned int master_port= ap->port_no ? 0x42 : 0x40;
unsigned int slave_port = 0x44;
@@ -669,10 +583,18 @@ static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev)
control |= 1; /* TIME1 enable */
if (ata_pio_need_iordy(adev))
control |= 2; /* IE enable */
-
/* Intel specifies that the PPE functionality is for disk only */
if (adev->class == ATA_DEV_ATA)
control |= 4; /* PPE enable */
+ /*
+ * If the drive MWDMA is faster than it can do PIO then
+ * we must force PIO into PIO0
+ */
+ if (adev->pio_mode < XFER_PIO_0 + pio)
+ /* Enable DMA timing only */
+ control |= 8; /* PIO cycles in PIO0 */
+
+ spin_lock_irqsave(&piix_lock, flags);
/* PIO configuration clears DTE unconditionally. It will be
* programmed in set_dmamode which is guaranteed to be called
@@ -682,8 +604,6 @@ static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev)
if (is_slave) {
/* clear TIME1|IE1|PPE1|DTE1 */
master_data &= 0xff0f;
- /* Enable SITRE (separate slave timing register) */
- master_data |= 0x4000;
/* enable PPE1, IE1 and TIME1 as needed */
master_data |= (control << 4);
pci_read_config_byte(dev, slave_port, &slave_data);
@@ -701,6 +621,9 @@ static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev)
(timings[pio][0] << 12) |
(timings[pio][1] << 8);
}
+
+ /* Enable SITRE (separate slave timing register) */
+ master_data |= 0x4000;
pci_write_config_word(dev, master_port, master_data);
if (is_slave)
pci_write_config_byte(dev, slave_port, slave_data);
@@ -713,13 +636,30 @@ static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev)
udma_enable &= ~(1 << (2 * ap->port_no + adev->devno));
pci_write_config_byte(dev, 0x48, udma_enable);
}
+
+ spin_unlock_irqrestore(&piix_lock, flags);
+}
+
+/**
+ * piix_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Drive in question
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ piix_set_timings(ap, adev, adev->pio_mode - XFER_PIO_0);
}
/**
* do_pata_set_dmamode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
* @adev: Drive in question
- * @udma: udma mode, 0 - 6
* @isich: set if the chip is an ICH device
*
* Set UDMA mode for device, in host controller PCI config space.
@@ -731,29 +671,21 @@ static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void do_pata_set_dmamode(struct ata_port *ap, struct ata_device *adev, int isich)
{
struct pci_dev *dev = to_pci_dev(ap->host->dev);
- u8 master_port = ap->port_no ? 0x42 : 0x40;
- u16 master_data;
+ unsigned long flags;
u8 speed = adev->dma_mode;
int devid = adev->devno + 2 * ap->port_no;
u8 udma_enable = 0;
- static const /* ISP RTC */
- u8 timings[][2] = { { 0, 0 },
- { 0, 0 },
- { 1, 0 },
- { 2, 1 },
- { 2, 3 }, };
-
- pci_read_config_word(dev, master_port, &master_data);
- if (ap->udma_mask)
- pci_read_config_byte(dev, 0x48, &udma_enable);
-
if (speed >= XFER_UDMA_0) {
- unsigned int udma = adev->dma_mode - XFER_UDMA_0;
+ unsigned int udma = speed - XFER_UDMA_0;
u16 udma_timing;
u16 ideconf;
int u_clock, u_speed;
+ spin_lock_irqsave(&piix_lock, flags);
+
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+
/*
* UDMA is handled by a combination of clock switching and
* selection of dividers
@@ -786,54 +718,21 @@ static void do_pata_set_dmamode(struct ata_port *ap, struct ata_device *adev, in
performance (WR_PingPong_En) */
pci_write_config_word(dev, 0x54, ideconf);
}
+
+ pci_write_config_byte(dev, 0x48, udma_enable);
+
+ spin_unlock_irqrestore(&piix_lock, flags);
} else {
- /*
- * MWDMA is driven by the PIO timings. We must also enable
- * IORDY unconditionally along with TIME1. PPE has already
- * been set when the PIO timing was set.
- */
- unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
- unsigned int control;
- u8 slave_data;
+ /* MWDMA is driven by the PIO timings. */
+ unsigned int mwdma = speed - XFER_MW_DMA_0;
const unsigned int needed_pio[3] = {
XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
};
int pio = needed_pio[mwdma] - XFER_PIO_0;
- control = 3; /* IORDY|TIME1 */
-
- /* If the drive MWDMA is faster than it can do PIO then
- we must force PIO into PIO0 */
-
- if (adev->pio_mode < needed_pio[mwdma])
- /* Enable DMA timing only */
- control |= 8; /* PIO cycles in PIO0 */
-
- if (adev->devno) { /* Slave */
- master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */
- master_data |= control << 4;
- pci_read_config_byte(dev, 0x44, &slave_data);
- slave_data &= (ap->port_no ? 0x0f : 0xf0);
- /* Load the matching timing */
- slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
- pci_write_config_byte(dev, 0x44, slave_data);
- } else { /* Master */
- master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY
- and master timing bits */
- master_data |= control;
- master_data |=
- (timings[pio][0] << 12) |
- (timings[pio][1] << 8);
- }
-
- if (ap->udma_mask) {
- udma_enable &= ~(1 << devid);
- pci_write_config_word(dev, master_port, master_data);
- }
+ /* XFER_PIO_0 is never used currently */
+ piix_set_timings(ap, adev, pio);
}
- /* Don't scribble on 0x48 if the controller does not support UDMA */
- if (ap->udma_mask)
- pci_write_config_byte(dev, 0x48, udma_enable);
}
/**
@@ -872,23 +771,9 @@ static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev)
* Serial ATA Index/Data Pair Superset Registers access
*
* Beginning from ICH8, there's a sane way to access SCRs using index
- * and data register pair located at BAR5. This creates an
- * interesting problem of mapping two SCRs to one port.
- *
- * Although they have separate SCRs, the master and slave aren't
- * independent enough to be treated as separate links - e.g. softreset
- * resets both. Also, there's no protocol defined for hard resetting
- * singled device sharing the virtual port (no defined way to acquire
- * device signature). This is worked around by merging the SCR values
- * into one sensible value and requesting follow-up SRST after
- * hardreset.
- *
- * SCR merging is perfomed in nibbles which is the unit contents in
- * SCRs are organized. If two values are equal, the value is used.
- * When they differ, merge table which lists precedence of possible
- * values is consulted and the first match or the last entry when
- * nothing matches is used. When there's no merge table for the
- * specific nibble, value from the first port is used.
+ * and data register pair located at BAR5 which means that we have
+ * separate SCRs for master and slave. This is handled using libata
+ * slave_link facility.
*/
static const int piix_sidx_map[] = {
[SCR_STATUS] = 0,
@@ -896,124 +781,56 @@ static const int piix_sidx_map[] = {
[SCR_CONTROL] = 1,
};
-static void piix_sidpr_sel(struct ata_device *dev, unsigned int reg)
+static void piix_sidpr_sel(struct ata_link *link, unsigned int reg)
{
- struct ata_port *ap = dev->link->ap;
+ struct ata_port *ap = link->ap;
struct piix_host_priv *hpriv = ap->host->private_data;
- iowrite32(((ap->port_no * 2 + dev->devno) << 8) | piix_sidx_map[reg],
+ iowrite32(((ap->port_no * 2 + link->pmp) << 8) | piix_sidx_map[reg],
hpriv->sidpr + PIIX_SIDPR_IDX);
}
-static int piix_sidpr_read(struct ata_device *dev, unsigned int reg)
+static int piix_sidpr_scr_read(struct ata_link *link,
+ unsigned int reg, u32 *val)
{
- struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
+ struct piix_host_priv *hpriv = link->ap->host->private_data;
- piix_sidpr_sel(dev, reg);
- return ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
-}
-
-static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val)
-{
- struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
-
- piix_sidpr_sel(dev, reg);
- iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
-}
-
-static u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
-{
- u32 val = 0;
- int i, mi;
-
- for (i = 0, mi = 0; i < 32 / 4; i++) {
- u8 c0 = (val0 >> (i * 4)) & 0xf;
- u8 c1 = (val1 >> (i * 4)) & 0xf;
- u8 merged = c0;
- const int *cur;
-
- /* if no merge preference, assume the first value */
- cur = merge_tbl[mi];
- if (!cur)
- goto done;
- mi++;
-
- /* if two values equal, use it */
- if (c0 == c1)
- goto done;
-
- /* choose the first match or the last from the merge table */
- while (*cur != -1) {
- if (c0 == *cur || c1 == *cur)
- break;
- cur++;
- }
- if (*cur == -1)
- cur--;
- merged = *cur;
- done:
- val |= merged << (i * 4);
- }
+ if (reg >= ARRAY_SIZE(piix_sidx_map))
+ return -EINVAL;
- return val;
+ piix_sidpr_sel(link, reg);
+ *val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
+ return 0;
}
-static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val)
+static int piix_sidpr_scr_write(struct ata_link *link,
+ unsigned int reg, u32 val)
{
- const int * const sstatus_merge_tbl[] = {
- /* DET */ (const int []){ 1, 3, 0, 4, 3, -1 },
- /* SPD */ (const int []){ 2, 1, 0, -1 },
- /* IPM */ (const int []){ 6, 2, 1, 0, -1 },
- NULL,
- };
- const int * const scontrol_merge_tbl[] = {
- /* DET */ (const int []){ 1, 0, 4, 0, -1 },
- /* SPD */ (const int []){ 0, 2, 1, 0, -1 },
- /* IPM */ (const int []){ 0, 1, 2, 3, 0, -1 },
- NULL,
- };
- u32 v0, v1;
+ struct piix_host_priv *hpriv = link->ap->host->private_data;
if (reg >= ARRAY_SIZE(piix_sidx_map))
return -EINVAL;
- if (!(ap->flags & ATA_FLAG_SLAVE_POSS)) {
- *val = piix_sidpr_read(&ap->link.device[0], reg);
- return 0;
- }
-
- v0 = piix_sidpr_read(&ap->link.device[0], reg);
- v1 = piix_sidpr_read(&ap->link.device[1], reg);
-
- switch (reg) {
- case SCR_STATUS:
- *val = piix_merge_scr(v0, v1, sstatus_merge_tbl);
- break;
- case SCR_ERROR:
- *val = v0 | v1;
- break;
- case SCR_CONTROL:
- *val = piix_merge_scr(v0, v1, scontrol_merge_tbl);
- break;
- }
-
+ piix_sidpr_sel(link, reg);
+ iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
return 0;
}
-static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val)
+static int piix_sidpr_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+ unsigned hints)
{
- if (reg >= ARRAY_SIZE(piix_sidx_map))
- return -EINVAL;
-
- piix_sidpr_write(&ap->link.device[0], reg, val);
+ return sata_link_scr_lpm(link, policy, false);
+}
- if (ap->flags & ATA_FLAG_SLAVE_POSS)
- piix_sidpr_write(&ap->link.device[1], reg, val);
+static bool piix_irq_check(struct ata_port *ap)
+{
+ if (unlikely(!ap->ioaddr.bmdma_addr))
+ return false;
- return 0;
+ return ap->ops->bmdma_status(ap) & ATA_DMA_INTR;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int piix_broken_suspend(void)
{
static const struct dmi_system_id sysids[] = {
@@ -1039,6 +856,13 @@ static int piix_broken_suspend(void)
},
},
{
+ .ident = "TECRA M4",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M4"),
+ },
+ },
+ {
.ident = "TECRA M5",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
@@ -1116,12 +940,26 @@ static int piix_broken_suspend(void)
},
},
{
+ .ident = "Satellite Pro A120",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite Pro A120"),
+ },
+ },
+ {
.ident = "Portege M500",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M500"),
},
},
+ {
+ .ident = "VGN-BX297XP",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-BX297XP"),
+ },
+ },
{ } /* terminate list */
};
@@ -1137,12 +975,27 @@ static int piix_broken_suspend(void)
if (dmi_find_device(DMI_DEV_TYPE_OEM_STRING, oemstrs[i], NULL))
return 1;
+ /* TECRA M4 sometimes forgets its identify and reports bogus
+ * DMI information. As the bogus information is a bit
+ * generic, match as many entries as possible. This manual
+ * matching is necessary because dmi_system_id.matches is
+ * limited to four entries.
+ */
+ if (dmi_match(DMI_SYS_VENDOR, "TOSHIBA") &&
+ dmi_match(DMI_PRODUCT_NAME, "000000") &&
+ dmi_match(DMI_PRODUCT_VERSION, "000000") &&
+ dmi_match(DMI_PRODUCT_SERIAL, "000000") &&
+ dmi_match(DMI_BOARD_VENDOR, "TOSHIBA") &&
+ dmi_match(DMI_BOARD_NAME, "Portable PC") &&
+ dmi_match(DMI_BOARD_VERSION, "Version A0"))
+ return 1;
+
return 0;
}
static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
unsigned long flags;
int rc = 0;
@@ -1177,7 +1030,7 @@ static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
static int piix_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
unsigned long flags;
int rc;
@@ -1195,8 +1048,9 @@ static int piix_pci_device_resume(struct pci_dev *pdev)
*/
rc = pci_reenable_device(pdev);
if (rc)
- dev_printk(KERN_ERR, &pdev->dev, "failed to enable "
- "device after resume (%d)\n", rc);
+ dev_err(&pdev->dev,
+ "failed to enable device after resume (%d)\n",
+ rc);
} else
rc = ata_pci_device_do_resume(pdev);
@@ -1212,6 +1066,213 @@ static u8 piix_vmw_bmdma_status(struct ata_port *ap)
return ata_bmdma_status(ap) & ~ATA_DMA_ERR;
}
+static struct scsi_host_template piix_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations piix_sata_ops = {
+ .inherits = &ata_bmdma32_port_ops,
+ .sff_irq_check = piix_irq_check,
+ .port_start = piix_port_start,
+};
+
+static struct ata_port_operations piix_pata_ops = {
+ .inherits = &piix_sata_ops,
+ .cable_detect = ata_cable_40wire,
+ .set_piomode = piix_set_piomode,
+ .set_dmamode = piix_set_dmamode,
+ .prereset = piix_pata_prereset,
+};
+
+static struct ata_port_operations piix_vmw_ops = {
+ .inherits = &piix_pata_ops,
+ .bmdma_status = piix_vmw_bmdma_status,
+};
+
+static struct ata_port_operations ich_pata_ops = {
+ .inherits = &piix_pata_ops,
+ .cable_detect = ich_pata_cable_detect,
+ .set_dmamode = ich_set_dmamode,
+};
+
+static struct device_attribute *piix_sidpr_shost_attrs[] = {
+ &dev_attr_link_power_management_policy,
+ NULL
+};
+
+static struct scsi_host_template piix_sidpr_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+ .shost_attrs = piix_sidpr_shost_attrs,
+};
+
+static struct ata_port_operations piix_sidpr_sata_ops = {
+ .inherits = &piix_sata_ops,
+ .hardreset = sata_std_hardreset,
+ .scr_read = piix_sidpr_scr_read,
+ .scr_write = piix_sidpr_scr_write,
+ .set_lpm = piix_sidpr_set_lpm,
+};
+
+static struct ata_port_info piix_port_info[] = {
+ [piix_pata_mwdma] = /* PIIX3 MWDMA only */
+ {
+ .flags = PIIX_PATA_FLAGS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA12_ONLY, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
+ .port_ops = &piix_pata_ops,
+ },
+
+ [piix_pata_33] = /* PIIX4 at 33MHz */
+ {
+ .flags = PIIX_PATA_FLAGS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA12_ONLY, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
+ .udma_mask = ATA_UDMA2,
+ .port_ops = &piix_pata_ops,
+ },
+
+ [ich_pata_33] = /* ICH0 - ICH at 33Mhz*/
+ {
+ .flags = PIIX_PATA_FLAGS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA12_ONLY, /* Check: maybe MWDMA0 is ok */
+ .udma_mask = ATA_UDMA2,
+ .port_ops = &ich_pata_ops,
+ },
+
+ [ich_pata_66] = /* ICH controllers up to 66MHz */
+ {
+ .flags = PIIX_PATA_FLAGS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA12_ONLY, /* MWDMA0 is broken on chip */
+ .udma_mask = ATA_UDMA4,
+ .port_ops = &ich_pata_ops,
+ },
+
+ [ich_pata_100] =
+ {
+ .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA12_ONLY,
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &ich_pata_ops,
+ },
+
+ [ich_pata_100_nomwdma1] =
+ {
+ .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2_ONLY,
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &ich_pata_ops,
+ },
+
+ [ich5_sata] =
+ {
+ .flags = PIIX_SATA_FLAGS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
+
+ [ich6_sata] =
+ {
+ .flags = PIIX_SATA_FLAGS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
+
+ [ich6m_sata] =
+ {
+ .flags = PIIX_SATA_FLAGS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
+
+ [ich8_sata] =
+ {
+ .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
+
+ [ich8_2port_sata] =
+ {
+ .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
+
+ [tolapai_sata] =
+ {
+ .flags = PIIX_SATA_FLAGS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
+
+ [ich8m_apple_sata] =
+ {
+ .flags = PIIX_SATA_FLAGS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
+
+ [piix_pata_vmw] =
+ {
+ .flags = PIIX_PATA_FLAGS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA12_ONLY, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
+ .udma_mask = ATA_UDMA2,
+ .port_ops = &piix_vmw_ops,
+ },
+
+ /*
+ * some Sandybridge chipsets have broken 32 mode up to now,
+ * see https://bugzilla.kernel.org/show_bug.cgi?id=40592
+ */
+ [ich8_sata_snb] =
+ {
+ .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR | PIIX_FLAG_PIO16,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
+
+ [ich8_2port_sata_snb] =
+ {
+ .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR
+ | PIIX_FLAG_PIO16,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
+
+ [ich8_2port_sata_byt] =
+ {
+ .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR | PIIX_FLAG_PIO16,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
+
+};
+
#define AHCI_PCI_BAR 5
#define AHCI_GLOBAL_CTL 0x04
#define AHCI_ENABLE (1 << 31)
@@ -1255,7 +1316,7 @@ static int piix_disable_ahci(struct pci_dev *pdev)
* they are found return an error code so we can turn off DMA
*/
-static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
+static int piix_check_450nx_errata(struct pci_dev *ata_dev)
{
struct pci_dev *pdev = NULL;
u16 cfg;
@@ -1273,14 +1334,16 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
no_piix_dma = 2;
}
if (no_piix_dma)
- dev_printk(KERN_WARNING, &ata_dev->dev, "450NX errata present, disabling IDE DMA.\n");
- if (no_piix_dma == 2)
- dev_printk(KERN_WARNING, &ata_dev->dev, "A BIOS update may resolve this.\n");
+ dev_warn(&ata_dev->dev,
+ "450NX errata present, disabling IDE DMA%s\n",
+ no_piix_dma == 2 ? " - a BIOS update may resolve this"
+ : "");
+
return no_piix_dma;
}
-static void __devinit piix_init_pcs(struct ata_host *host,
- const struct piix_map_db *map_db)
+static void piix_init_pcs(struct ata_host *host,
+ const struct piix_map_db *map_db)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
u16 pcs, new_pcs;
@@ -1296,80 +1359,154 @@ static void __devinit piix_init_pcs(struct ata_host *host,
}
}
-static const int *__devinit piix_init_sata_map(struct pci_dev *pdev,
- struct ata_port_info *pinfo,
- const struct piix_map_db *map_db)
+static const int *piix_init_sata_map(struct pci_dev *pdev,
+ struct ata_port_info *pinfo,
+ const struct piix_map_db *map_db)
{
const int *map;
int i, invalid_map = 0;
u8 map_value;
+ char buf[32];
+ char *p = buf, *end = buf + sizeof(buf);
pci_read_config_byte(pdev, ICH5_PMR, &map_value);
map = map_db->map[map_value & map_db->mask];
- dev_printk(KERN_INFO, &pdev->dev, "MAP [");
for (i = 0; i < 4; i++) {
switch (map[i]) {
case RV:
invalid_map = 1;
- printk(" XX");
+ p += scnprintf(p, end - p, " XX");
break;
case NA:
- printk(" --");
+ p += scnprintf(p, end - p, " --");
break;
case IDE:
WARN_ON((i & 1) || map[i + 1] != IDE);
pinfo[i / 2] = piix_port_info[ich_pata_100];
i++;
- printk(" IDE IDE");
+ p += scnprintf(p, end - p, " IDE IDE");
break;
default:
- printk(" P%d", map[i]);
+ p += scnprintf(p, end - p, " P%d", map[i]);
if (i & 1)
pinfo[i / 2].flags |= ATA_FLAG_SLAVE_POSS;
break;
}
}
- printk(" ]\n");
+ dev_info(&pdev->dev, "MAP [%s ]\n", buf);
if (invalid_map)
- dev_printk(KERN_ERR, &pdev->dev,
- "invalid MAP value %u\n", map_value);
+ dev_err(&pdev->dev, "invalid MAP value %u\n", map_value);
return map;
}
-static void __devinit piix_init_sidpr(struct ata_host *host)
+static bool piix_no_sidpr(struct ata_host *host)
+{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+
+ /*
+ * Samsung DB-P70 only has three ATA ports exposed and
+ * curiously the unconnected first port reports link online
+ * while not responding to SRST protocol causing excessive
+ * detection delay.
+ *
+ * Unfortunately, the system doesn't carry enough DMI
+ * information to identify the machine but does have subsystem
+ * vendor and device set. As it's unclear whether the
+ * subsystem vendor/device is used only for this specific
+ * board, the port can't be disabled solely with the
+ * information; however, turning off SIDPR access works around
+ * the problem. Turn it off.
+ *
+ * This problem is reported in bnc#441240.
+ *
+ * https://bugzilla.novell.com/show_bug.cgi?id=441420
+ */
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == 0x2920 &&
+ pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG &&
+ pdev->subsystem_device == 0xb049) {
+ dev_warn(host->dev,
+ "Samsung DB-P70 detected, disabling SIDPR\n");
+ return true;
+ }
+
+ return false;
+}
+
+static int piix_init_sidpr(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
struct piix_host_priv *hpriv = host->private_data;
- int i;
+ struct ata_link *link0 = &host->ports[0]->link;
+ u32 scontrol;
+ int i, rc;
/* check for availability */
for (i = 0; i < 4; i++)
if (hpriv->map[i] == IDE)
- return;
+ return 0;
+
+ /* is it blacklisted? */
+ if (piix_no_sidpr(host))
+ return 0;
if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR))
- return;
+ return 0;
if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 ||
pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN)
- return;
+ return 0;
if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME))
- return;
+ return 0;
hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR];
- host->ports[0]->ops = &piix_sidpr_sata_ops;
- host->ports[1]->ops = &piix_sidpr_sata_ops;
+
+ /* SCR access via SIDPR doesn't work on some configurations.
+ * Give it a test drive by inhibiting power save modes which
+ * we'll do anyway.
+ */
+ piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol);
+
+ /* if IPM is already 3, SCR access is probably working. Don't
+ * un-inhibit power save modes as BIOS might have inhibited
+ * them for a reason.
+ */
+ if ((scontrol & 0xf00) != 0x300) {
+ scontrol |= 0x300;
+ piix_sidpr_scr_write(link0, SCR_CONTROL, scontrol);
+ piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol);
+
+ if ((scontrol & 0xf00) != 0x300) {
+ dev_info(host->dev,
+ "SCR access via SIDPR is available but doesn't work\n");
+ return 0;
+ }
+ }
+
+ /* okay, SCRs available, set ops and ask libata for slave_link */
+ for (i = 0; i < 2; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ ap->ops = &piix_sidpr_sata_ops;
+
+ if (ap->flags & ATA_FLAG_SLAVE_POSS) {
+ rc = ata_slave_link_init(ap);
+ if (rc)
+ return rc;
+ }
+ }
+
+ return 0;
}
-static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
+static void piix_iocfg_bit18_quirk(struct ata_host *host)
{
static const struct dmi_system_id sysids[] = {
{
@@ -1386,7 +1523,8 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
{ } /* terminate list */
};
- u32 iocfg;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ struct piix_host_priv *hpriv = host->private_data;
if (!dmi_check_system(sysids))
return;
@@ -1395,13 +1533,102 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
* seem to use it to disable a channel. Clear the bit on the
* affected systems.
*/
- pci_read_config_dword(pdev, PIIX_IOCFG, &iocfg);
- if (iocfg & (1 << 18)) {
- dev_printk(KERN_INFO, &pdev->dev,
- "applying IOCFG bit18 quirk\n");
- iocfg &= ~(1 << 18);
- pci_write_config_dword(pdev, PIIX_IOCFG, iocfg);
+ if (hpriv->saved_iocfg & (1 << 18)) {
+ dev_info(&pdev->dev, "applying IOCFG bit18 quirk\n");
+ pci_write_config_dword(pdev, PIIX_IOCFG,
+ hpriv->saved_iocfg & ~(1 << 18));
+ }
+}
+
+static bool piix_broken_system_poweroff(struct pci_dev *pdev)
+{
+ static const struct dmi_system_id broken_systems[] = {
+ {
+ .ident = "HP Compaq 2510p",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 2510p"),
+ },
+ /* PCI slot number of the controller */
+ .driver_data = (void *)0x1FUL,
+ },
+ {
+ .ident = "HP Compaq nc6000",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nc6000"),
+ },
+ /* PCI slot number of the controller */
+ .driver_data = (void *)0x1FUL,
+ },
+
+ { } /* terminate list */
+ };
+ const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
+
+ if (dmi) {
+ unsigned long slot = (unsigned long)dmi->driver_data;
+ /* apply the quirk only to on-board controllers */
+ return slot == PCI_SLOT(pdev->devfn);
}
+
+ return false;
+}
+
+static int prefer_ms_hyperv = 1;
+module_param(prefer_ms_hyperv, int, 0);
+MODULE_PARM_DESC(prefer_ms_hyperv,
+ "Prefer Hyper-V paravirtualization drivers instead of ATA, "
+ "0 - Use ATA drivers, "
+ "1 (Default) - Use the paravirtualization drivers.");
+
+static void piix_ignore_devices_quirk(struct ata_host *host)
+{
+#if IS_ENABLED(CONFIG_HYPERV_STORAGE)
+ static const struct dmi_system_id ignore_hyperv[] = {
+ {
+ /* On Hyper-V hypervisors the disks are exposed on
+ * both the emulated SATA controller and on the
+ * paravirtualised drivers. The CD/DVD devices
+ * are only exposed on the emulated controller.
+ * Request we ignore ATA devices on this host.
+ */
+ .ident = "Hyper-V Virtual Machine",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+ },
+ },
+ { } /* terminate list */
+ };
+ static const struct dmi_system_id allow_virtual_pc[] = {
+ {
+ /* In MS Virtual PC guests the DMI ident is nearly
+ * identical to a Hyper-V guest. One difference is the
+ * product version which is used here to identify
+ * a Virtual PC guest. This entry allows ata_piix to
+ * drive the emulated hardware.
+ */
+ .ident = "MS Virtual PC 2007",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "VS2005R2"),
+ },
+ },
+ { } /* terminate list */
+ };
+ const struct dmi_system_id *ignore = dmi_first_match(ignore_hyperv);
+ const struct dmi_system_id *allow = dmi_first_match(allow_virtual_pc);
+
+ if (ignore && !allow && prefer_ms_hyperv) {
+ host->flags |= ATA_HOST_IGNORE_ATA;
+ dev_info(host->dev, "%s detected, ATA device ignore set\n",
+ ignore->ident);
+ }
+#endif
}
/**
@@ -1419,26 +1646,31 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
* Zero on success, or -ERRNO value.
*/
-static int __devinit piix_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
struct device *dev = &pdev->dev;
struct ata_port_info port_info[2];
const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] };
+ struct scsi_host_template *sht = &piix_sht;
unsigned long port_flags;
struct ata_host *host;
struct piix_host_priv *hpriv;
int rc;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev,
- "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
- /* no hotplugging support (FIXME) */
- if (!in_module_init)
+ /* no hotplugging support for later devices (FIXME) */
+ if (!in_module_init && ent->driver_data >= ich5_sata)
return -ENODEV;
+ if (piix_broken_system_poweroff(pdev)) {
+ piix_port_info[ent->driver_data].flags |=
+ ATA_FLAG_NO_POWEROFF_SPINDOWN |
+ ATA_FLAG_NO_HIBERNATE_SPINDOWN;
+ dev_info(&pdev->dev, "quirky BIOS, skipping spindown "
+ "on poweroff and hibernation\n");
+ }
+
port_info[0] = piix_port_info[ent->driver_data];
port_info[1] = piix_port_info[ent->driver_data];
@@ -1449,26 +1681,33 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
if (rc)
return rc;
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
+
+ /* Save IOCFG, this will be used for cable detection, quirk
+ * detection and restoration on detach. This is necessary
+ * because some ACPI implementations mess up cable related
+ * bits on _STM. Reported on kernel bz#11879.
+ */
+ pci_read_config_dword(pdev, PIIX_IOCFG, &hpriv->saved_iocfg);
+
/* ICH6R may be driven by either ata_piix or ahci driver
* regardless of BIOS configuration. Make sure AHCI mode is
* off.
*/
if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == 0x2652) {
- int rc = piix_disable_ahci(pdev);
+ rc = piix_disable_ahci(pdev);
if (rc)
return rc;
}
/* SATA map init can change port_info, do it before prepping host */
- hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv)
- return -ENOMEM;
-
if (port_flags & ATA_FLAG_SATA)
hpriv->map = piix_init_sata_map(pdev, port_info,
piix_map_db_table[ent->driver_data]);
- rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+ rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
if (rc)
return rc;
host->private_data = hpriv;
@@ -1476,11 +1715,15 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
/* initialize controller */
if (port_flags & ATA_FLAG_SATA) {
piix_init_pcs(host, piix_map_db_table[ent->driver_data]);
- piix_init_sidpr(host);
+ rc = piix_init_sidpr(host);
+ if (rc)
+ return rc;
+ if (host->ports[0]->ops == &piix_sidpr_sata_ops)
+ sht = &piix_sidpr_sht;
}
/* apply IOCFG bit18 quirk */
- piix_iocfg_bit18_quirk(pdev);
+ piix_iocfg_bit18_quirk(host);
/* On ICH5, some BIOSen disable the interrupt using the
* PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
@@ -1500,11 +1743,36 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
host->ports[1]->mwdma_mask = 0;
host->ports[1]->udma_mask = 0;
}
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+
+ /* Allow hosts to specify device types to ignore when scanning. */
+ piix_ignore_devices_quirk(host);
pci_set_master(pdev);
- return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht);
+ return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht);
}
+static void piix_remove_one(struct pci_dev *pdev)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+ struct piix_host_priv *hpriv = host->private_data;
+
+ pci_write_config_dword(pdev, PIIX_IOCFG, hpriv->saved_iocfg);
+
+ ata_pci_remove_one(pdev);
+}
+
+static struct pci_driver piix_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = piix_pci_tbl,
+ .probe = piix_init_one,
+ .remove = piix_remove_one,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = piix_pci_device_suspend,
+ .resume = piix_pci_device_resume,
+#endif
+};
+
static int __init piix_init(void)
{
int rc;
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
new file mode 100644
index 00000000000..d72ce047030
--- /dev/null
+++ b/drivers/ata/libahci.c
@@ -0,0 +1,2482 @@
+/*
+ * libahci.c - Common AHCI SATA low-level routines
+ *
+ * Maintained by: Tejun Heo <tj@kernel.org>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2004-2005 Red Hat, Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * AHCI hardware documentation:
+ * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
+ * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <linux/libata.h>
+#include "ahci.h"
+#include "libata.h"
+
+static int ahci_skip_host_reset;
+int ahci_ignore_sss;
+EXPORT_SYMBOL_GPL(ahci_ignore_sss);
+
+module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444);
+MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)");
+
+module_param_named(ignore_sss, ahci_ignore_sss, int, 0444);
+MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)");
+
+static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+ unsigned hints);
+static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
+static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
+ size_t size);
+static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
+ ssize_t size);
+
+
+
+static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
+static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
+static int ahci_port_start(struct ata_port *ap);
+static void ahci_port_stop(struct ata_port *ap);
+static void ahci_qc_prep(struct ata_queued_cmd *qc);
+static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc);
+static void ahci_freeze(struct ata_port *ap);
+static void ahci_thaw(struct ata_port *ap);
+static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep);
+static void ahci_enable_fbs(struct ata_port *ap);
+static void ahci_disable_fbs(struct ata_port *ap);
+static void ahci_pmp_attach(struct ata_port *ap);
+static void ahci_pmp_detach(struct ata_port *ap);
+static int ahci_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline);
+static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline);
+static int ahci_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline);
+static void ahci_postreset(struct ata_link *link, unsigned int *class);
+static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
+static void ahci_dev_config(struct ata_device *dev);
+#ifdef CONFIG_PM
+static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
+#endif
+static ssize_t ahci_activity_show(struct ata_device *dev, char *buf);
+static ssize_t ahci_activity_store(struct ata_device *dev,
+ enum sw_activity val);
+static void ahci_init_sw_activity(struct ata_link *link);
+
+static ssize_t ahci_show_host_caps(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t ahci_show_host_cap2(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t ahci_show_host_version(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t ahci_show_port_cmd(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t ahci_read_em_buffer(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t ahci_store_em_buffer(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size);
+static ssize_t ahci_show_em_supported(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
+static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
+static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
+static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
+static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO,
+ ahci_read_em_buffer, ahci_store_em_buffer);
+static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL);
+
+struct device_attribute *ahci_shost_attrs[] = {
+ &dev_attr_link_power_management_policy,
+ &dev_attr_em_message_type,
+ &dev_attr_em_message,
+ &dev_attr_ahci_host_caps,
+ &dev_attr_ahci_host_cap2,
+ &dev_attr_ahci_host_version,
+ &dev_attr_ahci_port_cmd,
+ &dev_attr_em_buffer,
+ &dev_attr_em_message_supported,
+ NULL
+};
+EXPORT_SYMBOL_GPL(ahci_shost_attrs);
+
+struct device_attribute *ahci_sdev_attrs[] = {
+ &dev_attr_sw_activity,
+ &dev_attr_unload_heads,
+ NULL
+};
+EXPORT_SYMBOL_GPL(ahci_sdev_attrs);
+
+struct ata_port_operations ahci_ops = {
+ .inherits = &sata_pmp_port_ops,
+
+ .qc_defer = ahci_pmp_qc_defer,
+ .qc_prep = ahci_qc_prep,
+ .qc_issue = ahci_qc_issue,
+ .qc_fill_rtf = ahci_qc_fill_rtf,
+
+ .freeze = ahci_freeze,
+ .thaw = ahci_thaw,
+ .softreset = ahci_softreset,
+ .hardreset = ahci_hardreset,
+ .postreset = ahci_postreset,
+ .pmp_softreset = ahci_softreset,
+ .error_handler = ahci_error_handler,
+ .post_internal_cmd = ahci_post_internal_cmd,
+ .dev_config = ahci_dev_config,
+
+ .scr_read = ahci_scr_read,
+ .scr_write = ahci_scr_write,
+ .pmp_attach = ahci_pmp_attach,
+ .pmp_detach = ahci_pmp_detach,
+
+ .set_lpm = ahci_set_lpm,
+ .em_show = ahci_led_show,
+ .em_store = ahci_led_store,
+ .sw_activity_show = ahci_activity_show,
+ .sw_activity_store = ahci_activity_store,
+ .transmit_led_message = ahci_transmit_led_message,
+#ifdef CONFIG_PM
+ .port_suspend = ahci_port_suspend,
+ .port_resume = ahci_port_resume,
+#endif
+ .port_start = ahci_port_start,
+ .port_stop = ahci_port_stop,
+};
+EXPORT_SYMBOL_GPL(ahci_ops);
+
+struct ata_port_operations ahci_pmp_retry_srst_ops = {
+ .inherits = &ahci_ops,
+ .softreset = ahci_pmp_retry_softreset,
+};
+EXPORT_SYMBOL_GPL(ahci_pmp_retry_srst_ops);
+
+static bool ahci_em_messages __read_mostly = true;
+EXPORT_SYMBOL_GPL(ahci_em_messages);
+module_param(ahci_em_messages, bool, 0444);
+/* add other LED protocol types when they become supported */
+MODULE_PARM_DESC(ahci_em_messages,
+ "AHCI Enclosure Management Message control (0 = off, 1 = on)");
+
+/* device sleep idle timeout in ms */
+static int devslp_idle_timeout __read_mostly = 1000;
+module_param(devslp_idle_timeout, int, 0644);
+MODULE_PARM_DESC(devslp_idle_timeout, "device sleep idle timeout");
+
+static void ahci_enable_ahci(void __iomem *mmio)
+{
+ int i;
+ u32 tmp;
+
+ /* turn on AHCI_EN */
+ tmp = readl(mmio + HOST_CTL);
+ if (tmp & HOST_AHCI_EN)
+ return;
+
+ /* Some controllers need AHCI_EN to be written multiple times.
+ * Try a few times before giving up.
+ */
+ for (i = 0; i < 5; i++) {
+ tmp |= HOST_AHCI_EN;
+ writel(tmp, mmio + HOST_CTL);
+ tmp = readl(mmio + HOST_CTL); /* flush && sanity check */
+ if (tmp & HOST_AHCI_EN)
+ return;
+ msleep(10);
+ }
+
+ WARN_ON(1);
+}
+
+static ssize_t ahci_show_host_caps(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
+ return sprintf(buf, "%x\n", hpriv->cap);
+}
+
+static ssize_t ahci_show_host_cap2(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
+ return sprintf(buf, "%x\n", hpriv->cap2);
+}
+
+static ssize_t ahci_show_host_version(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+
+ return sprintf(buf, "%x\n", readl(mmio + HOST_VERSION));
+}
+
+static ssize_t ahci_show_port_cmd(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ void __iomem *port_mmio = ahci_port_base(ap);
+
+ return sprintf(buf, "%x\n", readl(port_mmio + PORT_CMD));
+}
+
+static ssize_t ahci_read_em_buffer(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ void __iomem *em_mmio = mmio + hpriv->em_loc;
+ u32 em_ctl, msg;
+ unsigned long flags;
+ size_t count;
+ int i;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ em_ctl = readl(mmio + HOST_EM_CTL);
+ if (!(ap->flags & ATA_FLAG_EM) || em_ctl & EM_CTL_XMT ||
+ !(hpriv->em_msg_type & EM_MSG_TYPE_SGPIO)) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return -EINVAL;
+ }
+
+ if (!(em_ctl & EM_CTL_MR)) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return -EAGAIN;
+ }
+
+ if (!(em_ctl & EM_CTL_SMB))
+ em_mmio += hpriv->em_buf_sz;
+
+ count = hpriv->em_buf_sz;
+
+ /* the count should not be larger than PAGE_SIZE */
+ if (count > PAGE_SIZE) {
+ if (printk_ratelimit())
+ ata_port_warn(ap,
+ "EM read buffer size too large: "
+ "buffer size %u, page size %lu\n",
+ hpriv->em_buf_sz, PAGE_SIZE);
+ count = PAGE_SIZE;
+ }
+
+ for (i = 0; i < count; i += 4) {
+ msg = readl(em_mmio + i);
+ buf[i] = msg & 0xff;
+ buf[i + 1] = (msg >> 8) & 0xff;
+ buf[i + 2] = (msg >> 16) & 0xff;
+ buf[i + 3] = (msg >> 24) & 0xff;
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return i;
+}
+
+static ssize_t ahci_store_em_buffer(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ void __iomem *em_mmio = mmio + hpriv->em_loc;
+ const unsigned char *msg_buf = buf;
+ u32 em_ctl, msg;
+ unsigned long flags;
+ int i;
+
+ /* check size validity */
+ if (!(ap->flags & ATA_FLAG_EM) ||
+ !(hpriv->em_msg_type & EM_MSG_TYPE_SGPIO) ||
+ size % 4 || size > hpriv->em_buf_sz)
+ return -EINVAL;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ em_ctl = readl(mmio + HOST_EM_CTL);
+ if (em_ctl & EM_CTL_TM) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return -EBUSY;
+ }
+
+ for (i = 0; i < size; i += 4) {
+ msg = msg_buf[i] | msg_buf[i + 1] << 8 |
+ msg_buf[i + 2] << 16 | msg_buf[i + 3] << 24;
+ writel(msg, em_mmio + i);
+ }
+
+ writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return size;
+}
+
+static ssize_t ahci_show_em_supported(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ u32 em_ctl;
+
+ em_ctl = readl(mmio + HOST_EM_CTL);
+
+ return sprintf(buf, "%s%s%s%s\n",
+ em_ctl & EM_CTL_LED ? "led " : "",
+ em_ctl & EM_CTL_SAFTE ? "saf-te " : "",
+ em_ctl & EM_CTL_SES ? "ses-2 " : "",
+ em_ctl & EM_CTL_SGPIO ? "sgpio " : "");
+}
+
+/**
+ * ahci_save_initial_config - Save and fixup initial config values
+ * @dev: target AHCI device
+ * @hpriv: host private area to store config values
+ * @force_port_map: force port map to a specified value
+ * @mask_port_map: mask out particular bits from port map
+ *
+ * Some registers containing configuration info might be setup by
+ * BIOS and might be cleared on reset. This function saves the
+ * initial values of those registers into @hpriv such that they
+ * can be restored after controller reset.
+ *
+ * If inconsistent, config values are fixed up by this function.
+ *
+ * If it is not set already this function sets hpriv->start_engine to
+ * ahci_start_engine.
+ *
+ * LOCKING:
+ * None.
+ */
+void ahci_save_initial_config(struct device *dev,
+ struct ahci_host_priv *hpriv,
+ unsigned int force_port_map,
+ unsigned int mask_port_map)
+{
+ void __iomem *mmio = hpriv->mmio;
+ u32 cap, cap2, vers, port_map;
+ int i;
+
+ /* make sure AHCI mode is enabled before accessing CAP */
+ ahci_enable_ahci(mmio);
+
+ /* Values prefixed with saved_ are written back to host after
+ * reset. Values without are used for driver operation.
+ */
+ hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
+ hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
+
+ /* CAP2 register is only defined for AHCI 1.2 and later */
+ vers = readl(mmio + HOST_VERSION);
+ if ((vers >> 16) > 1 ||
+ ((vers >> 16) == 1 && (vers & 0xFFFF) >= 0x200))
+ hpriv->saved_cap2 = cap2 = readl(mmio + HOST_CAP2);
+ else
+ hpriv->saved_cap2 = cap2 = 0;
+
+ /* some chips have errata preventing 64bit use */
+ if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
+ dev_info(dev, "controller can't do 64bit DMA, forcing 32bit\n");
+ cap &= ~HOST_CAP_64;
+ }
+
+ if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
+ dev_info(dev, "controller can't do NCQ, turning off CAP_NCQ\n");
+ cap &= ~HOST_CAP_NCQ;
+ }
+
+ if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) {
+ dev_info(dev, "controller can do NCQ, turning on CAP_NCQ\n");
+ cap |= HOST_CAP_NCQ;
+ }
+
+ if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
+ dev_info(dev, "controller can't do PMP, turning off CAP_PMP\n");
+ cap &= ~HOST_CAP_PMP;
+ }
+
+ if ((cap & HOST_CAP_SNTF) && (hpriv->flags & AHCI_HFLAG_NO_SNTF)) {
+ dev_info(dev,
+ "controller can't do SNTF, turning off CAP_SNTF\n");
+ cap &= ~HOST_CAP_SNTF;
+ }
+
+ if ((cap2 & HOST_CAP2_SDS) && (hpriv->flags & AHCI_HFLAG_NO_DEVSLP)) {
+ dev_info(dev,
+ "controller can't do DEVSLP, turning off\n");
+ cap2 &= ~HOST_CAP2_SDS;
+ cap2 &= ~HOST_CAP2_SADM;
+ }
+
+ if (!(cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_YES_FBS)) {
+ dev_info(dev, "controller can do FBS, turning on CAP_FBS\n");
+ cap |= HOST_CAP_FBS;
+ }
+
+ if ((cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_NO_FBS)) {
+ dev_info(dev, "controller can't do FBS, turning off CAP_FBS\n");
+ cap &= ~HOST_CAP_FBS;
+ }
+
+ if (force_port_map && port_map != force_port_map) {
+ dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
+ port_map, force_port_map);
+ port_map = force_port_map;
+ }
+
+ if (mask_port_map) {
+ dev_warn(dev, "masking port_map 0x%x -> 0x%x\n",
+ port_map,
+ port_map & mask_port_map);
+ port_map &= mask_port_map;
+ }
+
+ /* cross check port_map and cap.n_ports */
+ if (port_map) {
+ int map_ports = 0;
+
+ for (i = 0; i < AHCI_MAX_PORTS; i++)
+ if (port_map & (1 << i))
+ map_ports++;
+
+ /* If PI has more ports than n_ports, whine, clear
+ * port_map and let it be generated from n_ports.
+ */
+ if (map_ports > ahci_nr_ports(cap)) {
+ dev_warn(dev,
+ "implemented port map (0x%x) contains more ports than nr_ports (%u), using nr_ports\n",
+ port_map, ahci_nr_ports(cap));
+ port_map = 0;
+ }
+ }
+
+ /* fabricate port_map from cap.nr_ports */
+ if (!port_map) {
+ port_map = (1 << ahci_nr_ports(cap)) - 1;
+ dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map);
+
+ /* write the fixed up value to the PI register */
+ hpriv->saved_port_map = port_map;
+ }
+
+ /* record values to use during operation */
+ hpriv->cap = cap;
+ hpriv->cap2 = cap2;
+ hpriv->port_map = port_map;
+
+ if (!hpriv->start_engine)
+ hpriv->start_engine = ahci_start_engine;
+}
+EXPORT_SYMBOL_GPL(ahci_save_initial_config);
+
+/**
+ * ahci_restore_initial_config - Restore initial config
+ * @host: target ATA host
+ *
+ * Restore initial config stored by ahci_save_initial_config().
+ *
+ * LOCKING:
+ * None.
+ */
+static void ahci_restore_initial_config(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+
+ writel(hpriv->saved_cap, mmio + HOST_CAP);
+ if (hpriv->saved_cap2)
+ writel(hpriv->saved_cap2, mmio + HOST_CAP2);
+ writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
+ (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
+}
+
+static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
+{
+ static const int offset[] = {
+ [SCR_STATUS] = PORT_SCR_STAT,
+ [SCR_CONTROL] = PORT_SCR_CTL,
+ [SCR_ERROR] = PORT_SCR_ERR,
+ [SCR_ACTIVE] = PORT_SCR_ACT,
+ [SCR_NOTIFICATION] = PORT_SCR_NTF,
+ };
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
+ if (sc_reg < ARRAY_SIZE(offset) &&
+ (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
+ return offset[sc_reg];
+ return 0;
+}
+
+static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
+{
+ void __iomem *port_mmio = ahci_port_base(link->ap);
+ int offset = ahci_scr_offset(link->ap, sc_reg);
+
+ if (offset) {
+ *val = readl(port_mmio + offset);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
+{
+ void __iomem *port_mmio = ahci_port_base(link->ap);
+ int offset = ahci_scr_offset(link->ap, sc_reg);
+
+ if (offset) {
+ writel(val, port_mmio + offset);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+void ahci_start_engine(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 tmp;
+
+ /* start DMA */
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp |= PORT_CMD_START;
+ writel(tmp, port_mmio + PORT_CMD);
+ readl(port_mmio + PORT_CMD); /* flush */
+}
+EXPORT_SYMBOL_GPL(ahci_start_engine);
+
+int ahci_stop_engine(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 tmp;
+
+ tmp = readl(port_mmio + PORT_CMD);
+
+ /* check if the HBA is idle */
+ if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
+ return 0;
+
+ /* setting HBA to idle */
+ tmp &= ~PORT_CMD_START;
+ writel(tmp, port_mmio + PORT_CMD);
+
+ /* wait for engine to stop. This could be as long as 500 msec */
+ tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
+ PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
+ if (tmp & PORT_CMD_LIST_ON)
+ return -EIO;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ahci_stop_engine);
+
+void ahci_start_fis_rx(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 tmp;
+
+ /* set FIS registers */
+ if (hpriv->cap & HOST_CAP_64)
+ writel((pp->cmd_slot_dma >> 16) >> 16,
+ port_mmio + PORT_LST_ADDR_HI);
+ writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
+
+ if (hpriv->cap & HOST_CAP_64)
+ writel((pp->rx_fis_dma >> 16) >> 16,
+ port_mmio + PORT_FIS_ADDR_HI);
+ writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
+
+ /* enable FIS reception */
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp |= PORT_CMD_FIS_RX;
+ writel(tmp, port_mmio + PORT_CMD);
+
+ /* flush */
+ readl(port_mmio + PORT_CMD);
+}
+EXPORT_SYMBOL_GPL(ahci_start_fis_rx);
+
+static int ahci_stop_fis_rx(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 tmp;
+
+ /* disable FIS reception */
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp &= ~PORT_CMD_FIS_RX;
+ writel(tmp, port_mmio + PORT_CMD);
+
+ /* wait for completion, spec says 500ms, give it 1000 */
+ tmp = ata_wait_register(ap, port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
+ PORT_CMD_FIS_ON, 10, 1000);
+ if (tmp & PORT_CMD_FIS_ON)
+ return -EBUSY;
+
+ return 0;
+}
+
+static void ahci_power_up(struct ata_port *ap)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 cmd;
+
+ cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
+
+ /* spin up device */
+ if (hpriv->cap & HOST_CAP_SSS) {
+ cmd |= PORT_CMD_SPIN_UP;
+ writel(cmd, port_mmio + PORT_CMD);
+ }
+
+ /* wake up link */
+ writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
+}
+
+static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+ unsigned int hints)
+{
+ struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+
+ if (policy != ATA_LPM_MAX_POWER) {
+ /*
+ * Disable interrupts on Phy Ready. This keeps us from
+ * getting woken up due to spurious phy ready
+ * interrupts.
+ */
+ pp->intr_mask &= ~PORT_IRQ_PHYRDY;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+
+ sata_link_scr_lpm(link, policy, false);
+ }
+
+ if (hpriv->cap & HOST_CAP_ALPM) {
+ u32 cmd = readl(port_mmio + PORT_CMD);
+
+ if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) {
+ cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
+ cmd |= PORT_CMD_ICC_ACTIVE;
+
+ writel(cmd, port_mmio + PORT_CMD);
+ readl(port_mmio + PORT_CMD);
+
+ /* wait 10ms to be sure we've come out of LPM state */
+ ata_msleep(ap, 10);
+ } else {
+ cmd |= PORT_CMD_ALPE;
+ if (policy == ATA_LPM_MIN_POWER)
+ cmd |= PORT_CMD_ASP;
+
+ /* write out new cmd value */
+ writel(cmd, port_mmio + PORT_CMD);
+ }
+ }
+
+ /* set aggressive device sleep */
+ if ((hpriv->cap2 & HOST_CAP2_SDS) &&
+ (hpriv->cap2 & HOST_CAP2_SADM) &&
+ (link->device->flags & ATA_DFLAG_DEVSLP)) {
+ if (policy == ATA_LPM_MIN_POWER)
+ ahci_set_aggressive_devslp(ap, true);
+ else
+ ahci_set_aggressive_devslp(ap, false);
+ }
+
+ if (policy == ATA_LPM_MAX_POWER) {
+ sata_link_scr_lpm(link, policy, false);
+
+ /* turn PHYRDY IRQ back on */
+ pp->intr_mask |= PORT_IRQ_PHYRDY;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static void ahci_power_down(struct ata_port *ap)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 cmd, scontrol;
+
+ if (!(hpriv->cap & HOST_CAP_SSS))
+ return;
+
+ /* put device into listen mode, first set PxSCTL.DET to 0 */
+ scontrol = readl(port_mmio + PORT_SCR_CTL);
+ scontrol &= ~0xf;
+ writel(scontrol, port_mmio + PORT_SCR_CTL);
+
+ /* then set PxCMD.SUD to 0 */
+ cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
+ cmd &= ~PORT_CMD_SPIN_UP;
+ writel(cmd, port_mmio + PORT_CMD);
+}
+#endif
+
+static void ahci_start_port(struct ata_port *ap)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ata_link *link;
+ struct ahci_em_priv *emp;
+ ssize_t rc;
+ int i;
+
+ /* enable FIS reception */
+ ahci_start_fis_rx(ap);
+
+ /* enable DMA */
+ if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
+ hpriv->start_engine(ap);
+
+ /* turn on LEDs */
+ if (ap->flags & ATA_FLAG_EM) {
+ ata_for_each_link(link, ap, EDGE) {
+ emp = &pp->em_priv[link->pmp];
+
+ /* EM Transmit bit maybe busy during init */
+ for (i = 0; i < EM_MAX_RETRY; i++) {
+ rc = ap->ops->transmit_led_message(ap,
+ emp->led_state,
+ 4);
+ /*
+ * If busy, give a breather but do not
+ * release EH ownership by using msleep()
+ * instead of ata_msleep(). EM Transmit
+ * bit is busy for the whole host and
+ * releasing ownership will cause other
+ * ports to fail the same way.
+ */
+ if (rc == -EBUSY)
+ msleep(1);
+ else
+ break;
+ }
+ }
+ }
+
+ if (ap->flags & ATA_FLAG_SW_ACTIVITY)
+ ata_for_each_link(link, ap, EDGE)
+ ahci_init_sw_activity(link);
+
+}
+
+static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
+{
+ int rc;
+
+ /* disable DMA */
+ rc = ahci_stop_engine(ap);
+ if (rc) {
+ *emsg = "failed to stop engine";
+ return rc;
+ }
+
+ /* disable FIS reception */
+ rc = ahci_stop_fis_rx(ap);
+ if (rc) {
+ *emsg = "failed stop FIS RX";
+ return rc;
+ }
+
+ return 0;
+}
+
+int ahci_reset_controller(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ u32 tmp;
+
+ /* we must be in AHCI mode, before using anything
+ * AHCI-specific, such as HOST_RESET.
+ */
+ ahci_enable_ahci(mmio);
+
+ /* global controller reset */
+ if (!ahci_skip_host_reset) {
+ tmp = readl(mmio + HOST_CTL);
+ if ((tmp & HOST_RESET) == 0) {
+ writel(tmp | HOST_RESET, mmio + HOST_CTL);
+ readl(mmio + HOST_CTL); /* flush */
+ }
+
+ /*
+ * to perform host reset, OS should set HOST_RESET
+ * and poll until this bit is read to be "0".
+ * reset must complete within 1 second, or
+ * the hardware should be considered fried.
+ */
+ tmp = ata_wait_register(NULL, mmio + HOST_CTL, HOST_RESET,
+ HOST_RESET, 10, 1000);
+
+ if (tmp & HOST_RESET) {
+ dev_err(host->dev, "controller reset failed (0x%x)\n",
+ tmp);
+ return -EIO;
+ }
+
+ /* turn on AHCI mode */
+ ahci_enable_ahci(mmio);
+
+ /* Some registers might be cleared on reset. Restore
+ * initial values.
+ */
+ ahci_restore_initial_config(host);
+ } else
+ dev_info(host->dev, "skipping global host reset\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ahci_reset_controller);
+
+static void ahci_sw_activity(struct ata_link *link)
+{
+ struct ata_port *ap = link->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
+
+ if (!(link->flags & ATA_LFLAG_SW_ACTIVITY))
+ return;
+
+ emp->activity++;
+ if (!timer_pending(&emp->timer))
+ mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10));
+}
+
+static void ahci_sw_activity_blink(unsigned long arg)
+{
+ struct ata_link *link = (struct ata_link *)arg;
+ struct ata_port *ap = link->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
+ unsigned long led_message = emp->led_state;
+ u32 activity_led_state;
+ unsigned long flags;
+
+ led_message &= EM_MSG_LED_VALUE;
+ led_message |= ap->port_no | (link->pmp << 8);
+
+ /* check to see if we've had activity. If so,
+ * toggle state of LED and reset timer. If not,
+ * turn LED to desired idle state.
+ */
+ spin_lock_irqsave(ap->lock, flags);
+ if (emp->saved_activity != emp->activity) {
+ emp->saved_activity = emp->activity;
+ /* get the current LED state */
+ activity_led_state = led_message & EM_MSG_LED_VALUE_ON;
+
+ if (activity_led_state)
+ activity_led_state = 0;
+ else
+ activity_led_state = 1;
+
+ /* clear old state */
+ led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
+
+ /* toggle state */
+ led_message |= (activity_led_state << 16);
+ mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100));
+ } else {
+ /* switch to idle */
+ led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
+ if (emp->blink_policy == BLINK_OFF)
+ led_message |= (1 << 16);
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+ ap->ops->transmit_led_message(ap, led_message, 4);
+}
+
+static void ahci_init_sw_activity(struct ata_link *link)
+{
+ struct ata_port *ap = link->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
+
+ /* init activity stats, setup timer */
+ emp->saved_activity = emp->activity = 0;
+ setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link);
+
+ /* check our blink policy and set flag for link if it's enabled */
+ if (emp->blink_policy)
+ link->flags |= ATA_LFLAG_SW_ACTIVITY;
+}
+
+int ahci_reset_em(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ u32 em_ctl;
+
+ em_ctl = readl(mmio + HOST_EM_CTL);
+ if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST))
+ return -EINVAL;
+
+ writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ahci_reset_em);
+
+static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
+ ssize_t size)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ u32 em_ctl;
+ u32 message[] = {0, 0};
+ unsigned long flags;
+ int pmp;
+ struct ahci_em_priv *emp;
+
+ /* get the slot number from the message */
+ pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
+ if (pmp < EM_MAX_SLOTS)
+ emp = &pp->em_priv[pmp];
+ else
+ return -EINVAL;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /*
+ * if we are still busy transmitting a previous message,
+ * do not allow
+ */
+ em_ctl = readl(mmio + HOST_EM_CTL);
+ if (em_ctl & EM_CTL_TM) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return -EBUSY;
+ }
+
+ if (hpriv->em_msg_type & EM_MSG_TYPE_LED) {
+ /*
+ * create message header - this is all zero except for
+ * the message size, which is 4 bytes.
+ */
+ message[0] |= (4 << 8);
+
+ /* ignore 0:4 of byte zero, fill in port info yourself */
+ message[1] = ((state & ~EM_MSG_LED_HBA_PORT) | ap->port_no);
+
+ /* write message to EM_LOC */
+ writel(message[0], mmio + hpriv->em_loc);
+ writel(message[1], mmio + hpriv->em_loc+4);
+
+ /*
+ * tell hardware to transmit the message
+ */
+ writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
+ }
+
+ /* save off new led state for port/slot */
+ emp->led_state = state;
+
+ spin_unlock_irqrestore(ap->lock, flags);
+ return size;
+}
+
+static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ata_link *link;
+ struct ahci_em_priv *emp;
+ int rc = 0;
+
+ ata_for_each_link(link, ap, EDGE) {
+ emp = &pp->em_priv[link->pmp];
+ rc += sprintf(buf, "%lx\n", emp->led_state);
+ }
+ return rc;
+}
+
+static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
+ size_t size)
+{
+ unsigned int state;
+ int pmp;
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_em_priv *emp;
+
+ if (kstrtouint(buf, 0, &state) < 0)
+ return -EINVAL;
+
+ /* get the slot number from the message */
+ pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
+ if (pmp < EM_MAX_SLOTS)
+ emp = &pp->em_priv[pmp];
+ else
+ return -EINVAL;
+
+ /* mask off the activity bits if we are in sw_activity
+ * mode, user should turn off sw_activity before setting
+ * activity led through em_message
+ */
+ if (emp->blink_policy)
+ state &= ~EM_MSG_LED_VALUE_ACTIVITY;
+
+ return ap->ops->transmit_led_message(ap, state, size);
+}
+
+static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
+ u32 port_led_state = emp->led_state;
+
+ /* save the desired Activity LED behavior */
+ if (val == OFF) {
+ /* clear LFLAG */
+ link->flags &= ~(ATA_LFLAG_SW_ACTIVITY);
+
+ /* set the LED to OFF */
+ port_led_state &= EM_MSG_LED_VALUE_OFF;
+ port_led_state |= (ap->port_no | (link->pmp << 8));
+ ap->ops->transmit_led_message(ap, port_led_state, 4);
+ } else {
+ link->flags |= ATA_LFLAG_SW_ACTIVITY;
+ if (val == BLINK_OFF) {
+ /* set LED to ON for idle */
+ port_led_state &= EM_MSG_LED_VALUE_OFF;
+ port_led_state |= (ap->port_no | (link->pmp << 8));
+ port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */
+ ap->ops->transmit_led_message(ap, port_led_state, 4);
+ }
+ }
+ emp->blink_policy = val;
+ return 0;
+}
+
+static ssize_t ahci_activity_show(struct ata_device *dev, char *buf)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
+
+ /* display the saved value of activity behavior for this
+ * disk.
+ */
+ return sprintf(buf, "%d\n", emp->blink_policy);
+}
+
+static void ahci_port_init(struct device *dev, struct ata_port *ap,
+ int port_no, void __iomem *mmio,
+ void __iomem *port_mmio)
+{
+ const char *emsg = NULL;
+ int rc;
+ u32 tmp;
+
+ /* make sure port is not active */
+ rc = ahci_deinit_port(ap, &emsg);
+ if (rc)
+ dev_warn(dev, "%s (%d)\n", emsg, rc);
+
+ /* clear SError */
+ tmp = readl(port_mmio + PORT_SCR_ERR);
+ VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
+ writel(tmp, port_mmio + PORT_SCR_ERR);
+
+ /* clear port IRQ */
+ tmp = readl(port_mmio + PORT_IRQ_STAT);
+ VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
+ if (tmp)
+ writel(tmp, port_mmio + PORT_IRQ_STAT);
+
+ writel(1 << port_no, mmio + HOST_IRQ_STAT);
+}
+
+void ahci_init_controller(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ int i;
+ void __iomem *port_mmio;
+ u32 tmp;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ port_mmio = ahci_port_base(ap);
+ if (ata_port_is_dummy(ap))
+ continue;
+
+ ahci_port_init(host->dev, ap, i, mmio, port_mmio);
+ }
+
+ tmp = readl(mmio + HOST_CTL);
+ VPRINTK("HOST_CTL 0x%x\n", tmp);
+ writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
+ tmp = readl(mmio + HOST_CTL);
+ VPRINTK("HOST_CTL 0x%x\n", tmp);
+}
+EXPORT_SYMBOL_GPL(ahci_init_controller);
+
+static void ahci_dev_config(struct ata_device *dev)
+{
+ struct ahci_host_priv *hpriv = dev->link->ap->host->private_data;
+
+ if (hpriv->flags & AHCI_HFLAG_SECT255) {
+ dev->max_sectors = 255;
+ ata_dev_info(dev,
+ "SB600 AHCI: limiting to 255 sectors per cmd\n");
+ }
+}
+
+unsigned int ahci_dev_classify(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ata_taskfile tf;
+ u32 tmp;
+
+ tmp = readl(port_mmio + PORT_SIG);
+ tf.lbah = (tmp >> 24) & 0xff;
+ tf.lbam = (tmp >> 16) & 0xff;
+ tf.lbal = (tmp >> 8) & 0xff;
+ tf.nsect = (tmp) & 0xff;
+
+ return ata_dev_classify(&tf);
+}
+EXPORT_SYMBOL_GPL(ahci_dev_classify);
+
+void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
+ u32 opts)
+{
+ dma_addr_t cmd_tbl_dma;
+
+ cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
+
+ pp->cmd_slot[tag].opts = cpu_to_le32(opts);
+ pp->cmd_slot[tag].status = 0;
+ pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
+ pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
+}
+EXPORT_SYMBOL_GPL(ahci_fill_cmd_slot);
+
+int ahci_kick_engine(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
+ u32 tmp;
+ int busy, rc;
+
+ /* stop engine */
+ rc = ahci_stop_engine(ap);
+ if (rc)
+ goto out_restart;
+
+ /* need to do CLO?
+ * always do CLO if PMP is attached (AHCI-1.3 9.2)
+ */
+ busy = status & (ATA_BUSY | ATA_DRQ);
+ if (!busy && !sata_pmp_attached(ap)) {
+ rc = 0;
+ goto out_restart;
+ }
+
+ if (!(hpriv->cap & HOST_CAP_CLO)) {
+ rc = -EOPNOTSUPP;
+ goto out_restart;
+ }
+
+ /* perform CLO */
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp |= PORT_CMD_CLO;
+ writel(tmp, port_mmio + PORT_CMD);
+
+ rc = 0;
+ tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
+ PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
+ if (tmp & PORT_CMD_CLO)
+ rc = -EIO;
+
+ /* restart engine */
+ out_restart:
+ hpriv->start_engine(ap);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_kick_engine);
+
+static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
+ struct ata_taskfile *tf, int is_cmd, u16 flags,
+ unsigned long timeout_msec)
+{
+ const u32 cmd_fis_len = 5; /* five dwords */
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u8 *fis = pp->cmd_tbl;
+ u32 tmp;
+
+ /* prep the command */
+ ata_tf_to_fis(tf, pmp, is_cmd, fis);
+ ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
+
+ /* issue & wait */
+ writel(1, port_mmio + PORT_CMD_ISSUE);
+
+ if (timeout_msec) {
+ tmp = ata_wait_register(ap, port_mmio + PORT_CMD_ISSUE,
+ 0x1, 0x1, 1, timeout_msec);
+ if (tmp & 0x1) {
+ ahci_kick_engine(ap);
+ return -EBUSY;
+ }
+ } else
+ readl(port_mmio + PORT_CMD_ISSUE); /* flush */
+
+ return 0;
+}
+
+int ahci_do_softreset(struct ata_link *link, unsigned int *class,
+ int pmp, unsigned long deadline,
+ int (*check_ready)(struct ata_link *link))
+{
+ struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ const char *reason = NULL;
+ unsigned long now, msecs;
+ struct ata_taskfile tf;
+ bool fbs_disabled = false;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ /* prepare for SRST (AHCI-1.1 10.4.1) */
+ rc = ahci_kick_engine(ap);
+ if (rc && rc != -EOPNOTSUPP)
+ ata_link_warn(link, "failed to reset engine (errno=%d)\n", rc);
+
+ /*
+ * According to AHCI-1.2 9.3.9: if FBS is enable, software shall
+ * clear PxFBS.EN to '0' prior to issuing software reset to devices
+ * that is attached to port multiplier.
+ */
+ if (!ata_is_host_link(link) && pp->fbs_enabled) {
+ ahci_disable_fbs(ap);
+ fbs_disabled = true;
+ }
+
+ ata_tf_init(link->device, &tf);
+
+ /* issue the first D2H Register FIS */
+ msecs = 0;
+ now = jiffies;
+ if (time_after(deadline, now))
+ msecs = jiffies_to_msecs(deadline - now);
+
+ tf.ctl |= ATA_SRST;
+ if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
+ AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
+ rc = -EIO;
+ reason = "1st FIS failed";
+ goto fail;
+ }
+
+ /* spec says at least 5us, but be generous and sleep for 1ms */
+ ata_msleep(ap, 1);
+
+ /* issue the second D2H Register FIS */
+ tf.ctl &= ~ATA_SRST;
+ ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
+
+ /* wait for link to become ready */
+ rc = ata_wait_after_reset(link, deadline, check_ready);
+ if (rc == -EBUSY && hpriv->flags & AHCI_HFLAG_SRST_TOUT_IS_OFFLINE) {
+ /*
+ * Workaround for cases where link online status can't
+ * be trusted. Treat device readiness timeout as link
+ * offline.
+ */
+ ata_link_info(link, "device not ready, treating as offline\n");
+ *class = ATA_DEV_NONE;
+ } else if (rc) {
+ /* link occupied, -ENODEV too is an error */
+ reason = "device not ready";
+ goto fail;
+ } else
+ *class = ahci_dev_classify(ap);
+
+ /* re-enable FBS if disabled before */
+ if (fbs_disabled)
+ ahci_enable_fbs(ap);
+
+ DPRINTK("EXIT, class=%u\n", *class);
+ return 0;
+
+ fail:
+ ata_link_err(link, "softreset failed (%s)\n", reason);
+ return rc;
+}
+
+int ahci_check_ready(struct ata_link *link)
+{
+ void __iomem *port_mmio = ahci_port_base(link->ap);
+ u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
+
+ return ata_check_ready(status);
+}
+EXPORT_SYMBOL_GPL(ahci_check_ready);
+
+static int ahci_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ int pmp = sata_srst_pmp(link);
+
+ DPRINTK("ENTER\n");
+
+ return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
+}
+EXPORT_SYMBOL_GPL(ahci_do_softreset);
+
+static int ahci_bad_pmp_check_ready(struct ata_link *link)
+{
+ void __iomem *port_mmio = ahci_port_base(link->ap);
+ u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
+ u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
+
+ /*
+ * There is no need to check TFDATA if BAD PMP is found due to HW bug,
+ * which can save timeout delay.
+ */
+ if (irq_status & PORT_IRQ_BAD_PMP)
+ return -EIO;
+
+ return ata_check_ready(status);
+}
+
+static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ int pmp = sata_srst_pmp(link);
+ int rc;
+ u32 irq_sts;
+
+ DPRINTK("ENTER\n");
+
+ rc = ahci_do_softreset(link, class, pmp, deadline,
+ ahci_bad_pmp_check_ready);
+
+ /*
+ * Soft reset fails with IPMS set when PMP is enabled but
+ * SATA HDD/ODD is connected to SATA port, do soft reset
+ * again to port 0.
+ */
+ if (rc == -EIO) {
+ irq_sts = readl(port_mmio + PORT_IRQ_STAT);
+ if (irq_sts & PORT_IRQ_BAD_PMP) {
+ ata_link_warn(link,
+ "applying PMP SRST workaround "
+ "and retrying\n");
+ rc = ahci_do_softreset(link, class, 0, deadline,
+ ahci_check_ready);
+ }
+ }
+
+ return rc;
+}
+
+static int ahci_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+ struct ata_port *ap = link->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ struct ata_taskfile tf;
+ bool online;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ ahci_stop_engine(ap);
+
+ /* clear D2H reception area to properly wait for D2H FIS */
+ ata_tf_init(link->device, &tf);
+ tf.command = ATA_BUSY;
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+
+ rc = sata_link_hardreset(link, timing, deadline, &online,
+ ahci_check_ready);
+
+ hpriv->start_engine(ap);
+
+ if (online)
+ *class = ahci_dev_classify(ap);
+
+ DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
+ return rc;
+}
+
+static void ahci_postreset(struct ata_link *link, unsigned int *class)
+{
+ struct ata_port *ap = link->ap;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 new_tmp, tmp;
+
+ ata_std_postreset(link, class);
+
+ /* Make sure port's ATAPI bit is set appropriately */
+ new_tmp = tmp = readl(port_mmio + PORT_CMD);
+ if (*class == ATA_DEV_ATAPI)
+ new_tmp |= PORT_CMD_ATAPI;
+ else
+ new_tmp &= ~PORT_CMD_ATAPI;
+ if (new_tmp != tmp) {
+ writel(new_tmp, port_mmio + PORT_CMD);
+ readl(port_mmio + PORT_CMD); /* flush */
+ }
+}
+
+static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
+{
+ struct scatterlist *sg;
+ struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
+ unsigned int si;
+
+ VPRINTK("ENTER\n");
+
+ /*
+ * Next, the S/G list.
+ */
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ dma_addr_t addr = sg_dma_address(sg);
+ u32 sg_len = sg_dma_len(sg);
+
+ ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
+ ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
+ ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
+ }
+
+ return si;
+}
+
+static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+
+ if (!sata_pmp_attached(ap) || pp->fbs_enabled)
+ return ata_std_qc_defer(qc);
+ else
+ return sata_pmp_qc_defer_cmd_switch(qc);
+}
+
+static void ahci_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+ int is_atapi = ata_is_atapi(qc->tf.protocol);
+ void *cmd_tbl;
+ u32 opts;
+ const u32 cmd_fis_len = 5; /* five dwords */
+ unsigned int n_elem;
+
+ /*
+ * Fill in command table information. First, the header,
+ * a SATA Register - Host to Device command FIS.
+ */
+ cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
+
+ ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
+ if (is_atapi) {
+ memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
+ memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
+ }
+
+ n_elem = 0;
+ if (qc->flags & ATA_QCFLAG_DMAMAP)
+ n_elem = ahci_fill_sg(qc, cmd_tbl);
+
+ /*
+ * Fill in command slot information.
+ */
+ opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ opts |= AHCI_CMD_WRITE;
+ if (is_atapi)
+ opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
+
+ ahci_fill_cmd_slot(pp, qc->tag, opts);
+}
+
+static void ahci_fbs_dec_intr(struct ata_port *ap)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs = readl(port_mmio + PORT_FBS);
+ int retries = 3;
+
+ DPRINTK("ENTER\n");
+ BUG_ON(!pp->fbs_enabled);
+
+ /* time to wait for DEC is not specified by AHCI spec,
+ * add a retry loop for safety.
+ */
+ writel(fbs | PORT_FBS_DEC, port_mmio + PORT_FBS);
+ fbs = readl(port_mmio + PORT_FBS);
+ while ((fbs & PORT_FBS_DEC) && retries--) {
+ udelay(1);
+ fbs = readl(port_mmio + PORT_FBS);
+ }
+
+ if (fbs & PORT_FBS_DEC)
+ dev_err(ap->host->dev, "failed to clear device error\n");
+}
+
+static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ata_eh_info *host_ehi = &ap->link.eh_info;
+ struct ata_link *link = NULL;
+ struct ata_queued_cmd *active_qc;
+ struct ata_eh_info *active_ehi;
+ bool fbs_need_dec = false;
+ u32 serror;
+
+ /* determine active link with error */
+ if (pp->fbs_enabled) {
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs = readl(port_mmio + PORT_FBS);
+ int pmp = fbs >> PORT_FBS_DWE_OFFSET;
+
+ if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links)) {
+ link = &ap->pmp_link[pmp];
+ fbs_need_dec = true;
+ }
+
+ } else
+ ata_for_each_link(link, ap, EDGE)
+ if (ata_link_active(link))
+ break;
+
+ if (!link)
+ link = &ap->link;
+
+ active_qc = ata_qc_from_tag(ap, link->active_tag);
+ active_ehi = &link->eh_info;
+
+ /* record irq stat */
+ ata_ehi_clear_desc(host_ehi);
+ ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
+
+ /* AHCI needs SError cleared; otherwise, it might lock up */
+ ahci_scr_read(&ap->link, SCR_ERROR, &serror);
+ ahci_scr_write(&ap->link, SCR_ERROR, serror);
+ host_ehi->serror |= serror;
+
+ /* some controllers set IRQ_IF_ERR on device errors, ignore it */
+ if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
+ irq_stat &= ~PORT_IRQ_IF_ERR;
+
+ if (irq_stat & PORT_IRQ_TF_ERR) {
+ /* If qc is active, charge it; otherwise, the active
+ * link. There's no active qc on NCQ errors. It will
+ * be determined by EH by reading log page 10h.
+ */
+ if (active_qc)
+ active_qc->err_mask |= AC_ERR_DEV;
+ else
+ active_ehi->err_mask |= AC_ERR_DEV;
+
+ if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
+ host_ehi->serror &= ~SERR_INTERNAL;
+ }
+
+ if (irq_stat & PORT_IRQ_UNK_FIS) {
+ u32 *unk = pp->rx_fis + RX_FIS_UNK;
+
+ active_ehi->err_mask |= AC_ERR_HSM;
+ active_ehi->action |= ATA_EH_RESET;
+ ata_ehi_push_desc(active_ehi,
+ "unknown FIS %08x %08x %08x %08x" ,
+ unk[0], unk[1], unk[2], unk[3]);
+ }
+
+ if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
+ active_ehi->err_mask |= AC_ERR_HSM;
+ active_ehi->action |= ATA_EH_RESET;
+ ata_ehi_push_desc(active_ehi, "incorrect PMP");
+ }
+
+ if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
+ host_ehi->err_mask |= AC_ERR_HOST_BUS;
+ host_ehi->action |= ATA_EH_RESET;
+ ata_ehi_push_desc(host_ehi, "host bus error");
+ }
+
+ if (irq_stat & PORT_IRQ_IF_ERR) {
+ if (fbs_need_dec)
+ active_ehi->err_mask |= AC_ERR_DEV;
+ else {
+ host_ehi->err_mask |= AC_ERR_ATA_BUS;
+ host_ehi->action |= ATA_EH_RESET;
+ }
+
+ ata_ehi_push_desc(host_ehi, "interface fatal error");
+ }
+
+ if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
+ ata_ehi_hotplugged(host_ehi);
+ ata_ehi_push_desc(host_ehi, "%s",
+ irq_stat & PORT_IRQ_CONNECT ?
+ "connection status changed" : "PHY RDY changed");
+ }
+
+ /* okay, let's hand over to EH */
+
+ if (irq_stat & PORT_IRQ_FREEZE)
+ ata_port_freeze(ap);
+ else if (fbs_need_dec) {
+ ata_link_abort(link);
+ ahci_fbs_dec_intr(ap);
+ } else
+ ata_port_abort(ap);
+}
+
+static void ahci_handle_port_interrupt(struct ata_port *ap,
+ void __iomem *port_mmio, u32 status)
+{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
+ u32 qc_active = 0;
+ int rc;
+
+ /* ignore BAD_PMP while resetting */
+ if (unlikely(resetting))
+ status &= ~PORT_IRQ_BAD_PMP;
+
+ /* if LPM is enabled, PHYRDY doesn't mean anything */
+ if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) {
+ status &= ~PORT_IRQ_PHYRDY;
+ ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG);
+ }
+
+ if (unlikely(status & PORT_IRQ_ERROR)) {
+ ahci_error_intr(ap, status);
+ return;
+ }
+
+ if (status & PORT_IRQ_SDB_FIS) {
+ /* If SNotification is available, leave notification
+ * handling to sata_async_notification(). If not,
+ * emulate it by snooping SDB FIS RX area.
+ *
+ * Snooping FIS RX area is probably cheaper than
+ * poking SNotification but some constrollers which
+ * implement SNotification, ICH9 for example, don't
+ * store AN SDB FIS into receive area.
+ */
+ if (hpriv->cap & HOST_CAP_SNTF)
+ sata_async_notification(ap);
+ else {
+ /* If the 'N' bit in word 0 of the FIS is set,
+ * we just received asynchronous notification.
+ * Tell libata about it.
+ *
+ * Lack of SNotification should not appear in
+ * ahci 1.2, so the workaround is unnecessary
+ * when FBS is enabled.
+ */
+ if (pp->fbs_enabled)
+ WARN_ON_ONCE(1);
+ else {
+ const __le32 *f = pp->rx_fis + RX_FIS_SDB;
+ u32 f0 = le32_to_cpu(f[0]);
+ if (f0 & (1 << 15))
+ sata_async_notification(ap);
+ }
+ }
+ }
+
+ /* pp->active_link is not reliable once FBS is enabled, both
+ * PORT_SCR_ACT and PORT_CMD_ISSUE should be checked because
+ * NCQ and non-NCQ commands may be in flight at the same time.
+ */
+ if (pp->fbs_enabled) {
+ if (ap->qc_active) {
+ qc_active = readl(port_mmio + PORT_SCR_ACT);
+ qc_active |= readl(port_mmio + PORT_CMD_ISSUE);
+ }
+ } else {
+ /* pp->active_link is valid iff any command is in flight */
+ if (ap->qc_active && pp->active_link->sactive)
+ qc_active = readl(port_mmio + PORT_SCR_ACT);
+ else
+ qc_active = readl(port_mmio + PORT_CMD_ISSUE);
+ }
+
+
+ rc = ata_qc_complete_multiple(ap, qc_active);
+
+ /* while resetting, invalid completions are expected */
+ if (unlikely(rc < 0 && !resetting)) {
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_RESET;
+ ata_port_freeze(ap);
+ }
+}
+
+static void ahci_port_intr(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 status;
+
+ status = readl(port_mmio + PORT_IRQ_STAT);
+ writel(status, port_mmio + PORT_IRQ_STAT);
+
+ ahci_handle_port_interrupt(ap, port_mmio, status);
+}
+
+irqreturn_t ahci_thread_fn(int irq, void *dev_instance)
+{
+ struct ata_port *ap = dev_instance;
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ unsigned long flags;
+ u32 status;
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ status = pp->intr_status;
+ if (status)
+ pp->intr_status = 0;
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+
+ spin_lock_bh(ap->lock);
+ ahci_handle_port_interrupt(ap, port_mmio, status);
+ spin_unlock_bh(ap->lock);
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(ahci_thread_fn);
+
+static void ahci_hw_port_interrupt(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 status;
+
+ status = readl(port_mmio + PORT_IRQ_STAT);
+ writel(status, port_mmio + PORT_IRQ_STAT);
+
+ pp->intr_status |= status;
+}
+
+irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance)
+{
+ struct ata_port *ap_this = dev_instance;
+ struct ahci_port_priv *pp = ap_this->private_data;
+ struct ata_host *host = ap_this->host;
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ unsigned int i;
+ u32 irq_stat, irq_masked;
+
+ VPRINTK("ENTER\n");
+
+ spin_lock(&host->lock);
+
+ irq_stat = readl(mmio + HOST_IRQ_STAT);
+
+ if (!irq_stat) {
+ u32 status = pp->intr_status;
+
+ spin_unlock(&host->lock);
+
+ VPRINTK("EXIT\n");
+
+ return status ? IRQ_WAKE_THREAD : IRQ_NONE;
+ }
+
+ irq_masked = irq_stat & hpriv->port_map;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap;
+
+ if (!(irq_masked & (1 << i)))
+ continue;
+
+ ap = host->ports[i];
+ if (ap) {
+ ahci_hw_port_interrupt(ap);
+ VPRINTK("port %u\n", i);
+ } else {
+ VPRINTK("port %u (no irq)\n", i);
+ if (ata_ratelimit())
+ dev_warn(host->dev,
+ "interrupt on disabled port %u\n", i);
+ }
+ }
+
+ writel(irq_stat, mmio + HOST_IRQ_STAT);
+
+ spin_unlock(&host->lock);
+
+ VPRINTK("EXIT\n");
+
+ return IRQ_WAKE_THREAD;
+}
+EXPORT_SYMBOL_GPL(ahci_hw_interrupt);
+
+irqreturn_t ahci_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ struct ahci_host_priv *hpriv;
+ unsigned int i, handled = 0;
+ void __iomem *mmio;
+ u32 irq_stat, irq_masked;
+
+ VPRINTK("ENTER\n");
+
+ hpriv = host->private_data;
+ mmio = hpriv->mmio;
+
+ /* sigh. 0xffffffff is a valid return from h/w */
+ irq_stat = readl(mmio + HOST_IRQ_STAT);
+ if (!irq_stat)
+ return IRQ_NONE;
+
+ irq_masked = irq_stat & hpriv->port_map;
+
+ spin_lock(&host->lock);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap;
+
+ if (!(irq_masked & (1 << i)))
+ continue;
+
+ ap = host->ports[i];
+ if (ap) {
+ ahci_port_intr(ap);
+ VPRINTK("port %u\n", i);
+ } else {
+ VPRINTK("port %u (no irq)\n", i);
+ if (ata_ratelimit())
+ dev_warn(host->dev,
+ "interrupt on disabled port %u\n", i);
+ }
+
+ handled = 1;
+ }
+
+ /* HOST_IRQ_STAT behaves as level triggered latch meaning that
+ * it should be cleared after all the port events are cleared;
+ * otherwise, it will raise a spurious interrupt after each
+ * valid one. Please read section 10.6.2 of ahci 1.1 for more
+ * information.
+ *
+ * Also, use the unmasked value to clear interrupt as spurious
+ * pending event on a dummy port might cause screaming IRQ.
+ */
+ writel(irq_stat, mmio + HOST_IRQ_STAT);
+
+ spin_unlock(&host->lock);
+
+ VPRINTK("EXIT\n");
+
+ return IRQ_RETVAL(handled);
+}
+EXPORT_SYMBOL_GPL(ahci_interrupt);
+
+unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+
+ /* Keep track of the currently active link. It will be used
+ * in completion path to determine whether NCQ phase is in
+ * progress.
+ */
+ pp->active_link = qc->dev->link;
+
+ if (qc->tf.protocol == ATA_PROT_NCQ)
+ writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
+
+ if (pp->fbs_enabled && pp->fbs_last_dev != qc->dev->link->pmp) {
+ u32 fbs = readl(port_mmio + PORT_FBS);
+ fbs &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC);
+ fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET;
+ writel(fbs, port_mmio + PORT_FBS);
+ pp->fbs_last_dev = qc->dev->link->pmp;
+ }
+
+ writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
+
+ ahci_sw_activity(qc->dev->link);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ahci_qc_issue);
+
+static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
+{
+ struct ahci_port_priv *pp = qc->ap->private_data;
+ u8 *rx_fis = pp->rx_fis;
+
+ if (pp->fbs_enabled)
+ rx_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
+
+ /*
+ * After a successful execution of an ATA PIO data-in command,
+ * the device doesn't send D2H Reg FIS to update the TF and
+ * the host should take TF and E_Status from the preceding PIO
+ * Setup FIS.
+ */
+ if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE &&
+ !(qc->flags & ATA_QCFLAG_FAILED)) {
+ ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
+ qc->result_tf.command = (rx_fis + RX_FIS_PIO_SETUP)[15];
+ } else
+ ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
+
+ return true;
+}
+
+static void ahci_freeze(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+
+ /* turn IRQ off */
+ writel(0, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ahci_thaw(struct ata_port *ap)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 tmp;
+ struct ahci_port_priv *pp = ap->private_data;
+
+ /* clear IRQ */
+ tmp = readl(port_mmio + PORT_IRQ_STAT);
+ writel(tmp, port_mmio + PORT_IRQ_STAT);
+ writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
+
+ /* turn IRQ back on */
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
+void ahci_error_handler(struct ata_port *ap)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
+ if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
+ /* restart engine */
+ ahci_stop_engine(ap);
+ hpriv->start_engine(ap);
+ }
+
+ sata_pmp_error_handler(ap);
+
+ if (!ata_dev_enabled(ap->link.device))
+ ahci_stop_engine(ap);
+}
+EXPORT_SYMBOL_GPL(ahci_error_handler);
+
+static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ /* make DMA engine forget about the failed command */
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ ahci_kick_engine(ap);
+}
+
+static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ata_device *dev = ap->link.device;
+ u32 devslp, dm, dito, mdat, deto;
+ int rc;
+ unsigned int err_mask;
+
+ devslp = readl(port_mmio + PORT_DEVSLP);
+ if (!(devslp & PORT_DEVSLP_DSP)) {
+ dev_err(ap->host->dev, "port does not support device sleep\n");
+ return;
+ }
+
+ /* disable device sleep */
+ if (!sleep) {
+ if (devslp & PORT_DEVSLP_ADSE) {
+ writel(devslp & ~PORT_DEVSLP_ADSE,
+ port_mmio + PORT_DEVSLP);
+ err_mask = ata_dev_set_feature(dev,
+ SETFEATURES_SATA_DISABLE,
+ SATA_DEVSLP);
+ if (err_mask && err_mask != AC_ERR_DEV)
+ ata_dev_warn(dev, "failed to disable DEVSLP\n");
+ }
+ return;
+ }
+
+ /* device sleep was already enabled */
+ if (devslp & PORT_DEVSLP_ADSE)
+ return;
+
+ /* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */
+ rc = ahci_stop_engine(ap);
+ if (rc)
+ return;
+
+ dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET;
+ dito = devslp_idle_timeout / (dm + 1);
+ if (dito > 0x3ff)
+ dito = 0x3ff;
+
+ /* Use the nominal value 10 ms if the read MDAT is zero,
+ * the nominal value of DETO is 20 ms.
+ */
+ if (dev->devslp_timing[ATA_LOG_DEVSLP_VALID] &
+ ATA_LOG_DEVSLP_VALID_MASK) {
+ mdat = dev->devslp_timing[ATA_LOG_DEVSLP_MDAT] &
+ ATA_LOG_DEVSLP_MDAT_MASK;
+ if (!mdat)
+ mdat = 10;
+ deto = dev->devslp_timing[ATA_LOG_DEVSLP_DETO];
+ if (!deto)
+ deto = 20;
+ } else {
+ mdat = 10;
+ deto = 20;
+ }
+
+ devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) |
+ (mdat << PORT_DEVSLP_MDAT_OFFSET) |
+ (deto << PORT_DEVSLP_DETO_OFFSET) |
+ PORT_DEVSLP_ADSE);
+ writel(devslp, port_mmio + PORT_DEVSLP);
+
+ hpriv->start_engine(ap);
+
+ /* enable device sleep feature for the drive */
+ err_mask = ata_dev_set_feature(dev,
+ SETFEATURES_SATA_ENABLE,
+ SATA_DEVSLP);
+ if (err_mask && err_mask != AC_ERR_DEV)
+ ata_dev_warn(dev, "failed to enable DEVSLP\n");
+}
+
+static void ahci_enable_fbs(struct ata_port *ap)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs;
+ int rc;
+
+ if (!pp->fbs_supported)
+ return;
+
+ fbs = readl(port_mmio + PORT_FBS);
+ if (fbs & PORT_FBS_EN) {
+ pp->fbs_enabled = true;
+ pp->fbs_last_dev = -1; /* initialization */
+ return;
+ }
+
+ rc = ahci_stop_engine(ap);
+ if (rc)
+ return;
+
+ writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS);
+ fbs = readl(port_mmio + PORT_FBS);
+ if (fbs & PORT_FBS_EN) {
+ dev_info(ap->host->dev, "FBS is enabled\n");
+ pp->fbs_enabled = true;
+ pp->fbs_last_dev = -1; /* initialization */
+ } else
+ dev_err(ap->host->dev, "Failed to enable FBS\n");
+
+ hpriv->start_engine(ap);
+}
+
+static void ahci_disable_fbs(struct ata_port *ap)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs;
+ int rc;
+
+ if (!pp->fbs_supported)
+ return;
+
+ fbs = readl(port_mmio + PORT_FBS);
+ if ((fbs & PORT_FBS_EN) == 0) {
+ pp->fbs_enabled = false;
+ return;
+ }
+
+ rc = ahci_stop_engine(ap);
+ if (rc)
+ return;
+
+ writel(fbs & ~PORT_FBS_EN, port_mmio + PORT_FBS);
+ fbs = readl(port_mmio + PORT_FBS);
+ if (fbs & PORT_FBS_EN)
+ dev_err(ap->host->dev, "Failed to disable FBS\n");
+ else {
+ dev_info(ap->host->dev, "FBS is disabled\n");
+ pp->fbs_enabled = false;
+ }
+
+ hpriv->start_engine(ap);
+}
+
+static void ahci_pmp_attach(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 cmd;
+
+ cmd = readl(port_mmio + PORT_CMD);
+ cmd |= PORT_CMD_PMP;
+ writel(cmd, port_mmio + PORT_CMD);
+
+ ahci_enable_fbs(ap);
+
+ pp->intr_mask |= PORT_IRQ_BAD_PMP;
+
+ /*
+ * We must not change the port interrupt mask register if the
+ * port is marked frozen, the value in pp->intr_mask will be
+ * restored later when the port is thawed.
+ *
+ * Note that during initialization, the port is marked as
+ * frozen since the irq handler is not yet registered.
+ */
+ if (!(ap->pflags & ATA_PFLAG_FROZEN))
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ahci_pmp_detach(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 cmd;
+
+ ahci_disable_fbs(ap);
+
+ cmd = readl(port_mmio + PORT_CMD);
+ cmd &= ~PORT_CMD_PMP;
+ writel(cmd, port_mmio + PORT_CMD);
+
+ pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
+
+ /* see comment above in ahci_pmp_attach() */
+ if (!(ap->pflags & ATA_PFLAG_FROZEN))
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
+int ahci_port_resume(struct ata_port *ap)
+{
+ ahci_power_up(ap);
+ ahci_start_port(ap);
+
+ if (sata_pmp_attached(ap))
+ ahci_pmp_attach(ap);
+ else
+ ahci_pmp_detach(ap);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ahci_port_resume);
+
+#ifdef CONFIG_PM
+static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
+{
+ const char *emsg = NULL;
+ int rc;
+
+ rc = ahci_deinit_port(ap, &emsg);
+ if (rc == 0)
+ ahci_power_down(ap);
+ else {
+ ata_port_err(ap, "%s (%d)\n", emsg, rc);
+ ata_port_freeze(ap);
+ }
+
+ return rc;
+}
+#endif
+
+static int ahci_port_start(struct ata_port *ap)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct device *dev = ap->host->dev;
+ struct ahci_port_priv *pp;
+ void *mem;
+ dma_addr_t mem_dma;
+ size_t dma_sz, rx_fis_sz;
+
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+
+ if (ap->host->n_ports > 1) {
+ pp->irq_desc = devm_kzalloc(dev, 8, GFP_KERNEL);
+ if (!pp->irq_desc) {
+ devm_kfree(dev, pp);
+ return -ENOMEM;
+ }
+ snprintf(pp->irq_desc, 8,
+ "%s%d", dev_driver_string(dev), ap->port_no);
+ }
+
+ /* check FBS capability */
+ if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) {
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 cmd = readl(port_mmio + PORT_CMD);
+ if (cmd & PORT_CMD_FBSCP)
+ pp->fbs_supported = true;
+ else if (hpriv->flags & AHCI_HFLAG_YES_FBS) {
+ dev_info(dev, "port %d can do FBS, forcing FBSCP\n",
+ ap->port_no);
+ pp->fbs_supported = true;
+ } else
+ dev_warn(dev, "port %d is not capable of FBS\n",
+ ap->port_no);
+ }
+
+ if (pp->fbs_supported) {
+ dma_sz = AHCI_PORT_PRIV_FBS_DMA_SZ;
+ rx_fis_sz = AHCI_RX_FIS_SZ * 16;
+ } else {
+ dma_sz = AHCI_PORT_PRIV_DMA_SZ;
+ rx_fis_sz = AHCI_RX_FIS_SZ;
+ }
+
+ mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
+ memset(mem, 0, dma_sz);
+
+ /*
+ * First item in chunk of DMA memory: 32-slot command table,
+ * 32 bytes each in size
+ */
+ pp->cmd_slot = mem;
+ pp->cmd_slot_dma = mem_dma;
+
+ mem += AHCI_CMD_SLOT_SZ;
+ mem_dma += AHCI_CMD_SLOT_SZ;
+
+ /*
+ * Second item: Received-FIS area
+ */
+ pp->rx_fis = mem;
+ pp->rx_fis_dma = mem_dma;
+
+ mem += rx_fis_sz;
+ mem_dma += rx_fis_sz;
+
+ /*
+ * Third item: data area for storing a single command
+ * and its scatter-gather table
+ */
+ pp->cmd_tbl = mem;
+ pp->cmd_tbl_dma = mem_dma;
+
+ /*
+ * Save off initial list of interrupts to be enabled.
+ * This could be changed later
+ */
+ pp->intr_mask = DEF_PORT_IRQ;
+
+ /*
+ * Switch to per-port locking in case each port has its own MSI vector.
+ */
+ if ((hpriv->flags & AHCI_HFLAG_MULTI_MSI)) {
+ spin_lock_init(&pp->lock);
+ ap->lock = &pp->lock;
+ }
+
+ ap->private_data = pp;
+
+ /* engage engines, captain */
+ return ahci_port_resume(ap);
+}
+
+static void ahci_port_stop(struct ata_port *ap)
+{
+ const char *emsg = NULL;
+ int rc;
+
+ /* de-initialize port */
+ rc = ahci_deinit_port(ap, &emsg);
+ if (rc)
+ ata_port_warn(ap, "%s (%d)\n", emsg, rc);
+}
+
+void ahci_print_info(struct ata_host *host, const char *scc_s)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ u32 vers, cap, cap2, impl, speed;
+ const char *speed_s;
+
+ vers = readl(mmio + HOST_VERSION);
+ cap = hpriv->cap;
+ cap2 = hpriv->cap2;
+ impl = hpriv->port_map;
+
+ speed = (cap >> 20) & 0xf;
+ if (speed == 1)
+ speed_s = "1.5";
+ else if (speed == 2)
+ speed_s = "3";
+ else if (speed == 3)
+ speed_s = "6";
+ else
+ speed_s = "?";
+
+ dev_info(host->dev,
+ "AHCI %02x%02x.%02x%02x "
+ "%u slots %u ports %s Gbps 0x%x impl %s mode\n"
+ ,
+
+ (vers >> 24) & 0xff,
+ (vers >> 16) & 0xff,
+ (vers >> 8) & 0xff,
+ vers & 0xff,
+
+ ((cap >> 8) & 0x1f) + 1,
+ (cap & 0x1f) + 1,
+ speed_s,
+ impl,
+ scc_s);
+
+ dev_info(host->dev,
+ "flags: "
+ "%s%s%s%s%s%s%s"
+ "%s%s%s%s%s%s%s"
+ "%s%s%s%s%s%s%s"
+ "%s%s\n"
+ ,
+
+ cap & HOST_CAP_64 ? "64bit " : "",
+ cap & HOST_CAP_NCQ ? "ncq " : "",
+ cap & HOST_CAP_SNTF ? "sntf " : "",
+ cap & HOST_CAP_MPS ? "ilck " : "",
+ cap & HOST_CAP_SSS ? "stag " : "",
+ cap & HOST_CAP_ALPM ? "pm " : "",
+ cap & HOST_CAP_LED ? "led " : "",
+ cap & HOST_CAP_CLO ? "clo " : "",
+ cap & HOST_CAP_ONLY ? "only " : "",
+ cap & HOST_CAP_PMP ? "pmp " : "",
+ cap & HOST_CAP_FBS ? "fbs " : "",
+ cap & HOST_CAP_PIO_MULTI ? "pio " : "",
+ cap & HOST_CAP_SSC ? "slum " : "",
+ cap & HOST_CAP_PART ? "part " : "",
+ cap & HOST_CAP_CCC ? "ccc " : "",
+ cap & HOST_CAP_EMS ? "ems " : "",
+ cap & HOST_CAP_SXS ? "sxs " : "",
+ cap2 & HOST_CAP2_DESO ? "deso " : "",
+ cap2 & HOST_CAP2_SADM ? "sadm " : "",
+ cap2 & HOST_CAP2_SDS ? "sds " : "",
+ cap2 & HOST_CAP2_APST ? "apst " : "",
+ cap2 & HOST_CAP2_NVMHCI ? "nvmp " : "",
+ cap2 & HOST_CAP2_BOH ? "boh " : ""
+ );
+}
+EXPORT_SYMBOL_GPL(ahci_print_info);
+
+void ahci_set_em_messages(struct ahci_host_priv *hpriv,
+ struct ata_port_info *pi)
+{
+ u8 messages;
+ void __iomem *mmio = hpriv->mmio;
+ u32 em_loc = readl(mmio + HOST_EM_LOC);
+ u32 em_ctl = readl(mmio + HOST_EM_CTL);
+
+ if (!ahci_em_messages || !(hpriv->cap & HOST_CAP_EMS))
+ return;
+
+ messages = (em_ctl & EM_CTRL_MSG_TYPE) >> 16;
+
+ if (messages) {
+ /* store em_loc */
+ hpriv->em_loc = ((em_loc >> 16) * 4);
+ hpriv->em_buf_sz = ((em_loc & 0xff) * 4);
+ hpriv->em_msg_type = messages;
+ pi->flags |= ATA_FLAG_EM;
+ if (!(em_ctl & EM_CTL_ALHD))
+ pi->flags |= ATA_FLAG_SW_ACTIVITY;
+ }
+}
+EXPORT_SYMBOL_GPL(ahci_set_em_messages);
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("Common AHCI SATA low-level routines");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
new file mode 100644
index 00000000000..b0077589f06
--- /dev/null
+++ b/drivers/ata/libahci_platform.c
@@ -0,0 +1,549 @@
+/*
+ * AHCI SATA platform library
+ *
+ * Copyright 2004-2005 Red Hat, Inc.
+ * Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2010 MontaVista Software, LLC.
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/pm_runtime.h>
+#include "ahci.h"
+
+static void ahci_host_stop(struct ata_host *host);
+
+struct ata_port_operations ahci_platform_ops = {
+ .inherits = &ahci_ops,
+ .host_stop = ahci_host_stop,
+};
+EXPORT_SYMBOL_GPL(ahci_platform_ops);
+
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT("ahci_platform"),
+};
+
+/**
+ * ahci_platform_enable_clks - Enable platform clocks
+ * @hpriv: host private area to store config values
+ *
+ * This function enables all the clks found in hpriv->clks, starting at
+ * index 0. If any clk fails to enable it disables all the clks already
+ * enabled in reverse order, and then returns an error.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
+{
+ int c, rc;
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
+ rc = clk_prepare_enable(hpriv->clks[c]);
+ if (rc)
+ goto disable_unprepare_clk;
+ }
+ return 0;
+
+disable_unprepare_clk:
+ while (--c >= 0)
+ clk_disable_unprepare(hpriv->clks[c]);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
+
+/**
+ * ahci_platform_disable_clks - Disable platform clocks
+ * @hpriv: host private area to store config values
+ *
+ * This function disables all the clks found in hpriv->clks, in reverse
+ * order of ahci_platform_enable_clks (starting at the end of the array).
+ */
+void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
+{
+ int c;
+
+ for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
+ if (hpriv->clks[c])
+ clk_disable_unprepare(hpriv->clks[c]);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
+
+/**
+ * ahci_platform_enable_resources - Enable platform resources
+ * @hpriv: host private area to store config values
+ *
+ * This function enables all ahci_platform managed resources in the
+ * following order:
+ * 1) Regulator
+ * 2) Clocks (through ahci_platform_enable_clks)
+ * 3) Phy
+ *
+ * If resource enabling fails at any point the previous enabled resources
+ * are disabled in reverse order.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
+{
+ int rc;
+
+ if (hpriv->target_pwr) {
+ rc = regulator_enable(hpriv->target_pwr);
+ if (rc)
+ return rc;
+ }
+
+ rc = ahci_platform_enable_clks(hpriv);
+ if (rc)
+ goto disable_regulator;
+
+ if (hpriv->phy) {
+ rc = phy_init(hpriv->phy);
+ if (rc)
+ goto disable_clks;
+
+ rc = phy_power_on(hpriv->phy);
+ if (rc) {
+ phy_exit(hpriv->phy);
+ goto disable_clks;
+ }
+ }
+
+ return 0;
+
+disable_clks:
+ ahci_platform_disable_clks(hpriv);
+
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
+
+/**
+ * ahci_platform_disable_resources - Disable platform resources
+ * @hpriv: host private area to store config values
+ *
+ * This function disables all ahci_platform managed resources in the
+ * following order:
+ * 1) Phy
+ * 2) Clocks (through ahci_platform_disable_clks)
+ * 3) Regulator
+ */
+void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
+{
+ if (hpriv->phy) {
+ phy_power_off(hpriv->phy);
+ phy_exit(hpriv->phy);
+ }
+
+ ahci_platform_disable_clks(hpriv);
+
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
+
+static void ahci_platform_put_resources(struct device *dev, void *res)
+{
+ struct ahci_host_priv *hpriv = res;
+ int c;
+
+ if (hpriv->got_runtime_pm) {
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+ }
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
+ clk_put(hpriv->clks[c]);
+}
+
+/**
+ * ahci_platform_get_resources - Get platform resources
+ * @pdev: platform device to get resources for
+ *
+ * This function allocates an ahci_host_priv struct, and gets the following
+ * resources, storing a reference to them inside the returned struct:
+ *
+ * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
+ * 2) regulator for controlling the targets power (optional)
+ * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
+ * or for non devicetree enabled platforms a single clock
+ * 4) phy (optional)
+ *
+ * RETURNS:
+ * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
+ */
+struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct clk *clk;
+ int i, rc = -ENOMEM;
+
+ if (!devres_open_group(dev, NULL, GFP_KERNEL))
+ return ERR_PTR(-ENOMEM);
+
+ hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
+ GFP_KERNEL);
+ if (!hpriv)
+ goto err_out;
+
+ devres_add(dev, hpriv);
+
+ hpriv->mmio = devm_ioremap_resource(dev,
+ platform_get_resource(pdev, IORESOURCE_MEM, 0));
+ if (IS_ERR(hpriv->mmio)) {
+ dev_err(dev, "no mmio space\n");
+ rc = PTR_ERR(hpriv->mmio);
+ goto err_out;
+ }
+
+ hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
+ if (IS_ERR(hpriv->target_pwr)) {
+ rc = PTR_ERR(hpriv->target_pwr);
+ if (rc == -EPROBE_DEFER)
+ goto err_out;
+ hpriv->target_pwr = NULL;
+ }
+
+ for (i = 0; i < AHCI_MAX_CLKS; i++) {
+ /*
+ * For now we must use clk_get(dev, NULL) for the first clock,
+ * because some platforms (da850, spear13xx) are not yet
+ * converted to use devicetree for clocks. For new platforms
+ * this is equivalent to of_clk_get(dev->of_node, 0).
+ */
+ if (i == 0)
+ clk = clk_get(dev, NULL);
+ else
+ clk = of_clk_get(dev->of_node, i);
+
+ if (IS_ERR(clk)) {
+ rc = PTR_ERR(clk);
+ if (rc == -EPROBE_DEFER)
+ goto err_out;
+ break;
+ }
+ hpriv->clks[i] = clk;
+ }
+
+ hpriv->phy = devm_phy_get(dev, "sata-phy");
+ if (IS_ERR(hpriv->phy)) {
+ rc = PTR_ERR(hpriv->phy);
+ switch (rc) {
+ case -ENOSYS:
+ /* No PHY support. Check if PHY is required. */
+ if (of_find_property(dev->of_node, "phys", NULL)) {
+ dev_err(dev, "couldn't get sata-phy: ENOSYS\n");
+ goto err_out;
+ }
+ case -ENODEV:
+ /* continue normally */
+ hpriv->phy = NULL;
+ break;
+
+ case -EPROBE_DEFER:
+ goto err_out;
+
+ default:
+ dev_err(dev, "couldn't get sata-phy\n");
+ goto err_out;
+ }
+ }
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+ hpriv->got_runtime_pm = true;
+
+ devres_remove_group(dev, NULL);
+ return hpriv;
+
+err_out:
+ devres_release_group(dev, NULL);
+ return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
+
+/**
+ * ahci_platform_init_host - Bring up an ahci-platform host
+ * @pdev: platform device pointer for the host
+ * @hpriv: ahci-host private data for the host
+ * @pi_template: template for the ata_port_info to use
+ * @host_flags: ahci host flags used in ahci_host_priv
+ * @force_port_map: param passed to ahci_save_initial_config
+ * @mask_port_map: param passed to ahci_save_initial_config
+ *
+ * This function does all the usual steps needed to bring up an
+ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
+ * must be initialized / enabled before calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_init_host(struct platform_device *pdev,
+ struct ahci_host_priv *hpriv,
+ const struct ata_port_info *pi_template,
+ unsigned long host_flags,
+ unsigned int force_port_map,
+ unsigned int mask_port_map)
+{
+ struct device *dev = &pdev->dev;
+ struct ata_port_info pi = *pi_template;
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+ struct ata_host *host;
+ int i, irq, n_ports, rc;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(dev, "no irq\n");
+ return -EINVAL;
+ }
+
+ /* prepare host */
+ pi.private_data = (void *)host_flags;
+ hpriv->flags |= host_flags;
+
+ ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map);
+
+ if (hpriv->cap & HOST_CAP_NCQ)
+ pi.flags |= ATA_FLAG_NCQ;
+
+ if (hpriv->cap & HOST_CAP_PMP)
+ pi.flags |= ATA_FLAG_PMP;
+
+ ahci_set_em_messages(hpriv, &pi);
+
+ /* CAP.NP sometimes indicate the index of the last enabled
+ * port, at other times, that of the last possible port, so
+ * determining the maximum port number requires looking at
+ * both CAP.NP and port_map.
+ */
+ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+ host = ata_host_alloc_pinfo(dev, ppi, n_ports);
+ if (!host)
+ return -ENOMEM;
+
+ host->private_data = hpriv;
+
+ if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+ else
+ dev_info(dev, "SSS flag set, parallel bus scan disabled\n");
+
+ if (pi.flags & ATA_FLAG_EM)
+ ahci_reset_em(host);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ ata_port_desc(ap, "mmio %pR",
+ platform_get_resource(pdev, IORESOURCE_MEM, 0));
+ ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
+
+ /* set enclosure management message type */
+ if (ap->flags & ATA_FLAG_EM)
+ ap->em_message_type = hpriv->em_msg_type;
+
+ /* disabled/not-implemented port */
+ if (!(hpriv->port_map & (1 << i)))
+ ap->ops = &ata_dummy_port_ops;
+ }
+
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(host);
+ ahci_print_info(host, "platform");
+
+ return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
+ &ahci_platform_sht);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_init_host);
+
+static void ahci_host_stop(struct ata_host *host)
+{
+ struct device *dev = host->dev;
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+
+ if (pdata && pdata->exit)
+ pdata->exit(dev);
+
+ ahci_platform_disable_resources(hpriv);
+}
+
+#ifdef CONFIG_PM_SLEEP
+/**
+ * ahci_platform_suspend_host - Suspend an ahci-platform host
+ * @dev: device pointer for the host
+ *
+ * This function does all the usual steps needed to suspend an
+ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
+ * must be disabled after calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_suspend_host(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ u32 ctl;
+
+ if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
+ dev_err(dev, "firmware update required for suspend/resume\n");
+ return -EIO;
+ }
+
+ /*
+ * AHCI spec rev1.1 section 8.3.3:
+ * Software must disable interrupts prior to requesting a
+ * transition of the HBA to D3 state.
+ */
+ ctl = readl(mmio + HOST_CTL);
+ ctl &= ~HOST_IRQ_EN;
+ writel(ctl, mmio + HOST_CTL);
+ readl(mmio + HOST_CTL); /* flush */
+
+ return ata_host_suspend(host, PMSG_SUSPEND);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
+
+/**
+ * ahci_platform_resume_host - Resume an ahci-platform host
+ * @dev: device pointer for the host
+ *
+ * This function does all the usual steps needed to resume an ahci-platform
+ * host, note any necessary resources (ie clks, phy, etc.) must be
+ * initialized / enabled before calling this.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_resume_host(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ int rc;
+
+ if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(host);
+ }
+
+ ata_host_resume(host);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
+
+/**
+ * ahci_platform_suspend - Suspend an ahci-platform device
+ * @dev: the platform device to suspend
+ *
+ * This function suspends the host associated with the device, followed by
+ * disabling all the resources of the device.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_suspend(struct device *dev)
+{
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
+ rc = ahci_platform_suspend_host(dev);
+ if (rc)
+ return rc;
+
+ if (pdata && pdata->suspend) {
+ rc = pdata->suspend(dev);
+ if (rc)
+ goto resume_host;
+ }
+
+ ahci_platform_disable_resources(hpriv);
+
+ return 0;
+
+resume_host:
+ ahci_platform_resume_host(dev);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_suspend);
+
+/**
+ * ahci_platform_resume - Resume an ahci-platform device
+ * @dev: the platform device to resume
+ *
+ * This function enables all the resources of the device followed by
+ * resuming the host associated with the device.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_resume(struct device *dev)
+{
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ if (pdata && pdata->resume) {
+ rc = pdata->resume(dev);
+ if (rc)
+ goto disable_resources;
+ }
+
+ rc = ahci_platform_resume_host(dev);
+ if (rc)
+ goto disable_resources;
+
+ /* We resumed so update PM runtime state */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_resume);
+#endif
+
+MODULE_DESCRIPTION("AHCI SATA platform library");
+MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 8c1cfc645c8..97a14fe47de 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -15,28 +15,14 @@
#include <linux/acpi.h>
#include <linux/libata.h>
#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
#include <scsi/scsi_device.h>
#include "libata.h"
-#include <acpi/acpi_bus.h>
-#include <acpi/acnames.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acparser.h>
-#include <acpi/acexcep.h>
-#include <acpi/acmacros.h>
-#include <acpi/actypes.h>
-
-enum {
- ATA_ACPI_FILTER_SETXFER = 1 << 0,
- ATA_ACPI_FILTER_LOCK = 1 << 1,
-
- ATA_ACPI_FILTER_DEFAULT = ATA_ACPI_FILTER_SETXFER |
- ATA_ACPI_FILTER_LOCK,
-};
-
-static unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT;
+unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT;
module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644);
-MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock)");
+MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM, 0x8=FPDMA non-zero offset, 0x10=FPDMA DMA Setup FIS auto-activate)");
#define NO_PORT_MULT 0xffff
#define SATA_ADR(root, pmp) (((root) << 16) | (pmp))
@@ -46,120 +32,125 @@ struct ata_acpi_gtf {
u8 tf[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
} __packed;
-/*
- * Helper - belongs in the PCI layer somewhere eventually
- */
-static int is_pci_dev(struct device *dev)
-{
- return (dev->bus == &pci_bus_type);
-}
-
static void ata_acpi_clear_gtf(struct ata_device *dev)
{
kfree(dev->gtf_cache);
dev->gtf_cache = NULL;
}
+struct ata_acpi_hotplug_context {
+ struct acpi_hotplug_context hp;
+ union {
+ struct ata_port *ap;
+ struct ata_device *dev;
+ } data;
+};
+
+#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data)
+
/**
- * ata_acpi_associate_sata_port - associate SATA port with ACPI objects
- * @ap: target SATA port
- *
- * Look up ACPI objects associated with @ap and initialize acpi_handle
- * fields of @ap, the port and devices accordingly.
- *
- * LOCKING:
- * EH context.
+ * ata_dev_acpi_handle - provide the acpi_handle for an ata_device
+ * @dev: the acpi_handle returned will correspond to this device
*
- * RETURNS:
- * 0 on success, -errno on failure.
+ * Returns the acpi_handle for the ACPI namespace object corresponding to
+ * the ata_device passed into the function, or NULL if no such object exists
+ * or ACPI is disabled for this device due to consecutive errors.
*/
-void ata_acpi_associate_sata_port(struct ata_port *ap)
+acpi_handle ata_dev_acpi_handle(struct ata_device *dev)
{
- WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA));
-
- if (!sata_pmp_attached(ap)) {
- acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
-
- ap->link.device->acpi_handle =
- acpi_get_child(ap->host->acpi_handle, adr);
- } else {
- struct ata_link *link;
-
- ap->link.device->acpi_handle = NULL;
-
- ata_port_for_each_link(link, ap) {
- acpi_integer adr = SATA_ADR(ap->port_no, link->pmp);
-
- link->device->acpi_handle =
- acpi_get_child(ap->host->acpi_handle, adr);
- }
- }
+ return dev->flags & ATA_DFLAG_ACPI_DISABLED ?
+ NULL : ACPI_HANDLE(&dev->tdev);
}
-static void ata_acpi_associate_ide_port(struct ata_port *ap)
+/* @ap and @dev are the same as ata_acpi_handle_hotplug() */
+static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
{
- int max_devices, i;
-
- ap->acpi_handle = acpi_get_child(ap->host->acpi_handle, ap->port_no);
- if (!ap->acpi_handle)
- return;
-
- max_devices = 1;
- if (ap->flags & ATA_FLAG_SLAVE_POSS)
- max_devices++;
-
- for (i = 0; i < max_devices; i++) {
- struct ata_device *dev = &ap->link.device[i];
-
- dev->acpi_handle = acpi_get_child(ap->acpi_handle, i);
+ if (dev)
+ dev->flags |= ATA_DFLAG_DETACH;
+ else {
+ struct ata_link *tlink;
+ struct ata_device *tdev;
+
+ ata_for_each_link(tlink, ap, EDGE)
+ ata_for_each_dev(tdev, tlink, ALL)
+ tdev->flags |= ATA_DFLAG_DETACH;
}
- if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
- ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
+ ata_port_schedule_eh(ap);
}
+/**
+ * ata_acpi_handle_hotplug - ACPI event handler backend
+ * @ap: ATA port ACPI event occurred
+ * @dev: ATA device ACPI event occurred (can be NULL)
+ * @event: ACPI event which occurred
+ *
+ * All ACPI bay / device realted events end up in this function. If
+ * the event is port-wide @dev is NULL. If the event is specific to a
+ * device, @dev points to it.
+ *
+ * Hotplug (as opposed to unplug) notification is always handled as
+ * port-wide while unplug only kills the target device on device-wide
+ * event.
+ *
+ * LOCKING:
+ * ACPI notify handler context. May sleep.
+ */
static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
u32 event)
{
- char event_string[12];
- char *envp[] = { event_string, NULL };
- struct ata_eh_info *ehi;
- struct kobject *kobj = NULL;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
int wait = 0;
unsigned long flags;
- if (!ap)
- ap = dev->link->ap;
- ehi = &ap->link.eh_info;
-
spin_lock_irqsave(ap->lock, flags);
-
+ /*
+ * When dock driver calls into the routine, it will always use
+ * ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
+ * ACPI_NOTIFY_EJECT_REQUEST for remove
+ */
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
ata_ehi_push_desc(ehi, "ACPI event");
+
ata_ehi_hotplugged(ehi);
ata_port_freeze(ap);
break;
-
case ACPI_NOTIFY_EJECT_REQUEST:
ata_ehi_push_desc(ehi, "ACPI event");
- if (dev)
- dev->flags |= ATA_DFLAG_DETACH;
- else {
- struct ata_link *tlink;
- struct ata_device *tdev;
-
- ata_port_for_each_link(tlink, ap)
- ata_link_for_each_dev(tdev, tlink)
- tdev->flags |= ATA_DFLAG_DETACH;
- }
- ata_port_schedule_eh(ap);
+ ata_acpi_detach_device(ap, dev);
wait = 1;
break;
}
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ if (wait)
+ ata_port_wait_eh(ap);
+}
+
+static int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event)
+{
+ struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
+ ata_acpi_handle_hotplug(dev->link->ap, dev, event);
+ return 0;
+}
+
+static int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event)
+{
+ ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event);
+ return 0;
+}
+
+static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
+ u32 event)
+{
+ struct kobject *kobj = NULL;
+ char event_string[20];
+ char *envp[] = { event_string, NULL };
+
if (dev) {
if (dev->sdev)
kobj = &dev->sdev->sdev_gendev.kobj;
@@ -167,88 +158,90 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
kobj = &ap->dev->kobj;
if (kobj) {
- sprintf(event_string, "BAY_EVENT=%d", event);
+ snprintf(event_string, 20, "BAY_EVENT=%d", event);
kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
}
-
- spin_unlock_irqrestore(ap->lock, flags);
-
- if (wait)
- ata_port_wait_eh(ap);
}
-static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event)
{
- struct ata_device *dev = data;
-
- ata_acpi_handle_hotplug(NULL, dev, event);
+ ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event);
}
-static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
+static void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event)
{
- struct ata_port *ap = data;
-
- ata_acpi_handle_hotplug(ap, NULL, event);
+ struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
+ ata_acpi_uevent(dev->link->ap, dev, event);
}
-/**
- * ata_acpi_associate - associate ATA host with ACPI objects
- * @host: target ATA host
- *
- * Look up ACPI objects associated with @host and initialize
- * acpi_handle fields of @host, its ports and devices accordingly.
- *
- * LOCKING:
- * EH context.
- *
- * RETURNS:
- * 0 on success, -errno on failure.
- */
-void ata_acpi_associate(struct ata_host *host)
+/* bind acpi handle to pata port */
+void ata_acpi_bind_port(struct ata_port *ap)
{
- int i, j;
+ struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
+ struct acpi_device *adev;
+ struct ata_acpi_hotplug_context *context;
- if (!is_pci_dev(host->dev) || libata_noacpi)
+ if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion)
return;
- host->acpi_handle = DEVICE_ACPI_HANDLE(host->dev);
- if (!host->acpi_handle)
+ acpi_preset_companion(&ap->tdev, host_companion, ap->port_no);
+
+ if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
+ ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
+
+ adev = ACPI_COMPANION(&ap->tdev);
+ if (!adev || adev->hp)
return;
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return;
- if (host->ports[0]->flags & ATA_FLAG_ACPI_SATA)
- ata_acpi_associate_sata_port(ap);
- else
- ata_acpi_associate_ide_port(ap);
-
- if (ap->acpi_handle) {
- acpi_install_notify_handler(ap->acpi_handle,
- ACPI_SYSTEM_NOTIFY,
- ata_acpi_ap_notify, ap);
-#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
- /* we might be on a docking station */
- register_hotplug_dock_device(ap->acpi_handle,
- ata_acpi_ap_notify, ap);
-#endif
- }
+ context->data.ap = ap;
+ acpi_initialize_hp_context(adev, &context->hp, ata_acpi_ap_notify_dock,
+ ata_acpi_ap_uevent);
+}
- for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
- struct ata_device *dev = &ap->link.device[j];
-
- if (dev->acpi_handle) {
- acpi_install_notify_handler(dev->acpi_handle,
- ACPI_SYSTEM_NOTIFY,
- ata_acpi_dev_notify, dev);
-#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
- /* we might be on a docking station */
- register_hotplug_dock_device(dev->acpi_handle,
- ata_acpi_dev_notify, dev);
-#endif
- }
- }
+void ata_acpi_bind_dev(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->link->ap;
+ struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev);
+ struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
+ struct acpi_device *parent, *adev;
+ struct ata_acpi_hotplug_context *context;
+ u64 adr;
+
+ /*
+ * For both sata/pata devices, host companion device is required.
+ * For pata device, port companion device is also required.
+ */
+ if (libata_noacpi || !host_companion ||
+ (!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_companion))
+ return;
+
+ if (ap->flags & ATA_FLAG_ACPI_SATA) {
+ if (!sata_pmp_attached(ap))
+ adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+ else
+ adr = SATA_ADR(ap->port_no, dev->link->pmp);
+ parent = host_companion;
+ } else {
+ adr = dev->devno;
+ parent = port_companion;
}
+
+ acpi_preset_companion(&dev->tdev, parent, adr);
+ adev = ACPI_COMPANION(&dev->tdev);
+ if (!adev || adev->hp)
+ return;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return;
+
+ context->data.dev = dev;
+ acpi_initialize_hp_context(adev, &context->hp, ata_acpi_dev_notify_dock,
+ ata_acpi_dev_uevent);
}
/**
@@ -272,7 +265,7 @@ void ata_acpi_dissociate(struct ata_host *host)
struct ata_port *ap = host->ports[i];
const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap);
- if (ap->acpi_handle && gtm)
+ if (ACPI_HANDLE(&ap->tdev) && gtm)
ata_acpi_stm(ap, gtm);
}
}
@@ -296,8 +289,12 @@ int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)
union acpi_object *out_obj;
acpi_status status;
int rc = 0;
+ acpi_handle handle = ACPI_HANDLE(&ap->tdev);
- status = acpi_evaluate_object(ap->acpi_handle, "_GTM", NULL, &output);
+ if (!handle)
+ return -EINVAL;
+
+ status = acpi_evaluate_object(handle, "_GTM", NULL, &output);
rc = -ENOENT;
if (status == AE_NOT_FOUND)
@@ -305,25 +302,22 @@ int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)
rc = -EINVAL;
if (ACPI_FAILURE(status)) {
- ata_port_printk(ap, KERN_ERR,
- "ACPI get timing mode failed (AE 0x%x)\n",
- status);
+ ata_port_err(ap, "ACPI get timing mode failed (AE 0x%x)\n",
+ status);
goto out_free;
}
out_obj = output.pointer;
if (out_obj->type != ACPI_TYPE_BUFFER) {
- ata_port_printk(ap, KERN_WARNING,
- "_GTM returned unexpected object type 0x%x\n",
- out_obj->type);
+ ata_port_warn(ap, "_GTM returned unexpected object type 0x%x\n",
+ out_obj->type);
goto out_free;
}
if (out_obj->buffer.length != sizeof(struct ata_acpi_gtm)) {
- ata_port_printk(ap, KERN_ERR,
- "_GTM returned invalid length %d\n",
- out_obj->buffer.length);
+ ata_port_err(ap, "_GTM returned invalid length %d\n",
+ out_obj->buffer.length);
goto out_free;
}
@@ -370,13 +364,14 @@ int ata_acpi_stm(struct ata_port *ap, const struct ata_acpi_gtm *stm)
input.count = 3;
input.pointer = in_params;
- status = acpi_evaluate_object(ap->acpi_handle, "_STM", &input, NULL);
+ status = acpi_evaluate_object(ACPI_HANDLE(&ap->tdev), "_STM",
+ &input, NULL);
if (status == AE_NOT_FOUND)
return -ENOENT;
if (ACPI_FAILURE(status)) {
- ata_port_printk(ap, KERN_ERR,
- "ACPI set timing mode failed (status=0x%x)\n", status);
+ ata_port_err(ap, "ACPI set timing mode failed (status=0x%x)\n",
+ status);
return -EINVAL;
}
return 0;
@@ -423,18 +418,18 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf)
output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n",
- __func__, ap->port_no);
+ ata_dev_dbg(dev, "%s: ENTER: port#: %d\n",
+ __func__, ap->port_no);
/* _GTF has no input parameters */
- status = acpi_evaluate_object(dev->acpi_handle, "_GTF", NULL, &output);
+ status = acpi_evaluate_object(ata_dev_acpi_handle(dev), "_GTF", NULL,
+ &output);
out_obj = dev->gtf_cache = output.pointer;
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND) {
- ata_dev_printk(dev, KERN_WARNING,
- "_GTF evaluation failed (AE 0x%x)\n",
- status);
+ ata_dev_warn(dev, "_GTF evaluation failed (AE 0x%x)\n",
+ status);
rc = -EINVAL;
}
goto out_free;
@@ -442,27 +437,24 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf)
if (!output.length || !output.pointer) {
if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: Run _GTF: "
- "length or ptr is NULL (0x%llx, 0x%p)\n",
- __func__,
- (unsigned long long)output.length,
- output.pointer);
+ ata_dev_dbg(dev, "%s: Run _GTF: length or ptr is NULL (0x%llx, 0x%p)\n",
+ __func__,
+ (unsigned long long)output.length,
+ output.pointer);
rc = -EINVAL;
goto out_free;
}
if (out_obj->type != ACPI_TYPE_BUFFER) {
- ata_dev_printk(dev, KERN_WARNING,
- "_GTF unexpected object type 0x%x\n",
- out_obj->type);
+ ata_dev_warn(dev, "_GTF unexpected object type 0x%x\n",
+ out_obj->type);
rc = -EINVAL;
goto out_free;
}
if (out_obj->buffer.length % REGS_PER_GTF) {
- ata_dev_printk(dev, KERN_WARNING,
- "unexpected _GTF length (%d)\n",
- out_obj->buffer.length);
+ ata_dev_warn(dev, "unexpected _GTF length (%d)\n",
+ out_obj->buffer.length);
rc = -EINVAL;
goto out_free;
}
@@ -472,9 +464,8 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf)
if (gtf) {
*gtf = (void *)out_obj->buffer.pointer;
if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG,
- "%s: returning gtf=%p, gtf_count=%d\n",
- __func__, *gtf, rc);
+ ata_dev_dbg(dev, "%s: returning gtf=%p, gtf_count=%d\n",
+ __func__, *gtf, rc);
}
return rc;
@@ -540,12 +531,9 @@ int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm)
{
struct ata_device *dev;
- ata_link_for_each_dev(dev, &ap->link) {
+ ata_for_each_dev(dev, &ap->link, ENABLED) {
unsigned long xfer_mask, udma_mask;
- if (!ata_dev_enabled(dev))
- continue;
-
xfer_mask = ata_acpi_gtm_xfermask(dev, gtm);
ata_unpack_xfermask(xfer_mask, NULL, NULL, &udma_mask);
@@ -574,10 +562,11 @@ static void ata_acpi_gtf_to_tf(struct ata_device *dev,
tf->command = gtf->tf[6]; /* 0x1f7 */
}
-static int ata_acpi_filter_tf(const struct ata_taskfile *tf,
+static int ata_acpi_filter_tf(struct ata_device *dev,
+ const struct ata_taskfile *tf,
const struct ata_taskfile *ptf)
{
- if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_SETXFER) {
+ if (dev->gtf_filter & ATA_ACPI_FILTER_SETXFER) {
/* libata doesn't use ACPI to configure transfer mode.
* It will only confuse device configuration. Skip.
*/
@@ -586,7 +575,7 @@ static int ata_acpi_filter_tf(const struct ata_taskfile *tf,
return 1;
}
- if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_LOCK) {
+ if (dev->gtf_filter & ATA_ACPI_FILTER_LOCK) {
/* BIOS writers, sorry but we don't wanna lock
* features unless the user explicitly said so.
*/
@@ -608,6 +597,25 @@ static int ata_acpi_filter_tf(const struct ata_taskfile *tf,
return 1;
}
+ if (tf->command == ATA_CMD_SET_FEATURES &&
+ tf->feature == SETFEATURES_SATA_ENABLE) {
+ /* inhibit enabling DIPM */
+ if (dev->gtf_filter & ATA_ACPI_FILTER_DIPM &&
+ tf->nsect == SATA_DIPM)
+ return 1;
+
+ /* inhibit FPDMA non-zero offset */
+ if (dev->gtf_filter & ATA_ACPI_FILTER_FPDMA_OFFSET &&
+ (tf->nsect == SATA_FPDMA_OFFSET ||
+ tf->nsect == SATA_FPDMA_IN_ORDER))
+ return 1;
+
+ /* inhibit FPDMA auto activation */
+ if (dev->gtf_filter & ATA_ACPI_FILTER_FPDMA_AA &&
+ tf->nsect == SATA_FPDMA_AA)
+ return 1;
+ }
+
return 0;
}
@@ -616,8 +624,7 @@ static int ata_acpi_filter_tf(const struct ata_taskfile *tf,
* @dev: target ATA device
* @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
*
- * Outputs ATA taskfile to standard ATA host controller using MMIO
- * or PIO as indicated by the ATA_FLAG_MMIO flag.
+ * Outputs ATA taskfile to standard ATA host controller.
* Writes the control, feature, nsect, lbal, lbam, and lbah registers.
* Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
* hob_lbal, hob_lbam, and hob_lbah.
@@ -642,6 +649,7 @@ static int ata_acpi_run_tf(struct ata_device *dev,
struct ata_taskfile tf, ptf, rtf;
unsigned int err_mask;
const char *level;
+ const char *descr;
char msg[60];
int rc;
@@ -656,7 +664,7 @@ static int ata_acpi_run_tf(struct ata_device *dev,
pptf = &ptf;
}
- if (!ata_acpi_filter_tf(&tf, pptf)) {
+ if (!ata_acpi_filter_tf(dev, &tf, pptf)) {
rtf = tf;
err_mask = ata_exec_internal(dev, &rtf, NULL,
DMA_NONE, NULL, 0, 0);
@@ -689,11 +697,13 @@ static int ata_acpi_run_tf(struct ata_device *dev,
snprintf(msg, sizeof(msg), "filtered out");
rc = 0;
}
+ descr = ata_get_cmd_descript(tf.command);
ata_dev_printk(dev, level,
- "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x %s\n",
+ "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x (%s) %s\n",
tf.command, tf.feature, tf.nsect, tf.lbal,
- tf.lbam, tf.lbah, tf.device, msg);
+ tf.lbam, tf.lbah, tf.device,
+ (descr ? descr : "unknown"), msg);
return rc;
}
@@ -701,9 +711,9 @@ static int ata_acpi_run_tf(struct ata_device *dev,
/**
* ata_acpi_exec_tfs - get then write drive taskfile settings
* @dev: target ATA device
- * @nr_executed: out paramter for the number of executed commands
+ * @nr_executed: out parameter for the number of executed commands
*
- * Evaluate _GTF and excute returned taskfiles.
+ * Evaluate _GTF and execute returned taskfiles.
*
* LOCKING:
* EH context.
@@ -755,19 +765,18 @@ static int ata_acpi_exec_tfs(struct ata_device *dev, int *nr_executed)
* EH context.
*
* RETURNS:
- * 0 on success, -errno on failure.
+ * 0 on success, -ENOENT if _SDD doesn't exist, -errno on failure.
*/
static int ata_acpi_push_id(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
- int err;
acpi_status status;
struct acpi_object_list input;
union acpi_object in_params[1];
if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: ix = %d, port#: %d\n",
- __func__, dev->devno, ap->port_no);
+ ata_dev_dbg(dev, "%s: ix = %d, port#: %d\n",
+ __func__, dev->devno, ap->port_no);
/* Give the drive Identify data to the drive via the _SDD method */
/* _SDD: set up input parameters */
@@ -780,15 +789,19 @@ static int ata_acpi_push_id(struct ata_device *dev)
/* It's OK for _SDD to be missing too. */
swap_buf_le16(dev->id, ATA_ID_WORDS);
- status = acpi_evaluate_object(dev->acpi_handle, "_SDD", &input, NULL);
+ status = acpi_evaluate_object(ata_dev_acpi_handle(dev), "_SDD", &input,
+ NULL);
swap_buf_le16(dev->id, ATA_ID_WORDS);
- err = ACPI_FAILURE(status) ? -EIO : 0;
- if (err < 0)
- ata_dev_printk(dev, KERN_WARNING,
- "ACPI _SDD failed (AE 0x%x)\n", status);
+ if (status == AE_NOT_FOUND)
+ return -ENOENT;
+
+ if (ACPI_FAILURE(status)) {
+ ata_dev_warn(dev, "ACPI _SDD failed (AE 0x%x)\n", status);
+ return -EIO;
+ }
- return err;
+ return 0;
}
/**
@@ -827,7 +840,7 @@ void ata_acpi_on_resume(struct ata_port *ap)
const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap);
struct ata_device *dev;
- if (ap->acpi_handle && gtm) {
+ if (ACPI_HANDLE(&ap->tdev) && gtm) {
/* _GTM valid */
/* restore timing parameters */
@@ -837,9 +850,10 @@ void ata_acpi_on_resume(struct ata_port *ap)
* use values set by _STM. Cache _GTF result and
* schedule _GTF.
*/
- ata_link_for_each_dev(dev, &ap->link) {
+ ata_for_each_dev(dev, &ap->link, ALL) {
ata_acpi_clear_gtf(dev);
if (ata_dev_enabled(dev) &&
+ ata_dev_acpi_handle(dev) &&
ata_dev_get_GTF(dev, NULL) >= 0)
dev->flags |= ATA_DFLAG_ACPI_PENDING;
}
@@ -848,7 +862,7 @@ void ata_acpi_on_resume(struct ata_port *ap)
* there's no reason to evaluate IDE _GTF early
* without _STM. Clear cache and schedule _GTF.
*/
- ata_link_for_each_dev(dev, &ap->link) {
+ ata_for_each_dev(dev, &ap->link, ALL) {
ata_acpi_clear_gtf(dev);
if (ata_dev_enabled(dev))
dev->flags |= ATA_DFLAG_ACPI_PENDING;
@@ -856,34 +870,94 @@ void ata_acpi_on_resume(struct ata_port *ap)
}
}
-/**
- * ata_acpi_set_state - set the port power state
- * @ap: target ATA port
- * @state: state, on/off
- *
- * This function executes the _PS0/_PS3 ACPI method to set the power state.
- * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
- */
-void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)
+static int ata_acpi_choose_suspend_state(struct ata_device *dev, bool runtime)
+{
+ int d_max_in = ACPI_STATE_D3_COLD;
+ if (!runtime)
+ goto out;
+
+ /*
+ * For ATAPI, runtime D3 cold is only allowed
+ * for ZPODD in zero power ready state
+ */
+ if (dev->class == ATA_DEV_ATAPI &&
+ !(zpodd_dev_enabled(dev) && zpodd_zpready(dev)))
+ d_max_in = ACPI_STATE_D3_HOT;
+
+out:
+ return acpi_pm_device_sleep_state(&dev->tdev, NULL, d_max_in);
+}
+
+static void sata_acpi_set_state(struct ata_port *ap, pm_message_t state)
+{
+ bool runtime = PMSG_IS_AUTO(state);
+ struct ata_device *dev;
+ acpi_handle handle;
+ int acpi_state;
+
+ ata_for_each_dev(dev, &ap->link, ENABLED) {
+ handle = ata_dev_acpi_handle(dev);
+ if (!handle)
+ continue;
+
+ if (!(state.event & PM_EVENT_RESUME)) {
+ acpi_state = ata_acpi_choose_suspend_state(dev, runtime);
+ if (acpi_state == ACPI_STATE_D0)
+ continue;
+ if (runtime && zpodd_dev_enabled(dev) &&
+ acpi_state == ACPI_STATE_D3_COLD)
+ zpodd_enable_run_wake(dev);
+ acpi_bus_set_power(handle, acpi_state);
+ } else {
+ if (runtime && zpodd_dev_enabled(dev))
+ zpodd_disable_run_wake(dev);
+ acpi_bus_set_power(handle, ACPI_STATE_D0);
+ }
+ }
+}
+
+/* ACPI spec requires _PS0 when IDE power on and _PS3 when power off */
+static void pata_acpi_set_state(struct ata_port *ap, pm_message_t state)
{
struct ata_device *dev;
+ acpi_handle port_handle;
- if (!ap->acpi_handle || (ap->flags & ATA_FLAG_ACPI_SATA))
+ port_handle = ACPI_HANDLE(&ap->tdev);
+ if (!port_handle)
return;
/* channel first and then drives for power on and vica versa
for power off */
- if (state.event == PM_EVENT_ON)
- acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D0);
-
- ata_link_for_each_dev(dev, &ap->link) {
- if (dev->acpi_handle && ata_dev_enabled(dev))
- acpi_bus_set_power(dev->acpi_handle,
- state.event == PM_EVENT_ON ?
- ACPI_STATE_D0 : ACPI_STATE_D3);
+ if (state.event & PM_EVENT_RESUME)
+ acpi_bus_set_power(port_handle, ACPI_STATE_D0);
+
+ ata_for_each_dev(dev, &ap->link, ENABLED) {
+ acpi_handle dev_handle = ata_dev_acpi_handle(dev);
+ if (!dev_handle)
+ continue;
+
+ acpi_bus_set_power(dev_handle, state.event & PM_EVENT_RESUME ?
+ ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
}
- if (state.event != PM_EVENT_ON)
- acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D3);
+
+ if (!(state.event & PM_EVENT_RESUME))
+ acpi_bus_set_power(port_handle, ACPI_STATE_D3_COLD);
+}
+
+/**
+ * ata_acpi_set_state - set the port power state
+ * @ap: target ATA port
+ * @state: state, on/off
+ *
+ * This function sets a proper ACPI D state for the device on
+ * system and runtime PM operations.
+ */
+void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)
+{
+ if (ap->flags & ATA_FLAG_ACPI_SATA)
+ sata_acpi_set_state(ap, state);
+ else
+ pata_acpi_set_state(ap, state);
}
/**
@@ -908,7 +982,7 @@ int ata_acpi_on_devcfg(struct ata_device *dev)
int nr_executed = 0;
int rc;
- if (!dev->acpi_handle)
+ if (!ata_dev_acpi_handle(dev))
return 0;
/* do we need to do _GTF? */
@@ -919,7 +993,7 @@ int ata_acpi_on_devcfg(struct ata_device *dev)
/* do _SDD if SATA */
if (acpi_sata) {
rc = ata_acpi_push_id(dev);
- if (rc)
+ if (rc && rc != -ENOENT)
goto acpi_err;
}
@@ -934,8 +1008,8 @@ int ata_acpi_on_devcfg(struct ata_device *dev)
if (nr_executed) {
rc = ata_dev_reread_id(dev, 0);
if (rc < 0) {
- ata_dev_printk(dev, KERN_ERR, "failed to IDENTIFY "
- "after ACPI commands\n");
+ ata_dev_err(dev,
+ "failed to IDENTIFY after ACPI commands\n");
return rc;
}
}
@@ -953,9 +1027,8 @@ int ata_acpi_on_devcfg(struct ata_device *dev)
return rc;
}
- ata_dev_printk(dev, KERN_WARNING,
- "ACPI: failed the second time, disabled\n");
- dev->acpi_handle = NULL;
+ dev->flags |= ATA_DFLAG_ACPI_DISABLED;
+ ata_dev_warn(dev, "ACPI: failed the second time, disabled\n");
/* We can safely continue if no _GTF command has been executed
* and port is not frozen.
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index b0b00af90d0..677c0c1b03b 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1,7 +1,7 @@
/*
* libata-core.c - helper library for ATA
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -54,18 +54,23 @@
#include <linux/completion.h>
#include <linux/suspend.h>
#include <linux/workqueue.h>
-#include <linux/jiffies.h>
#include <linux/scatterlist.h>
#include <linux/io.h>
+#include <linux/async.h>
+#include <linux/log2.h>
+#include <linux/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <asm/byteorder.h>
#include <linux/cdrom.h>
+#include <linux/ratelimit.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
#include "libata.h"
-
+#include "libata-transport.h"
/* debounce timing parameters in msecs { interval, duration, timeout } */
const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
@@ -76,6 +81,8 @@ const struct ata_port_operations ata_base_port_ops = {
.prereset = ata_std_prereset,
.postreset = ata_std_postreset,
.error_handler = ata_std_error_handler,
+ .sched_eh = ata_std_sched_eh,
+ .end_eh = ata_std_end_eh,
};
const struct ata_port_operations sata_port_ops = {
@@ -88,15 +95,10 @@ const struct ata_port_operations sata_port_ops = {
static unsigned int ata_dev_init_params(struct ata_device *dev,
u16 heads, u16 sectors);
static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
-static unsigned int ata_dev_set_feature(struct ata_device *dev,
- u8 enable, u8 feature);
static void ata_dev_xfermask(struct ata_device *dev);
static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
-unsigned int ata_print_id = 1;
-static struct workqueue_struct *ata_wq;
-
-struct workqueue_struct *ata_aux_wq;
+atomic_t ata_print_id = ATOMIC_INIT(0);
struct ata_force_param {
const char *name;
@@ -105,6 +107,7 @@ struct ata_force_param {
unsigned long xfer_mask;
unsigned int horkage_on;
unsigned int horkage_off;
+ unsigned int lflags;
};
struct ata_force_ent {
@@ -121,21 +124,21 @@ static char ata_force_param_buf[PAGE_SIZE] __initdata;
module_param_string(force, ata_force_param_buf, sizeof(ata_force_param_buf), 0);
MODULE_PARM_DESC(force, "Force ATA configurations including cable type, link speed and transfer mode (see Documentation/kernel-parameters.txt for details)");
-int atapi_enabled = 1;
+static int atapi_enabled = 1;
module_param(atapi_enabled, int, 0444);
-MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
+MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on [default])");
static int atapi_dmadir = 0;
module_param(atapi_dmadir, int, 0444);
-MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
+MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off [default], 1=on)");
int atapi_passthru16 = 1;
module_param(atapi_passthru16, int, 0444);
-MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices; on by default (0=off, 1=on)");
+MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices (0=off, 1=on [default])");
int libata_fua = 0;
module_param_named(fua, libata_fua, int, 0444);
-MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
+MODULE_PARM_DESC(fua, "FUA support (0=off [default], 1=on)");
static int ata_ignore_hpa;
module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644);
@@ -145,17 +148,21 @@ static int libata_dma_mask = ATA_DMA_MASK_ATA|ATA_DMA_MASK_ATAPI|ATA_DMA_MASK_CF
module_param_named(dma, libata_dma_mask, int, 0444);
MODULE_PARM_DESC(dma, "DMA enable/disable (0x1==ATA, 0x2==ATAPI, 0x4==CF)");
-static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
+static int ata_probe_timeout;
module_param(ata_probe_timeout, int, 0444);
MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
int libata_noacpi = 0;
module_param_named(noacpi, libata_noacpi, int, 0444);
-MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set");
+MODULE_PARM_DESC(noacpi, "Disable the use of ACPI in probe/suspend/resume (0=off [default], 1=on)");
int libata_allow_tpm = 0;
module_param_named(allow_tpm, libata_allow_tpm, int, 0444);
-MODULE_PARM_DESC(allow_tpm, "Permit the use of TPM commands");
+MODULE_PARM_DESC(allow_tpm, "Permit the use of TPM commands (0=off [default], 1=on)");
+
+static int atapi_an;
+module_param(atapi_an, int, 0444);
+MODULE_PARM_DESC(atapi_an, "Enable ATAPI AN media presence notification (0=0ff [default], 1=on)");
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("Library module for ATA devices");
@@ -163,6 +170,148 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+static bool ata_sstatus_online(u32 sstatus)
+{
+ return (sstatus & 0xf) == 0x3;
+}
+
+/**
+ * ata_link_next - link iteration helper
+ * @link: the previous link, NULL to start
+ * @ap: ATA port containing links to iterate
+ * @mode: iteration mode, one of ATA_LITER_*
+ *
+ * LOCKING:
+ * Host lock or EH context.
+ *
+ * RETURNS:
+ * Pointer to the next link.
+ */
+struct ata_link *ata_link_next(struct ata_link *link, struct ata_port *ap,
+ enum ata_link_iter_mode mode)
+{
+ BUG_ON(mode != ATA_LITER_EDGE &&
+ mode != ATA_LITER_PMP_FIRST && mode != ATA_LITER_HOST_FIRST);
+
+ /* NULL link indicates start of iteration */
+ if (!link)
+ switch (mode) {
+ case ATA_LITER_EDGE:
+ case ATA_LITER_PMP_FIRST:
+ if (sata_pmp_attached(ap))
+ return ap->pmp_link;
+ /* fall through */
+ case ATA_LITER_HOST_FIRST:
+ return &ap->link;
+ }
+
+ /* we just iterated over the host link, what's next? */
+ if (link == &ap->link)
+ switch (mode) {
+ case ATA_LITER_HOST_FIRST:
+ if (sata_pmp_attached(ap))
+ return ap->pmp_link;
+ /* fall through */
+ case ATA_LITER_PMP_FIRST:
+ if (unlikely(ap->slave_link))
+ return ap->slave_link;
+ /* fall through */
+ case ATA_LITER_EDGE:
+ return NULL;
+ }
+
+ /* slave_link excludes PMP */
+ if (unlikely(link == ap->slave_link))
+ return NULL;
+
+ /* we were over a PMP link */
+ if (++link < ap->pmp_link + ap->nr_pmp_links)
+ return link;
+
+ if (mode == ATA_LITER_PMP_FIRST)
+ return &ap->link;
+
+ return NULL;
+}
+
+/**
+ * ata_dev_next - device iteration helper
+ * @dev: the previous device, NULL to start
+ * @link: ATA link containing devices to iterate
+ * @mode: iteration mode, one of ATA_DITER_*
+ *
+ * LOCKING:
+ * Host lock or EH context.
+ *
+ * RETURNS:
+ * Pointer to the next device.
+ */
+struct ata_device *ata_dev_next(struct ata_device *dev, struct ata_link *link,
+ enum ata_dev_iter_mode mode)
+{
+ BUG_ON(mode != ATA_DITER_ENABLED && mode != ATA_DITER_ENABLED_REVERSE &&
+ mode != ATA_DITER_ALL && mode != ATA_DITER_ALL_REVERSE);
+
+ /* NULL dev indicates start of iteration */
+ if (!dev)
+ switch (mode) {
+ case ATA_DITER_ENABLED:
+ case ATA_DITER_ALL:
+ dev = link->device;
+ goto check;
+ case ATA_DITER_ENABLED_REVERSE:
+ case ATA_DITER_ALL_REVERSE:
+ dev = link->device + ata_link_max_devices(link) - 1;
+ goto check;
+ }
+
+ next:
+ /* move to the next one */
+ switch (mode) {
+ case ATA_DITER_ENABLED:
+ case ATA_DITER_ALL:
+ if (++dev < link->device + ata_link_max_devices(link))
+ goto check;
+ return NULL;
+ case ATA_DITER_ENABLED_REVERSE:
+ case ATA_DITER_ALL_REVERSE:
+ if (--dev >= link->device)
+ goto check;
+ return NULL;
+ }
+
+ check:
+ if ((mode == ATA_DITER_ENABLED || mode == ATA_DITER_ENABLED_REVERSE) &&
+ !ata_dev_enabled(dev))
+ goto next;
+ return dev;
+}
+
+/**
+ * ata_dev_phys_link - find physical link for a device
+ * @dev: ATA device to look up physical link for
+ *
+ * Look up physical link which @dev is attached to. Note that
+ * this is different from @dev->link only when @dev is on slave
+ * link. For all other cases, it's the same as @dev->link.
+ *
+ * LOCKING:
+ * Don't care.
+ *
+ * RETURNS:
+ * Pointer to the found physical link.
+ */
+struct ata_link *ata_dev_phys_link(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->link->ap;
+
+ if (!ap->slave_link)
+ return dev->link;
+ if (!dev->devno)
+ return &ap->link;
+ return ap->slave_link;
+}
+
/**
* ata_force_cbl - force cable type according to libata.force
* @ap: ATA port of interest
@@ -190,35 +339,35 @@ void ata_force_cbl(struct ata_port *ap)
continue;
ap->cbl = fe->param.cbl;
- ata_port_printk(ap, KERN_NOTICE,
- "FORCE: cable set to %s\n", fe->param.name);
+ ata_port_notice(ap, "FORCE: cable set to %s\n", fe->param.name);
return;
}
}
/**
- * ata_force_spd_limit - force SATA spd limit according to libata.force
+ * ata_force_link_limits - force link limits according to libata.force
* @link: ATA link of interest
*
- * Force SATA spd limit according to libata.force and whine about
- * it. When only the port part is specified (e.g. 1:), the limit
- * applies to all links connected to both the host link and all
- * fan-out ports connected via PMP. If the device part is
- * specified as 0 (e.g. 1.00:), it specifies the first fan-out
- * link not the host link. Device number 15 always points to the
- * host link whether PMP is attached or not.
+ * Force link flags and SATA spd limit according to libata.force
+ * and whine about it. When only the port part is specified
+ * (e.g. 1:), the limit applies to all links connected to both
+ * the host link and all fan-out ports connected via PMP. If the
+ * device part is specified as 0 (e.g. 1.00:), it specifies the
+ * first fan-out link not the host link. Device number 15 always
+ * points to the host link whether PMP is attached or not. If the
+ * controller has slave link, device number 16 points to it.
*
* LOCKING:
* EH context.
*/
-static void ata_force_spd_limit(struct ata_link *link)
+static void ata_force_link_limits(struct ata_link *link)
{
- int linkno, i;
+ bool did_spd = false;
+ int linkno = link->pmp;
+ int i;
if (ata_is_host_link(link))
- linkno = 15;
- else
- linkno = link->pmp;
+ linkno += 15;
for (i = ata_force_tbl_size - 1; i >= 0; i--) {
const struct ata_force_ent *fe = &ata_force_tbl[i];
@@ -229,13 +378,21 @@ static void ata_force_spd_limit(struct ata_link *link)
if (fe->device != -1 && fe->device != linkno)
continue;
- if (!fe->param.spd_limit)
- continue;
+ /* only honor the first spd limit */
+ if (!did_spd && fe->param.spd_limit) {
+ link->hw_sata_spd_limit = (1 << fe->param.spd_limit) - 1;
+ ata_link_notice(link, "FORCE: PHY spd limit set to %s\n",
+ fe->param.name);
+ did_spd = true;
+ }
- link->hw_sata_spd_limit = (1 << fe->param.spd_limit) - 1;
- ata_link_printk(link, KERN_NOTICE,
- "FORCE: PHY spd limit set to %s\n", fe->param.name);
- return;
+ /* let lflags stack */
+ if (fe->param.lflags) {
+ link->flags |= fe->param.lflags;
+ ata_link_notice(link,
+ "FORCE: link flag 0x%x forced -> 0x%x\n",
+ fe->param.lflags, link->flags);
+ }
}
}
@@ -256,9 +413,9 @@ static void ata_force_xfermask(struct ata_device *dev)
int alt_devno = devno;
int i;
- /* allow n.15 for the first device attached to host port */
- if (ata_is_host_link(dev->link) && devno == 0)
- alt_devno = 15;
+ /* allow n.15/16 for devices attached to host port */
+ if (ata_is_host_link(dev->link))
+ alt_devno += 15;
for (i = ata_force_tbl_size - 1; i >= 0; i--) {
const struct ata_force_ent *fe = &ata_force_tbl[i];
@@ -287,8 +444,8 @@ static void ata_force_xfermask(struct ata_device *dev)
dev->pio_mask = pio_mask;
}
- ata_dev_printk(dev, KERN_NOTICE,
- "FORCE: xfer_mask set to %s\n", fe->param.name);
+ ata_dev_notice(dev, "FORCE: xfer_mask set to %s\n",
+ fe->param.name);
return;
}
}
@@ -310,9 +467,9 @@ static void ata_force_horkage(struct ata_device *dev)
int alt_devno = devno;
int i;
- /* allow n.15 for the first device attached to host port */
- if (ata_is_host_link(dev->link) && devno == 0)
- alt_devno = 15;
+ /* allow n.15/16 for devices attached to host port */
+ if (ata_is_host_link(dev->link))
+ alt_devno += 15;
for (i = 0; i < ata_force_tbl_size; i++) {
const struct ata_force_ent *fe = &ata_force_tbl[i];
@@ -331,8 +488,8 @@ static void ata_force_horkage(struct ata_device *dev)
dev->horkage |= fe->param.horkage_on;
dev->horkage &= ~fe->param.horkage_off;
- ata_dev_printk(dev, KERN_NOTICE,
- "FORCE: horkage modified (%s)\n", fe->param.name);
+ ata_dev_notice(dev, "FORCE: horkage modified (%s)\n",
+ fe->param.name);
}
}
@@ -412,10 +569,10 @@ void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
fis[14] = 0;
fis[15] = tf->ctl;
- fis[16] = 0;
- fis[17] = 0;
- fis[18] = 0;
- fis[19] = 0;
+ fis[16] = tf->auxiliary & 0xff;
+ fis[17] = (tf->auxiliary >> 8) & 0xff;
+ fis[18] = (tf->auxiliary >> 16) & 0xff;
+ fis[19] = (tf->auxiliary >> 24) & 0xff;
}
/**
@@ -541,7 +698,7 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
if (tf->flags & ATA_TFLAG_LBA48) {
block |= (u64)tf->hob_lbah << 40;
block |= (u64)tf->hob_lbam << 32;
- block |= tf->hob_lbal << 24;
+ block |= (u64)tf->hob_lbal << 24;
} else
block |= (tf->device & 0xf) << 24;
@@ -555,7 +712,13 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
head = tf->device & 0xf;
sect = tf->lbal;
- block = (cyl * dev->heads + head) * dev->sectors + sect;
+ if (!sect) {
+ ata_dev_warn(dev,
+ "device reported invalid CHS sector 0\n");
+ sect = 1; /* oh well */
+ }
+
+ block = (cyl * dev->heads + head) * dev->sectors + sect - 1;
}
return block;
@@ -612,7 +775,7 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
tf->lbam = (block >> 8) & 0xff;
tf->lbal = block & 0xff;
- tf->device = 1 << 6;
+ tf->device = ATA_LBA;
if (tf->flags & ATA_TFLAG_FUA)
tf->device |= 1 << 7;
} else if (dev->flags & ATA_DFLAG_LBA) {
@@ -854,11 +1017,12 @@ const char *ata_mode_string(unsigned long xfer_mask)
return "<n/a>";
}
-static const char *sata_spd_string(unsigned int spd)
+const char *sata_spd_string(unsigned int spd)
{
static const char * const spd_str[] = {
"1.5 Gbps",
"3.0 Gbps",
+ "6.0 Gbps",
};
if (spd == 0 || (spd - 1) >= ARRAY_SIZE(spd_str))
@@ -866,194 +1030,6 @@ static const char *sata_spd_string(unsigned int spd)
return spd_str[spd - 1];
}
-void ata_dev_disable(struct ata_device *dev)
-{
- if (ata_dev_enabled(dev)) {
- if (ata_msg_drv(dev->link->ap))
- ata_dev_printk(dev, KERN_WARNING, "disabled\n");
- ata_acpi_on_disable(dev);
- ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 |
- ATA_DNXFER_QUIET);
- dev->class++;
- }
-}
-
-static int ata_dev_set_dipm(struct ata_device *dev, enum link_pm policy)
-{
- struct ata_link *link = dev->link;
- struct ata_port *ap = link->ap;
- u32 scontrol;
- unsigned int err_mask;
- int rc;
-
- /*
- * disallow DIPM for drivers which haven't set
- * ATA_FLAG_IPM. This is because when DIPM is enabled,
- * phy ready will be set in the interrupt status on
- * state changes, which will cause some drivers to
- * think there are errors - additionally drivers will
- * need to disable hot plug.
- */
- if (!(ap->flags & ATA_FLAG_IPM) || !ata_dev_enabled(dev)) {
- ap->pm_policy = NOT_AVAILABLE;
- return -EINVAL;
- }
-
- /*
- * For DIPM, we will only enable it for the
- * min_power setting.
- *
- * Why? Because Disks are too stupid to know that
- * If the host rejects a request to go to SLUMBER
- * they should retry at PARTIAL, and instead it
- * just would give up. So, for medium_power to
- * work at all, we need to only allow HIPM.
- */
- rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
- if (rc)
- return rc;
-
- switch (policy) {
- case MIN_POWER:
- /* no restrictions on IPM transitions */
- scontrol &= ~(0x3 << 8);
- rc = sata_scr_write(link, SCR_CONTROL, scontrol);
- if (rc)
- return rc;
-
- /* enable DIPM */
- if (dev->flags & ATA_DFLAG_DIPM)
- err_mask = ata_dev_set_feature(dev,
- SETFEATURES_SATA_ENABLE, SATA_DIPM);
- break;
- case MEDIUM_POWER:
- /* allow IPM to PARTIAL */
- scontrol &= ~(0x1 << 8);
- scontrol |= (0x2 << 8);
- rc = sata_scr_write(link, SCR_CONTROL, scontrol);
- if (rc)
- return rc;
-
- /*
- * we don't have to disable DIPM since IPM flags
- * disallow transitions to SLUMBER, which effectively
- * disable DIPM if it does not support PARTIAL
- */
- break;
- case NOT_AVAILABLE:
- case MAX_PERFORMANCE:
- /* disable all IPM transitions */
- scontrol |= (0x3 << 8);
- rc = sata_scr_write(link, SCR_CONTROL, scontrol);
- if (rc)
- return rc;
-
- /*
- * we don't have to disable DIPM since IPM flags
- * disallow all transitions which effectively
- * disable DIPM anyway.
- */
- break;
- }
-
- /* FIXME: handle SET FEATURES failure */
- (void) err_mask;
-
- return 0;
-}
-
-/**
- * ata_dev_enable_pm - enable SATA interface power management
- * @dev: device to enable power management
- * @policy: the link power management policy
- *
- * Enable SATA Interface power management. This will enable
- * Device Interface Power Management (DIPM) for min_power
- * policy, and then call driver specific callbacks for
- * enabling Host Initiated Power management.
- *
- * Locking: Caller.
- * Returns: -EINVAL if IPM is not supported, 0 otherwise.
- */
-void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy)
-{
- int rc = 0;
- struct ata_port *ap = dev->link->ap;
-
- /* set HIPM first, then DIPM */
- if (ap->ops->enable_pm)
- rc = ap->ops->enable_pm(ap, policy);
- if (rc)
- goto enable_pm_out;
- rc = ata_dev_set_dipm(dev, policy);
-
-enable_pm_out:
- if (rc)
- ap->pm_policy = MAX_PERFORMANCE;
- else
- ap->pm_policy = policy;
- return /* rc */; /* hopefully we can use 'rc' eventually */
-}
-
-#ifdef CONFIG_PM
-/**
- * ata_dev_disable_pm - disable SATA interface power management
- * @dev: device to disable power management
- *
- * Disable SATA Interface power management. This will disable
- * Device Interface Power Management (DIPM) without changing
- * policy, call driver specific callbacks for disabling Host
- * Initiated Power management.
- *
- * Locking: Caller.
- * Returns: void
- */
-static void ata_dev_disable_pm(struct ata_device *dev)
-{
- struct ata_port *ap = dev->link->ap;
-
- ata_dev_set_dipm(dev, MAX_PERFORMANCE);
- if (ap->ops->disable_pm)
- ap->ops->disable_pm(ap);
-}
-#endif /* CONFIG_PM */
-
-void ata_lpm_schedule(struct ata_port *ap, enum link_pm policy)
-{
- ap->pm_policy = policy;
- ap->link.eh_info.action |= ATA_EH_LPM;
- ap->link.eh_info.flags |= ATA_EHI_NO_AUTOPSY;
- ata_port_schedule_eh(ap);
-}
-
-#ifdef CONFIG_PM
-static void ata_lpm_enable(struct ata_host *host)
-{
- struct ata_link *link;
- struct ata_port *ap;
- struct ata_device *dev;
- int i;
-
- for (i = 0; i < host->n_ports; i++) {
- ap = host->ports[i];
- ata_port_for_each_link(link, ap) {
- ata_link_for_each_dev(dev, link)
- ata_dev_disable_pm(dev);
- }
- }
-}
-
-static void ata_lpm_disable(struct ata_host *host)
-{
- int i;
-
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
- ata_lpm_schedule(ap, ap->pm_policy);
- }
-}
-#endif /* CONFIG_PM */
-
/**
* ata_dev_classify - determine device type based on ATA-spec signature
* @tf: ATA taskfile register set for device to be identified
@@ -1088,6 +1064,9 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
*
* We follow the current spec and consider that 0x69/0x96
* identifies a port multiplier and 0x3c/0xc3 a SEMB device.
+ * Unfortunately, WDC WD1600JS-62MHB5 (a hard drive) reports
+ * SEMB signature. This is worked around in
+ * ata_dev_read_id().
*/
if ((tf->lbam == 0) && (tf->lbah == 0)) {
DPRINTK("found ATA device by sig\n");
@@ -1105,8 +1084,8 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
}
if ((tf->lbam == 0x3c) && (tf->lbah == 0xc3)) {
- printk(KERN_INFO "ata: SEMB device ignored\n");
- return ATA_DEV_SEMB_UNSUP; /* not yet */
+ DPRINTK("found SEMB device by sig (could be ATA device)\n");
+ return ATA_DEV_SEMB;
}
DPRINTK("unknown device\n");
@@ -1133,6 +1112,8 @@ void ata_id_string(const u16 *id, unsigned char *s,
{
unsigned int c;
+ BUG_ON(len & 1);
+
while (len > 0) {
c = id[ofs] >> 8;
*s = c;
@@ -1166,8 +1147,6 @@ void ata_id_c_string(const u16 *id, unsigned char *s,
{
unsigned char *p;
- WARN_ON(!(len & 1));
-
ata_id_string(id, s, ofs, len - 1);
p = s + strnlen(s, len - 1);
@@ -1180,14 +1159,16 @@ static u64 ata_id_n_sectors(const u16 *id)
{
if (ata_id_has_lba(id)) {
if (ata_id_has_lba48(id))
- return ata_id_u64(id, 100);
+ return ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
else
- return ata_id_u32(id, 60);
+ return ata_id_u32(id, ATA_ID_LBA_CAPACITY);
} else {
if (ata_id_current_chs_valid(id))
- return ata_id_u32(id, 57);
+ return id[ATA_ID_CUR_CYLS] * id[ATA_ID_CUR_HEADS] *
+ id[ATA_ID_CUR_SECTORS];
else
- return id[1] * id[3] * id[6];
+ return id[ATA_ID_CYLS] * id[ATA_ID_HEADS] *
+ id[ATA_ID_SECTORS];
}
}
@@ -1197,7 +1178,7 @@ u64 ata_tf_to_lba48(const struct ata_taskfile *tf)
sectors |= ((u64)(tf->hob_lbah & 0xff)) << 40;
sectors |= ((u64)(tf->hob_lbam & 0xff)) << 32;
- sectors |= (tf->hob_lbal & 0xff) << 24;
+ sectors |= ((u64)(tf->hob_lbal & 0xff)) << 24;
sectors |= (tf->lbah & 0xff) << 16;
sectors |= (tf->lbam & 0xff) << 8;
sectors |= (tf->lbal & 0xff);
@@ -1251,8 +1232,9 @@ static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors)
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
if (err_mask) {
- ata_dev_printk(dev, KERN_WARNING, "failed to read native "
- "max address (err_mask=0x%x)\n", err_mask);
+ ata_dev_warn(dev,
+ "failed to read native max address (err_mask=0x%x)\n",
+ err_mask);
if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED))
return -EACCES;
return -EIO;
@@ -1313,8 +1295,9 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors)
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
if (err_mask) {
- ata_dev_printk(dev, KERN_WARNING, "failed to set "
- "max address (err_mask=0x%x)\n", err_mask);
+ ata_dev_warn(dev,
+ "failed to set max address (err_mask=0x%x)\n",
+ err_mask);
if (err_mask == AC_ERR_DEV &&
(tf.feature & (ATA_ABORTED | ATA_IDNF)))
return -EACCES;
@@ -1339,6 +1322,7 @@ static int ata_hpa_resize(struct ata_device *dev)
{
struct ata_eh_context *ehc = &dev->link->eh_context;
int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
+ bool unlock_hpa = ata_ignore_hpa || dev->flags & ATA_DFLAG_UNLOCK_HPA;
u64 sectors = ata_id_n_sectors(dev->id);
u64 native_sectors;
int rc;
@@ -1355,9 +1339,9 @@ static int ata_hpa_resize(struct ata_device *dev)
/* If device aborted the command or HPA isn't going to
* be unlocked, skip HPA resizing.
*/
- if (rc == -EACCES || !ata_ignore_hpa) {
- ata_dev_printk(dev, KERN_WARNING, "HPA support seems "
- "broken, skipping HPA handling\n");
+ if (rc == -EACCES || !unlock_hpa) {
+ ata_dev_warn(dev,
+ "HPA support seems broken, skipping HPA handling\n");
dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
/* we can continue if device aborted the command */
@@ -1367,21 +1351,21 @@ static int ata_hpa_resize(struct ata_device *dev)
return rc;
}
+ dev->n_native_sectors = native_sectors;
/* nothing to do? */
- if (native_sectors <= sectors || !ata_ignore_hpa) {
+ if (native_sectors <= sectors || !unlock_hpa) {
if (!print_info || native_sectors == sectors)
return 0;
if (native_sectors > sectors)
- ata_dev_printk(dev, KERN_INFO,
+ ata_dev_info(dev,
"HPA detected: current %llu, native %llu\n",
(unsigned long long)sectors,
(unsigned long long)native_sectors);
else if (native_sectors < sectors)
- ata_dev_printk(dev, KERN_WARNING,
- "native sectors (%llu) is smaller than "
- "sectors (%llu)\n",
+ ata_dev_warn(dev,
+ "native sectors (%llu) is smaller than sectors (%llu)\n",
(unsigned long long)native_sectors,
(unsigned long long)sectors);
return 0;
@@ -1391,10 +1375,10 @@ static int ata_hpa_resize(struct ata_device *dev)
rc = ata_set_max_sectors(dev, native_sectors);
if (rc == -EACCES) {
/* if device aborted the command, skip HPA resizing */
- ata_dev_printk(dev, KERN_WARNING, "device aborted resize "
- "(%llu -> %llu), skipping HPA handling\n",
- (unsigned long long)sectors,
- (unsigned long long)native_sectors);
+ ata_dev_warn(dev,
+ "device aborted resize (%llu -> %llu), skipping HPA handling\n",
+ (unsigned long long)sectors,
+ (unsigned long long)native_sectors);
dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
return 0;
} else if (rc)
@@ -1403,14 +1387,14 @@ static int ata_hpa_resize(struct ata_device *dev)
/* re-read IDENTIFY data */
rc = ata_dev_reread_id(dev, 0);
if (rc) {
- ata_dev_printk(dev, KERN_ERR, "failed to re-read IDENTIFY "
- "data after HPA resizing\n");
+ ata_dev_err(dev,
+ "failed to re-read IDENTIFY data after HPA resizing\n");
return rc;
}
if (print_info) {
u64 new_sectors = ata_id_n_sectors(dev->id);
- ata_dev_printk(dev, KERN_INFO,
+ ata_dev_info(dev,
"HPA unlocked: %llu -> %llu, native %llu\n",
(unsigned long long)sectors,
(unsigned long long)new_sectors,
@@ -1508,8 +1492,8 @@ unsigned long ata_id_xfermask(const u16 *id)
/*
* Process compact flash extended modes
*/
- int pio = id[163] & 0x7;
- int dma = (id[163] >> 3) & 7;
+ int pio = (id[ATA_ID_CFA_MODES] >> 0) & 0x7;
+ int dma = (id[ATA_ID_CFA_MODES] >> 3) & 0x7;
if (pio)
pio_mask |= (1 << 5);
@@ -1528,53 +1512,6 @@ unsigned long ata_id_xfermask(const u16 *id)
return ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask);
}
-/**
- * ata_pio_queue_task - Queue port_task
- * @ap: The ata_port to queue port_task for
- * @fn: workqueue function to be scheduled
- * @data: data for @fn to use
- * @delay: delay time for workqueue function
- *
- * Schedule @fn(@data) for execution after @delay jiffies using
- * port_task. There is one port_task per port and it's the
- * user(low level driver)'s responsibility to make sure that only
- * one task is active at any given time.
- *
- * libata core layer takes care of synchronization between
- * port_task and EH. ata_pio_queue_task() may be ignored for EH
- * synchronization.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void ata_pio_queue_task(struct ata_port *ap, void *data, unsigned long delay)
-{
- ap->port_task_data = data;
-
- /* may fail if ata_port_flush_task() in progress */
- queue_delayed_work(ata_wq, &ap->port_task, delay);
-}
-
-/**
- * ata_port_flush_task - Flush port_task
- * @ap: The ata_port to flush port_task for
- *
- * After this function completes, port_task is guranteed not to
- * be running or scheduled.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- */
-void ata_port_flush_task(struct ata_port *ap)
-{
- DPRINTK("ENTER\n");
-
- cancel_rearming_delayed_work(&ap->port_task);
-
- if (ata_msg_ctl(ap))
- ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __func__);
-}
-
static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
{
struct completion *waiting = qc->private_data;
@@ -1587,7 +1524,7 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
* @dev: Device to which the command is sent
* @tf: Taskfile registers for the command and the result
* @cdb: CDB for packet command
- * @dma_dir: Data tranfer direction of the command
+ * @dma_dir: Data transfer direction of the command
* @sgl: sg list for the data buffer of the command
* @n_elem: Number of sg entries
* @timeout: Timeout in msecs (0 for default)
@@ -1612,6 +1549,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
struct ata_link *link = dev->link;
struct ata_port *ap = link->ap;
u8 command = tf->command;
+ int auto_timeout = 0;
struct ata_queued_cmd *qc;
unsigned int tag, preempted_tag;
u32 preempted_sactive, preempted_qc_active;
@@ -1664,6 +1602,12 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
qc->tf = *tf;
if (cdb)
memcpy(qc->cdb, cdb, ATAPI_CDB_LEN);
+
+ /* some SATA bridges need us to indicate data xfer direction */
+ if (tf->protocol == ATAPI_PROT_DMA && (dev->flags & ATA_DFLAG_DMADIR) &&
+ dma_dir == DMA_FROM_DEVICE)
+ qc->tf.feature |= ATAPI_DMADIR;
+
qc->flags |= ATA_QCFLAG_RESULT_TF;
qc->dma_dir = dma_dir;
if (dma_dir != DMA_NONE) {
@@ -1684,12 +1628,24 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
spin_unlock_irqrestore(ap->lock, flags);
- if (!timeout)
- timeout = ata_probe_timeout * 1000 / HZ;
+ if (!timeout) {
+ if (ata_probe_timeout)
+ timeout = ata_probe_timeout * 1000;
+ else {
+ timeout = ata_internal_cmd_timeout(dev, command);
+ auto_timeout = 1;
+ }
+ }
+
+ if (ap->ops->error_handler)
+ ata_eh_release(ap);
rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout));
- ata_port_flush_task(ap);
+ if (ap->ops->error_handler)
+ ata_eh_acquire(ap);
+
+ ata_sff_flush_pio_task(ap);
if (!rc) {
spin_lock_irqsave(ap->lock, flags);
@@ -1708,8 +1664,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
ata_qc_complete(qc);
if (ata_msg_warn(ap))
- ata_dev_printk(dev, KERN_WARNING,
- "qc timeout (cmd 0x%x)\n", command);
+ ata_dev_warn(dev, "qc timeout (cmd 0x%x)\n",
+ command);
}
spin_unlock_irqrestore(ap->lock, flags);
@@ -1743,24 +1699,11 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
ap->qc_active = preempted_qc_active;
ap->nr_active_links = preempted_nr_active_links;
- /* XXX - Some LLDDs (sata_mv) disable port on command failure.
- * Until those drivers are fixed, we detect the condition
- * here, fail the command with AC_ERR_SYSTEM and reenable the
- * port.
- *
- * Note that this doesn't change any behavior as internal
- * command failure results in disabling the device in the
- * higher layer for LLDDs without new reset/EH callbacks.
- *
- * Kill the following code as soon as those drivers are fixed.
- */
- if (ap->flags & ATA_FLAG_DISABLED) {
- err_mask |= AC_ERR_SYSTEM;
- ata_port_probe(ap);
- }
-
spin_unlock_irqrestore(ap->lock, flags);
+ if ((err_mask & AC_ERR_TIMEOUT) && auto_timeout)
+ ata_internal_cmd_timed_out(dev, command);
+
return err_mask;
}
@@ -1769,7 +1712,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
* @dev: Device to which the command is sent
* @tf: Taskfile registers for the command and the result
* @cdb: CDB for packet command
- * @dma_dir: Data tranfer direction of the command
+ * @dma_dir: Data transfer direction of the command
* @buf: Data buffer of the command
* @buflen: Length of data buffer
* @timeout: Timeout in msecs (0 for default)
@@ -1836,13 +1779,23 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
* Check if the current speed of the device requires IORDY. Used
* by various controllers for chip configuration.
*/
-
unsigned int ata_pio_need_iordy(const struct ata_device *adev)
{
- /* Controller doesn't support IORDY. Probably a pointless check
- as the caller should know this */
+ /* Don't set IORDY if we're preparing for reset. IORDY may
+ * lead to controller lock up on certain controllers if the
+ * port is not occupied. See bko#11703 for details.
+ */
+ if (adev->link->ap->pflags & ATA_PFLAG_RESETTING)
+ return 0;
+ /* Controller doesn't support IORDY. Probably a pointless
+ * check as the caller should know this.
+ */
if (adev->link->ap->flags & ATA_FLAG_NO_IORDY)
return 0;
+ /* CF spec. r4.1 Table 22 says no iordy on PIO5 and PIO6. */
+ if (ata_id_is_cfa(adev->id)
+ && (adev->pio_mode == XFER_PIO_5 || adev->pio_mode == XFER_PIO_6))
+ return 0;
/* PIO3 and higher it is mandatory */
if (adev->pio_mode > XFER_PIO_2)
return 1;
@@ -1859,7 +1812,6 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
* Compute the highest mode possible if we are not using iordy. Return
* -1 if no iordy mode is available.
*/
-
static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
{
/* If we have no drive specific rule, then PIO 2 is non IORDY */
@@ -1877,6 +1829,23 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
}
/**
+ * ata_do_dev_read_id - default ID read method
+ * @dev: device
+ * @tf: proposed taskfile
+ * @id: data buffer
+ *
+ * Issue the identify taskfile and hand back the buffer containing
+ * identify data. For some RAID controllers and for pre ATA devices
+ * this function is wrapped or replaced by the driver
+ */
+unsigned int ata_do_dev_read_id(struct ata_device *dev,
+ struct ata_taskfile *tf, u16 *id)
+{
+ return ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE,
+ id, sizeof(id[0]) * ATA_ID_WORDS, 0);
+}
+
+/**
* ata_dev_read_id - Read ID data from the specified device
* @dev: target device
* @p_class: pointer to class of the target device (may be changed)
@@ -1905,16 +1874,19 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
struct ata_taskfile tf;
unsigned int err_mask = 0;
const char *reason;
+ bool is_semb = class == ATA_DEV_SEMB;
int may_fallback = 1, tried_spinup = 0;
int rc;
if (ata_msg_ctl(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __func__);
+ ata_dev_dbg(dev, "%s: ENTER\n", __func__);
- retry:
+retry:
ata_tf_init(dev, &tf);
switch (class) {
+ case ATA_DEV_SEMB:
+ class = ATA_DEV_ATA; /* some hard drives report SEMB sig */
case ATA_DEV_ATA:
tf.command = ATA_CMD_ID_ATA;
break;
@@ -1939,15 +1911,25 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
*/
tf.flags |= ATA_TFLAG_POLLING;
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
- id, sizeof(id[0]) * ATA_ID_WORDS, 0);
+ if (ap->ops->read_id)
+ err_mask = ap->ops->read_id(dev, &tf, id);
+ else
+ err_mask = ata_do_dev_read_id(dev, &tf, id);
+
if (err_mask) {
if (err_mask & AC_ERR_NODEV_HINT) {
- ata_dev_printk(dev, KERN_DEBUG,
- "NODEV after polling detection\n");
+ ata_dev_dbg(dev, "NODEV after polling detection\n");
return -ENOENT;
}
+ if (is_semb) {
+ ata_dev_info(dev,
+ "IDENTIFY failed on device w/ SEMB sig, disabled\n");
+ /* SEMB is not supported yet */
+ *p_class = ATA_DEV_SEMB_UNSUP;
+ return 0;
+ }
+
if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) {
/* Device or controller might have reported
* the wrong device class. Give a shot at the
@@ -1968,8 +1950,8 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
* both flavors of IDENTIFYs which happens
* sometimes with phantom devices.
*/
- ata_dev_printk(dev, KERN_DEBUG,
- "both IDENTIFYs aborted, assuming NODEV\n");
+ ata_dev_dbg(dev,
+ "both IDENTIFYs aborted, assuming NODEV\n");
return -ENOENT;
}
@@ -1978,6 +1960,14 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
goto err_out;
}
+ if (dev->horkage & ATA_HORKAGE_DUMP_ID) {
+ ata_dev_dbg(dev, "dumping IDENTIFY data, "
+ "class=%d may_fallback=%d tried_spinup=%d\n",
+ class, may_fallback, tried_spinup);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,
+ 16, 2, id, ATA_ID_WORDS * sizeof(*id), true);
+ }
+
/* Falling back doesn't make sense if ID data was read
* successfully at least once.
*/
@@ -1992,6 +1982,12 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
if (class == ATA_DEV_ATA) {
if (!ata_id_is_ata(id) && !ata_id_is_cfa(id))
goto err_out;
+ if (ap->host->flags & ATA_HOST_IGNORE_ATA &&
+ ata_id_is_ata(id)) {
+ ata_dev_dbg(dev,
+ "host indicates ignore ATA devices, ignored\n");
+ return -ENOENT;
+ }
} else {
if (ata_id_is_ata(id))
goto err_out;
@@ -2028,7 +2024,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
* Some drives were very specific about that exact sequence.
*
* Note that ATA4 says lba is mandatory so the second check
- * shoud never trigger.
+ * should never trigger.
*/
if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
err_mask = ata_dev_init_params(dev, id[3], id[6]);
@@ -2052,40 +2048,121 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
err_out:
if (ata_msg_warn(ap))
- ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY "
- "(%s, err_mask=0x%x)\n", reason, err_mask);
+ ata_dev_warn(dev, "failed to IDENTIFY (%s, err_mask=0x%x)\n",
+ reason, err_mask);
return rc;
}
+static int ata_do_link_spd_horkage(struct ata_device *dev)
+{
+ struct ata_link *plink = ata_dev_phys_link(dev);
+ u32 target, target_limit;
+
+ if (!sata_scr_valid(plink))
+ return 0;
+
+ if (dev->horkage & ATA_HORKAGE_1_5_GBPS)
+ target = 1;
+ else
+ return 0;
+
+ target_limit = (1 << target) - 1;
+
+ /* if already on stricter limit, no need to push further */
+ if (plink->sata_spd_limit <= target_limit)
+ return 0;
+
+ plink->sata_spd_limit = target_limit;
+
+ /* Request another EH round by returning -EAGAIN if link is
+ * going faster than the target speed. Forward progress is
+ * guaranteed by setting sata_spd_limit to target_limit above.
+ */
+ if (plink->sata_spd > target) {
+ ata_dev_info(dev, "applying link speed limit horkage to %s\n",
+ sata_spd_string(target));
+ return -EAGAIN;
+ }
+ return 0;
+}
+
static inline u8 ata_dev_knobble(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
+
+ if (ata_dev_blacklisted(dev) & ATA_HORKAGE_BRIDGE_OK)
+ return 0;
+
return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
}
-static void ata_dev_config_ncq(struct ata_device *dev,
+static int ata_dev_config_ncq(struct ata_device *dev,
char *desc, size_t desc_sz)
{
struct ata_port *ap = dev->link->ap;
int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
+ unsigned int err_mask;
+ char *aa_desc = "";
if (!ata_id_has_ncq(dev->id)) {
desc[0] = '\0';
- return;
+ return 0;
}
if (dev->horkage & ATA_HORKAGE_NONCQ) {
snprintf(desc, desc_sz, "NCQ (not used)");
- return;
+ return 0;
}
if (ap->flags & ATA_FLAG_NCQ) {
hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1);
dev->flags |= ATA_DFLAG_NCQ;
}
+ if (!(dev->horkage & ATA_HORKAGE_BROKEN_FPDMA_AA) &&
+ (ap->flags & ATA_FLAG_FPDMA_AA) &&
+ ata_id_has_fpdma_aa(dev->id)) {
+ err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_ENABLE,
+ SATA_FPDMA_AA);
+ if (err_mask) {
+ ata_dev_err(dev,
+ "failed to enable AA (error_mask=0x%x)\n",
+ err_mask);
+ if (err_mask != AC_ERR_DEV) {
+ dev->horkage |= ATA_HORKAGE_BROKEN_FPDMA_AA;
+ return -EIO;
+ }
+ } else
+ aa_desc = ", AA";
+ }
+
if (hdepth >= ddepth)
- snprintf(desc, desc_sz, "NCQ (depth %d)", ddepth);
+ snprintf(desc, desc_sz, "NCQ (depth %d)%s", ddepth, aa_desc);
else
- snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
+ snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth,
+ ddepth, aa_desc);
+
+ if ((ap->flags & ATA_FLAG_FPDMA_AUX) &&
+ ata_id_has_ncq_send_and_recv(dev->id)) {
+ err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_SEND_RECV,
+ 0, ap->sector_buf, 1);
+ if (err_mask) {
+ ata_dev_dbg(dev,
+ "failed to get NCQ Send/Recv Log Emask 0x%x\n",
+ err_mask);
+ } else {
+ u8 *cmds = dev->ncq_send_recv_cmds;
+
+ dev->flags |= ATA_DFLAG_NCQ_SEND_RECV;
+ memcpy(cmds, ap->sector_buf, ATA_LOG_NCQ_SEND_RECV_SIZE);
+
+ if (dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM) {
+ ata_dev_dbg(dev, "disabling queued TRIM support\n");
+ cmds[ATA_LOG_NCQ_SEND_RECV_DSM_OFFSET] &=
+ ~ATA_LOG_NCQ_SEND_RECV_DSM_TRIM;
+ }
+ }
+ }
+
+ return 0;
}
/**
@@ -2108,24 +2185,53 @@ int ata_dev_configure(struct ata_device *dev)
int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
const u16 *id = dev->id;
unsigned long xfer_mask;
+ unsigned int err_mask;
char revbuf[7]; /* XYZ-99\0 */
char fwrevbuf[ATA_ID_FW_REV_LEN+1];
char modelbuf[ATA_ID_PROD_LEN+1];
int rc;
if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
- ata_dev_printk(dev, KERN_INFO, "%s: ENTER/EXIT -- nodev\n",
- __func__);
+ ata_dev_info(dev, "%s: ENTER/EXIT -- nodev\n", __func__);
return 0;
}
if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __func__);
+ ata_dev_dbg(dev, "%s: ENTER\n", __func__);
/* set horkage */
dev->horkage |= ata_dev_blacklisted(dev);
ata_force_horkage(dev);
+ if (dev->horkage & ATA_HORKAGE_DISABLE) {
+ ata_dev_info(dev, "unsupported device, disabling\n");
+ ata_dev_disable(dev);
+ return 0;
+ }
+
+ if ((!atapi_enabled || (ap->flags & ATA_FLAG_NO_ATAPI)) &&
+ dev->class == ATA_DEV_ATAPI) {
+ ata_dev_warn(dev, "WARNING: ATAPI is %s, device ignored\n",
+ atapi_enabled ? "not supported with this driver"
+ : "disabled");
+ ata_dev_disable(dev);
+ return 0;
+ }
+
+ rc = ata_do_link_spd_horkage(dev);
+ if (rc)
+ return rc;
+
+ /* some WD SATA-1 drives have issues with LPM, turn on NOLPM for them */
+ if ((dev->horkage & ATA_HORKAGE_WD_BROKEN_LPM) &&
+ (id[ATA_ID_SATA_CAPABILITY] & 0xe) == 0x2)
+ dev->horkage |= ATA_HORKAGE_NOLPM;
+
+ if (dev->horkage & ATA_HORKAGE_NOLPM) {
+ ata_dev_warn(dev, "LPM support broken, forcing max_power\n");
+ dev->link->ap->target_lpm_policy = ATA_LPM_MAX_POWER;
+ }
+
/* let ACPI work its magic */
rc = ata_acpi_on_devcfg(dev);
if (rc)
@@ -2138,12 +2244,12 @@ int ata_dev_configure(struct ata_device *dev)
/* print device capabilities */
if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG,
- "%s: cfg 49:%04x 82:%04x 83:%04x 84:%04x "
- "85:%04x 86:%04x 87:%04x 88:%04x\n",
- __func__,
- id[49], id[82], id[83], id[84],
- id[85], id[86], id[87], id[88]);
+ ata_dev_dbg(dev,
+ "%s: cfg 49:%04x 82:%04x 83:%04x 84:%04x "
+ "85:%04x 86:%04x 87:%04x 88:%04x\n",
+ __func__,
+ id[49], id[82], id[83], id[84],
+ id[85], id[86], id[87], id[88]);
/* initialize to-be-configured parameters */
dev->flags &= ~ATA_DFLAG_CFG_MASK;
@@ -2153,6 +2259,7 @@ int ata_dev_configure(struct ata_device *dev)
dev->cylinders = 0;
dev->heads = 0;
dev->sectors = 0;
+ dev->multi_count = 0;
/*
* common ATA, ATAPI feature tests
@@ -2174,28 +2281,34 @@ int ata_dev_configure(struct ata_device *dev)
/* ATA-specific feature tests */
if (dev->class == ATA_DEV_ATA) {
if (ata_id_is_cfa(id)) {
- if (id[162] & 1) /* CPRM may make this media unusable */
- ata_dev_printk(dev, KERN_WARNING,
- "supports DRM functions and may "
- "not be fully accessable.\n");
+ /* CPRM may make this media unusable */
+ if (id[ATA_ID_CFA_KEY_MGMT] & 1)
+ ata_dev_warn(dev,
+ "supports DRM functions and may not be fully accessible\n");
snprintf(revbuf, 7, "CFA");
} else {
snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id));
/* Warn the user if the device has TPM extensions */
if (ata_id_has_tpm(id))
- ata_dev_printk(dev, KERN_WARNING,
- "supports DRM functions and may "
- "not be fully accessable.\n");
+ ata_dev_warn(dev,
+ "supports DRM functions and may not be fully accessible\n");
}
dev->n_sectors = ata_id_n_sectors(id);
- if (dev->id[59] & 0x100)
- dev->multi_count = dev->id[59] & 0xff;
+ /* get current R/W Multiple count setting */
+ if ((dev->id[47] >> 8) == 0x80 && (dev->id[59] & 0x100)) {
+ unsigned int max = dev->id[47] & 0xff;
+ unsigned int cnt = dev->id[59] & 0xff;
+ /* only recognize/allow powers of two here */
+ if (is_power_of_2(max) && is_power_of_2(cnt))
+ if (cnt <= max)
+ dev->multi_count = cnt;
+ }
if (ata_id_has_lba(id)) {
const char *lba_desc;
- char ncq_desc[20];
+ char ncq_desc[24];
lba_desc = "LBA";
dev->flags |= ATA_DFLAG_LBA;
@@ -2209,16 +2322,17 @@ int ata_dev_configure(struct ata_device *dev)
}
/* config NCQ */
- ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
+ rc = ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
+ if (rc)
+ return rc;
/* print device info to dmesg */
if (ata_msg_drv(ap) && print_info) {
- ata_dev_printk(dev, KERN_INFO,
- "%s: %s, %s, max %s\n",
- revbuf, modelbuf, fwrevbuf,
- ata_mode_string(xfer_mask));
- ata_dev_printk(dev, KERN_INFO,
- "%Lu sectors, multi %u: %s %s\n",
+ ata_dev_info(dev, "%s: %s, %s, max %s\n",
+ revbuf, modelbuf, fwrevbuf,
+ ata_mode_string(xfer_mask));
+ ata_dev_info(dev,
+ "%llu sectors, multi %u: %s %s\n",
(unsigned long long)dev->n_sectors,
dev->multi_count, lba_desc, ncq_desc);
}
@@ -2239,18 +2353,41 @@ int ata_dev_configure(struct ata_device *dev)
/* print device info to dmesg */
if (ata_msg_drv(ap) && print_info) {
- ata_dev_printk(dev, KERN_INFO,
- "%s: %s, %s, max %s\n",
- revbuf, modelbuf, fwrevbuf,
- ata_mode_string(xfer_mask));
- ata_dev_printk(dev, KERN_INFO,
- "%Lu sectors, multi %u, CHS %u/%u/%u\n",
- (unsigned long long)dev->n_sectors,
- dev->multi_count, dev->cylinders,
- dev->heads, dev->sectors);
+ ata_dev_info(dev, "%s: %s, %s, max %s\n",
+ revbuf, modelbuf, fwrevbuf,
+ ata_mode_string(xfer_mask));
+ ata_dev_info(dev,
+ "%llu sectors, multi %u, CHS %u/%u/%u\n",
+ (unsigned long long)dev->n_sectors,
+ dev->multi_count, dev->cylinders,
+ dev->heads, dev->sectors);
}
}
+ /* Check and mark DevSlp capability. Get DevSlp timing variables
+ * from SATA Settings page of Identify Device Data Log.
+ */
+ if (ata_id_has_devslp(dev->id)) {
+ u8 *sata_setting = ap->sector_buf;
+ int i, j;
+
+ dev->flags |= ATA_DFLAG_DEVSLP;
+ err_mask = ata_read_log_page(dev,
+ ATA_LOG_SATA_ID_DEV_DATA,
+ ATA_LOG_SATA_SETTINGS,
+ sata_setting,
+ 1);
+ if (err_mask)
+ ata_dev_dbg(dev,
+ "failed to get Identify Device Data, Emask 0x%x\n",
+ err_mask);
+ else
+ for (i = 0; i < ATA_LOG_DEVSLP_SIZE; i++) {
+ j = ATA_LOG_DEVSLP_OFFSET + i;
+ dev->devslp_timing[i] = sata_setting[j];
+ }
+ }
+
dev->cdb_len = 16;
}
@@ -2264,8 +2401,7 @@ int ata_dev_configure(struct ata_device *dev)
rc = atapi_cdb_len(id);
if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
if (ata_msg_warn(ap))
- ata_dev_printk(dev, KERN_WARNING,
- "unsupported CDB len\n");
+ ata_dev_warn(dev, "unsupported CDB len\n");
rc = -EINVAL;
goto err_out_nosup;
}
@@ -2276,18 +2412,17 @@ int ata_dev_configure(struct ata_device *dev)
* to enable ATAPI AN to discern between PHY status
* changed notifications and ATAPI ANs.
*/
- if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
+ if (atapi_an &&
+ (ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
(!sata_pmp_attached(ap) ||
sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) {
- unsigned int err_mask;
-
/* issue SET feature command to turn this on */
err_mask = ata_dev_set_feature(dev,
SETFEATURES_SATA_ENABLE, SATA_AN);
if (err_mask)
- ata_dev_printk(dev, KERN_ERR,
- "failed to enable ATAPI AN "
- "(err_mask=0x%x)\n", err_mask);
+ ata_dev_err(dev,
+ "failed to enable ATAPI AN (err_mask=0x%x)\n",
+ err_mask);
else {
dev->flags |= ATA_DFLAG_AN;
atapi_an_string = ", ATAPI AN";
@@ -2299,19 +2434,24 @@ int ata_dev_configure(struct ata_device *dev)
cdb_intr_string = ", CDB intr";
}
- if (atapi_dmadir || atapi_id_dmadir(dev->id)) {
+ if (atapi_dmadir || (dev->horkage & ATA_HORKAGE_ATAPI_DMADIR) || atapi_id_dmadir(dev->id)) {
dev->flags |= ATA_DFLAG_DMADIR;
dma_dir_string = ", DMADIR";
}
+ if (ata_id_has_da(dev->id)) {
+ dev->flags |= ATA_DFLAG_DA;
+ zpodd_init(dev);
+ }
+
/* print device info to dmesg */
if (ata_msg_drv(ap) && print_info)
- ata_dev_printk(dev, KERN_INFO,
- "ATAPI: %s, %s, max %s%s%s%s\n",
- modelbuf, fwrevbuf,
- ata_mode_string(xfer_mask),
- cdb_intr_string, atapi_an_string,
- dma_dir_string);
+ ata_dev_info(dev,
+ "ATAPI: %s, %s, max %s%s%s%s\n",
+ modelbuf, fwrevbuf,
+ ata_mode_string(xfer_mask),
+ cdb_intr_string, atapi_an_string,
+ dma_dir_string);
}
/* determine max_sectors */
@@ -2319,19 +2459,11 @@ int ata_dev_configure(struct ata_device *dev)
if (dev->flags & ATA_DFLAG_LBA48)
dev->max_sectors = ATA_MAX_SECTORS_LBA48;
- if (!(dev->horkage & ATA_HORKAGE_IPM)) {
- if (ata_id_has_hipm(dev->id))
- dev->flags |= ATA_DFLAG_HIPM;
- if (ata_id_has_dipm(dev->id))
- dev->flags |= ATA_DFLAG_DIPM;
- }
-
/* Limit PATA drive on SATA cable bridge transfers to udma5,
200 sectors */
if (ata_dev_knobble(dev)) {
if (ata_msg_drv(ap) && print_info)
- ata_dev_printk(dev, KERN_INFO,
- "applying bridge limits\n");
+ ata_dev_info(dev, "applying bridge limits\n");
dev->udma_mask &= ATA_UDMA5;
dev->max_sectors = ATA_MAX_SECTORS;
}
@@ -2346,12 +2478,8 @@ int ata_dev_configure(struct ata_device *dev)
dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
dev->max_sectors);
- if (ata_dev_blacklisted(dev) & ATA_HORKAGE_IPM) {
- dev->horkage |= ATA_HORKAGE_IPM;
-
- /* reset link pm_policy for this port to no pm */
- ap->pm_policy = MAX_PERFORMANCE;
- }
+ if (dev->horkage & ATA_HORKAGE_MAX_SEC_LBA48)
+ dev->max_sectors = ATA_MAX_SECTORS_LBA48;
if (ap->ops->dev_config)
ap->ops->dev_config(dev);
@@ -2364,19 +2492,23 @@ int ata_dev_configure(struct ata_device *dev)
bugs */
if (print_info) {
- ata_dev_printk(dev, KERN_WARNING,
+ ata_dev_warn(dev,
"Drive reports diagnostics failure. This may indicate a drive\n");
- ata_dev_printk(dev, KERN_WARNING,
+ ata_dev_warn(dev,
"fault or invalid emulation. Contact drive vendor for information.\n");
}
}
+ if ((dev->horkage & ATA_HORKAGE_FIRMWARE_WARN) && print_info) {
+ ata_dev_warn(dev, "WARNING: device requires firmware update to be fully functional\n");
+ ata_dev_warn(dev, " contact the vendor or visit http://ata.wiki.kernel.org\n");
+ }
+
return 0;
err_out_nosup:
if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG,
- "%s: EXIT, err\n", __func__);
+ ata_dev_dbg(dev, "%s: EXIT, err\n", __func__);
return rc;
}
@@ -2464,13 +2596,11 @@ int ata_bus_probe(struct ata_port *ap)
int rc;
struct ata_device *dev;
- ata_port_probe(ap);
-
- ata_link_for_each_dev(dev, &ap->link)
+ ata_for_each_dev(dev, &ap->link, ALL)
tries[dev->devno] = ATA_PROBE_MAX_TRIES;
retry:
- ata_link_for_each_dev(dev, &ap->link) {
+ ata_for_each_dev(dev, &ap->link, ALL) {
/* If we issue an SRST then an ATA drive (not ATAPI)
* may change configuration and be in PIO0 timing. If
* we do a hard reset (or are coming from power on)
@@ -2479,6 +2609,7 @@ int ata_bus_probe(struct ata_port *ap)
* bus as we may be talking too fast.
*/
dev->pio_mode = XFER_PIO_0;
+ dev->dma_mode = 0xff;
/* If the controller has a pio mode setup function
* then use it to set the chipset to rights. Don't
@@ -2492,9 +2623,8 @@ int ata_bus_probe(struct ata_port *ap)
/* reset and determine device classes */
ap->ops->phy_reset(ap);
- ata_link_for_each_dev(dev, &ap->link) {
- if (!(ap->flags & ATA_FLAG_DISABLED) &&
- dev->class != ATA_DEV_UNKNOWN)
+ ata_for_each_dev(dev, &ap->link, ALL) {
+ if (dev->class != ATA_DEV_UNKNOWN)
classes[dev->devno] = dev->class;
else
classes[dev->devno] = ATA_DEV_NONE;
@@ -2502,13 +2632,11 @@ int ata_bus_probe(struct ata_port *ap)
dev->class = ATA_DEV_UNKNOWN;
}
- ata_port_probe(ap);
-
/* read IDENTIFY page and configure devices. We have to do the identify
specific sequence bass-ackwards so that PDIAG- is released by
the slave device */
- ata_link_for_each_dev_reverse(dev, &ap->link) {
+ ata_for_each_dev(dev, &ap->link, ALL_REVERSE) {
if (tries[dev->devno])
dev->class = classes[dev->devno];
@@ -2525,24 +2653,19 @@ int ata_bus_probe(struct ata_port *ap)
if (ap->ops->cable_detect)
ap->cbl = ap->ops->cable_detect(ap);
- /* We may have SATA bridge glue hiding here irrespective of the
- reported cable types and sensed types */
- ata_link_for_each_dev(dev, &ap->link) {
- if (!ata_dev_enabled(dev))
- continue;
- /* SATA drives indicate we have a bridge. We don't know which
- end of the link the bridge is which is a problem */
+ /* We may have SATA bridge glue hiding here irrespective of
+ * the reported cable types and sensed types. When SATA
+ * drives indicate we have a bridge, we don't know which end
+ * of the link the bridge is which is a problem.
+ */
+ ata_for_each_dev(dev, &ap->link, ENABLED)
if (ata_id_is_sata(dev->id))
ap->cbl = ATA_CBL_SATA;
- }
/* After the identify sequence we can now set up the devices. We do
this in the normal order so that the user doesn't get confused */
- ata_link_for_each_dev(dev, &ap->link) {
- if (!ata_dev_enabled(dev))
- continue;
-
+ ata_for_each_dev(dev, &ap->link, ENABLED) {
ap->link.eh_context.i.flags |= ATA_EHI_PRINTINFO;
rc = ata_dev_configure(dev);
ap->link.eh_context.i.flags &= ~ATA_EHI_PRINTINFO;
@@ -2555,12 +2678,9 @@ int ata_bus_probe(struct ata_port *ap)
if (rc)
goto fail;
- ata_link_for_each_dev(dev, &ap->link)
- if (ata_dev_enabled(dev))
- return 0;
+ ata_for_each_dev(dev, &ap->link, ENABLED)
+ return 0;
- /* no device present, disable port */
- ata_port_disable(ap);
return -ENODEV;
fail:
@@ -2580,7 +2700,7 @@ int ata_bus_probe(struct ata_port *ap)
/* This is the last chance, better to slow
* down than lose it.
*/
- sata_down_spd_limit(&ap->link);
+ sata_down_spd_limit(&ap->link, 0);
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
}
}
@@ -2592,22 +2712,6 @@ int ata_bus_probe(struct ata_port *ap)
}
/**
- * ata_port_probe - Mark port as enabled
- * @ap: Port for which we indicate enablement
- *
- * Modify @ap data structure such that the system
- * thinks that the entire port is enabled.
- *
- * LOCKING: host lock, or some other form of
- * serialization.
- */
-
-void ata_port_probe(struct ata_port *ap)
-{
- ap->flags &= ~ATA_FLAG_DISABLED;
-}
-
-/**
* sata_print_link_status - Print SATA link status
* @link: SATA link to printk link status about
*
@@ -2616,7 +2720,7 @@ void ata_port_probe(struct ata_port *ap)
* LOCKING:
* None.
*/
-void sata_print_link_status(struct ata_link *link)
+static void sata_print_link_status(struct ata_link *link)
{
u32 sstatus, scontrol, tmp;
@@ -2624,15 +2728,13 @@ void sata_print_link_status(struct ata_link *link)
return;
sata_scr_read(link, SCR_CONTROL, &scontrol);
- if (ata_link_online(link)) {
+ if (ata_phys_link_online(link)) {
tmp = (sstatus >> 4) & 0xf;
- ata_link_printk(link, KERN_INFO,
- "SATA link up %s (SStatus %X SControl %X)\n",
- sata_spd_string(tmp), sstatus, scontrol);
+ ata_link_info(link, "SATA link up %s (SStatus %X SControl %X)\n",
+ sata_spd_string(tmp), sstatus, scontrol);
} else {
- ata_link_printk(link, KERN_INFO,
- "SATA link down (SStatus %X SControl %X)\n",
- sstatus, scontrol);
+ ata_link_info(link, "SATA link down (SStatus %X SControl %X)\n",
+ sstatus, scontrol);
}
}
@@ -2654,43 +2756,29 @@ struct ata_device *ata_dev_pair(struct ata_device *adev)
}
/**
- * ata_port_disable - Disable port.
- * @ap: Port to be disabled.
- *
- * Modify @ap data structure such that the system
- * thinks that the entire port is disabled, and should
- * never attempt to probe or communicate with devices
- * on this port.
- *
- * LOCKING: host lock, or some other form of
- * serialization.
- */
-
-void ata_port_disable(struct ata_port *ap)
-{
- ap->link.device[0].class = ATA_DEV_NONE;
- ap->link.device[1].class = ATA_DEV_NONE;
- ap->flags |= ATA_FLAG_DISABLED;
-}
-
-/**
* sata_down_spd_limit - adjust SATA spd limit downward
* @link: Link to adjust SATA spd limit for
+ * @spd_limit: Additional limit
*
* Adjust SATA spd limit of @link downward. Note that this
* function only adjusts the limit. The change must be applied
* using sata_set_spd().
*
+ * If @spd_limit is non-zero, the speed is limited to equal to or
+ * lower than @spd_limit if such speed is supported. If
+ * @spd_limit is slower than any supported speed, only the lowest
+ * supported speed is allowed.
+ *
* LOCKING:
* Inherited from caller.
*
* RETURNS:
* 0 on success, negative errno on failure
*/
-int sata_down_spd_limit(struct ata_link *link)
+int sata_down_spd_limit(struct ata_link *link, u32 spd_limit)
{
u32 sstatus, spd, mask;
- int rc, highbit;
+ int rc, bit;
if (!sata_scr_valid(link))
return -EOPNOTSUPP;
@@ -2699,7 +2787,7 @@ int sata_down_spd_limit(struct ata_link *link)
* If not, use cached value in link->sata_spd.
*/
rc = sata_scr_read(link, SCR_STATUS, &sstatus);
- if (rc == 0)
+ if (rc == 0 && ata_sstatus_online(sstatus))
spd = (sstatus >> 4) & 0xf;
else
spd = link->sata_spd;
@@ -2709,8 +2797,8 @@ int sata_down_spd_limit(struct ata_link *link)
return -EINVAL;
/* unconditionally mask off the highest bit */
- highbit = fls(mask) - 1;
- mask &= ~(1 << highbit);
+ bit = fls(mask) - 1;
+ mask &= ~(1 << bit);
/* Mask off all speeds higher than or equal to the current
* one. Force 1.5Gbps if current SPD is not available.
@@ -2724,10 +2812,19 @@ int sata_down_spd_limit(struct ata_link *link)
if (!mask)
return -EINVAL;
+ if (spd_limit) {
+ if (mask & ((1 << spd_limit) - 1))
+ mask &= (1 << spd_limit) - 1;
+ else {
+ bit = ffs(mask) - 1;
+ mask = 1 << bit;
+ }
+ }
+
link->sata_spd_limit = mask;
- ata_link_printk(link, KERN_WARNING, "limiting SATA link speed to %s\n",
- sata_spd_string(fls(mask)));
+ ata_link_warn(link, "limiting SATA link speed to %s\n",
+ sata_spd_string(fls(mask)));
return 0;
}
@@ -2772,7 +2869,7 @@ static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol)
* RETURNS:
* 1 if SATA spd configuration is needed, 0 otherwise.
*/
-int sata_set_spd_needed(struct ata_link *link)
+static int sata_set_spd_needed(struct ata_link *link)
{
u32 scontrol;
@@ -2825,33 +2922,33 @@ int sata_set_spd(struct ata_link *link)
*/
static const struct ata_timing ata_timing[] = {
-/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */
- { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 },
- { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 },
- { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 },
- { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 },
- { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 },
- { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 },
- { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 },
-
- { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 },
- { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 },
- { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 },
-
- { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 },
- { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 },
- { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 },
- { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 100, 0 },
- { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 },
-
-/* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, */
- { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 },
- { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 },
- { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 },
- { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 },
- { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 },
- { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 },
- { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 },
+/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 0, 960, 0 }, */
+ { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 0, 600, 0 },
+ { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 0, 383, 0 },
+ { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 0, 240, 0 },
+ { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 0, 180, 0 },
+ { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 0, 120, 0 },
+ { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 0, 100, 0 },
+ { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 0, 80, 0 },
+
+ { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 50, 960, 0 },
+ { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 30, 480, 0 },
+ { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 20, 240, 0 },
+
+ { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 20, 480, 0 },
+ { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 5, 150, 0 },
+ { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 5, 120, 0 },
+ { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 5, 100, 0 },
+ { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 5, 80, 0 },
+
+/* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 0, 150 }, */
+ { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 0, 120 },
+ { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 0, 80 },
+ { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 0, 60 },
+ { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 0, 45 },
+ { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 0, 30 },
+ { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 0, 20 },
+ { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 0, 15 },
{ 0xFF }
};
@@ -2861,14 +2958,15 @@ static const struct ata_timing ata_timing[] = {
static void ata_timing_quantize(const struct ata_timing *t, struct ata_timing *q, int T, int UT)
{
- q->setup = EZ(t->setup * 1000, T);
- q->act8b = EZ(t->act8b * 1000, T);
- q->rec8b = EZ(t->rec8b * 1000, T);
- q->cyc8b = EZ(t->cyc8b * 1000, T);
- q->active = EZ(t->active * 1000, T);
- q->recover = EZ(t->recover * 1000, T);
- q->cycle = EZ(t->cycle * 1000, T);
- q->udma = EZ(t->udma * 1000, UT);
+ q->setup = EZ(t->setup * 1000, T);
+ q->act8b = EZ(t->act8b * 1000, T);
+ q->rec8b = EZ(t->rec8b * 1000, T);
+ q->cyc8b = EZ(t->cyc8b * 1000, T);
+ q->active = EZ(t->active * 1000, T);
+ q->recover = EZ(t->recover * 1000, T);
+ q->dmack_hold = EZ(t->dmack_hold * 1000, T);
+ q->cycle = EZ(t->cycle * 1000, T);
+ q->udma = EZ(t->udma * 1000, UT);
}
void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
@@ -2880,6 +2978,7 @@ void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
if (what & ATA_TIMING_CYC8B ) m->cyc8b = max(a->cyc8b, b->cyc8b);
if (what & ATA_TIMING_ACTIVE ) m->active = max(a->active, b->active);
if (what & ATA_TIMING_RECOVER) m->recover = max(a->recover, b->recover);
+ if (what & ATA_TIMING_DMACK_HOLD) m->dmack_hold = max(a->dmack_hold, b->dmack_hold);
if (what & ATA_TIMING_CYCLE ) m->cycle = max(a->cycle, b->cycle);
if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma);
}
@@ -2893,12 +2992,17 @@ const struct ata_timing *ata_timing_find_mode(u8 xfer_mode)
if (xfer_mode == t->mode)
return t;
+
+ WARN_ONCE(true, "%s: unable to find timing for xfer_mode 0x%x\n",
+ __func__, xfer_mode);
+
return NULL;
}
int ata_timing_compute(struct ata_device *adev, unsigned short speed,
struct ata_timing *t, int T, int UT)
{
+ const u16 *id = adev->id;
const struct ata_timing *s;
struct ata_timing p;
@@ -2916,14 +3020,18 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
* PIO/MW_DMA cycle timing.
*/
- if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
+ if (id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
memset(&p, 0, sizeof(p));
- if (speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) {
- if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO];
- else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY];
- } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) {
- p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN];
- }
+
+ if (speed >= XFER_PIO_0 && speed < XFER_SW_DMA_0) {
+ if (speed <= XFER_PIO_2)
+ p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
+ else if ((speed <= XFER_PIO_4) ||
+ (speed == XFER_PIO_5 && !ata_id_is_cfa(id)))
+ p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
+ } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+ p.cycle = id[ATA_ID_EIDE_DMA_MIN];
+
ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B);
}
@@ -3097,8 +3205,7 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
snprintf(buf, sizeof(buf), "%s",
ata_mode_string(xfer_mask));
- ata_dev_printk(dev, KERN_WARNING,
- "limiting speed to %s\n", buf);
+ ata_dev_warn(dev, "limiting speed to %s\n", buf);
}
ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask,
@@ -3109,17 +3216,27 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
static int ata_dev_set_mode(struct ata_device *dev)
{
+ struct ata_port *ap = dev->link->ap;
struct ata_eh_context *ehc = &dev->link->eh_context;
+ const bool nosetxfer = dev->horkage & ATA_HORKAGE_NOSETXFER;
const char *dev_err_whine = "";
int ign_dev_err = 0;
- unsigned int err_mask;
+ unsigned int err_mask = 0;
int rc;
dev->flags &= ~ATA_DFLAG_PIO;
if (dev->xfer_shift == ATA_SHIFT_PIO)
dev->flags |= ATA_DFLAG_PIO;
- err_mask = ata_dev_set_xfermode(dev);
+ if (nosetxfer && ap->flags & ATA_FLAG_SATA && ata_id_is_sata(dev->id))
+ dev_err_whine = " (SET_XFERMODE skipped)";
+ else {
+ if (nosetxfer)
+ ata_dev_warn(dev,
+ "NOSETXFER but PATA detected - can't "
+ "skip SETXFER, might malfunction\n");
+ err_mask = ata_dev_set_xfermode(dev);
+ }
if (err_mask & ~AC_ERR_DEV)
goto fail;
@@ -3167,15 +3284,14 @@ static int ata_dev_set_mode(struct ata_device *dev)
DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n",
dev->xfer_shift, (int)dev->xfer_mode);
- ata_dev_printk(dev, KERN_INFO, "configured for %s%s\n",
- ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)),
- dev_err_whine);
+ ata_dev_info(dev, "configured for %s%s\n",
+ ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)),
+ dev_err_whine);
return 0;
fail:
- ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
- "(err_mask=0x%x)\n", err_mask);
+ ata_dev_err(dev, "failed to set xfermode (err_mask=0x%x)\n", err_mask);
return -EIO;
}
@@ -3203,13 +3319,10 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
int rc = 0, used_dma = 0, found = 0;
/* step 1: calculate xfer_mask */
- ata_link_for_each_dev(dev, link) {
+ ata_for_each_dev(dev, link, ENABLED) {
unsigned long pio_mask, dma_mask;
unsigned int mode_mask;
- if (!ata_dev_enabled(dev))
- continue;
-
mode_mask = ATA_DMA_MASK_ATA;
if (dev->class == ATA_DEV_ATAPI)
mode_mask = ATA_DMA_MASK_ATAPI;
@@ -3220,10 +3333,10 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
ata_force_xfermask(dev);
pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
- dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
if (libata_dma_mask & mode_mask)
- dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+ dma_mask = ata_pack_xfermask(0, dev->mwdma_mask,
+ dev->udma_mask);
else
dma_mask = 0;
@@ -3231,19 +3344,16 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
dev->dma_mode = ata_xfer_mask2mode(dma_mask);
found = 1;
- if (dev->dma_mode != 0xff)
+ if (ata_dma_enabled(dev))
used_dma = 1;
}
if (!found)
goto out;
/* step 2: always set host PIO timings */
- ata_link_for_each_dev(dev, link) {
- if (!ata_dev_enabled(dev))
- continue;
-
+ ata_for_each_dev(dev, link, ENABLED) {
if (dev->pio_mode == 0xff) {
- ata_dev_printk(dev, KERN_WARNING, "no PIO support\n");
+ ata_dev_warn(dev, "no PIO support\n");
rc = -EINVAL;
goto out;
}
@@ -3255,8 +3365,8 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
}
/* step 3: set host DMA timings */
- ata_link_for_each_dev(dev, link) {
- if (!ata_dev_enabled(dev) || dev->dma_mode == 0xff)
+ ata_for_each_dev(dev, link, ENABLED) {
+ if (!ata_dma_enabled(dev))
continue;
dev->xfer_mode = dev->dma_mode;
@@ -3266,11 +3376,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
}
/* step 4: update devices' xfer mode */
- ata_link_for_each_dev(dev, link) {
- /* don't update suspended devices' xfer mode */
- if (!ata_dev_enabled(dev))
- continue;
-
+ ata_for_each_dev(dev, link, ENABLED) {
rc = ata_dev_set_mode(dev);
if (rc)
goto out;
@@ -3312,9 +3418,21 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline,
int (*check_ready)(struct ata_link *link))
{
unsigned long start = jiffies;
- unsigned long nodev_deadline = start + ATA_TMOUT_FF_WAIT;
+ unsigned long nodev_deadline;
int warned = 0;
+ /* choose which 0xff timeout to use, read comment in libata.h */
+ if (link->ap->host->flags & ATA_HOST_PARALLEL_SCAN)
+ nodev_deadline = ata_deadline(start, ATA_TMOUT_FF_WAIT_LONG);
+ else
+ nodev_deadline = ata_deadline(start, ATA_TMOUT_FF_WAIT);
+
+ /* Slave readiness can't be tested separately from master. On
+ * M/S emulation configuration, this function should be called
+ * only on the master and it will handle both master and slave.
+ */
+ WARN_ON(link == link->ap->slave_link);
+
if (time_after(nodev_deadline, deadline))
nodev_deadline = deadline;
@@ -3326,12 +3444,12 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline,
if (ready > 0)
return 0;
- /* -ENODEV could be transient. Ignore -ENODEV if link
+ /*
+ * -ENODEV could be transient. Ignore -ENODEV if link
* is online. Also, some SATA devices take a long
- * time to clear 0xff after reset. For example,
- * HHD424020F7SV00 iVDR needs >= 800ms while Quantum
- * GoVault needs even more than that. Wait for
- * ATA_TMOUT_FF_WAIT on -ENODEV if link isn't offline.
+ * time to clear 0xff after reset. Wait for
+ * ATA_TMOUT_FF_WAIT[_LONG] on -ENODEV if link isn't
+ * offline.
*
* Note that some PATA controllers (pata_ali) explode
* if status register is read more than once when
@@ -3353,13 +3471,13 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline,
if (!warned && time_after(now, start + 5 * HZ) &&
(deadline - now > 3 * HZ)) {
- ata_link_printk(link, KERN_WARNING,
+ ata_link_warn(link,
"link is slow to respond, please be patient "
"(ready=%d)\n", tmp);
warned = 1;
}
- msleep(50);
+ ata_msleep(link->ap, 50);
}
}
@@ -3377,10 +3495,10 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline,
* RETURNS:
* 0 if @linke is ready before @deadline; otherwise, -errno.
*/
-extern int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
+int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
int (*check_ready)(struct ata_link *link))
{
- msleep(ATA_WAIT_AFTER_RESET_MSECS);
+ ata_msleep(link->ap, ATA_WAIT_AFTER_RESET);
return ata_wait_ready(link, deadline, check_ready);
}
@@ -3391,7 +3509,7 @@ extern int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
* @params: timing parameters { interval, duratinon, timeout } in msec
* @deadline: deadline jiffies for the operation
*
-* Make sure SStatus of @link reaches stable state, determined by
+ * Make sure SStatus of @link reaches stable state, determined by
* holding the same value where DET is not 1 for @duration polled
* every @interval, before @timeout. Timeout constraints the
* beginning of the stable state. Because DET gets stuck at 1 on
@@ -3410,13 +3528,13 @@ extern int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
int sata_link_debounce(struct ata_link *link, const unsigned long *params,
unsigned long deadline)
{
- unsigned long interval_msec = params[0];
- unsigned long duration = msecs_to_jiffies(params[1]);
+ unsigned long interval = params[0];
+ unsigned long duration = params[1];
unsigned long last_jiffies, t;
u32 last, cur;
int rc;
- t = jiffies + msecs_to_jiffies(params[2]);
+ t = ata_deadline(jiffies, params[2]);
if (time_before(t, deadline))
deadline = t;
@@ -3428,7 +3546,7 @@ int sata_link_debounce(struct ata_link *link, const unsigned long *params,
last_jiffies = jiffies;
while (1) {
- msleep(interval_msec);
+ ata_msleep(link->ap, interval);
if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
return rc;
cur &= 0xf;
@@ -3437,7 +3555,8 @@ int sata_link_debounce(struct ata_link *link, const unsigned long *params,
if (cur == last) {
if (cur == 1 && time_before(jiffies, deadline))
continue;
- if (time_after(jiffies, last_jiffies + duration))
+ if (time_after(jiffies,
+ ata_deadline(last_jiffies, duration)))
return 0;
continue;
}
@@ -3471,41 +3590,124 @@ int sata_link_debounce(struct ata_link *link, const unsigned long *params,
int sata_link_resume(struct ata_link *link, const unsigned long *params,
unsigned long deadline)
{
+ int tries = ATA_LINK_RESUME_TRIES;
u32 scontrol, serror;
int rc;
if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
return rc;
- scontrol = (scontrol & 0x0f0) | 0x300;
+ /*
+ * Writes to SControl sometimes get ignored under certain
+ * controllers (ata_piix SIDPR). Make sure DET actually is
+ * cleared.
+ */
+ do {
+ scontrol = (scontrol & 0x0f0) | 0x300;
+ if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
+ return rc;
+ /*
+ * Some PHYs react badly if SStatus is pounded
+ * immediately after resuming. Delay 200ms before
+ * debouncing.
+ */
+ ata_msleep(link->ap, 200);
+
+ /* is SControl restored correctly? */
+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
+ return rc;
+ } while ((scontrol & 0xf0f) != 0x300 && --tries);
- if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
- return rc;
+ if ((scontrol & 0xf0f) != 0x300) {
+ ata_link_warn(link, "failed to resume link (SControl %X)\n",
+ scontrol);
+ return 0;
+ }
- /* Some PHYs react badly if SStatus is pounded immediately
- * after resuming. Delay 200ms before debouncing.
- */
- msleep(200);
+ if (tries < ATA_LINK_RESUME_TRIES)
+ ata_link_warn(link, "link resume succeeded after %d retries\n",
+ ATA_LINK_RESUME_TRIES - tries);
if ((rc = sata_link_debounce(link, params, deadline)))
return rc;
- /* Clear SError. PMP and some host PHYs require this to
- * operate and clearing should be done before checking PHY
- * online status to avoid race condition (hotplugging between
- * link resume and status check).
- */
+ /* clear SError, some PHYs require this even for SRST to work */
if (!(rc = sata_scr_read(link, SCR_ERROR, &serror)))
rc = sata_scr_write(link, SCR_ERROR, serror);
- if (rc == 0 || rc == -EINVAL) {
- unsigned long flags;
- spin_lock_irqsave(link->ap->lock, flags);
- link->eh_info.serror = 0;
- spin_unlock_irqrestore(link->ap->lock, flags);
- rc = 0;
+ return rc != -EINVAL ? rc : 0;
+}
+
+/**
+ * sata_link_scr_lpm - manipulate SControl IPM and SPM fields
+ * @link: ATA link to manipulate SControl for
+ * @policy: LPM policy to configure
+ * @spm_wakeup: initiate LPM transition to active state
+ *
+ * Manipulate the IPM field of the SControl register of @link
+ * according to @policy. If @policy is ATA_LPM_MAX_POWER and
+ * @spm_wakeup is %true, the SPM field is manipulated to wake up
+ * the link. This function also clears PHYRDY_CHG before
+ * returning.
+ *
+ * LOCKING:
+ * EH context.
+ *
+ * RETURNS:
+ * 0 on succes, -errno otherwise.
+ */
+int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+ bool spm_wakeup)
+{
+ struct ata_eh_context *ehc = &link->eh_context;
+ bool woken_up = false;
+ u32 scontrol;
+ int rc;
+
+ rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
+ if (rc)
+ return rc;
+
+ switch (policy) {
+ case ATA_LPM_MAX_POWER:
+ /* disable all LPM transitions */
+ scontrol |= (0x7 << 8);
+ /* initiate transition to active state */
+ if (spm_wakeup) {
+ scontrol |= (0x4 << 12);
+ woken_up = true;
+ }
+ break;
+ case ATA_LPM_MED_POWER:
+ /* allow LPM to PARTIAL */
+ scontrol &= ~(0x1 << 8);
+ scontrol |= (0x6 << 8);
+ break;
+ case ATA_LPM_MIN_POWER:
+ if (ata_link_nr_enabled(link) > 0)
+ /* no restrictions on LPM transitions */
+ scontrol &= ~(0x7 << 8);
+ else {
+ /* empty port, power off */
+ scontrol &= ~0xf;
+ scontrol |= (0x1 << 2);
+ }
+ break;
+ default:
+ WARN_ON(1);
}
- return rc;
+
+ rc = sata_scr_write(link, SCR_CONTROL, scontrol);
+ if (rc)
+ return rc;
+
+ /* give the link time to transit out of LPM state */
+ if (woken_up)
+ msleep(10);
+
+ /* clear PHYRDY_CHG from SError */
+ ehc->i.serror &= ~SERR_PHYRDY_CHG;
+ return sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
}
/**
@@ -3541,12 +3743,13 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline)
rc = sata_link_resume(link, timing, deadline);
/* whine about phy resume failure but proceed */
if (rc && rc != -EOPNOTSUPP)
- ata_link_printk(link, KERN_WARNING, "failed to resume "
- "link for reset (errno=%d)\n", rc);
+ ata_link_warn(link,
+ "failed to resume link for reset (errno=%d)\n",
+ rc);
}
/* no point in trying softreset on offline link */
- if (ata_link_offline(link))
+ if (ata_phys_link_offline(link))
ehc->i.action &= ~ATA_EH_SOFTRESET;
return 0;
@@ -3617,14 +3820,14 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
/* Couldn't find anything in SATA I/II specs, but AHCI-1.1
* 10.4.2 says at least 1 ms.
*/
- msleep(1);
+ ata_msleep(link->ap, 1);
/* bring link back */
rc = sata_link_resume(link, timing, deadline);
if (rc)
goto out;
/* if link is offline nothing more to do */
- if (ata_link_offline(link))
+ if (ata_phys_link_offline(link))
goto out;
/* Link is online. From this point, -ENODEV too is an error. */
@@ -3640,7 +3843,8 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
if (check_ready) {
unsigned long pmp_deadline;
- pmp_deadline = jiffies + ATA_TMOUT_PMP_SRST_WAIT;
+ pmp_deadline = ata_deadline(jiffies,
+ ATA_TMOUT_PMP_SRST_WAIT);
if (time_after(pmp_deadline, deadline))
pmp_deadline = deadline;
ata_wait_ready(link, pmp_deadline, check_ready);
@@ -3653,9 +3857,12 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
if (check_ready)
rc = ata_wait_ready(link, deadline, check_ready);
out:
- if (rc && rc != -EAGAIN)
- ata_link_printk(link, KERN_ERR,
- "COMRESET failed (errno=%d)\n", rc);
+ if (rc && rc != -EAGAIN) {
+ /* online is set iff link is online && reset succeeded */
+ if (online)
+ *online = false;
+ ata_link_err(link, "COMRESET failed (errno=%d)\n", rc);
+ }
DPRINTK("EXIT, rc=%d\n", rc);
return rc;
}
@@ -3700,8 +3907,14 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class,
*/
void ata_std_postreset(struct ata_link *link, unsigned int *classes)
{
+ u32 serror;
+
DPRINTK("ENTER\n");
+ /* reset complete, clear SError */
+ if (!sata_scr_read(link, SCR_ERROR, &serror))
+ sata_scr_write(link, SCR_ERROR, serror);
+
/* print link status */
sata_print_link_status(link);
@@ -3732,8 +3945,8 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
unsigned char serial[2][ATA_ID_SERNO_LEN + 1];
if (dev->class != new_class) {
- ata_dev_printk(dev, KERN_INFO, "class mismatch %d != %d\n",
- dev->class, new_class);
+ ata_dev_info(dev, "class mismatch %d != %d\n",
+ dev->class, new_class);
return 0;
}
@@ -3743,14 +3956,14 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
ata_id_c_string(new_id, serial[1], ATA_ID_SERNO, sizeof(serial[1]));
if (strcmp(model[0], model[1])) {
- ata_dev_printk(dev, KERN_INFO, "model number mismatch "
- "'%s' != '%s'\n", model[0], model[1]);
+ ata_dev_info(dev, "model number mismatch '%s' != '%s'\n",
+ model[0], model[1]);
return 0;
}
if (strcmp(serial[0], serial[1])) {
- ata_dev_printk(dev, KERN_INFO, "serial number mismatch "
- "'%s' != '%s'\n", serial[0], serial[1]);
+ ata_dev_info(dev, "serial number mismatch '%s' != '%s'\n",
+ serial[0], serial[1]);
return 0;
}
@@ -3809,6 +4022,7 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
unsigned int readid_flags)
{
u64 n_sectors = dev->n_sectors;
+ u64 n_native_sectors = dev->n_native_sectors;
int rc;
if (!ata_dev_enabled(dev))
@@ -3816,9 +4030,11 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
/* fail early if !ATA && !ATAPI to avoid issuing [P]IDENTIFY to PMP */
if (ata_class_enabled(new_class) &&
- new_class != ATA_DEV_ATA && new_class != ATA_DEV_ATAPI) {
- ata_dev_printk(dev, KERN_INFO, "class mismatch %u != %u\n",
- dev->class, new_class);
+ new_class != ATA_DEV_ATA &&
+ new_class != ATA_DEV_ATAPI &&
+ new_class != ATA_DEV_SEMB) {
+ ata_dev_info(dev, "class mismatch %u != %u\n",
+ dev->class, new_class);
rc = -ENODEV;
goto fail;
}
@@ -3834,24 +4050,52 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
goto fail;
/* verify n_sectors hasn't changed */
- if (dev->class == ATA_DEV_ATA && n_sectors &&
- dev->n_sectors != n_sectors) {
- ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch "
- "%llu != %llu\n",
- (unsigned long long)n_sectors,
- (unsigned long long)dev->n_sectors);
+ if (dev->class != ATA_DEV_ATA || !n_sectors ||
+ dev->n_sectors == n_sectors)
+ return 0;
- /* restore original n_sectors */
- dev->n_sectors = n_sectors;
+ /* n_sectors has changed */
+ ata_dev_warn(dev, "n_sectors mismatch %llu != %llu\n",
+ (unsigned long long)n_sectors,
+ (unsigned long long)dev->n_sectors);
- rc = -ENODEV;
- goto fail;
+ /*
+ * Something could have caused HPA to be unlocked
+ * involuntarily. If n_native_sectors hasn't changed and the
+ * new size matches it, keep the device.
+ */
+ if (dev->n_native_sectors == n_native_sectors &&
+ dev->n_sectors > n_sectors && dev->n_sectors == n_native_sectors) {
+ ata_dev_warn(dev,
+ "new n_sectors matches native, probably "
+ "late HPA unlock, n_sectors updated\n");
+ /* use the larger n_sectors */
+ return 0;
}
- return 0;
+ /*
+ * Some BIOSes boot w/o HPA but resume w/ HPA locked. Try
+ * unlocking HPA in those cases.
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=15396
+ */
+ if (dev->n_native_sectors == n_native_sectors &&
+ dev->n_sectors < n_sectors && n_sectors == n_native_sectors &&
+ !(dev->horkage & ATA_HORKAGE_BROKEN_HPA)) {
+ ata_dev_warn(dev,
+ "old n_sectors matches native, probably "
+ "late HPA lock, will try to unlock HPA\n");
+ /* try unlocking HPA */
+ dev->flags |= ATA_DFLAG_UNLOCK_HPA;
+ rc = -EIO;
+ } else
+ rc = -ENODEV;
+ /* restore original n_[native_]sectors and fail */
+ dev->n_native_sectors = n_native_sectors;
+ dev->n_sectors = n_sectors;
fail:
- ata_dev_printk(dev, KERN_ERR, "revalidation failed (errno=%d)\n", rc);
+ ata_dev_err(dev, "revalidation failed (errno=%d)\n", rc);
return rc;
}
@@ -3872,15 +4116,13 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "WDC AC23200L", "21.10N21", ATA_HORKAGE_NODMA },
{ "Compaq CRD-8241B", NULL, ATA_HORKAGE_NODMA },
{ "CRD-8400B", NULL, ATA_HORKAGE_NODMA },
- { "CRD-8480B", NULL, ATA_HORKAGE_NODMA },
- { "CRD-8482B", NULL, ATA_HORKAGE_NODMA },
+ { "CRD-848[02]B", NULL, ATA_HORKAGE_NODMA },
{ "CRD-84", NULL, ATA_HORKAGE_NODMA },
{ "SanDisk SDP3B", NULL, ATA_HORKAGE_NODMA },
{ "SanDisk SDP3B-64", NULL, ATA_HORKAGE_NODMA },
{ "SANYO CD-ROM CRD", NULL, ATA_HORKAGE_NODMA },
{ "HITACHI CDR-8", NULL, ATA_HORKAGE_NODMA },
- { "HITACHI CDR-8335", NULL, ATA_HORKAGE_NODMA },
- { "HITACHI CDR-8435", NULL, ATA_HORKAGE_NODMA },
+ { "HITACHI CDR-8[34]35",NULL, ATA_HORKAGE_NODMA },
{ "Toshiba CD-ROM XM-6202B", NULL, ATA_HORKAGE_NODMA },
{ "TOSHIBA CD-ROM XM-1702BC", NULL, ATA_HORKAGE_NODMA },
{ "CD-532E-A", NULL, ATA_HORKAGE_NODMA },
@@ -3893,12 +4135,15 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "_NEC DV5800A", NULL, ATA_HORKAGE_NODMA },
{ "SAMSUNG CD-ROM SN-124", "N001", ATA_HORKAGE_NODMA },
{ "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA },
+ { " 2GB ATA Flash Disk", "ADMA428M", ATA_HORKAGE_NODMA },
/* Odd clown on sil3726/4726 PMPs */
- { "Config Disk", NULL, ATA_HORKAGE_NODMA |
- ATA_HORKAGE_SKIP_PM },
+ { "Config Disk", NULL, ATA_HORKAGE_DISABLE },
/* Weird ATAPI devices */
{ "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 },
+ { "QUANTUM DAT DAT72-000", NULL, ATA_HORKAGE_ATAPI_MOD16_DMA },
+ { "Slimtype DVD A DS8A8SH", NULL, ATA_HORKAGE_MAX_SEC_LBA48 },
+ { "Slimtype DVD A DS8A9SH", NULL, ATA_HORKAGE_MAX_SEC_LBA48 },
/* Devices we expect to fail diagnostics */
@@ -3913,6 +4158,24 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ },
{ "ST380817AS", "3.42", ATA_HORKAGE_NONCQ },
{ "ST3160023AS", "3.42", ATA_HORKAGE_NONCQ },
+ { "OCZ CORE_SSD", "02.10104", ATA_HORKAGE_NONCQ },
+
+ /* Seagate NCQ + FLUSH CACHE firmware bug */
+ { "ST31500341AS", "SD1[5-9]", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+
+ { "ST31000333AS", "SD1[5-9]", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+
+ { "ST3640[36]23AS", "SD1[5-9]", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+
+ { "ST3320[68]13AS", "SD1[5-9]", ATA_HORKAGE_NONCQ |
+ ATA_HORKAGE_FIRMWARE_WARN },
+
+ /* Seagate Momentus SpinPoint M8 seem to have FPMDA_AA issues */
+ { "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA },
+ { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA },
/* Blacklist entries taken from Silicon Image 3124/3132
Windows driver .inf file - also several Linux problem reports */
@@ -3920,12 +4183,18 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "HTS541080G9SA00", "MB4OC60D", ATA_HORKAGE_NONCQ, },
{ "HTS541010G9SA00", "MBZOC60D", ATA_HORKAGE_NONCQ, },
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=15573 */
+ { "C300-CTFDDAC128MAG", "0001", ATA_HORKAGE_NONCQ, },
+
/* devices which puke on READ_NATIVE_MAX */
{ "HDS724040KLSA80", "KFAOA20N", ATA_HORKAGE_BROKEN_HPA, },
{ "WDC WD3200JD-00KLB0", "WD-WCAMR1130137", ATA_HORKAGE_BROKEN_HPA },
{ "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA },
{ "MAXTOR 6L080L4", "A93.0500", ATA_HORKAGE_BROKEN_HPA },
+ /* this one allows HPA unlocking but fails IOs on the area */
+ { "OCZ-VERTEX", "1.30", ATA_HORKAGE_BROKEN_HPA },
+
/* Devices which report 1 sector over size HPA */
{ "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, },
{ "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, },
@@ -3933,36 +4202,119 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Devices which get the IVB wrong */
{ "QUANTUM FIREBALLlct10 05", "A03.0900", ATA_HORKAGE_IVB, },
- { "TSSTcorp CDDVDW SH-S202J", "SB00", ATA_HORKAGE_IVB, },
- { "TSSTcorp CDDVDW SH-S202J", "SB01", ATA_HORKAGE_IVB, },
- { "TSSTcorp CDDVDW SH-S202N", "SB00", ATA_HORKAGE_IVB, },
- { "TSSTcorp CDDVDW SH-S202N", "SB01", ATA_HORKAGE_IVB, },
+ /* Maybe we should just blacklist TSSTcorp... */
+ { "TSSTcorp CDDVDW SH-S202[HJN]", "SB0[01]", ATA_HORKAGE_IVB, },
+
+ /* Devices that do not need bridging limits applied */
+ { "MTRON MSP-SATA*", NULL, ATA_HORKAGE_BRIDGE_OK, },
+ { "BUFFALO HD-QSU2/R5", NULL, ATA_HORKAGE_BRIDGE_OK, },
+
+ /* Devices which aren't very happy with higher link speeds */
+ { "WD My Book", NULL, ATA_HORKAGE_1_5_GBPS, },
+ { "Seagate FreeAgent GoFlex", NULL, ATA_HORKAGE_1_5_GBPS, },
+
+ /*
+ * Devices which choke on SETXFER. Applies only if both the
+ * device and controller are SATA.
+ */
+ { "PIONEER DVD-RW DVRTD08", NULL, ATA_HORKAGE_NOSETXFER },
+ { "PIONEER DVD-RW DVRTD08A", NULL, ATA_HORKAGE_NOSETXFER },
+ { "PIONEER DVD-RW DVR-215", NULL, ATA_HORKAGE_NOSETXFER },
+ { "PIONEER DVD-RW DVR-212D", NULL, ATA_HORKAGE_NOSETXFER },
+ { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER },
+
+ /* devices that don't properly handle queued TRIM commands */
+ { "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, },
+ { "Crucial_CT???M500SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, },
+ { "Micron_M550*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, },
+ { "Crucial_CT???M550SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, },
+
+ /*
+ * Some WD SATA-I drives spin up and down erratically when the link
+ * is put into the slumber mode. We don't have full list of the
+ * affected devices. Disable LPM if the device matches one of the
+ * known prefixes and is SATA-1. As a side effect LPM partial is
+ * lost too.
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=57211
+ */
+ { "WDC WD800JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
+ { "WDC WD1200JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
+ { "WDC WD1600JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
+ { "WDC WD2000JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
+ { "WDC WD2500JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
+ { "WDC WD3000JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
+ { "WDC WD3200JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM },
/* End Marker */
{ }
};
-static int strn_pattern_cmp(const char *patt, const char *name, int wildchar)
+/**
+ * glob_match - match a text string against a glob-style pattern
+ * @text: the string to be examined
+ * @pattern: the glob-style pattern to be matched against
+ *
+ * Either/both of text and pattern can be empty strings.
+ *
+ * Match text against a glob-style pattern, with wildcards and simple sets:
+ *
+ * ? matches any single character.
+ * * matches any run of characters.
+ * [xyz] matches a single character from the set: x, y, or z.
+ * [a-d] matches a single character from the range: a, b, c, or d.
+ * [a-d0-9] matches a single character from either range.
+ *
+ * The special characters ?, [, -, or *, can be matched using a set, eg. [*]
+ * Behaviour with malformed patterns is undefined, though generally reasonable.
+ *
+ * Sample patterns: "SD1?", "SD1[0-5]", "*R0", "SD*1?[012]*xx"
+ *
+ * This function uses one level of recursion per '*' in pattern.
+ * Since it calls _nothing_ else, and has _no_ explicit local variables,
+ * this will not cause stack problems for any reasonable use here.
+ *
+ * RETURNS:
+ * 0 on match, 1 otherwise.
+ */
+static int glob_match (const char *text, const char *pattern)
{
- const char *p;
- int len;
-
- /*
- * check for trailing wildcard: *\0
- */
- p = strchr(patt, wildchar);
- if (p && ((*(p + 1)) == 0))
- len = p - patt;
- else {
- len = strlen(name);
- if (!len) {
- if (!*patt)
- return 0;
- return -1;
+ do {
+ /* Match single character or a '?' wildcard */
+ if (*text == *pattern || *pattern == '?') {
+ if (!*pattern++)
+ return 0; /* End of both strings: match */
+ } else {
+ /* Match single char against a '[' bracketed ']' pattern set */
+ if (!*text || *pattern != '[')
+ break; /* Not a pattern set */
+ while (*++pattern && *pattern != ']' && *text != *pattern) {
+ if (*pattern == '-' && *(pattern - 1) != '[')
+ if (*text > *(pattern - 1) && *text < *(pattern + 1)) {
+ ++pattern;
+ break;
+ }
+ }
+ if (!*pattern || *pattern == ']')
+ return 1; /* No match */
+ while (*pattern && *pattern++ != ']');
+ }
+ } while (*++text && *pattern);
+
+ /* Match any run of chars against a '*' wildcard */
+ if (*pattern == '*') {
+ if (!*++pattern)
+ return 0; /* Match: avoid recursion at end of pattern */
+ /* Loop to handle additional pattern chars after the wildcard */
+ while (*text) {
+ if (glob_match(text, pattern) == 0)
+ return 0; /* Remainder matched */
+ ++text; /* Absorb (match) this char and try again */
}
}
-
- return strncmp(patt, name, len);
+ if (!*text && !*pattern)
+ return 0; /* End of both strings: match */
+ return 1; /* No match */
}
static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
@@ -3975,10 +4327,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev));
while (ad->model_num) {
- if (!strn_pattern_cmp(ad->model_num, model_num, '*')) {
+ if (!glob_match(model_num, ad->model_num)) {
if (ad->model_rev == NULL)
return ad->horkage;
- if (!strn_pattern_cmp(ad->model_rev, model_rev, '*'))
+ if (!glob_match(model_rev, ad->model_rev))
return ad->horkage;
}
ad++;
@@ -4031,28 +4383,32 @@ static int cable_is_40wire(struct ata_port *ap)
struct ata_link *link;
struct ata_device *dev;
- /* If the controller thinks we are 40 wire, we are */
+ /* If the controller thinks we are 40 wire, we are. */
if (ap->cbl == ATA_CBL_PATA40)
return 1;
- /* If the controller thinks we are 80 wire, we are */
+
+ /* If the controller thinks we are 80 wire, we are. */
if (ap->cbl == ATA_CBL_PATA80 || ap->cbl == ATA_CBL_SATA)
return 0;
- /* If the system is known to be 40 wire short cable (eg laptop),
- then we allow 80 wire modes even if the drive isn't sure */
+
+ /* If the system is known to be 40 wire short cable (eg
+ * laptop), then we allow 80 wire modes even if the drive
+ * isn't sure.
+ */
if (ap->cbl == ATA_CBL_PATA40_SHORT)
return 0;
- /* If the controller doesn't know we scan
-
- - Note: We look for all 40 wire detects at this point.
- Any 80 wire detect is taken to be 80 wire cable
- because
- - In many setups only the one drive (slave if present)
- will give a valid detect
- - If you have a non detect capable drive you don't
- want it to colour the choice
- */
- ata_port_for_each_link(link, ap) {
- ata_link_for_each_dev(dev, link) {
+
+ /* If the controller doesn't know, we scan.
+ *
+ * Note: We look for all 40 wire detects at this point. Any
+ * 80 wire detect is taken to be 80 wire cable because
+ * - in many setups only the one drive (slave if present) will
+ * give a valid detect
+ * - if you have a non detect capable drive you don't want it
+ * to colour the choice
+ */
+ ata_for_each_link(link, ap, EDGE) {
+ ata_for_each_dev(dev, link, ENABLED) {
if (!ata_is_40wire(dev))
return 0;
}
@@ -4101,15 +4457,15 @@ static void ata_dev_xfermask(struct ata_device *dev)
if (ata_dma_blacklisted(dev)) {
xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
- ata_dev_printk(dev, KERN_WARNING,
- "device is on DMA blacklist, disabling DMA\n");
+ ata_dev_warn(dev,
+ "device is on DMA blacklist, disabling DMA\n");
}
if ((host->flags & ATA_HOST_SIMPLEX) &&
host->simplex_claimed && host->simplex_claimed != ap) {
xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
- ata_dev_printk(dev, KERN_WARNING, "simplex DMA is claimed by "
- "other device, disabling DMA\n");
+ ata_dev_warn(dev,
+ "simplex DMA is claimed by other device, disabling DMA\n");
}
if (ap->flags & ATA_FLAG_NO_IORDY)
@@ -4129,8 +4485,8 @@ static void ata_dev_xfermask(struct ata_device *dev)
if (xfer_mask & (0xF8 << ATA_SHIFT_UDMA))
/* UDMA/44 or higher would be available */
if (cable_is_40wire(ap)) {
- ata_dev_printk(dev, KERN_WARNING,
- "limited to UDMA/33 due to 40-wire cable\n");
+ ata_dev_warn(dev,
+ "limited to UDMA/33 due to 40-wire cable\n");
xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
}
@@ -4182,6 +4538,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
}
+
/**
* ata_dev_set_feature - Issue SET FEATURES - SATA FEATURES
* @dev: Device to which command will be sent
@@ -4197,8 +4554,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
* RETURNS:
* 0 on success, AC_ERR_* mask otherwise.
*/
-static unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable,
- u8 feature)
+unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, u8 feature)
{
struct ata_taskfile tf;
unsigned int err_mask;
@@ -4218,6 +4574,7 @@ static unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable,
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
}
+EXPORT_SYMBOL_GPL(ata_dev_set_feature);
/**
* ata_dev_init_params - Issue INIT DEV PARAMS command
@@ -4277,19 +4634,19 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
struct scatterlist *sg = qc->sg;
int dir = qc->dma_dir;
- WARN_ON(sg == NULL);
+ WARN_ON_ONCE(sg == NULL);
VPRINTK("unmapping %u sg elements\n", qc->n_elem);
if (qc->n_elem)
- dma_unmap_sg(ap->dev, sg, qc->n_elem, dir);
+ dma_unmap_sg(ap->dev, sg, qc->orig_n_elem, dir);
qc->flags &= ~ATA_QCFLAG_DMAMAP;
qc->sg = NULL;
}
/**
- * ata_check_atapi_dma - Check whether ATAPI DMA can be supported
+ * atapi_check_dma - Check whether ATAPI DMA can be supported
* @qc: Metadata associated with taskfile to check
*
* Allow low-level driver to filter ATA PACKET commands, returning
@@ -4302,14 +4659,15 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
* RETURNS: 0 when ATAPI DMA can be used
* nonzero otherwise
*/
-int ata_check_atapi_dma(struct ata_queued_cmd *qc)
+int atapi_check_dma(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
/* Don't allow DMA if it isn't multiple of 16 bytes. Quite a
* few ATAPI devices choke on such DMA requests.
*/
- if (unlikely(qc->nbytes & 15))
+ if (!(qc->dev->horkage & ATA_HORKAGE_ATAPI_MOD16_DMA) &&
+ unlikely(qc->nbytes & 15))
return 1;
if (ap->ops->check_atapi_dma)
@@ -4396,7 +4754,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
return -1;
DPRINTK("%d sg elements mapped\n", n_elem);
-
+ qc->orig_n_elem = qc->n_elem;
qc->n_elem = n_elem;
qc->flags |= ATA_QCFLAG_DMAMAP;
@@ -4427,8 +4785,11 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
/**
* ata_qc_new - Request an available ATA command, for queueing
- * @ap: Port associated with device @dev
- * @dev: Device from whom we request an available command structure
+ * @ap: target port
+ *
+ * Some ATA host controllers may implement a queue depth which is less
+ * than ATA_MAX_QUEUE. So we shouldn't allocate a tag which is beyond
+ * the hardware limitation.
*
* LOCKING:
* None.
@@ -4437,21 +4798,27 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
{
struct ata_queued_cmd *qc = NULL;
- unsigned int i;
+ unsigned int max_queue = ap->host->n_tags;
+ unsigned int i, tag;
/* no command while frozen */
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
return NULL;
- /* the last tag is reserved for internal command. */
- for (i = 0; i < ATA_MAX_QUEUE - 1; i++)
- if (!test_and_set_bit(i, &ap->qc_allocated)) {
- qc = __ata_qc_from_tag(ap, i);
+ for (i = 0, tag = ap->last_tag + 1; i < max_queue; i++, tag++) {
+ tag = tag < max_queue ? tag : 0;
+
+ /* the last tag is reserved for internal command. */
+ if (tag == ATA_TAG_INTERNAL)
+ continue;
+
+ if (!test_and_set_bit(tag, &ap->qc_allocated)) {
+ qc = __ata_qc_from_tag(ap, tag);
+ qc->tag = tag;
+ ap->last_tag = tag;
break;
}
-
- if (qc)
- qc->tag = i;
+ }
return qc;
}
@@ -4493,10 +4860,11 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
*/
void ata_qc_free(struct ata_queued_cmd *qc)
{
- struct ata_port *ap = qc->ap;
+ struct ata_port *ap;
unsigned int tag;
- WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
+ WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
+ ap = qc->ap;
qc->flags = 0;
tag = qc->tag;
@@ -4508,11 +4876,13 @@ void ata_qc_free(struct ata_queued_cmd *qc)
void __ata_qc_complete(struct ata_queued_cmd *qc)
{
- struct ata_port *ap = qc->ap;
- struct ata_link *link = qc->dev->link;
+ struct ata_port *ap;
+ struct ata_link *link;
- WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
- WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+ WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
+ WARN_ON_ONCE(!(qc->flags & ATA_QCFLAG_ACTIVE));
+ ap = qc->ap;
+ link = qc->dev->link;
if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
ata_sg_clean(qc);
@@ -4555,9 +4925,6 @@ static void ata_verify_xfer(struct ata_queued_cmd *qc)
{
struct ata_device *dev = qc->dev;
- if (ata_tag_internal(qc->tag))
- return;
-
if (ata_is_nodata(qc->tf.protocol))
return;
@@ -4570,10 +4937,14 @@ static void ata_verify_xfer(struct ata_queued_cmd *qc)
/**
* ata_qc_complete - Complete an active ATA command
* @qc: Command to complete
- * @err_mask: ATA Status register contents
*
- * Indicate to the mid and upper layers that an ATA
- * command has completed, with either an ok or not-ok status.
+ * Indicate to the mid and upper layers that an ATA command has
+ * completed, with either an ok or not-ok status.
+ *
+ * Refrain from calling this function multiple times when
+ * successfully completing multiple NCQ commands.
+ * ata_qc_complete_multiple() should be used instead, which will
+ * properly update IRQ expect state.
*
* LOCKING:
* spin_lock_irqsave(host lock)
@@ -4599,20 +4970,31 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
struct ata_device *dev = qc->dev;
struct ata_eh_info *ehi = &dev->link->eh_info;
- WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
-
if (unlikely(qc->err_mask))
qc->flags |= ATA_QCFLAG_FAILED;
+ /*
+ * Finish internal commands without any further processing
+ * and always with the result TF filled.
+ */
+ if (unlikely(ata_tag_internal(qc->tag))) {
+ fill_result_tf(qc);
+ __ata_qc_complete(qc);
+ return;
+ }
+
+ /*
+ * Non-internal qc has failed. Fill the result TF and
+ * summon EH.
+ */
if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
- if (!ata_tag_internal(qc->tag)) {
- /* always fill result TF for failed qc */
- fill_result_tf(qc);
- ata_qc_schedule_eh(qc);
- return;
- }
+ fill_result_tf(qc);
+ ata_qc_schedule_eh(qc);
+ return;
}
+ WARN_ON_ONCE(ap->pflags & ATA_PFLAG_FROZEN);
+
/* read result TF if requested */
if (qc->flags & ATA_QCFLAG_RESULT_TF)
fill_result_tf(qc);
@@ -4664,6 +5046,10 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
* requests normally. ap->qc_active and @qc_active is compared
* and commands are completed accordingly.
*
+ * Always use this function when completing multiple NCQ commands
+ * from IRQ handlers instead of calling ata_qc_complete()
+ * multiple times to keep IRQ expect status properly in sync.
+ *
* LOCKING:
* spin_lock_irqsave(host lock)
*
@@ -4674,26 +5060,25 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active)
{
int nr_done = 0;
u32 done_mask;
- int i;
done_mask = ap->qc_active ^ qc_active;
if (unlikely(done_mask & qc_active)) {
- ata_port_printk(ap, KERN_ERR, "illegal qc_active transition "
- "(%08x->%08x)\n", ap->qc_active, qc_active);
+ ata_port_err(ap, "illegal qc_active transition (%08x->%08x)\n",
+ ap->qc_active, qc_active);
return -EINVAL;
}
- for (i = 0; i < ATA_MAX_QUEUE; i++) {
+ while (done_mask) {
struct ata_queued_cmd *qc;
+ unsigned int tag = __ffs(done_mask);
- if (!(done_mask & (1 << i)))
- continue;
-
- if ((qc = ata_qc_from_tag(ap, i))) {
+ qc = ata_qc_from_tag(ap, tag);
+ if (qc) {
ata_qc_complete(qc);
nr_done++;
}
+ done_mask &= ~(1 << tag);
}
return nr_done;
@@ -4721,16 +5106,16 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
* check is skipped for old EH because it reuses active qc to
* request ATAPI sense.
*/
- WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag));
+ WARN_ON_ONCE(ap->ops->error_handler && ata_tag_valid(link->active_tag));
if (ata_is_ncq(prot)) {
- WARN_ON(link->sactive & (1 << qc->tag));
+ WARN_ON_ONCE(link->sactive & (1 << qc->tag));
if (!link->sactive)
ap->nr_active_links++;
link->sactive |= 1 << qc->tag;
} else {
- WARN_ON(link->sactive);
+ WARN_ON_ONCE(link->sactive);
ap->nr_active_links++;
link->active_tag = qc->tag;
@@ -4739,15 +5124,18 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
qc->flags |= ATA_QCFLAG_ACTIVE;
ap->qc_active |= 1 << qc->tag;
- /* We guarantee to LLDs that they will have at least one
+ /*
+ * We guarantee to LLDs that they will have at least one
* non-zero sg if the command is a data command.
*/
- BUG_ON(ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes));
+ if (WARN_ON_ONCE(ata_is_data(prot) &&
+ (!qc->sg || !qc->n_elem || !qc->nbytes)))
+ goto sys_err;
if (ata_is_dma(prot) || (ata_is_pio(prot) &&
(ap->flags & ATA_FLAG_PIO_DMA)))
if (ata_sg_setup(qc))
- goto sg_err;
+ goto sys_err;
/* if device is sleeping, schedule reset and abort the link */
if (unlikely(qc->dev->flags & ATA_DFLAG_SLEEPING)) {
@@ -4764,7 +5152,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
goto err;
return;
-sg_err:
+sys_err:
qc->err_mask |= AC_ERR_SYSTEM;
err:
ata_qc_complete(qc);
@@ -4808,10 +5196,8 @@ int sata_scr_valid(struct ata_link *link)
int sata_scr_read(struct ata_link *link, int reg, u32 *val)
{
if (ata_is_host_link(link)) {
- struct ata_port *ap = link->ap;
-
if (sata_scr_valid(link))
- return ap->ops->scr_read(ap, reg, val);
+ return link->ap->ops->scr_read(link, reg, val);
return -EOPNOTSUPP;
}
@@ -4837,10 +5223,8 @@ int sata_scr_read(struct ata_link *link, int reg, u32 *val)
int sata_scr_write(struct ata_link *link, int reg, u32 val)
{
if (ata_is_host_link(link)) {
- struct ata_port *ap = link->ap;
-
if (sata_scr_valid(link))
- return ap->ops->scr_write(ap, reg, val);
+ return link->ap->ops->scr_write(link, reg, val);
return -EOPNOTSUPP;
}
@@ -4865,13 +5249,12 @@ int sata_scr_write(struct ata_link *link, int reg, u32 val)
int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
{
if (ata_is_host_link(link)) {
- struct ata_port *ap = link->ap;
int rc;
if (sata_scr_valid(link)) {
- rc = ap->ops->scr_write(ap, reg, val);
+ rc = link->ap->ops->scr_write(link, reg, val);
if (rc == 0)
- rc = ap->ops->scr_read(ap, reg, &val);
+ rc = link->ap->ops->scr_read(link, reg, &val);
return rc;
}
return -EOPNOTSUPP;
@@ -4881,7 +5264,7 @@ int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
}
/**
- * ata_link_online - test whether the given link is online
+ * ata_phys_link_online - test whether the given link is online
* @link: ATA link to test
*
* Test whether @link is online. Note that this function returns
@@ -4892,20 +5275,20 @@ int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
* None.
*
* RETURNS:
- * 1 if the port online status is available and online.
+ * True if the port online status is available and online.
*/
-int ata_link_online(struct ata_link *link)
+bool ata_phys_link_online(struct ata_link *link)
{
u32 sstatus;
if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
- (sstatus & 0xf) == 0x3)
- return 1;
- return 0;
+ ata_sstatus_online(sstatus))
+ return true;
+ return false;
}
/**
- * ata_link_offline - test whether the given link is offline
+ * ata_phys_link_offline - test whether the given link is offline
* @link: ATA link to test
*
* Test whether @link is offline. Note that this function
@@ -4916,145 +5299,274 @@ int ata_link_online(struct ata_link *link)
* None.
*
* RETURNS:
- * 1 if the port offline status is available and offline.
+ * True if the port offline status is available and offline.
*/
-int ata_link_offline(struct ata_link *link)
+bool ata_phys_link_offline(struct ata_link *link)
{
u32 sstatus;
if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
- (sstatus & 0xf) != 0x3)
- return 1;
- return 0;
+ !ata_sstatus_online(sstatus))
+ return true;
+ return false;
+}
+
+/**
+ * ata_link_online - test whether the given link is online
+ * @link: ATA link to test
+ *
+ * Test whether @link is online. This is identical to
+ * ata_phys_link_online() when there's no slave link. When
+ * there's a slave link, this function should only be called on
+ * the master link and will return true if any of M/S links is
+ * online.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * True if the port online status is available and online.
+ */
+bool ata_link_online(struct ata_link *link)
+{
+ struct ata_link *slave = link->ap->slave_link;
+
+ WARN_ON(link == slave); /* shouldn't be called on slave link */
+
+ return ata_phys_link_online(link) ||
+ (slave && ata_phys_link_online(slave));
+}
+
+/**
+ * ata_link_offline - test whether the given link is offline
+ * @link: ATA link to test
+ *
+ * Test whether @link is offline. This is identical to
+ * ata_phys_link_offline() when there's no slave link. When
+ * there's a slave link, this function should only be called on
+ * the master link and will return true if both M/S links are
+ * offline.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * True if the port offline status is available and offline.
+ */
+bool ata_link_offline(struct ata_link *link)
+{
+ struct ata_link *slave = link->ap->slave_link;
+
+ WARN_ON(link == slave); /* shouldn't be called on slave link */
+
+ return ata_phys_link_offline(link) &&
+ (!slave || ata_phys_link_offline(slave));
}
#ifdef CONFIG_PM
-static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
- unsigned int action, unsigned int ehi_flags,
- int wait)
+static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
+ unsigned int action, unsigned int ehi_flags,
+ bool async)
{
+ struct ata_link *link;
unsigned long flags;
- int i, rc;
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
- struct ata_link *link;
+ /* Previous resume operation might still be in
+ * progress. Wait for PM_PENDING to clear.
+ */
+ if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+ ata_port_wait_eh(ap);
+ WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+ }
- /* Previous resume operation might still be in
- * progress. Wait for PM_PENDING to clear.
- */
- if (ap->pflags & ATA_PFLAG_PM_PENDING) {
- ata_port_wait_eh(ap);
- WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
- }
+ /* request PM ops to EH */
+ spin_lock_irqsave(ap->lock, flags);
- /* request PM ops to EH */
- spin_lock_irqsave(ap->lock, flags);
+ ap->pm_mesg = mesg;
+ ap->pflags |= ATA_PFLAG_PM_PENDING;
+ ata_for_each_link(link, ap, HOST_FIRST) {
+ link->eh_info.action |= action;
+ link->eh_info.flags |= ehi_flags;
+ }
- ap->pm_mesg = mesg;
- if (wait) {
- rc = 0;
- ap->pm_result = &rc;
- }
+ ata_port_schedule_eh(ap);
- ap->pflags |= ATA_PFLAG_PM_PENDING;
- __ata_port_for_each_link(link, ap) {
- link->eh_info.action |= action;
- link->eh_info.flags |= ehi_flags;
- }
+ spin_unlock_irqrestore(ap->lock, flags);
- ata_port_schedule_eh(ap);
+ if (!async) {
+ ata_port_wait_eh(ap);
+ WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+ }
+}
- spin_unlock_irqrestore(ap->lock, flags);
+/*
+ * On some hardware, device fails to respond after spun down for suspend. As
+ * the device won't be used before being resumed, we don't need to touch the
+ * device. Ask EH to skip the usual stuff and proceed directly to suspend.
+ *
+ * http://thread.gmane.org/gmane.linux.ide/46764
+ */
+static const unsigned int ata_port_suspend_ehi = ATA_EHI_QUIET
+ | ATA_EHI_NO_AUTOPSY
+ | ATA_EHI_NO_RECOVERY;
- /* wait and check result */
- if (wait) {
- ata_port_wait_eh(ap);
- WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
- if (rc)
- return rc;
- }
+static void ata_port_suspend(struct ata_port *ap, pm_message_t mesg)
+{
+ ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, false);
+}
+
+static void ata_port_suspend_async(struct ata_port *ap, pm_message_t mesg)
+{
+ ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, true);
+}
+
+static int ata_port_pm_suspend(struct device *dev)
+{
+ struct ata_port *ap = to_ata_port(dev);
+
+ if (pm_runtime_suspended(dev))
+ return 0;
+
+ ata_port_suspend(ap, PMSG_SUSPEND);
+ return 0;
+}
+
+static int ata_port_pm_freeze(struct device *dev)
+{
+ struct ata_port *ap = to_ata_port(dev);
+
+ if (pm_runtime_suspended(dev))
+ return 0;
+
+ ata_port_suspend(ap, PMSG_FREEZE);
+ return 0;
+}
+
+static int ata_port_pm_poweroff(struct device *dev)
+{
+ ata_port_suspend(to_ata_port(dev), PMSG_HIBERNATE);
+ return 0;
+}
+
+static const unsigned int ata_port_resume_ehi = ATA_EHI_NO_AUTOPSY
+ | ATA_EHI_QUIET;
+
+static void ata_port_resume(struct ata_port *ap, pm_message_t mesg)
+{
+ ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, false);
+}
+
+static void ata_port_resume_async(struct ata_port *ap, pm_message_t mesg)
+{
+ ata_port_request_pm(ap, mesg, ATA_EH_RESET, ata_port_resume_ehi, true);
+}
+
+static int ata_port_pm_resume(struct device *dev)
+{
+ ata_port_resume_async(to_ata_port(dev), PMSG_RESUME);
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ return 0;
+}
+
+/*
+ * For ODDs, the upper layer will poll for media change every few seconds,
+ * which will make it enter and leave suspend state every few seconds. And
+ * as each suspend will cause a hard/soft reset, the gain of runtime suspend
+ * is very little and the ODD may malfunction after constantly being reset.
+ * So the idle callback here will not proceed to suspend if a non-ZPODD capable
+ * ODD is attached to the port.
+ */
+static int ata_port_runtime_idle(struct device *dev)
+{
+ struct ata_port *ap = to_ata_port(dev);
+ struct ata_link *link;
+ struct ata_device *adev;
+
+ ata_for_each_link(link, ap, HOST_FIRST) {
+ ata_for_each_dev(adev, link, ENABLED)
+ if (adev->class == ATA_DEV_ATAPI &&
+ !zpodd_dev_enabled(adev))
+ return -EBUSY;
}
return 0;
}
+static int ata_port_runtime_suspend(struct device *dev)
+{
+ ata_port_suspend(to_ata_port(dev), PMSG_AUTO_SUSPEND);
+ return 0;
+}
+
+static int ata_port_runtime_resume(struct device *dev)
+{
+ ata_port_resume(to_ata_port(dev), PMSG_AUTO_RESUME);
+ return 0;
+}
+
+static const struct dev_pm_ops ata_port_pm_ops = {
+ .suspend = ata_port_pm_suspend,
+ .resume = ata_port_pm_resume,
+ .freeze = ata_port_pm_freeze,
+ .thaw = ata_port_pm_resume,
+ .poweroff = ata_port_pm_poweroff,
+ .restore = ata_port_pm_resume,
+
+ .runtime_suspend = ata_port_runtime_suspend,
+ .runtime_resume = ata_port_runtime_resume,
+ .runtime_idle = ata_port_runtime_idle,
+};
+
+/* sas ports don't participate in pm runtime management of ata_ports,
+ * and need to resume ata devices at the domain level, not the per-port
+ * level. sas suspend/resume is async to allow parallel port recovery
+ * since sas has multiple ata_port instances per Scsi_Host.
+ */
+void ata_sas_port_suspend(struct ata_port *ap)
+{
+ ata_port_suspend_async(ap, PMSG_SUSPEND);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_suspend);
+
+void ata_sas_port_resume(struct ata_port *ap)
+{
+ ata_port_resume_async(ap, PMSG_RESUME);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_resume);
+
/**
* ata_host_suspend - suspend host
* @host: host to suspend
* @mesg: PM message
*
- * Suspend @host. Actual operation is performed by EH. This
- * function requests EH to perform PM operations and waits for EH
- * to finish.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- *
- * RETURNS:
- * 0 on success, -errno on failure.
+ * Suspend @host. Actual operation is performed by port suspend.
*/
int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
{
- int rc;
-
- /*
- * disable link pm on all ports before requesting
- * any pm activity
- */
- ata_lpm_enable(host);
-
- rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1);
- if (rc == 0)
- host->dev->power.power_state = mesg;
- return rc;
+ host->dev->power.power_state = mesg;
+ return 0;
}
/**
* ata_host_resume - resume host
* @host: host to resume
*
- * Resume @host. Actual operation is performed by EH. This
- * function requests EH to perform PM operations and returns.
- * Note that all resume operations are performed parallely.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
+ * Resume @host. Actual operation is performed by port resume.
*/
void ata_host_resume(struct ata_host *host)
{
- ata_host_request_pm(host, PMSG_ON, ATA_EH_RESET,
- ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
host->dev->power.power_state = PMSG_ON;
-
- /* reenable link pm */
- ata_lpm_disable(host);
}
#endif
-/**
- * ata_port_start - Set port up for dma.
- * @ap: Port to initialize
- *
- * Called just after data structures for each port are
- * initialized. Allocates space for PRD table.
- *
- * May be used as the port_start() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-int ata_port_start(struct ata_port *ap)
-{
- struct device *dev = ap->dev;
-
- ap->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma,
- GFP_KERNEL);
- if (!ap->prd)
- return -ENOMEM;
-
- return 0;
-}
+struct device_type ata_port_type = {
+ .name = "ata_port",
+#ifdef CONFIG_PM
+ .pm = &ata_port_pm_ops,
+#endif
+};
/**
* ata_dev_init - Initialize an ata_device structure
@@ -5067,11 +5579,11 @@ int ata_port_start(struct ata_port *ap)
*/
void ata_dev_init(struct ata_device *dev)
{
- struct ata_link *link = dev->link;
+ struct ata_link *link = ata_dev_phys_link(dev);
struct ata_port *ap = link->ap;
unsigned long flags;
- /* SATA spd limit is bound to the first device */
+ /* SATA spd limit is bound to the attached device, reset together */
link->sata_spd_limit = link->hw_sata_spd_limit;
link->sata_spd = 0;
@@ -5084,8 +5596,8 @@ void ata_dev_init(struct ata_device *dev)
dev->horkage = 0;
spin_unlock_irqrestore(ap->lock, flags);
- memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0,
- sizeof(*dev) - ATA_DEVICE_CLEAR_OFFSET);
+ memset((void *)dev + ATA_DEVICE_CLEAR_BEGIN, 0,
+ ATA_DEVICE_CLEAR_END - ATA_DEVICE_CLEAR_BEGIN);
dev->pio_mask = UINT_MAX;
dev->mwdma_mask = UINT_MAX;
dev->udma_mask = UINT_MAX;
@@ -5107,7 +5619,8 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
int i;
/* clear everything except for devices */
- memset(link, 0, offsetof(struct ata_link, device[0]));
+ memset((void *)link + ATA_LINK_CLEAR_BEGIN, 0,
+ ATA_LINK_CLEAR_END - ATA_LINK_CLEAR_BEGIN);
link->ap = ap;
link->pmp = pmp;
@@ -5120,6 +5633,9 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
dev->link = link;
dev->devno = dev - link->device;
+#ifdef CONFIG_ATA_ACPI
+ dev->gtf_filter = ata_acpi_gtf_filter;
+#endif
ata_dev_init(dev);
}
}
@@ -5139,19 +5655,18 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
*/
int sata_link_init_spd(struct ata_link *link)
{
- u32 scontrol;
u8 spd;
int rc;
- rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
+ rc = sata_scr_read(link, SCR_CONTROL, &link->saved_scontrol);
if (rc)
return rc;
- spd = (scontrol >> 4) & 0xf;
+ spd = (link->saved_scontrol >> 4) & 0xf;
if (spd)
link->hw_sata_spd_limit &= (1 << spd) - 1;
- ata_force_spd_limit(link);
+ ata_force_link_limits(link);
link->sata_spd_limit = link->hw_sata_spd_limit;
@@ -5180,14 +5695,12 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
if (!ap)
return NULL;
- ap->pflags |= ATA_PFLAG_INITIALIZING;
+ ap->pflags |= ATA_PFLAG_INITIALIZING | ATA_PFLAG_FROZEN;
ap->lock = &host->lock;
- ap->flags = ATA_FLAG_DISABLED;
ap->print_id = -1;
- ap->ctl = ATA_DEVCTL_OBS;
+ ap->local_port_no = -1;
ap->host = host;
ap->dev = host->dev;
- ap->last_ctl = 0xFF;
#if defined(ATA_VERBOSE_DEBUG)
/* turn on all debugging levels */
@@ -5198,13 +5711,12 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
#endif
-#ifdef CONFIG_ATA_SFF
- INIT_DELAYED_WORK(&ap->port_task, ata_pio_task);
-#endif
+ mutex_init(&ap->scsi_scan_mutex);
INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug);
INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
INIT_LIST_HEAD(&ap->eh_done_q);
init_waitqueue_head(&ap->eh_wait_q);
+ init_completion(&ap->park_req_pending);
init_timer_deferrable(&ap->fastdrain_timer);
ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn;
ap->fastdrain_timer.data = (unsigned long)ap;
@@ -5217,6 +5729,8 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
ap->stats.unhandled_irq = 1;
ap->stats.idle_irq = 1;
#endif
+ ata_sff_port_init(ap);
+
return ap;
}
@@ -5235,6 +5749,7 @@ static void ata_host_release(struct device *gendev, void *res)
scsi_host_put(ap->scsi_host);
kfree(ap->pmp_link);
+ kfree(ap->slave_link);
kfree(ap);
host->ports[i] = NULL;
}
@@ -5284,6 +5799,7 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
dev_set_drvdata(dev, host);
spin_lock_init(&host->lock);
+ mutex_init(&host->eh_mutex);
host->dev = dev;
host->n_ports = max_ports;
@@ -5355,6 +5871,68 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
return host;
}
+/**
+ * ata_slave_link_init - initialize slave link
+ * @ap: port to initialize slave link for
+ *
+ * Create and initialize slave link for @ap. This enables slave
+ * link handling on the port.
+ *
+ * In libata, a port contains links and a link contains devices.
+ * There is single host link but if a PMP is attached to it,
+ * there can be multiple fan-out links. On SATA, there's usually
+ * a single device connected to a link but PATA and SATA
+ * controllers emulating TF based interface can have two - master
+ * and slave.
+ *
+ * However, there are a few controllers which don't fit into this
+ * abstraction too well - SATA controllers which emulate TF
+ * interface with both master and slave devices but also have
+ * separate SCR register sets for each device. These controllers
+ * need separate links for physical link handling
+ * (e.g. onlineness, link speed) but should be treated like a
+ * traditional M/S controller for everything else (e.g. command
+ * issue, softreset).
+ *
+ * slave_link is libata's way of handling this class of
+ * controllers without impacting core layer too much. For
+ * anything other than physical link handling, the default host
+ * link is used for both master and slave. For physical link
+ * handling, separate @ap->slave_link is used. All dirty details
+ * are implemented inside libata core layer. From LLD's POV, the
+ * only difference is that prereset, hardreset and postreset are
+ * called once more for the slave link, so the reset sequence
+ * looks like the following.
+ *
+ * prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) ->
+ * softreset(M) -> postreset(M) -> postreset(S)
+ *
+ * Note that softreset is called only for the master. Softreset
+ * resets both M/S by definition, so SRST on master should handle
+ * both (the standard method will work just fine).
+ *
+ * LOCKING:
+ * Should be called before host is registered.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int ata_slave_link_init(struct ata_port *ap)
+{
+ struct ata_link *link;
+
+ WARN_ON(ap->slave_link);
+ WARN_ON(ap->flags & ATA_FLAG_PMP);
+
+ link = kzalloc(sizeof(*link), GFP_KERNEL);
+ if (!link)
+ return -ENOMEM;
+
+ ata_link_init(ap, link, 1);
+ ap->slave_link = link;
+ return 0;
+}
+
static void ata_host_stop(struct device *gendev, void *res)
{
struct ata_host *host = dev_get_drvdata(gendev);
@@ -5395,7 +5973,7 @@ static void ata_host_stop(struct device *gendev, void *res)
*/
static void ata_finalize_port_ops(struct ata_port_operations *ops)
{
- static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+ static DEFINE_SPINLOCK(lock);
const struct ata_port_operations *cur;
void **begin = (void **)ops;
void **end = (void **)&ops->inherits;
@@ -5478,9 +6056,9 @@ int ata_host_start(struct ata_host *host)
rc = ap->ops->port_start(ap);
if (rc) {
if (rc != -ENODEV)
- dev_printk(KERN_ERR, host->dev,
- "failed to start port %d "
- "(errno=%d)\n", i, rc);
+ dev_err(host->dev,
+ "failed to start port %d (errno=%d)\n",
+ i, rc);
goto err_out;
}
}
@@ -5504,26 +6082,79 @@ int ata_host_start(struct ata_host *host)
}
/**
- * ata_sas_host_init - Initialize a host struct
+ * ata_sas_host_init - Initialize a host struct for sas (ipr, libsas)
* @host: host to initialize
* @dev: device host is attached to
- * @flags: host flags
* @ops: port_ops
*
- * LOCKING:
- * PCI/etc. bus probe sem.
- *
*/
-/* KILLME - the only user left is ipr */
void ata_host_init(struct ata_host *host, struct device *dev,
- unsigned long flags, struct ata_port_operations *ops)
+ struct ata_port_operations *ops)
{
spin_lock_init(&host->lock);
+ mutex_init(&host->eh_mutex);
+ host->n_tags = ATA_MAX_QUEUE - 1;
host->dev = dev;
- host->flags = flags;
host->ops = ops;
}
+void __ata_port_probe(struct ata_port *ap)
+{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ unsigned long flags;
+
+ /* kick EH for boot probing */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ehi->probe_mask |= ATA_ALL_DEVICES;
+ ehi->action |= ATA_EH_RESET;
+ ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
+
+ ap->pflags &= ~ATA_PFLAG_INITIALIZING;
+ ap->pflags |= ATA_PFLAG_LOADING;
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+int ata_port_probe(struct ata_port *ap)
+{
+ int rc = 0;
+
+ if (ap->ops->error_handler) {
+ __ata_port_probe(ap);
+ ata_port_wait_eh(ap);
+ } else {
+ DPRINTK("ata%u: bus probe begin\n", ap->print_id);
+ rc = ata_bus_probe(ap);
+ DPRINTK("ata%u: bus probe end\n", ap->print_id);
+ }
+ return rc;
+}
+
+
+static void async_port_probe(void *data, async_cookie_t cookie)
+{
+ struct ata_port *ap = data;
+
+ /*
+ * If we're not allowed to scan this host in parallel,
+ * we need to wait until all previous scans have completed
+ * before going further.
+ * Jeff Garzik says this is only within a controller, so we
+ * don't need to wait for port 0, only for later ports.
+ */
+ if (!(ap->host->flags & ATA_HOST_PARALLEL_SCAN) && ap->port_no != 0)
+ async_synchronize_cookie(cookie);
+
+ (void)ata_port_probe(ap);
+
+ /* in order to keep device order, we need to synchronize at this point */
+ async_synchronize_cookie(cookie);
+
+ ata_scsi_scan_host(ap, 1);
+}
+
/**
* ata_host_register - register initialized ATA host
* @host: ATA host to register
@@ -5544,10 +6175,11 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
{
int i, rc;
+ host->n_tags = clamp(sht->can_queue, 1, ATA_MAX_QUEUE - 1);
+
/* host must have been started */
if (!(host->flags & ATA_HOST_STARTED)) {
- dev_printk(KERN_ERR, host->dev,
- "BUG: trying to register unstarted host\n");
+ dev_err(host->dev, "BUG: trying to register unstarted host\n");
WARN_ON(1);
return -EINVAL;
}
@@ -5560,15 +6192,22 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
kfree(host->ports[i]);
/* give ports names and add SCSI hosts */
- for (i = 0; i < host->n_ports; i++)
- host->ports[i]->print_id = ata_print_id++;
+ for (i = 0; i < host->n_ports; i++) {
+ host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
+ host->ports[i]->local_port_no = i + 1;
+ }
+
+ /* Create associated sysfs transport objects */
+ for (i = 0; i < host->n_ports; i++) {
+ rc = ata_tport_add(host->dev,host->ports[i]);
+ if (rc) {
+ goto err_tadd;
+ }
+ }
rc = ata_scsi_add_hosts(host, sht);
if (rc)
- return rc;
-
- /* associate with ACPI nodes */
- ata_acpi_associate(host);
+ goto err_tadd;
/* set cable, sata_spd_limit and report */
for (i = 0; i < host->n_ports; i++) {
@@ -5581,75 +6220,37 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
/* init sata_spd_limit to the current value */
sata_link_init_spd(&ap->link);
+ if (ap->slave_link)
+ sata_link_init_spd(ap->slave_link);
/* print per-port info to dmesg */
xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
ap->udma_mask);
if (!ata_port_is_dummy(ap)) {
- ata_port_printk(ap, KERN_INFO,
- "%cATA max %s %s\n",
- (ap->flags & ATA_FLAG_SATA) ? 'S' : 'P',
- ata_mode_string(xfer_mask),
- ap->link.eh_info.desc);
+ ata_port_info(ap, "%cATA max %s %s\n",
+ (ap->flags & ATA_FLAG_SATA) ? 'S' : 'P',
+ ata_mode_string(xfer_mask),
+ ap->link.eh_info.desc);
ata_ehi_clear_desc(&ap->link.eh_info);
} else
- ata_port_printk(ap, KERN_INFO, "DUMMY\n");
+ ata_port_info(ap, "DUMMY\n");
}
- /* perform each probe synchronously */
- DPRINTK("probe begin\n");
+ /* perform each probe asynchronously */
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
-
- /* probe */
- if (ap->ops->error_handler) {
- struct ata_eh_info *ehi = &ap->link.eh_info;
- unsigned long flags;
-
- ata_port_probe(ap);
-
- /* kick EH for boot probing */
- spin_lock_irqsave(ap->lock, flags);
-
- ehi->probe_mask |= ATA_ALL_DEVICES;
- ehi->action |= ATA_EH_RESET;
- ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
-
- ap->pflags &= ~ATA_PFLAG_INITIALIZING;
- ap->pflags |= ATA_PFLAG_LOADING;
- ata_port_schedule_eh(ap);
-
- spin_unlock_irqrestore(ap->lock, flags);
-
- /* wait for EH to finish */
- ata_port_wait_eh(ap);
- } else {
- DPRINTK("ata%u: bus probe begin\n", ap->print_id);
- rc = ata_bus_probe(ap);
- DPRINTK("ata%u: bus probe end\n", ap->print_id);
-
- if (rc) {
- /* FIXME: do something useful here?
- * Current libata behavior will
- * tear down everything when
- * the module is removed
- * or the h/w is unplugged.
- */
- }
- }
+ async_schedule(async_port_probe, ap);
}
- /* probes are done, now scan each port's disk(s) */
- DPRINTK("host probe begin\n");
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
+ return 0;
- ata_scsi_scan_host(ap, 1);
- ata_lpm_schedule(ap, ap->pm_policy);
+ err_tadd:
+ while (--i >= 0) {
+ ata_tport_delete(host->ports[i]);
}
+ return rc;
- return 0;
}
/**
@@ -5730,32 +6331,33 @@ static void ata_port_detach(struct ata_port *ap)
/* tell EH we're leaving & flush EH */
spin_lock_irqsave(ap->lock, flags);
ap->pflags |= ATA_PFLAG_UNLOADING;
+ ata_port_schedule_eh(ap);
spin_unlock_irqrestore(ap->lock, flags);
+ /* wait till EH commits suicide */
ata_port_wait_eh(ap);
- /* EH is now guaranteed to see UNLOADING - EH context belongs
- * to us. Disable all existing devices.
- */
- ata_port_for_each_link(link, ap) {
- ata_link_for_each_dev(dev, link)
- ata_dev_disable(dev);
- }
+ /* it better be dead now */
+ WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED));
- /* Final freeze & EH. All in-flight commands are aborted. EH
- * will be skipped and retrials will be terminated with bad
- * target.
- */
- spin_lock_irqsave(ap->lock, flags);
- ata_port_freeze(ap); /* won't be thawed */
- spin_unlock_irqrestore(ap->lock, flags);
-
- ata_port_wait_eh(ap);
- cancel_rearming_delayed_work(&ap->hotplug_task);
+ cancel_delayed_work_sync(&ap->hotplug_task);
skip_eh:
+ /* clean up zpodd on port removal */
+ ata_for_each_link(link, ap, HOST_FIRST) {
+ ata_for_each_dev(dev, link, ALL) {
+ if (zpodd_dev_enabled(dev))
+ zpodd_exit(dev);
+ }
+ }
+ if (ap->pmp_link) {
+ int i;
+ for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+ ata_tlink_delete(&ap->pmp_link[i]);
+ }
/* remove the associated SCSI host */
scsi_remove_host(ap->scsi_host);
+ ata_tport_delete(ap);
}
/**
@@ -5793,8 +6395,7 @@ void ata_host_detach(struct ata_host *host)
*/
void ata_pci_remove_one(struct pci_dev *pdev)
{
- struct device *dev = &pdev->dev;
- struct ata_host *host = dev_get_drvdata(dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
ata_host_detach(host);
}
@@ -5852,8 +6453,8 @@ int ata_pci_device_do_resume(struct pci_dev *pdev)
rc = pcim_enable_device(pdev);
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to enable device after resume (%d)\n", rc);
+ dev_err(&pdev->dev,
+ "failed to enable device after resume (%d)\n", rc);
return rc;
}
@@ -5863,7 +6464,7 @@ int ata_pci_device_do_resume(struct pci_dev *pdev)
int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc = 0;
rc = ata_host_suspend(host, mesg);
@@ -5877,7 +6478,7 @@ int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
int ata_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -5889,6 +6490,26 @@ int ata_pci_device_resume(struct pci_dev *pdev)
#endif /* CONFIG_PCI */
+/**
+ * ata_platform_remove_one - Platform layer callback for device removal
+ * @pdev: Platform device that was removed
+ *
+ * Platform layer indicates to libata via this hook that hot-unplug or
+ * module unload event has occurred. Detach all ports. Resource
+ * release is handled via devres.
+ *
+ * LOCKING:
+ * Inherited from platform layer (may sleep).
+ */
+int ata_platform_remove_one(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+
+ ata_host_detach(host);
+
+ return 0;
+}
+
static int __init ata_parse_force_one(char **cur,
struct ata_force_ent *force_ent,
const char **reason)
@@ -5909,6 +6530,7 @@ static int __init ata_parse_force_one(char **cur,
{ "3.0Gbps", .spd_limit = 2 },
{ "noncq", .horkage_on = ATA_HORKAGE_NONCQ },
{ "ncq", .horkage_off = ATA_HORKAGE_NONCQ },
+ { "dump_id", .horkage_on = ATA_HORKAGE_DUMP_ID },
{ "pio0", .xfer_mask = 1 << (ATA_SHIFT_PIO + 0) },
{ "pio1", .xfer_mask = 1 << (ATA_SHIFT_PIO + 1) },
{ "pio2", .xfer_mask = 1 << (ATA_SHIFT_PIO + 2) },
@@ -5943,6 +6565,12 @@ static int __init ata_parse_force_one(char **cur,
{ "udma133", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 6) },
{ "udma/133", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 6) },
{ "udma7", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 7) },
+ { "nohrst", .lflags = ATA_LFLAG_NO_HRST },
+ { "nosrst", .lflags = ATA_LFLAG_NO_SRST },
+ { "norst", .lflags = ATA_LFLAG_NO_HRST | ATA_LFLAG_NO_SRST },
+ { "rstonce", .lflags = ATA_LFLAG_RST_ONCE },
+ { "atapi_dmadir", .horkage_on = ATA_HORKAGE_ATAPI_DMADIR },
+ { "disable", .horkage_on = ATA_HORKAGE_DISABLE },
};
char *start = *cur, *p = *cur;
char *id, *val, *endp;
@@ -6066,62 +6694,84 @@ static void __init ata_parse_force_param(void)
static int __init ata_init(void)
{
- ata_probe_timeout *= HZ;
+ int rc;
ata_parse_force_param();
- ata_wq = create_workqueue("ata");
- if (!ata_wq)
- return -ENOMEM;
+ rc = ata_sff_init();
+ if (rc) {
+ kfree(ata_force_tbl);
+ return rc;
+ }
- ata_aux_wq = create_singlethread_workqueue("ata_aux");
- if (!ata_aux_wq) {
- destroy_workqueue(ata_wq);
- return -ENOMEM;
+ libata_transport_init();
+ ata_scsi_transport_template = ata_attach_transport();
+ if (!ata_scsi_transport_template) {
+ ata_sff_exit();
+ rc = -ENOMEM;
+ goto err_out;
}
printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
return 0;
+
+err_out:
+ return rc;
}
static void __exit ata_exit(void)
{
+ ata_release_transport(ata_scsi_transport_template);
+ libata_transport_exit();
+ ata_sff_exit();
kfree(ata_force_tbl);
- destroy_workqueue(ata_wq);
- destroy_workqueue(ata_aux_wq);
}
subsys_initcall(ata_init);
module_exit(ata_exit);
-static unsigned long ratelimit_time;
-static DEFINE_SPINLOCK(ata_ratelimit_lock);
+static DEFINE_RATELIMIT_STATE(ratelimit, HZ / 5, 1);
int ata_ratelimit(void)
{
- int rc;
- unsigned long flags;
+ return __ratelimit(&ratelimit);
+}
- spin_lock_irqsave(&ata_ratelimit_lock, flags);
+/**
+ * ata_msleep - ATA EH owner aware msleep
+ * @ap: ATA port to attribute the sleep to
+ * @msecs: duration to sleep in milliseconds
+ *
+ * Sleeps @msecs. If the current task is owner of @ap's EH, the
+ * ownership is released before going to sleep and reacquired
+ * after the sleep is complete. IOW, other ports sharing the
+ * @ap->host will be allowed to own the EH while this task is
+ * sleeping.
+ *
+ * LOCKING:
+ * Might sleep.
+ */
+void ata_msleep(struct ata_port *ap, unsigned int msecs)
+{
+ bool owns_eh = ap && ap->host->eh_owner == current;
- if (time_after(jiffies, ratelimit_time)) {
- rc = 1;
- ratelimit_time = jiffies + (HZ/5);
- } else
- rc = 0;
+ if (owns_eh)
+ ata_eh_release(ap);
- spin_unlock_irqrestore(&ata_ratelimit_lock, flags);
+ msleep(msecs);
- return rc;
+ if (owns_eh)
+ ata_eh_acquire(ap);
}
/**
* ata_wait_register - wait until register value changes
+ * @ap: ATA port to wait register for, can be NULL
* @reg: IO-mapped register
* @mask: Mask to apply to read register value
* @val: Wait condition
- * @interval_msec: polling interval in milliseconds
- * @timeout_msec: timeout in milliseconds
+ * @interval: polling interval in milliseconds
+ * @timeout: timeout in milliseconds
*
* Waiting for some bits of register to change is a common
* operation for ATA controllers. This function reads 32bit LE
@@ -6138,11 +6788,10 @@ int ata_ratelimit(void)
* RETURNS:
* The final register value.
*/
-u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
- unsigned long interval_msec,
- unsigned long timeout_msec)
+u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val,
+ unsigned long interval, unsigned long timeout)
{
- unsigned long timeout;
+ unsigned long deadline;
u32 tmp;
tmp = ioread32(reg);
@@ -6151,10 +6800,10 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
* preceding writes reach the controller before starting to
* eat away the timeout.
*/
- timeout = jiffies + (timeout_msec * HZ) / 1000;
+ deadline = ata_deadline(jiffies, timeout);
- while ((tmp & mask) == val && time_before(jiffies, timeout)) {
- msleep(interval_msec);
+ while ((tmp & mask) == val && time_before(jiffies, deadline)) {
+ ata_msleep(ap, interval);
tmp = ioread32(reg);
}
@@ -6178,6 +6827,8 @@ struct ata_port_operations ata_dummy_port_ops = {
.qc_prep = ata_noop_qc_prep,
.qc_issue = ata_dummy_qc_issue,
.error_handler = ata_dummy_error_handler,
+ .sched_eh = ata_std_sched_eh,
+ .end_eh = ata_std_end_eh,
};
const struct ata_port_info ata_dummy_port_info = {
@@ -6185,6 +6836,82 @@ const struct ata_port_info ata_dummy_port_info = {
};
/*
+ * Utility print functions
+ */
+int ata_port_printk(const struct ata_port *ap, const char *level,
+ const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+ int r;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ r = printk("%sata%u: %pV", level, ap->print_id, &vaf);
+
+ va_end(args);
+
+ return r;
+}
+EXPORT_SYMBOL(ata_port_printk);
+
+int ata_link_printk(const struct ata_link *link, const char *level,
+ const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+ int r;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ if (sata_pmp_attached(link->ap) || link->ap->slave_link)
+ r = printk("%sata%u.%02u: %pV",
+ level, link->ap->print_id, link->pmp, &vaf);
+ else
+ r = printk("%sata%u: %pV",
+ level, link->ap->print_id, &vaf);
+
+ va_end(args);
+
+ return r;
+}
+EXPORT_SYMBOL(ata_link_printk);
+
+int ata_dev_printk(const struct ata_device *dev, const char *level,
+ const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+ int r;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ r = printk("%sata%u.%02u: %pV",
+ level, dev->link->ap->print_id, dev->link->pmp + dev->devno,
+ &vaf);
+
+ va_end(args);
+
+ return r;
+}
+EXPORT_SYMBOL(ata_dev_printk);
+
+void ata_print_version(const struct device *dev, const char *version)
+{
+ dev_printk(KERN_DEBUG, dev, "version %s\n", version);
+}
+EXPORT_SYMBOL(ata_print_version);
+
+/*
* libata is essentially a library of internal helper functions for
* low-level ATA host controller drivers. As such, the API/ABI is
* likely to change as new drivers are added and updated.
@@ -6197,10 +6924,14 @@ EXPORT_SYMBOL_GPL(ata_base_port_ops);
EXPORT_SYMBOL_GPL(sata_port_ops);
EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
EXPORT_SYMBOL_GPL(ata_dummy_port_info);
+EXPORT_SYMBOL_GPL(ata_link_next);
+EXPORT_SYMBOL_GPL(ata_dev_next);
EXPORT_SYMBOL_GPL(ata_std_bios_param);
+EXPORT_SYMBOL_GPL(ata_scsi_unlock_native_capacity);
EXPORT_SYMBOL_GPL(ata_host_init);
EXPORT_SYMBOL_GPL(ata_host_alloc);
EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
+EXPORT_SYMBOL_GPL(ata_slave_link_init);
EXPORT_SYMBOL_GPL(ata_host_start);
EXPORT_SYMBOL_GPL(ata_host_register);
EXPORT_SYMBOL_GPL(ata_host_activate);
@@ -6208,7 +6939,6 @@ EXPORT_SYMBOL_GPL(ata_host_detach);
EXPORT_SYMBOL_GPL(ata_sg_init);
EXPORT_SYMBOL_GPL(ata_qc_complete);
EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
-EXPORT_SYMBOL_GPL(sata_print_link_status);
EXPORT_SYMBOL_GPL(atapi_cmd_type);
EXPORT_SYMBOL_GPL(ata_tf_to_fis);
EXPORT_SYMBOL_GPL(ata_tf_from_fis);
@@ -6219,30 +6949,29 @@ EXPORT_SYMBOL_GPL(ata_xfer_mode2mask);
EXPORT_SYMBOL_GPL(ata_xfer_mode2shift);
EXPORT_SYMBOL_GPL(ata_mode_string);
EXPORT_SYMBOL_GPL(ata_id_xfermask);
-EXPORT_SYMBOL_GPL(ata_port_start);
EXPORT_SYMBOL_GPL(ata_do_set_mode);
EXPORT_SYMBOL_GPL(ata_std_qc_defer);
EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
-EXPORT_SYMBOL_GPL(ata_port_probe);
EXPORT_SYMBOL_GPL(ata_dev_disable);
EXPORT_SYMBOL_GPL(sata_set_spd);
EXPORT_SYMBOL_GPL(ata_wait_after_reset);
EXPORT_SYMBOL_GPL(sata_link_debounce);
EXPORT_SYMBOL_GPL(sata_link_resume);
+EXPORT_SYMBOL_GPL(sata_link_scr_lpm);
EXPORT_SYMBOL_GPL(ata_std_prereset);
EXPORT_SYMBOL_GPL(sata_link_hardreset);
EXPORT_SYMBOL_GPL(sata_std_hardreset);
EXPORT_SYMBOL_GPL(ata_std_postreset);
EXPORT_SYMBOL_GPL(ata_dev_classify);
EXPORT_SYMBOL_GPL(ata_dev_pair);
-EXPORT_SYMBOL_GPL(ata_port_disable);
EXPORT_SYMBOL_GPL(ata_ratelimit);
+EXPORT_SYMBOL_GPL(ata_msleep);
EXPORT_SYMBOL_GPL(ata_wait_register);
-EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
+EXPORT_SYMBOL_GPL(__ata_change_queue_depth);
EXPORT_SYMBOL_GPL(sata_scr_valid);
EXPORT_SYMBOL_GPL(sata_scr_read);
EXPORT_SYMBOL_GPL(sata_scr_write);
@@ -6255,6 +6984,7 @@ EXPORT_SYMBOL_GPL(ata_host_resume);
#endif /* CONFIG_PM */
EXPORT_SYMBOL_GPL(ata_id_string);
EXPORT_SYMBOL_GPL(ata_id_c_string);
+EXPORT_SYMBOL_GPL(ata_do_dev_read_id);
EXPORT_SYMBOL_GPL(ata_scsi_simulate);
EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
@@ -6274,6 +7004,8 @@ EXPORT_SYMBOL_GPL(ata_pci_device_resume);
#endif /* CONFIG_PM */
#endif /* CONFIG_PCI */
+EXPORT_SYMBOL_GPL(ata_platform_remove_one);
+
EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
@@ -6290,6 +7022,7 @@ EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
+EXPORT_SYMBOL_GPL(ata_eh_analyze_ncq_error);
EXPORT_SYMBOL_GPL(ata_do_eh);
EXPORT_SYMBOL_GPL(ata_std_error_handler);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index d94359a24d4..dad83df555c 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1,7 +1,7 @@
/*
* libata-eh.c - libata error handling
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -33,12 +33,15 @@
*/
#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/export.h>
#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
#include "../scsi/scsi_transport_api.h"
#include <linux/libata.h>
@@ -55,6 +58,7 @@ enum {
/* error flags */
ATA_EFLAG_IS_IO = (1 << 0),
ATA_EFLAG_DUBIOUS_XFER = (1 << 1),
+ ATA_EFLAG_OLD_ER = (1 << 31),
/* error categories */
ATA_ECAT_NONE = 0,
@@ -66,31 +70,98 @@ enum {
ATA_ECAT_DUBIOUS_TOUT_HSM = 6,
ATA_ECAT_DUBIOUS_UNK_DEV = 7,
ATA_ECAT_NR = 8,
-};
-/* Waiting in ->prereset can never be reliable. It's sometimes nice
- * to wait there but it can't be depended upon; otherwise, we wouldn't
- * be resetting. Just give it enough time for most drives to spin up.
- */
-enum {
- ATA_EH_PRERESET_TIMEOUT = 10 * HZ,
- ATA_EH_FASTDRAIN_INTERVAL = 3 * HZ,
+ ATA_EH_CMD_DFL_TIMEOUT = 5000,
+
+ /* always put at least this amount of time between resets */
+ ATA_EH_RESET_COOL_DOWN = 5000,
+
+ /* Waiting in ->prereset can never be reliable. It's
+ * sometimes nice to wait there but it can't be depended upon;
+ * otherwise, we wouldn't be resetting. Just give it enough
+ * time for most drives to spin up.
+ */
+ ATA_EH_PRERESET_TIMEOUT = 10000,
+ ATA_EH_FASTDRAIN_INTERVAL = 3000,
+
+ ATA_EH_UA_TRIES = 5,
+
+ /* probe speed down parameters, see ata_eh_schedule_probe() */
+ ATA_EH_PROBE_TRIAL_INTERVAL = 60000, /* 1 min */
+ ATA_EH_PROBE_TRIALS = 2,
};
/* The following table determines how we sequence resets. Each entry
* represents timeout for that try. The first try can be soft or
* hardreset. All others are hardreset if available. In most cases
* the first reset w/ 10sec timeout should succeed. Following entries
- * are mostly for error handling, hotplug and retarded devices.
+ * are mostly for error handling, hotplug and those outlier devices that
+ * take an exceptionally long time to recover from reset.
*/
static const unsigned long ata_eh_reset_timeouts[] = {
- 10 * HZ, /* most drives spin up by 10sec */
- 10 * HZ, /* > 99% working drives spin up before 20sec */
- 35 * HZ, /* give > 30 secs of idleness for retarded devices */
- 5 * HZ, /* and sweet one last chance */
- /* > 1 min has elapsed, give up */
+ 10000, /* most drives spin up by 10sec */
+ 10000, /* > 99% working drives spin up before 20sec */
+ 35000, /* give > 30 secs of idleness for outlier devices */
+ 5000, /* and sweet one last chance */
+ ULONG_MAX, /* > 1 min has elapsed, give up */
};
+static const unsigned long ata_eh_identify_timeouts[] = {
+ 5000, /* covers > 99% of successes and not too boring on failures */
+ 10000, /* combined time till here is enough even for media access */
+ 30000, /* for true idiots */
+ ULONG_MAX,
+};
+
+static const unsigned long ata_eh_flush_timeouts[] = {
+ 15000, /* be generous with flush */
+ 15000, /* ditto */
+ 30000, /* and even more generous */
+ ULONG_MAX,
+};
+
+static const unsigned long ata_eh_other_timeouts[] = {
+ 5000, /* same rationale as identify timeout */
+ 10000, /* ditto */
+ /* but no merciful 30sec for other commands, it just isn't worth it */
+ ULONG_MAX,
+};
+
+struct ata_eh_cmd_timeout_ent {
+ const u8 *commands;
+ const unsigned long *timeouts;
+};
+
+/* The following table determines timeouts to use for EH internal
+ * commands. Each table entry is a command class and matches the
+ * commands the entry applies to and the timeout table to use.
+ *
+ * On the retry after a command timed out, the next timeout value from
+ * the table is used. If the table doesn't contain further entries,
+ * the last value is used.
+ *
+ * ehc->cmd_timeout_idx keeps track of which timeout to use per
+ * command class, so if SET_FEATURES times out on the first try, the
+ * next try will use the second timeout value only for that class.
+ */
+#define CMDS(cmds...) (const u8 []){ cmds, 0 }
+static const struct ata_eh_cmd_timeout_ent
+ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = {
+ { .commands = CMDS(ATA_CMD_ID_ATA, ATA_CMD_ID_ATAPI),
+ .timeouts = ata_eh_identify_timeouts, },
+ { .commands = CMDS(ATA_CMD_READ_NATIVE_MAX, ATA_CMD_READ_NATIVE_MAX_EXT),
+ .timeouts = ata_eh_other_timeouts, },
+ { .commands = CMDS(ATA_CMD_SET_MAX, ATA_CMD_SET_MAX_EXT),
+ .timeouts = ata_eh_other_timeouts, },
+ { .commands = CMDS(ATA_CMD_SET_FEATURES),
+ .timeouts = ata_eh_other_timeouts, },
+ { .commands = CMDS(ATA_CMD_INIT_DEV_PARAMS),
+ .timeouts = ata_eh_other_timeouts, },
+ { .commands = CMDS(ATA_CMD_FLUSH, ATA_CMD_FLUSH_EXT),
+ .timeouts = ata_eh_flush_timeouts },
+};
+#undef CMDS
+
static void __ata_port_freeze(struct ata_port *ap);
#ifdef CONFIG_PM
static void ata_eh_handle_port_suspend(struct ata_port *ap);
@@ -236,6 +307,73 @@ void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
#endif /* CONFIG_PCI */
+static int ata_lookup_timeout_table(u8 cmd)
+{
+ int i;
+
+ for (i = 0; i < ATA_EH_CMD_TIMEOUT_TABLE_SIZE; i++) {
+ const u8 *cur;
+
+ for (cur = ata_eh_cmd_timeout_table[i].commands; *cur; cur++)
+ if (*cur == cmd)
+ return i;
+ }
+
+ return -1;
+}
+
+/**
+ * ata_internal_cmd_timeout - determine timeout for an internal command
+ * @dev: target device
+ * @cmd: internal command to be issued
+ *
+ * Determine timeout for internal command @cmd for @dev.
+ *
+ * LOCKING:
+ * EH context.
+ *
+ * RETURNS:
+ * Determined timeout.
+ */
+unsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd)
+{
+ struct ata_eh_context *ehc = &dev->link->eh_context;
+ int ent = ata_lookup_timeout_table(cmd);
+ int idx;
+
+ if (ent < 0)
+ return ATA_EH_CMD_DFL_TIMEOUT;
+
+ idx = ehc->cmd_timeout_idx[dev->devno][ent];
+ return ata_eh_cmd_timeout_table[ent].timeouts[idx];
+}
+
+/**
+ * ata_internal_cmd_timed_out - notification for internal command timeout
+ * @dev: target device
+ * @cmd: internal command which timed out
+ *
+ * Notify EH that internal command @cmd for @dev timed out. This
+ * function should be called only for commands whose timeouts are
+ * determined using ata_internal_cmd_timeout().
+ *
+ * LOCKING:
+ * EH context.
+ */
+void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd)
+{
+ struct ata_eh_context *ehc = &dev->link->eh_context;
+ int ent = ata_lookup_timeout_table(cmd);
+ int idx;
+
+ if (ent < 0)
+ return;
+
+ idx = ehc->cmd_timeout_idx[dev->devno][ent];
+ if (ata_eh_cmd_timeout_table[ent].timeouts[idx + 1] != ULONG_MAX)
+ ehc->cmd_timeout_idx[dev->devno][ent]++;
+}
+
static void ata_ering_record(struct ata_ering *ering, unsigned int eflags,
unsigned int err_mask)
{
@@ -261,14 +399,9 @@ static struct ata_ering_entry *ata_ering_top(struct ata_ering *ering)
return NULL;
}
-static void ata_ering_clear(struct ata_ering *ering)
-{
- memset(ering, 0, sizeof(*ering));
-}
-
-static int ata_ering_map(struct ata_ering *ering,
- int (*map_fn)(struct ata_ering_entry *, void *),
- void *arg)
+int ata_ering_map(struct ata_ering *ering,
+ int (*map_fn)(struct ata_ering_entry *, void *),
+ void *arg)
{
int idx, rc = 0;
struct ata_ering_entry *ent;
@@ -287,6 +420,17 @@ static int ata_ering_map(struct ata_ering *ering,
return rc;
}
+static int ata_ering_clear_cb(struct ata_ering_entry *ent, void *void_arg)
+{
+ ent->eflags |= ATA_EFLAG_OLD_ER;
+ return 0;
+}
+
+static void ata_ering_clear(struct ata_ering *ering)
+{
+ ata_ering_map(ering, ata_ering_clear_cb, NULL);
+}
+
static unsigned int ata_eh_dev_action(struct ata_device *dev)
{
struct ata_eh_context *ehc = &dev->link->eh_context;
@@ -301,7 +445,7 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
if (!dev) {
ehi->action &= ~action;
- ata_link_for_each_dev(tdev, link)
+ ata_for_each_dev(tdev, link, ALL)
ehi->dev_action[tdev->devno] &= ~action;
} else {
/* doesn't make sense for port-wide EH actions */
@@ -309,7 +453,7 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
/* break ehi->action into ehi->dev_action */
if (ehi->action & action) {
- ata_link_for_each_dev(tdev, link)
+ ata_for_each_dev(tdev, link, ALL)
ehi->dev_action[tdev->devno] |=
ehi->action & action;
ehi->action &= ~action;
@@ -321,6 +465,41 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
}
/**
+ * ata_eh_acquire - acquire EH ownership
+ * @ap: ATA port to acquire EH ownership for
+ *
+ * Acquire EH ownership for @ap. This is the basic exclusion
+ * mechanism for ports sharing a host. Only one port hanging off
+ * the same host can claim the ownership of EH.
+ *
+ * LOCKING:
+ * EH context.
+ */
+void ata_eh_acquire(struct ata_port *ap)
+{
+ mutex_lock(&ap->host->eh_mutex);
+ WARN_ON_ONCE(ap->host->eh_owner);
+ ap->host->eh_owner = current;
+}
+
+/**
+ * ata_eh_release - release EH ownership
+ * @ap: ATA port to release EH ownership for
+ *
+ * Release EH ownership for @ap if the caller. The caller must
+ * have acquired EH ownership using ata_eh_acquire() previously.
+ *
+ * LOCKING:
+ * EH context.
+ */
+void ata_eh_release(struct ata_port *ap)
+{
+ WARN_ON_ONCE(ap->host->eh_owner != current);
+ ap->host->eh_owner = NULL;
+ mutex_unlock(&ap->host->eh_mutex);
+}
+
+/**
* ata_scsi_timed_out - SCSI layer time out callback
* @cmd: timed out SCSI command
*
@@ -339,29 +518,29 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
* RETURNS:
* EH_HANDLED or EH_NOT_HANDLED
*/
-enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
{
struct Scsi_Host *host = cmd->device->host;
struct ata_port *ap = ata_shost_to_port(host);
unsigned long flags;
struct ata_queued_cmd *qc;
- enum scsi_eh_timer_return ret;
+ enum blk_eh_timer_return ret;
DPRINTK("ENTER\n");
if (ap->ops->error_handler) {
- ret = EH_NOT_HANDLED;
+ ret = BLK_EH_NOT_HANDLED;
goto out;
}
- ret = EH_HANDLED;
+ ret = BLK_EH_HANDLED;
spin_lock_irqsave(ap->lock, flags);
qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc) {
WARN_ON(qc->scsicmd != cmd);
qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
qc->err_mask |= AC_ERR_TIMEOUT;
- ret = EH_NOT_HANDLED;
+ ret = BLK_EH_NOT_HANDLED;
}
spin_unlock_irqrestore(ap->lock, flags);
@@ -370,6 +549,31 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
return ret;
}
+static void ata_eh_unload(struct ata_port *ap)
+{
+ struct ata_link *link;
+ struct ata_device *dev;
+ unsigned long flags;
+
+ /* Restore SControl IPM and SPD for the next driver and
+ * disable attached devices.
+ */
+ ata_for_each_link(link, ap, PMP_FIRST) {
+ sata_scr_write(link, SCR_CONTROL, link->saved_scontrol & 0xff0);
+ ata_for_each_dev(dev, link, ALL)
+ ata_dev_disable(dev);
+ }
+
+ /* freeze and set UNLOADED */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ata_port_freeze(ap); /* won't be thawed */
+ ap->pflags &= ~ATA_PFLAG_EH_PENDING; /* clear pending from freeze */
+ ap->pflags |= ATA_PFLAG_UNLOADED;
+
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
/**
* ata_scsi_error - SCSI layer error handler callback
* @host: SCSI host on which error occurred
@@ -385,19 +589,51 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
void ata_scsi_error(struct Scsi_Host *host)
{
struct ata_port *ap = ata_shost_to_port(host);
- int i;
unsigned long flags;
+ LIST_HEAD(eh_work_q);
DPRINTK("ENTER\n");
- /* synchronize with port task */
- ata_port_flush_task(ap);
+ spin_lock_irqsave(host->host_lock, flags);
+ list_splice_init(&host->eh_cmd_q, &eh_work_q);
+ spin_unlock_irqrestore(host->host_lock, flags);
+
+ ata_scsi_cmd_error_handler(host, ap, &eh_work_q);
+
+ /* If we timed raced normal completion and there is nothing to
+ recover nr_timedout == 0 why exactly are we doing error recovery ? */
+ ata_scsi_port_error_handler(host, ap);
+
+ /* finish or retry handled scmd's and clean up */
+ WARN_ON(host->host_failed || !list_empty(&eh_work_q));
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_scsi_cmd_error_handler - error callback for a list of commands
+ * @host: scsi host containing the port
+ * @ap: ATA port within the host
+ * @eh_work_q: list of commands to process
+ *
+ * process the given list of commands and return those finished to the
+ * ap->eh_done_q. This function is the first part of the libata error
+ * handler which processes a given list of failed commands.
+ */
+void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
+ struct list_head *eh_work_q)
+{
+ int i;
+ unsigned long flags;
+
+ /* make sure sff pio task is not running */
+ ata_sff_flush_pio_task(ap);
/* synchronize with host lock and sort out timeouts */
/* For new EH, all qcs are finished in one of three ways -
* normal completion, error completion, and SCSI timeout.
- * Both cmpletions can race against SCSI timeout. When normal
+ * Both completions can race against SCSI timeout. When normal
* completion wins, the qc never reaches EH. When error
* completion wins, the qc has ATA_QCFLAG_FAILED set.
*
@@ -413,7 +649,19 @@ void ata_scsi_error(struct Scsi_Host *host)
spin_lock_irqsave(ap->lock, flags);
- list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
+ /* This must occur under the ap->lock as we don't want
+ a polled recovery to race the real interrupt handler
+
+ The lost_interrupt handler checks for any completed but
+ non-notified command and completes much like an IRQ handler.
+
+ We then fall into the error recovery code which will treat
+ this as if normal completion won the race */
+
+ if (ap->ops->lost_interrupt)
+ ap->ops->lost_interrupt(ap);
+
+ list_for_each_entry_safe(scmd, tmp, eh_work_q, eh_entry) {
struct ata_queued_cmd *qc;
for (i = 0; i < ATA_MAX_QUEUE; i++) {
@@ -457,11 +705,28 @@ void ata_scsi_error(struct Scsi_Host *host)
} else
spin_unlock_wait(ap->lock);
- repeat:
+}
+EXPORT_SYMBOL(ata_scsi_cmd_error_handler);
+
+/**
+ * ata_scsi_port_error_handler - recover the port after the commands
+ * @host: SCSI host containing the port
+ * @ap: the ATA port
+ *
+ * Handle the recovery of the port @ap after all the commands
+ * have been recovered.
+ */
+void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap)
+{
+ unsigned long flags;
+
/* invoke error handler */
if (ap->ops->error_handler) {
struct ata_link *link;
+ /* acquire EH ownership */
+ ata_eh_acquire(ap);
+ repeat:
/* kill fast drain timer */
del_timer_sync(&ap->fastdrain_timer);
@@ -471,7 +736,7 @@ void ata_scsi_error(struct Scsi_Host *host)
/* fetch & clear EH info */
spin_lock_irqsave(ap->lock, flags);
- __ata_port_for_each_link(link, ap) {
+ ata_for_each_link(link, ap, HOST_FIRST) {
struct ata_eh_context *ehc = &link->eh_context;
struct ata_device *dev;
@@ -479,7 +744,7 @@ void ata_scsi_error(struct Scsi_Host *host)
link->eh_context.i = link->eh_info;
memset(&link->eh_info, 0, sizeof(link->eh_info));
- ata_link_for_each_dev(dev, link) {
+ ata_for_each_dev(dev, link, ENABLED) {
int devno = dev->devno;
ehc->saved_xfer_mode[devno] = dev->xfer_mode;
@@ -497,13 +762,18 @@ void ata_scsi_error(struct Scsi_Host *host)
/* invoke EH, skip if unloading or suspended */
if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
ap->ops->error_handler(ap);
- else
+ else {
+ /* if unloading, commence suicide */
+ if ((ap->pflags & ATA_PFLAG_UNLOADING) &&
+ !(ap->pflags & ATA_PFLAG_UNLOADED))
+ ata_eh_unload(ap);
ata_eh_finish(ap);
+ }
/* process port suspend request */
ata_eh_handle_port_suspend(ap);
- /* Exception might have happend after ->error_handler
+ /* Exception might have happened after ->error_handler
* recovered the port but before this point. Repeat
* EH in such case.
*/
@@ -514,31 +784,30 @@ void ata_scsi_error(struct Scsi_Host *host)
spin_unlock_irqrestore(ap->lock, flags);
goto repeat;
}
- ata_port_printk(ap, KERN_ERR, "EH pending after %d "
- "tries, giving up\n", ATA_EH_MAX_TRIES);
+ ata_port_err(ap,
+ "EH pending after %d tries, giving up\n",
+ ATA_EH_MAX_TRIES);
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
}
/* this run is complete, make sure EH info is clear */
- __ata_port_for_each_link(link, ap)
+ ata_for_each_link(link, ap, HOST_FIRST)
memset(&link->eh_info, 0, sizeof(link->eh_info));
- /* Clear host_eh_scheduled while holding ap->lock such
- * that if exception occurs after this point but
- * before EH completion, SCSI midlayer will
+ /* end eh (clear host_eh_scheduled) while holding
+ * ap->lock such that if exception occurs after this
+ * point but before EH completion, SCSI midlayer will
* re-initiate EH.
*/
- host->host_eh_scheduled = 0;
+ ap->ops->end_eh(ap);
spin_unlock_irqrestore(ap->lock, flags);
+ ata_eh_release(ap);
} else {
WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL);
ap->ops->eng_timeout(ap);
}
- /* finish or retry handled scmd's and clean up */
- WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q));
-
scsi_eh_flush_done_q(&ap->eh_done_q);
/* clean up */
@@ -547,10 +816,10 @@ void ata_scsi_error(struct Scsi_Host *host)
if (ap->pflags & ATA_PFLAG_LOADING)
ap->pflags &= ~ATA_PFLAG_LOADING;
else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
- queue_delayed_work(ata_aux_wq, &ap->hotplug_task, 0);
+ schedule_delayed_work(&ap->hotplug_task, 0);
if (ap->pflags & ATA_PFLAG_RECOVERED)
- ata_port_printk(ap, KERN_INFO, "EH complete\n");
+ ata_port_info(ap, "EH complete\n");
ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED);
@@ -559,9 +828,8 @@ void ata_scsi_error(struct Scsi_Host *host)
wake_up_all(&ap->eh_wait_q);
spin_unlock_irqrestore(ap->lock, flags);
-
- DPRINTK("EXIT\n");
}
+EXPORT_SYMBOL_GPL(ata_scsi_port_error_handler);
/**
* ata_port_wait_eh - Wait for the currently pending EH to complete
@@ -592,10 +860,11 @@ void ata_port_wait_eh(struct ata_port *ap)
/* make sure SCSI EH is complete */
if (scsi_host_in_recovery(ap->scsi_host)) {
- msleep(10);
+ ata_msleep(ap, 10);
goto retry;
}
}
+EXPORT_SYMBOL_GPL(ata_port_wait_eh);
static int ata_eh_nr_in_flight(struct ata_port *ap)
{
@@ -641,7 +910,7 @@ void ata_eh_fastdrain_timerfn(unsigned long arg)
/* some qcs have finished, give it another chance */
ap->fastdrain_cnt = cnt;
ap->fastdrain_timer.expires =
- jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+ ata_deadline(jiffies, ATA_EH_FASTDRAIN_INTERVAL);
add_timer(&ap->fastdrain_timer);
}
@@ -681,7 +950,8 @@ static void ata_eh_set_pending(struct ata_port *ap, int fastdrain)
/* activate fast drain */
ap->fastdrain_cnt = cnt;
- ap->fastdrain_timer.expires = jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+ ap->fastdrain_timer.expires =
+ ata_deadline(jiffies, ATA_EH_FASTDRAIN_INTERVAL);
add_timer(&ap->fastdrain_timer);
}
@@ -698,6 +968,8 @@ static void ata_eh_set_pending(struct ata_port *ap, int fastdrain)
void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ struct request_queue *q = qc->scsicmd->device->request_queue;
+ unsigned long flags;
WARN_ON(!ap->ops->error_handler);
@@ -709,20 +981,19 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
* Note that ATA_QCFLAG_FAILED is unconditionally set after
* this function completes.
*/
- scsi_req_abort_cmd(qc->scsicmd);
+ spin_lock_irqsave(q->queue_lock, flags);
+ blk_abort_request(qc->scsicmd->request);
+ spin_unlock_irqrestore(q->queue_lock, flags);
}
/**
- * ata_port_schedule_eh - schedule error handling without a qc
- * @ap: ATA port to schedule EH for
- *
- * Schedule error handling for @ap. EH will kick in as soon as
- * all commands are drained.
+ * ata_std_sched_eh - non-libsas ata_ports issue eh with this common routine
+ * @ap: ATA port to schedule EH for
*
- * LOCKING:
+ * LOCKING: inherited from ata_port_schedule_eh
* spin_lock_irqsave(host lock)
*/
-void ata_port_schedule_eh(struct ata_port *ap)
+void ata_std_sched_eh(struct ata_port *ap)
{
WARN_ON(!ap->ops->error_handler);
@@ -734,6 +1005,44 @@ void ata_port_schedule_eh(struct ata_port *ap)
DPRINTK("port EH scheduled\n");
}
+EXPORT_SYMBOL_GPL(ata_std_sched_eh);
+
+/**
+ * ata_std_end_eh - non-libsas ata_ports complete eh with this common routine
+ * @ap: ATA port to end EH for
+ *
+ * In the libata object model there is a 1:1 mapping of ata_port to
+ * shost, so host fields can be directly manipulated under ap->lock, in
+ * the libsas case we need to hold a lock at the ha->level to coordinate
+ * these events.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_std_end_eh(struct ata_port *ap)
+{
+ struct Scsi_Host *host = ap->scsi_host;
+
+ host->host_eh_scheduled = 0;
+}
+EXPORT_SYMBOL(ata_std_end_eh);
+
+
+/**
+ * ata_port_schedule_eh - schedule error handling without a qc
+ * @ap: ATA port to schedule EH for
+ *
+ * Schedule error handling for @ap. EH will kick in as soon as
+ * all commands are drained.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_port_schedule_eh(struct ata_port *ap)
+{
+ /* see: ata_std_sched_eh, unless you know better */
+ ap->ops->sched_eh(ap);
+}
static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link)
{
@@ -828,7 +1137,9 @@ static void __ata_port_freeze(struct ata_port *ap)
* ata_port_freeze - abort & freeze port
* @ap: ATA port to freeze
*
- * Abort and freeze @ap.
+ * Abort and freeze @ap. The freeze operation must be called
+ * first, because some hardware requires special operations
+ * before the taskfile registers are accessible.
*
* LOCKING:
* spin_lock_irqsave(host lock)
@@ -842,8 +1153,8 @@ int ata_port_freeze(struct ata_port *ap)
WARN_ON(!ap->ops->error_handler);
- nr_aborted = ata_port_abort(ap);
__ata_port_freeze(ap);
+ nr_aborted = ata_port_abort(ap);
return nr_aborted;
}
@@ -900,7 +1211,7 @@ int sata_async_notification(struct ata_port *ap)
struct ata_link *link;
/* check and notify ATAPI AN */
- ata_port_for_each_link(link, ap) {
+ ata_for_each_link(link, ap, EDGE) {
if (!(sntf & (1 << link->pmp)))
continue;
@@ -1012,18 +1323,44 @@ void ata_eh_qc_complete(struct ata_queued_cmd *qc)
* should be retried. To be used from EH.
*
* SCSI midlayer limits the number of retries to scmd->allowed.
- * scmd->retries is decremented for commands which get retried
+ * scmd->allowed is incremented for commands which get retried
* due to unrelated failures (qc->err_mask is zero).
*/
void ata_eh_qc_retry(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *scmd = qc->scsicmd;
- if (!qc->err_mask && scmd->retries)
- scmd->retries--;
+ if (!qc->err_mask)
+ scmd->allowed++;
__ata_eh_qc_complete(qc);
}
/**
+ * ata_dev_disable - disable ATA device
+ * @dev: ATA device to disable
+ *
+ * Disable @dev.
+ *
+ * Locking:
+ * EH context.
+ */
+void ata_dev_disable(struct ata_device *dev)
+{
+ if (!ata_dev_enabled(dev))
+ return;
+
+ if (ata_msg_drv(dev->link->ap))
+ ata_dev_warn(dev, "disabled\n");
+ ata_acpi_on_disable(dev);
+ ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET);
+ dev->class++;
+
+ /* From now till the next successful probe, ering is used to
+ * track probe failures. Clear accumulated device error info.
+ */
+ ata_ering_clear(&dev->ering);
+}
+
+/**
* ata_eh_detach_dev - detach ATA device
* @dev: ATA device to detach
*
@@ -1036,6 +1373,7 @@ void ata_eh_detach_dev(struct ata_device *dev)
{
struct ata_link *link = dev->link;
struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
unsigned long flags;
ata_dev_disable(dev);
@@ -1049,9 +1387,11 @@ void ata_eh_detach_dev(struct ata_device *dev)
ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
}
- /* clear per-dev EH actions */
+ /* clear per-dev EH info */
ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK);
ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK);
+ ehc->saved_xfer_mode[dev->devno] = 0;
+ ehc->saved_ncq_enabled &= ~(1 << dev->devno);
spin_unlock_irqrestore(ap->lock, flags);
}
@@ -1081,7 +1421,10 @@ void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
ata_eh_clear_action(link, dev, ehi, action);
- if (!(ehc->i.flags & ATA_EHI_QUIET))
+ /* About to take EH action, set RECOVERED. Ignore actions on
+ * slave links as master will do them again.
+ */
+ if (!(ehc->i.flags & ATA_EHI_QUIET) && link != ap->slave_link)
ap->pflags |= ATA_PFLAG_RECOVERED;
spin_unlock_irqrestore(ap->lock, flags);
@@ -1145,6 +1488,7 @@ static const char *ata_err_string(unsigned int err_mask)
/**
* ata_read_log_page - read a specific log page
* @dev: target device
+ * @log: log to read
* @page: page to read
* @buf: buffer to store read page
* @sectors: number of sectors to read
@@ -1157,17 +1501,18 @@ static const char *ata_err_string(unsigned int err_mask)
* RETURNS:
* 0 on success, AC_ERR_* mask otherwise.
*/
-static unsigned int ata_read_log_page(struct ata_device *dev,
- u8 page, void *buf, unsigned int sectors)
+unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
+ u8 page, void *buf, unsigned int sectors)
{
struct ata_taskfile tf;
unsigned int err_mask;
- DPRINTK("read log page - page %d\n", page);
+ DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);
ata_tf_init(dev, &tf);
tf.command = ATA_CMD_READ_LOG_EXT;
- tf.lbal = page;
+ tf.lbal = log;
+ tf.lbam = page;
tf.nsect = sectors;
tf.hob_nsect = sectors >> 8;
tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
@@ -1203,7 +1548,7 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
u8 csum;
int i;
- err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, buf, 1);
+ err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, 0, buf, 1);
if (err_mask)
return -EIO;
@@ -1211,8 +1556,8 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
for (i = 0; i < ATA_SECT_SIZE; i++)
csum += buf[i];
if (csum)
- ata_dev_printk(dev, KERN_WARNING,
- "invalid checksum 0x%x on log page 10h\n", csum);
+ ata_dev_warn(dev, "invalid checksum 0x%x on log page 10h\n",
+ csum);
if (buf[0] & 0x80)
return -ENOENT;
@@ -1235,9 +1580,41 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
}
/**
+ * atapi_eh_tur - perform ATAPI TEST_UNIT_READY
+ * @dev: target ATAPI device
+ * @r_sense_key: out parameter for sense_key
+ *
+ * Perform ATAPI TEST_UNIT_READY.
+ *
+ * LOCKING:
+ * EH context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask on failure.
+ */
+unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
+{
+ u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 };
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ ata_tf_init(dev, &tf);
+
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.command = ATA_CMD_PACKET;
+ tf.protocol = ATAPI_PROT_NODATA;
+
+ err_mask = ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
+ if (err_mask == AC_ERR_DEV)
+ *r_sense_key = tf.feature >> 4;
+ return err_mask;
+}
+
+/**
* atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
* @dev: device to perform REQUEST_SENSE to
* @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
+ * @dfl_sense_key: default sense key to use
*
* Perform ATAPI REQUEST_SENSE after the device reported CHECK
* SENSE. This function is EH helper.
@@ -1248,13 +1625,13 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
* RETURNS:
* 0 on success, AC_ERR_* mask on failure
*/
-static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
+unsigned int atapi_eh_request_sense(struct ata_device *dev,
+ u8 *sense_buf, u8 dfl_sense_key)
{
- struct ata_device *dev = qc->dev;
- unsigned char *sense_buf = qc->scsicmd->sense_buffer;
+ u8 cdb[ATAPI_CDB_LEN] =
+ { REQUEST_SENSE, 0, 0, 0, SCSI_SENSE_BUFFERSIZE, 0 };
struct ata_port *ap = dev->link->ap;
struct ata_taskfile tf;
- u8 cdb[ATAPI_CDB_LEN];
DPRINTK("ATAPI request sense\n");
@@ -1265,15 +1642,11 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
* for the case where they are -not- overwritten
*/
sense_buf[0] = 0x70;
- sense_buf[2] = qc->result_tf.feature >> 4;
+ sense_buf[2] = dfl_sense_key;
/* some devices time out if garbage left in tf */
ata_tf_init(dev, &tf);
- memset(cdb, 0, ATAPI_CDB_LEN);
- cdb[0] = REQUEST_SENSE;
- cdb[4] = SCSI_SENSE_BUFFERSIZE;
-
tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf.command = ATA_CMD_PACKET;
@@ -1308,12 +1681,7 @@ static void ata_eh_analyze_serror(struct ata_link *link)
unsigned int err_mask = 0, action = 0;
u32 hotplug_mask;
- if (serror & SERR_PERSISTENT) {
- err_mask |= AC_ERR_ATA_BUS;
- action |= ATA_EH_RESET;
- }
- if (serror &
- (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) {
+ if (serror & (SERR_PERSISTENT | SERR_DATA)) {
err_mask |= AC_ERR_ATA_BUS;
action |= ATA_EH_RESET;
}
@@ -1331,9 +1699,9 @@ static void ata_eh_analyze_serror(struct ata_link *link)
* host links. For disabled PMP links, only N bit is
* considered as X bit is left at 1 for link plugging.
*/
- hotplug_mask = 0;
-
- if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
+ if (link->lpm_policy > ATA_LPM_MAX_POWER)
+ hotplug_mask = 0; /* hotplug doesn't work w/ LPM */
+ else if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
else
hotplug_mask = SERR_PHYRDY_CHG;
@@ -1357,7 +1725,7 @@ static void ata_eh_analyze_serror(struct ata_link *link)
* LOCKING:
* Kernel thread context (may sleep).
*/
-static void ata_eh_analyze_ncq_error(struct ata_link *link)
+void ata_eh_analyze_ncq_error(struct ata_link *link)
{
struct ata_port *ap = link->ap;
struct ata_eh_context *ehc = &link->eh_context;
@@ -1386,22 +1754,24 @@ static void ata_eh_analyze_ncq_error(struct ata_link *link)
}
/* okay, this error is ours */
+ memset(&tf, 0, sizeof(tf));
rc = ata_eh_read_log_10h(dev, &tag, &tf);
if (rc) {
- ata_link_printk(link, KERN_ERR, "failed to read log page 10h "
- "(errno=%d)\n", rc);
+ ata_link_err(link, "failed to read log page 10h (errno=%d)\n",
+ rc);
return;
}
if (!(link->sactive & (1 << tag))) {
- ata_link_printk(link, KERN_ERR, "log page 10h reported "
- "inactive tag %d\n", tag);
+ ata_link_err(link, "log page 10h reported inactive tag %d\n",
+ tag);
return;
}
/* we've got the perpetrator, condemn it */
qc = __ata_qc_from_tag(ap, tag);
memcpy(&qc->result_tf, &tf, sizeof(tf));
+ qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
ehc->i.err_mask &= ~AC_ERR_DEV;
}
@@ -1413,7 +1783,7 @@ static void ata_eh_analyze_ncq_error(struct ata_link *link)
*
* Analyze taskfile of @qc and further determine cause of
* failure. This function also requests ATAPI sense data if
- * avaliable.
+ * available.
*
* LOCKING:
* Kernel thread context (may sleep).
@@ -1441,7 +1811,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
case ATA_DEV_ATA:
if (err & ATA_ICRC)
qc->err_mask |= AC_ERR_ATA_BUS;
- if (err & ATA_UNC)
+ if (err & (ATA_UNC | ATA_AMNF))
qc->err_mask |= AC_ERR_MEDIA;
if (err & ATA_IDNF)
qc->err_mask |= AC_ERR_INVALID;
@@ -1449,7 +1819,9 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
case ATA_DEV_ATAPI:
if (!(qc->ap->pflags & ATA_PFLAG_FROZEN)) {
- tmp = atapi_eh_request_sense(qc);
+ tmp = atapi_eh_request_sense(qc->dev,
+ qc->scsicmd->sense_buffer,
+ qc->result_tf.feature >> 4);
if (!tmp) {
/* ATA_QCFLAG_SENSE_VALID is used to
* tell atapi_qc_complete() that sense
@@ -1509,7 +1881,7 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg)
struct speed_down_verdict_arg *arg = void_arg;
int cat;
- if (ent->timestamp < arg->since)
+ if ((ent->eflags & ATA_EFLAG_OLD_ER) || (ent->timestamp < arg->since))
return -1;
cat = ata_eh_categorize_error(ent->eflags, ent->err_mask,
@@ -1562,7 +1934,7 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg)
* occurred during last 5 mins, NCQ_OFF.
*
* 3. If more than 8 ATA_BUS, TOUT_HSM or UNK_DEV errors
- * ocurred during last 5 mins, FALLBACK_TO_PIO
+ * occurred during last 5 mins, FALLBACK_TO_PIO
*
* 4. If more than 3 TOUT_HSM or UNK_DEV errors occurred
* during last 10 mins, NCQ_OFF.
@@ -1639,7 +2011,7 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev)
static unsigned int ata_eh_speed_down(struct ata_device *dev,
unsigned int eflags, unsigned int err_mask)
{
- struct ata_link *link = dev->link;
+ struct ata_link *link = ata_dev_phys_link(dev);
int xfer_ok = 0;
unsigned int verdict;
unsigned int action = 0;
@@ -1657,15 +2029,14 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev,
(dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ |
ATA_DFLAG_NCQ_OFF)) == ATA_DFLAG_NCQ) {
dev->flags |= ATA_DFLAG_NCQ_OFF;
- ata_dev_printk(dev, KERN_WARNING,
- "NCQ disabled due to excessive errors\n");
+ ata_dev_warn(dev, "NCQ disabled due to excessive errors\n");
goto done;
}
/* speed down? */
if (verdict & ATA_EH_SPDN_SPEED_DOWN) {
/* speed down SATA link speed if possible */
- if (sata_down_spd_limit(link) == 0) {
+ if (sata_down_spd_limit(link, 0) == 0) {
action |= ATA_EH_RESET;
goto done;
}
@@ -1714,6 +2085,26 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev,
}
/**
+ * ata_eh_worth_retry - analyze error and decide whether to retry
+ * @qc: qc to possibly retry
+ *
+ * Look at the cause of the error and decide if a retry
+ * might be useful or not. We don't want to retry media errors
+ * because the drive itself has probably already taken 10-30 seconds
+ * doing its own internal retries before reporting the failure.
+ */
+static inline int ata_eh_worth_retry(struct ata_queued_cmd *qc)
+{
+ if (qc->err_mask & AC_ERR_MEDIA)
+ return 0; /* don't retry media errors */
+ if (qc->flags & ATA_QCFLAG_IO)
+ return 1; /* otherwise retry anything from fs stack */
+ if (qc->err_mask & AC_ERR_INVALID)
+ return 0; /* don't retry these */
+ return qc->err_mask != AC_ERR_DEV; /* retry if not dev error */
+}
+
+/**
* ata_eh_link_autopsy - analyze error and determine recovery action
* @link: host link to perform autopsy on
*
@@ -1763,7 +2154,8 @@ static void ata_eh_link_autopsy(struct ata_link *link)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
- if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
+ if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+ ata_dev_phys_link(qc->dev) != link)
continue;
/* inherit upper level err_mask */
@@ -1786,8 +2178,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
/* determine whether the command is worth retrying */
- if (!(qc->err_mask & AC_ERR_INVALID) &&
- ((qc->flags & ATA_QCFLAG_IO) || qc->err_mask != AC_ERR_DEV))
+ if (ata_eh_worth_retry(qc))
qc->flags |= ATA_QCFLAG_RETRY;
/* accumulate error info */
@@ -1847,9 +2238,31 @@ void ata_eh_autopsy(struct ata_port *ap)
{
struct ata_link *link;
- ata_port_for_each_link(link, ap)
+ ata_for_each_link(link, ap, EDGE)
ata_eh_link_autopsy(link);
+ /* Handle the frigging slave link. Autopsy is done similarly
+ * but actions and flags are transferred over to the master
+ * link and handled from there.
+ */
+ if (ap->slave_link) {
+ struct ata_eh_context *mehc = &ap->link.eh_context;
+ struct ata_eh_context *sehc = &ap->slave_link->eh_context;
+
+ /* transfer control flags from master to slave */
+ sehc->i.flags |= mehc->i.flags & ATA_EHI_TO_SLAVE_MASK;
+
+ /* perform autopsy on the slave link */
+ ata_eh_link_autopsy(ap->slave_link);
+
+ /* transfer actions from slave to master and clear slave */
+ ata_eh_about_to_do(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS);
+ mehc->i.action |= sehc->i.action;
+ mehc->i.dev_action[1] |= sehc->i.dev_action[1];
+ mehc->i.flags |= sehc->i.flags;
+ ata_eh_done(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS);
+ }
+
/* Autopsy of fanout ports can affect host link autopsy.
* Perform host link autopsy last.
*/
@@ -1858,6 +2271,125 @@ void ata_eh_autopsy(struct ata_port *ap)
}
/**
+ * ata_get_cmd_descript - get description for ATA command
+ * @command: ATA command code to get description for
+ *
+ * Return a textual description of the given command, or NULL if the
+ * command is not known.
+ *
+ * LOCKING:
+ * None
+ */
+const char *ata_get_cmd_descript(u8 command)
+{
+#ifdef CONFIG_ATA_VERBOSE_ERROR
+ static const struct
+ {
+ u8 command;
+ const char *text;
+ } cmd_descr[] = {
+ { ATA_CMD_DEV_RESET, "DEVICE RESET" },
+ { ATA_CMD_CHK_POWER, "CHECK POWER MODE" },
+ { ATA_CMD_STANDBY, "STANDBY" },
+ { ATA_CMD_IDLE, "IDLE" },
+ { ATA_CMD_EDD, "EXECUTE DEVICE DIAGNOSTIC" },
+ { ATA_CMD_DOWNLOAD_MICRO, "DOWNLOAD MICROCODE" },
+ { ATA_CMD_DOWNLOAD_MICRO_DMA, "DOWNLOAD MICROCODE DMA" },
+ { ATA_CMD_NOP, "NOP" },
+ { ATA_CMD_FLUSH, "FLUSH CACHE" },
+ { ATA_CMD_FLUSH_EXT, "FLUSH CACHE EXT" },
+ { ATA_CMD_ID_ATA, "IDENTIFY DEVICE" },
+ { ATA_CMD_ID_ATAPI, "IDENTIFY PACKET DEVICE" },
+ { ATA_CMD_SERVICE, "SERVICE" },
+ { ATA_CMD_READ, "READ DMA" },
+ { ATA_CMD_READ_EXT, "READ DMA EXT" },
+ { ATA_CMD_READ_QUEUED, "READ DMA QUEUED" },
+ { ATA_CMD_READ_STREAM_EXT, "READ STREAM EXT" },
+ { ATA_CMD_READ_STREAM_DMA_EXT, "READ STREAM DMA EXT" },
+ { ATA_CMD_WRITE, "WRITE DMA" },
+ { ATA_CMD_WRITE_EXT, "WRITE DMA EXT" },
+ { ATA_CMD_WRITE_QUEUED, "WRITE DMA QUEUED EXT" },
+ { ATA_CMD_WRITE_STREAM_EXT, "WRITE STREAM EXT" },
+ { ATA_CMD_WRITE_STREAM_DMA_EXT, "WRITE STREAM DMA EXT" },
+ { ATA_CMD_WRITE_FUA_EXT, "WRITE DMA FUA EXT" },
+ { ATA_CMD_WRITE_QUEUED_FUA_EXT, "WRITE DMA QUEUED FUA EXT" },
+ { ATA_CMD_FPDMA_READ, "READ FPDMA QUEUED" },
+ { ATA_CMD_FPDMA_WRITE, "WRITE FPDMA QUEUED" },
+ { ATA_CMD_FPDMA_SEND, "SEND FPDMA QUEUED" },
+ { ATA_CMD_FPDMA_RECV, "RECEIVE FPDMA QUEUED" },
+ { ATA_CMD_PIO_READ, "READ SECTOR(S)" },
+ { ATA_CMD_PIO_READ_EXT, "READ SECTOR(S) EXT" },
+ { ATA_CMD_PIO_WRITE, "WRITE SECTOR(S)" },
+ { ATA_CMD_PIO_WRITE_EXT, "WRITE SECTOR(S) EXT" },
+ { ATA_CMD_READ_MULTI, "READ MULTIPLE" },
+ { ATA_CMD_READ_MULTI_EXT, "READ MULTIPLE EXT" },
+ { ATA_CMD_WRITE_MULTI, "WRITE MULTIPLE" },
+ { ATA_CMD_WRITE_MULTI_EXT, "WRITE MULTIPLE EXT" },
+ { ATA_CMD_WRITE_MULTI_FUA_EXT, "WRITE MULTIPLE FUA EXT" },
+ { ATA_CMD_SET_FEATURES, "SET FEATURES" },
+ { ATA_CMD_SET_MULTI, "SET MULTIPLE MODE" },
+ { ATA_CMD_VERIFY, "READ VERIFY SECTOR(S)" },
+ { ATA_CMD_VERIFY_EXT, "READ VERIFY SECTOR(S) EXT" },
+ { ATA_CMD_WRITE_UNCORR_EXT, "WRITE UNCORRECTABLE EXT" },
+ { ATA_CMD_STANDBYNOW1, "STANDBY IMMEDIATE" },
+ { ATA_CMD_IDLEIMMEDIATE, "IDLE IMMEDIATE" },
+ { ATA_CMD_SLEEP, "SLEEP" },
+ { ATA_CMD_INIT_DEV_PARAMS, "INITIALIZE DEVICE PARAMETERS" },
+ { ATA_CMD_READ_NATIVE_MAX, "READ NATIVE MAX ADDRESS" },
+ { ATA_CMD_READ_NATIVE_MAX_EXT, "READ NATIVE MAX ADDRESS EXT" },
+ { ATA_CMD_SET_MAX, "SET MAX ADDRESS" },
+ { ATA_CMD_SET_MAX_EXT, "SET MAX ADDRESS EXT" },
+ { ATA_CMD_READ_LOG_EXT, "READ LOG EXT" },
+ { ATA_CMD_WRITE_LOG_EXT, "WRITE LOG EXT" },
+ { ATA_CMD_READ_LOG_DMA_EXT, "READ LOG DMA EXT" },
+ { ATA_CMD_WRITE_LOG_DMA_EXT, "WRITE LOG DMA EXT" },
+ { ATA_CMD_TRUSTED_NONDATA, "TRUSTED NON-DATA" },
+ { ATA_CMD_TRUSTED_RCV, "TRUSTED RECEIVE" },
+ { ATA_CMD_TRUSTED_RCV_DMA, "TRUSTED RECEIVE DMA" },
+ { ATA_CMD_TRUSTED_SND, "TRUSTED SEND" },
+ { ATA_CMD_TRUSTED_SND_DMA, "TRUSTED SEND DMA" },
+ { ATA_CMD_PMP_READ, "READ BUFFER" },
+ { ATA_CMD_PMP_READ_DMA, "READ BUFFER DMA" },
+ { ATA_CMD_PMP_WRITE, "WRITE BUFFER" },
+ { ATA_CMD_PMP_WRITE_DMA, "WRITE BUFFER DMA" },
+ { ATA_CMD_CONF_OVERLAY, "DEVICE CONFIGURATION OVERLAY" },
+ { ATA_CMD_SEC_SET_PASS, "SECURITY SET PASSWORD" },
+ { ATA_CMD_SEC_UNLOCK, "SECURITY UNLOCK" },
+ { ATA_CMD_SEC_ERASE_PREP, "SECURITY ERASE PREPARE" },
+ { ATA_CMD_SEC_ERASE_UNIT, "SECURITY ERASE UNIT" },
+ { ATA_CMD_SEC_FREEZE_LOCK, "SECURITY FREEZE LOCK" },
+ { ATA_CMD_SEC_DISABLE_PASS, "SECURITY DISABLE PASSWORD" },
+ { ATA_CMD_CONFIG_STREAM, "CONFIGURE STREAM" },
+ { ATA_CMD_SMART, "SMART" },
+ { ATA_CMD_MEDIA_LOCK, "DOOR LOCK" },
+ { ATA_CMD_MEDIA_UNLOCK, "DOOR UNLOCK" },
+ { ATA_CMD_DSM, "DATA SET MANAGEMENT" },
+ { ATA_CMD_CHK_MED_CRD_TYP, "CHECK MEDIA CARD TYPE" },
+ { ATA_CMD_CFA_REQ_EXT_ERR, "CFA REQUEST EXTENDED ERROR" },
+ { ATA_CMD_CFA_WRITE_NE, "CFA WRITE SECTORS WITHOUT ERASE" },
+ { ATA_CMD_CFA_TRANS_SECT, "CFA TRANSLATE SECTOR" },
+ { ATA_CMD_CFA_ERASE, "CFA ERASE SECTORS" },
+ { ATA_CMD_CFA_WRITE_MULT_NE, "CFA WRITE MULTIPLE WITHOUT ERASE" },
+ { ATA_CMD_REQ_SENSE_DATA, "REQUEST SENSE DATA EXT" },
+ { ATA_CMD_SANITIZE_DEVICE, "SANITIZE DEVICE" },
+ { ATA_CMD_READ_LONG, "READ LONG (with retries)" },
+ { ATA_CMD_READ_LONG_ONCE, "READ LONG (without retries)" },
+ { ATA_CMD_WRITE_LONG, "WRITE LONG (with retries)" },
+ { ATA_CMD_WRITE_LONG_ONCE, "WRITE LONG (without retries)" },
+ { ATA_CMD_RESTORE, "RECALIBRATE" },
+ { 0, NULL } /* terminate list */
+ };
+
+ unsigned int i;
+ for (i = 0; cmd_descr[i].text; i++)
+ if (cmd_descr[i].command == command)
+ return cmd_descr[i].text;
+#endif
+
+ return NULL;
+}
+
+/**
* ata_eh_link_report - report error handling to user
* @link: ATA link EH is going on
*
@@ -1871,7 +2403,7 @@ static void ata_eh_link_report(struct ata_link *link)
struct ata_port *ap = link->ap;
struct ata_eh_context *ehc = &link->eh_context;
const char *frozen, *desc;
- char tries_buf[6];
+ char tries_buf[6] = "";
int tag, nr_failed = 0;
if (ehc->i.flags & ATA_EHI_QUIET)
@@ -1884,7 +2416,8 @@ static void ata_eh_link_report(struct ata_link *link)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
- if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link ||
+ if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+ ata_dev_phys_link(qc->dev) != link ||
((qc->flags & ATA_QCFLAG_QUIET) &&
qc->err_mask == AC_ERR_DEV))
continue;
@@ -1901,29 +2434,29 @@ static void ata_eh_link_report(struct ata_link *link)
if (ap->pflags & ATA_PFLAG_FROZEN)
frozen = " frozen";
- memset(tries_buf, 0, sizeof(tries_buf));
if (ap->eh_tries < ATA_EH_MAX_TRIES)
- snprintf(tries_buf, sizeof(tries_buf) - 1, " t%d",
+ snprintf(tries_buf, sizeof(tries_buf), " t%d",
ap->eh_tries);
if (ehc->i.dev) {
- ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
- "SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
- ehc->i.err_mask, link->sactive, ehc->i.serror,
- ehc->i.action, frozen, tries_buf);
+ ata_dev_err(ehc->i.dev, "exception Emask 0x%x "
+ "SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
+ ehc->i.err_mask, link->sactive, ehc->i.serror,
+ ehc->i.action, frozen, tries_buf);
if (desc)
- ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc);
+ ata_dev_err(ehc->i.dev, "%s\n", desc);
} else {
- ata_link_printk(link, KERN_ERR, "exception Emask 0x%x "
- "SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
- ehc->i.err_mask, link->sactive, ehc->i.serror,
- ehc->i.action, frozen, tries_buf);
+ ata_link_err(link, "exception Emask 0x%x "
+ "SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
+ ehc->i.err_mask, link->sactive, ehc->i.serror,
+ ehc->i.action, frozen, tries_buf);
if (desc)
- ata_link_printk(link, KERN_ERR, "%s\n", desc);
+ ata_link_err(link, "%s\n", desc);
}
+#ifdef CONFIG_ATA_VERBOSE_ERROR
if (ehc->i.serror)
- ata_port_printk(ap, KERN_ERR,
+ ata_link_err(link,
"SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n",
ehc->i.serror & SERR_DATA_RECOVERED ? "RecovData " : "",
ehc->i.serror & SERR_COMM_RECOVERED ? "RecovComm " : "",
@@ -1942,6 +2475,7 @@ static void ata_eh_link_report(struct ata_link *link)
ehc->i.serror & SERR_TRANS_ST_ERROR ? "TrStaTrns " : "",
ehc->i.serror & SERR_UNRECOG_FIS ? "UnrecFIS " : "",
ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : "");
+#endif
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
@@ -1951,7 +2485,7 @@ static void ata_eh_link_report(struct ata_link *link)
char cdb_buf[70] = "";
if (!(qc->flags & ATA_QCFLAG_FAILED) ||
- qc->dev->link != link || !qc->err_mask)
+ ata_dev_phys_link(qc->dev) != link || !qc->err_mask)
continue;
if (qc->dma_dir != DMA_NONE) {
@@ -1973,16 +2507,25 @@ static void ata_eh_link_report(struct ata_link *link)
dma_str[qc->dma_dir]);
}
- if (ata_is_atapi(qc->tf.protocol))
- snprintf(cdb_buf, sizeof(cdb_buf),
+ if (ata_is_atapi(qc->tf.protocol)) {
+ if (qc->scsicmd)
+ scsi_print_command(qc->scsicmd);
+ else
+ snprintf(cdb_buf, sizeof(cdb_buf),
"cdb %02x %02x %02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x %02x %02x\n ",
cdb[0], cdb[1], cdb[2], cdb[3],
cdb[4], cdb[5], cdb[6], cdb[7],
cdb[8], cdb[9], cdb[10], cdb[11],
cdb[12], cdb[13], cdb[14], cdb[15]);
+ } else {
+ const char *descr = ata_get_cmd_descript(cmd->command);
+ if (descr)
+ ata_dev_err(qc->dev, "failed command: %s\n",
+ descr);
+ }
- ata_dev_printk(qc->dev, KERN_ERR,
+ ata_dev_err(qc->dev,
"cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
"tag %d%s\n %s"
"res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
@@ -1999,14 +2542,13 @@ static void ata_eh_link_report(struct ata_link *link)
res->device, qc->err_mask, ata_err_string(qc->err_mask),
qc->err_mask & AC_ERR_NCQ ? " <F>" : "");
+#ifdef CONFIG_ATA_VERBOSE_ERROR
if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
ATA_ERR)) {
if (res->command & ATA_BUSY)
- ata_dev_printk(qc->dev, KERN_ERR,
- "status: { Busy }\n");
+ ata_dev_err(qc->dev, "status: { Busy }\n");
else
- ata_dev_printk(qc->dev, KERN_ERR,
- "status: { %s%s%s%s}\n",
+ ata_dev_err(qc->dev, "status: { %s%s%s%s}\n",
res->command & ATA_DRDY ? "DRDY " : "",
res->command & ATA_DF ? "DF " : "",
res->command & ATA_DRQ ? "DRQ " : "",
@@ -2014,14 +2556,15 @@ static void ata_eh_link_report(struct ata_link *link)
}
if (cmd->command != ATA_CMD_PACKET &&
- (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF |
- ATA_ABORTED)))
- ata_dev_printk(qc->dev, KERN_ERR,
- "error: { %s%s%s%s}\n",
+ (res->feature & (ATA_ICRC | ATA_UNC | ATA_AMNF |
+ ATA_IDNF | ATA_ABORTED)))
+ ata_dev_err(qc->dev, "error: { %s%s%s%s%s}\n",
res->feature & ATA_ICRC ? "ICRC " : "",
res->feature & ATA_UNC ? "UNC " : "",
+ res->feature & ATA_AMNF ? "AMNF " : "",
res->feature & ATA_IDNF ? "IDNF " : "",
res->feature & ATA_ABORTED ? "ABRT " : "");
+#endif
}
}
@@ -2038,42 +2581,29 @@ void ata_eh_report(struct ata_port *ap)
{
struct ata_link *link;
- __ata_port_for_each_link(link, ap)
+ ata_for_each_link(link, ap, HOST_FIRST)
ata_eh_link_report(link);
}
static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
- unsigned int *classes, unsigned long deadline)
+ unsigned int *classes, unsigned long deadline,
+ bool clear_classes)
{
struct ata_device *dev;
- int rc;
- ata_link_for_each_dev(dev, link)
- classes[dev->devno] = ATA_DEV_UNKNOWN;
+ if (clear_classes)
+ ata_for_each_dev(dev, link, ALL)
+ classes[dev->devno] = ATA_DEV_UNKNOWN;
- rc = reset(link, classes, deadline);
-
- /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
- ata_link_for_each_dev(dev, link)
- if (classes[dev->devno] == ATA_DEV_UNKNOWN)
- classes[dev->devno] = ATA_DEV_NONE;
-
- return rc;
+ return reset(link, classes, deadline);
}
-static int ata_eh_followup_srst_needed(struct ata_link *link,
- int rc, int classify,
- const unsigned int *classes)
+static int ata_eh_followup_srst_needed(struct ata_link *link, int rc)
{
if ((link->flags & ATA_LFLAG_NO_SRST) || ata_link_offline(link))
return 0;
- if (rc == -EAGAIN) {
- if (classify)
- return 1;
- rc = 0;
- }
- if (rc != 0)
- return 0;
+ if (rc == -EAGAIN)
+ return 1;
if (sata_pmp_supported(link->ap) && ata_is_host_link(link))
return 1;
return 0;
@@ -2083,28 +2613,51 @@ int ata_eh_reset(struct ata_link *link, int classify,
ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
{
- const int max_tries = ARRAY_SIZE(ata_eh_reset_timeouts);
struct ata_port *ap = link->ap;
+ struct ata_link *slave = ap->slave_link;
struct ata_eh_context *ehc = &link->eh_context;
+ struct ata_eh_context *sehc = slave ? &slave->eh_context : NULL;
unsigned int *classes = ehc->classes;
unsigned int lflags = link->flags;
int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
- int try = 0;
+ int max_tries = 0, try = 0;
+ struct ata_link *failed_link;
struct ata_device *dev;
unsigned long deadline, now;
ata_reset_fn_t reset;
unsigned long flags;
u32 sstatus;
- int rc;
+ int nr_unknown, rc;
+
+ /*
+ * Prepare to reset
+ */
+ while (ata_eh_reset_timeouts[max_tries] != ULONG_MAX)
+ max_tries++;
+ if (link->flags & ATA_LFLAG_RST_ONCE)
+ max_tries = 1;
+ if (link->flags & ATA_LFLAG_NO_HRST)
+ hardreset = NULL;
+ if (link->flags & ATA_LFLAG_NO_SRST)
+ softreset = NULL;
+
+ /* make sure each reset attempt is at least COOL_DOWN apart */
+ if (ehc->i.flags & ATA_EHI_DID_RESET) {
+ now = jiffies;
+ WARN_ON(time_after(ehc->last_reset, now));
+ deadline = ata_deadline(ehc->last_reset,
+ ATA_EH_RESET_COOL_DOWN);
+ if (time_before(now, deadline))
+ schedule_timeout_uninterruptible(deadline - now);
+ }
- /* about to reset */
spin_lock_irqsave(ap->lock, flags);
ap->pflags |= ATA_PFLAG_RESETTING;
spin_unlock_irqrestore(ap->lock, flags);
ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
- ata_link_for_each_dev(dev, link) {
+ ata_for_each_dev(dev, link, ALL) {
/* If we issue an SRST then an ATA drive (not ATAPI)
* may change configuration and be in PIO0 timing. If
* we do a hard reset (or are coming from power on)
@@ -2113,6 +2666,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
* bus as we may be talking too fast.
*/
dev->pio_mode = XFER_PIO_0;
+ dev->dma_mode = 0xff;
/* If the controller has a pio mode setup function
* then use it to set the chipset to rights. Don't
@@ -2123,97 +2677,153 @@ int ata_eh_reset(struct ata_link *link, int classify,
ap->ops->set_piomode(ap, dev);
}
- if (!softreset && !hardreset) {
- if (verbose)
- ata_link_printk(link, KERN_INFO, "no reset method "
- "available, skipping reset\n");
- if (!(lflags & ATA_LFLAG_ASSUME_CLASS))
- lflags |= ATA_LFLAG_ASSUME_ATA;
- goto done;
- }
-
/* prefer hardreset */
+ reset = NULL;
ehc->i.action &= ~ATA_EH_RESET;
if (hardreset) {
reset = hardreset;
- ehc->i.action = ATA_EH_HARDRESET;
+ ehc->i.action |= ATA_EH_HARDRESET;
} else if (softreset) {
reset = softreset;
- ehc->i.action = ATA_EH_SOFTRESET;
- } else {
- ata_link_printk(link, KERN_ERR, "BUG: no reset method, "
- "please report to linux-ide@vger.kernel.org\n");
- dump_stack();
- return -EINVAL;
+ ehc->i.action |= ATA_EH_SOFTRESET;
}
if (prereset) {
- rc = prereset(link, jiffies + ATA_EH_PRERESET_TIMEOUT);
+ unsigned long deadline = ata_deadline(jiffies,
+ ATA_EH_PRERESET_TIMEOUT);
+
+ if (slave) {
+ sehc->i.action &= ~ATA_EH_RESET;
+ sehc->i.action |= ehc->i.action;
+ }
+
+ rc = prereset(link, deadline);
+
+ /* If present, do prereset on slave link too. Reset
+ * is skipped iff both master and slave links report
+ * -ENOENT or clear ATA_EH_RESET.
+ */
+ if (slave && (rc == 0 || rc == -ENOENT)) {
+ int tmp;
+
+ tmp = prereset(slave, deadline);
+ if (tmp != -ENOENT)
+ rc = tmp;
+
+ ehc->i.action |= sehc->i.action;
+ }
+
if (rc) {
if (rc == -ENOENT) {
- ata_link_printk(link, KERN_DEBUG,
- "port disabled. ignoring.\n");
+ ata_link_dbg(link, "port disabled--ignoring\n");
ehc->i.action &= ~ATA_EH_RESET;
- ata_link_for_each_dev(dev, link)
+ ata_for_each_dev(dev, link, ALL)
classes[dev->devno] = ATA_DEV_NONE;
rc = 0;
} else
- ata_link_printk(link, KERN_ERR,
- "prereset failed (errno=%d)\n", rc);
+ ata_link_err(link,
+ "prereset failed (errno=%d)\n",
+ rc);
goto out;
}
- }
- /* prereset() might have cleared ATA_EH_RESET */
- if (!(ehc->i.action & ATA_EH_RESET)) {
- /* prereset told us not to reset, bang classes and return */
- ata_link_for_each_dev(dev, link)
- classes[dev->devno] = ATA_DEV_NONE;
- rc = 0;
- goto out;
+ /* prereset() might have cleared ATA_EH_RESET. If so,
+ * bang classes, thaw and return.
+ */
+ if (reset && !(ehc->i.action & ATA_EH_RESET)) {
+ ata_for_each_dev(dev, link, ALL)
+ classes[dev->devno] = ATA_DEV_NONE;
+ if ((ap->pflags & ATA_PFLAG_FROZEN) &&
+ ata_is_host_link(link))
+ ata_eh_thaw_port(ap);
+ rc = 0;
+ goto out;
+ }
}
retry:
- deadline = jiffies + ata_eh_reset_timeouts[try++];
-
- /* shut up during boot probing */
- if (verbose)
- ata_link_printk(link, KERN_INFO, "%s resetting link\n",
- reset == softreset ? "soft" : "hard");
+ /*
+ * Perform reset
+ */
+ if (ata_is_host_link(link))
+ ata_eh_freeze_port(ap);
- /* mark that this EH session started with reset */
- if (reset == hardreset)
- ehc->i.flags |= ATA_EHI_DID_HARDRESET;
- else
- ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
+ deadline = ata_deadline(jiffies, ata_eh_reset_timeouts[try++]);
- rc = ata_do_reset(link, reset, classes, deadline);
+ if (reset) {
+ if (verbose)
+ ata_link_info(link, "%s resetting link\n",
+ reset == softreset ? "soft" : "hard");
- if (reset == hardreset &&
- ata_eh_followup_srst_needed(link, rc, classify, classes)) {
- /* okay, let's do follow-up softreset */
- reset = softreset;
+ /* mark that this EH session started with reset */
+ ehc->last_reset = jiffies;
+ if (reset == hardreset)
+ ehc->i.flags |= ATA_EHI_DID_HARDRESET;
+ else
+ ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
- if (!reset) {
- ata_link_printk(link, KERN_ERR,
- "follow-up softreset required "
- "but no softreset avaliable\n");
- rc = -EINVAL;
+ rc = ata_do_reset(link, reset, classes, deadline, true);
+ if (rc && rc != -EAGAIN) {
+ failed_link = link;
goto fail;
}
- ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
- rc = ata_do_reset(link, reset, classes, deadline);
- }
+ /* hardreset slave link if existent */
+ if (slave && reset == hardreset) {
+ int tmp;
- /* -EAGAIN can happen if we skipped followup SRST */
- if (rc && rc != -EAGAIN)
- goto fail;
+ if (verbose)
+ ata_link_info(slave, "hard resetting link\n");
- done:
- ata_link_for_each_dev(dev, link) {
+ ata_eh_about_to_do(slave, NULL, ATA_EH_RESET);
+ tmp = ata_do_reset(slave, reset, classes, deadline,
+ false);
+ switch (tmp) {
+ case -EAGAIN:
+ rc = -EAGAIN;
+ case 0:
+ break;
+ default:
+ failed_link = slave;
+ rc = tmp;
+ goto fail;
+ }
+ }
+
+ /* perform follow-up SRST if necessary */
+ if (reset == hardreset &&
+ ata_eh_followup_srst_needed(link, rc)) {
+ reset = softreset;
+
+ if (!reset) {
+ ata_link_err(link,
+ "follow-up softreset required but no softreset available\n");
+ failed_link = link;
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
+ rc = ata_do_reset(link, reset, classes, deadline, true);
+ if (rc) {
+ failed_link = link;
+ goto fail;
+ }
+ }
+ } else {
+ if (verbose)
+ ata_link_info(link,
+ "no reset method available, skipping reset\n");
+ if (!(lflags & ATA_LFLAG_ASSUME_CLASS))
+ lflags |= ATA_LFLAG_ASSUME_ATA;
+ }
+
+ /*
+ * Post-reset processing
+ */
+ ata_for_each_dev(dev, link, ALL) {
/* After the reset, the device state is PIO 0 and the
* controller state is undefined. Reset also wakes up
* drives from sleeping mode.
@@ -2221,31 +2831,113 @@ int ata_eh_reset(struct ata_link *link, int classify,
dev->pio_mode = XFER_PIO_0;
dev->flags &= ~ATA_DFLAG_SLEEPING;
- if (ata_link_offline(link))
+ if (ata_phys_link_offline(ata_dev_phys_link(dev)))
continue;
/* apply class override */
if (lflags & ATA_LFLAG_ASSUME_ATA)
classes[dev->devno] = ATA_DEV_ATA;
else if (lflags & ATA_LFLAG_ASSUME_SEMB)
- classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */
+ classes[dev->devno] = ATA_DEV_SEMB_UNSUP;
}
/* record current link speed */
if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0)
link->sata_spd = (sstatus >> 4) & 0xf;
-
- if (postreset)
+ if (slave && sata_scr_read(slave, SCR_STATUS, &sstatus) == 0)
+ slave->sata_spd = (sstatus >> 4) & 0xf;
+
+ /* thaw the port */
+ if (ata_is_host_link(link))
+ ata_eh_thaw_port(ap);
+
+ /* postreset() should clear hardware SError. Although SError
+ * is cleared during link resume, clearing SError here is
+ * necessary as some PHYs raise hotplug events after SRST.
+ * This introduces race condition where hotplug occurs between
+ * reset and here. This race is mediated by cross checking
+ * link onlineness and classification result later.
+ */
+ if (postreset) {
postreset(link, classes);
+ if (slave)
+ postreset(slave, classes);
+ }
+
+ /*
+ * Some controllers can't be frozen very well and may set spurious
+ * error conditions during reset. Clear accumulated error
+ * information and re-thaw the port if frozen. As reset is the
+ * final recovery action and we cross check link onlineness against
+ * device classification later, no hotplug event is lost by this.
+ */
+ spin_lock_irqsave(link->ap->lock, flags);
+ memset(&link->eh_info, 0, sizeof(link->eh_info));
+ if (slave)
+ memset(&slave->eh_info, 0, sizeof(link->eh_info));
+ ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+ spin_unlock_irqrestore(link->ap->lock, flags);
+
+ if (ap->pflags & ATA_PFLAG_FROZEN)
+ ata_eh_thaw_port(ap);
+
+ /*
+ * Make sure onlineness and classification result correspond.
+ * Hotplug could have happened during reset and some
+ * controllers fail to wait while a drive is spinning up after
+ * being hotplugged causing misdetection. By cross checking
+ * link on/offlineness and classification result, those
+ * conditions can be reliably detected and retried.
+ */
+ nr_unknown = 0;
+ ata_for_each_dev(dev, link, ALL) {
+ if (ata_phys_link_online(ata_dev_phys_link(dev))) {
+ if (classes[dev->devno] == ATA_DEV_UNKNOWN) {
+ ata_dev_dbg(dev, "link online but device misclassified\n");
+ classes[dev->devno] = ATA_DEV_NONE;
+ nr_unknown++;
+ }
+ } else if (ata_phys_link_offline(ata_dev_phys_link(dev))) {
+ if (ata_class_enabled(classes[dev->devno]))
+ ata_dev_dbg(dev,
+ "link offline, clearing class %d to NONE\n",
+ classes[dev->devno]);
+ classes[dev->devno] = ATA_DEV_NONE;
+ } else if (classes[dev->devno] == ATA_DEV_UNKNOWN) {
+ ata_dev_dbg(dev,
+ "link status unknown, clearing UNKNOWN to NONE\n");
+ classes[dev->devno] = ATA_DEV_NONE;
+ }
+ }
+
+ if (classify && nr_unknown) {
+ if (try < max_tries) {
+ ata_link_warn(link,
+ "link online but %d devices misclassified, retrying\n",
+ nr_unknown);
+ failed_link = link;
+ rc = -EAGAIN;
+ goto fail;
+ }
+ ata_link_warn(link,
+ "link online but %d devices misclassified, "
+ "device detection might fail\n", nr_unknown);
+ }
/* reset successful, schedule revalidation */
ata_eh_done(link, NULL, ATA_EH_RESET);
+ if (slave)
+ ata_eh_done(slave, NULL, ATA_EH_RESET);
+ ehc->last_reset = jiffies; /* update to completion time */
ehc->i.action |= ATA_EH_REVALIDATE;
+ link->lpm_policy = ATA_LPM_UNKNOWN; /* reset LPM state */
rc = 0;
out:
/* clear hotplug flag */
ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
+ if (slave)
+ sehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~ATA_PFLAG_RESETTING;
@@ -2259,28 +2951,128 @@ int ata_eh_reset(struct ata_link *link, int classify,
sata_scr_read(link, SCR_STATUS, &sstatus))
rc = -ERESTART;
- if (rc == -ERESTART || try >= max_tries)
+ if (try >= max_tries) {
+ /*
+ * Thaw host port even if reset failed, so that the port
+ * can be retried on the next phy event. This risks
+ * repeated EH runs but seems to be a better tradeoff than
+ * shutting down a port after a botched hotplug attempt.
+ */
+ if (ata_is_host_link(link))
+ ata_eh_thaw_port(ap);
goto out;
+ }
now = jiffies;
if (time_before(now, deadline)) {
unsigned long delta = deadline - now;
- ata_link_printk(link, KERN_WARNING, "reset failed "
- "(errno=%d), retrying in %u secs\n",
- rc, (jiffies_to_msecs(delta) + 999) / 1000);
+ ata_link_warn(failed_link,
+ "reset failed (errno=%d), retrying in %u secs\n",
+ rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000));
+ ata_eh_release(ap);
while (delta)
delta = schedule_timeout_uninterruptible(delta);
+ ata_eh_acquire(ap);
+ }
+
+ /*
+ * While disks spinup behind PMP, some controllers fail sending SRST.
+ * They need to be reset - as well as the PMP - before retrying.
+ */
+ if (rc == -ERESTART) {
+ if (ata_is_host_link(link))
+ ata_eh_thaw_port(ap);
+ goto out;
}
- if (rc == -EPIPE || try == max_tries - 1)
- sata_down_spd_limit(link);
+ if (try == max_tries - 1) {
+ sata_down_spd_limit(link, 0);
+ if (slave)
+ sata_down_spd_limit(slave, 0);
+ } else if (rc == -EPIPE)
+ sata_down_spd_limit(failed_link, 0);
+
if (hardreset)
reset = hardreset;
goto retry;
}
+static inline void ata_eh_pull_park_action(struct ata_port *ap)
+{
+ struct ata_link *link;
+ struct ata_device *dev;
+ unsigned long flags;
+
+ /*
+ * This function can be thought of as an extended version of
+ * ata_eh_about_to_do() specially crafted to accommodate the
+ * requirements of ATA_EH_PARK handling. Since the EH thread
+ * does not leave the do {} while () loop in ata_eh_recover as
+ * long as the timeout for a park request to *one* device on
+ * the port has not expired, and since we still want to pick
+ * up park requests to other devices on the same port or
+ * timeout updates for the same device, we have to pull
+ * ATA_EH_PARK actions from eh_info into eh_context.i
+ * ourselves at the beginning of each pass over the loop.
+ *
+ * Additionally, all write accesses to &ap->park_req_pending
+ * through reinit_completion() (see below) or complete_all()
+ * (see ata_scsi_park_store()) are protected by the host lock.
+ * As a result we have that park_req_pending.done is zero on
+ * exit from this function, i.e. when ATA_EH_PARK actions for
+ * *all* devices on port ap have been pulled into the
+ * respective eh_context structs. If, and only if,
+ * park_req_pending.done is non-zero by the time we reach
+ * wait_for_completion_timeout(), another ATA_EH_PARK action
+ * has been scheduled for at least one of the devices on port
+ * ap and we have to cycle over the do {} while () loop in
+ * ata_eh_recover() again.
+ */
+
+ spin_lock_irqsave(ap->lock, flags);
+ reinit_completion(&ap->park_req_pending);
+ ata_for_each_link(link, ap, EDGE) {
+ ata_for_each_dev(dev, link, ALL) {
+ struct ata_eh_info *ehi = &link->eh_info;
+
+ link->eh_context.i.dev_action[dev->devno] |=
+ ehi->dev_action[dev->devno] & ATA_EH_PARK;
+ ata_eh_clear_action(link, dev, ehi, ATA_EH_PARK);
+ }
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+static void ata_eh_park_issue_cmd(struct ata_device *dev, int park)
+{
+ struct ata_eh_context *ehc = &dev->link->eh_context;
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ ata_tf_init(dev, &tf);
+ if (park) {
+ ehc->unloaded_mask |= 1 << dev->devno;
+ tf.command = ATA_CMD_IDLEIMMEDIATE;
+ tf.feature = 0x44;
+ tf.lbal = 0x4c;
+ tf.lbam = 0x4e;
+ tf.lbah = 0x55;
+ } else {
+ ehc->unloaded_mask &= ~(1 << dev->devno);
+ tf.command = ATA_CMD_CHK_POWER;
+ }
+
+ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+ tf.protocol |= ATA_PROT_NODATA;
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+ if (park && (err_mask || tf.lbal != 0xc4)) {
+ ata_dev_err(dev, "head unload failed!\n");
+ ehc->unloaded_mask &= ~(1 << dev->devno);
+ }
+}
+
static int ata_eh_revalidate_and_attach(struct ata_link *link,
struct ata_device **r_failed_dev)
{
@@ -2297,7 +3089,7 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
* be done backwards such that PDIAG- is released by the slave
* device before the master device is identified.
*/
- ata_link_for_each_dev_reverse(dev, link) {
+ ata_for_each_dev(dev, link, ALL_REVERSE) {
unsigned int action = ata_eh_dev_action(dev);
unsigned int readid_flags = 0;
@@ -2307,7 +3099,7 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
WARN_ON(dev->class == ATA_DEV_PMP);
- if (ata_link_offline(link)) {
+ if (ata_phys_link_offline(ata_dev_phys_link(dev))) {
rc = -EIO;
goto err;
}
@@ -2326,10 +3118,16 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
ehc->i.flags |= ATA_EHI_SETMODE;
/* schedule the scsi_rescan_device() here */
- queue_work(ata_aux_wq, &(ap->scsi_rescan_task));
+ schedule_work(&(ap->scsi_rescan_task));
} else if (dev->class == ATA_DEV_UNKNOWN &&
ehc->tries[dev->devno] &&
ata_class_enabled(ehc->classes[dev->devno])) {
+ /* Temporarily set dev->class, it will be
+ * permanently set once all configurations are
+ * complete. This is necessary because new
+ * device configuration is done in two
+ * separate loops.
+ */
dev->class = ehc->classes[dev->devno];
if (dev->class == ATA_DEV_PMP)
@@ -2337,20 +3135,25 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
else
rc = ata_dev_read_id(dev, &dev->class,
readid_flags, dev->id);
+
+ /* read_id might have changed class, store and reset */
+ ehc->classes[dev->devno] = dev->class;
+ dev->class = ATA_DEV_UNKNOWN;
+
switch (rc) {
case 0:
+ /* clear error info accumulated during probe */
+ ata_ering_clear(&dev->ering);
new_mask |= 1 << dev->devno;
break;
case -ENOENT:
/* IDENTIFY was issued to non-existent
* device. No need to reset. Just
- * thaw and kill the device.
+ * thaw and ignore the device.
*/
ata_eh_thaw_port(ap);
- dev->class = ATA_DEV_UNKNOWN;
break;
default:
- dev->class = ATA_DEV_UNKNOWN;
goto err;
}
}
@@ -2366,16 +3169,22 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
/* Configure new devices forward such that user doesn't see
* device detection messages backwards.
*/
- ata_link_for_each_dev(dev, link) {
- if (!(new_mask & (1 << dev->devno)) ||
- dev->class == ATA_DEV_PMP)
+ ata_for_each_dev(dev, link, ALL) {
+ if (!(new_mask & (1 << dev->devno)))
+ continue;
+
+ dev->class = ehc->classes[dev->devno];
+
+ if (dev->class == ATA_DEV_PMP)
continue;
ehc->i.flags |= ATA_EHI_PRINTINFO;
rc = ata_dev_configure(dev);
ehc->i.flags &= ~ATA_EHI_PRINTINFO;
- if (rc)
+ if (rc) {
+ dev->class = ATA_DEV_UNKNOWN;
goto err;
+ }
spin_lock_irqsave(ap->lock, flags);
ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
@@ -2396,7 +3205,7 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
/**
* ata_set_mode - Program timings and issue SET FEATURES - XFER
* @link: link on which timings will be programmed
- * @r_failed_dev: out paramter for failed device
+ * @r_failed_dev: out parameter for failed device
*
* Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If
* ata_set_mode() fails, pointer to the failing device is
@@ -2415,7 +3224,7 @@ int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
int rc;
/* if data transfer is verified, clear DUBIOUS_XFER on ering top */
- ata_link_for_each_dev(dev, link) {
+ ata_for_each_dev(dev, link, ENABLED) {
if (!(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) {
struct ata_ering_entry *ent;
@@ -2432,7 +3241,7 @@ int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
rc = ata_do_set_mode(link, r_failed_dev);
/* if transfer mode has changed, set DUBIOUS_XFER on device */
- ata_link_for_each_dev(dev, link) {
+ ata_for_each_dev(dev, link, ENABLED) {
struct ata_eh_context *ehc = &link->eh_context;
u8 saved_xfer_mode = ehc->saved_xfer_mode[dev->devno];
u8 saved_ncq = !!(ehc->saved_ncq_enabled & (1 << dev->devno));
@@ -2445,14 +3254,267 @@ int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
return rc;
}
-static int ata_link_nr_enabled(struct ata_link *link)
+/**
+ * atapi_eh_clear_ua - Clear ATAPI UNIT ATTENTION after reset
+ * @dev: ATAPI device to clear UA for
+ *
+ * Resets and other operations can make an ATAPI device raise
+ * UNIT ATTENTION which causes the next operation to fail. This
+ * function clears UA.
+ *
+ * LOCKING:
+ * EH context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int atapi_eh_clear_ua(struct ata_device *dev)
+{
+ int i;
+
+ for (i = 0; i < ATA_EH_UA_TRIES; i++) {
+ u8 *sense_buffer = dev->link->ap->sector_buf;
+ u8 sense_key = 0;
+ unsigned int err_mask;
+
+ err_mask = atapi_eh_tur(dev, &sense_key);
+ if (err_mask != 0 && err_mask != AC_ERR_DEV) {
+ ata_dev_warn(dev,
+ "TEST_UNIT_READY failed (err_mask=0x%x)\n",
+ err_mask);
+ return -EIO;
+ }
+
+ if (!err_mask || sense_key != UNIT_ATTENTION)
+ return 0;
+
+ err_mask = atapi_eh_request_sense(dev, sense_buffer, sense_key);
+ if (err_mask) {
+ ata_dev_warn(dev, "failed to clear "
+ "UNIT ATTENTION (err_mask=0x%x)\n", err_mask);
+ return -EIO;
+ }
+ }
+
+ ata_dev_warn(dev, "UNIT ATTENTION persists after %d tries\n",
+ ATA_EH_UA_TRIES);
+
+ return 0;
+}
+
+/**
+ * ata_eh_maybe_retry_flush - Retry FLUSH if necessary
+ * @dev: ATA device which may need FLUSH retry
+ *
+ * If @dev failed FLUSH, it needs to be reported upper layer
+ * immediately as it means that @dev failed to remap and already
+ * lost at least a sector and further FLUSH retrials won't make
+ * any difference to the lost sector. However, if FLUSH failed
+ * for other reasons, for example transmission error, FLUSH needs
+ * to be retried.
+ *
+ * This function determines whether FLUSH failure retry is
+ * necessary and performs it if so.
+ *
+ * RETURNS:
+ * 0 if EH can continue, -errno if EH needs to be repeated.
+ */
+static int ata_eh_maybe_retry_flush(struct ata_device *dev)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ struct ata_queued_cmd *qc;
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+ int rc = 0;
+
+ /* did flush fail for this device? */
+ if (!ata_tag_valid(link->active_tag))
+ return 0;
+
+ qc = __ata_qc_from_tag(ap, link->active_tag);
+ if (qc->dev != dev || (qc->tf.command != ATA_CMD_FLUSH_EXT &&
+ qc->tf.command != ATA_CMD_FLUSH))
+ return 0;
+
+ /* if the device failed it, it should be reported to upper layers */
+ if (qc->err_mask & AC_ERR_DEV)
+ return 0;
+
+ /* flush failed for some other reason, give it another shot */
+ ata_tf_init(dev, &tf);
+
+ tf.command = qc->tf.command;
+ tf.flags |= ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_NODATA;
+
+ ata_dev_warn(dev, "retrying FLUSH 0x%x Emask 0x%x\n",
+ tf.command, qc->err_mask);
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+ if (!err_mask) {
+ /*
+ * FLUSH is complete but there's no way to
+ * successfully complete a failed command from EH.
+ * Making sure retry is allowed at least once and
+ * retrying it should do the trick - whatever was in
+ * the cache is already on the platter and this won't
+ * cause infinite loop.
+ */
+ qc->scsicmd->allowed = max(qc->scsicmd->allowed, 1);
+ } else {
+ ata_dev_warn(dev, "FLUSH failed Emask 0x%x\n",
+ err_mask);
+ rc = -EIO;
+
+ /* if device failed it, report it to upper layers */
+ if (err_mask & AC_ERR_DEV) {
+ qc->err_mask |= AC_ERR_DEV;
+ qc->result_tf = tf;
+ if (!(ap->pflags & ATA_PFLAG_FROZEN))
+ rc = 0;
+ }
+ }
+ return rc;
+}
+
+/**
+ * ata_eh_set_lpm - configure SATA interface power management
+ * @link: link to configure power management
+ * @policy: the link power management policy
+ * @r_failed_dev: out parameter for failed device
+ *
+ * Enable SATA Interface power management. This will enable
+ * Device Interface Power Management (DIPM) for min_power
+ * policy, and then call driver specific callbacks for
+ * enabling Host Initiated Power management.
+ *
+ * LOCKING:
+ * EH context.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+ struct ata_device **r_failed_dev)
+{
+ struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL;
+ struct ata_eh_context *ehc = &link->eh_context;
+ struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
+ enum ata_lpm_policy old_policy = link->lpm_policy;
+ bool no_dipm = link->ap->flags & ATA_FLAG_NO_DIPM;
+ unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
+ unsigned int err_mask;
+ int rc;
+
+ /* if the link or host doesn't do LPM, noop */
+ if ((link->flags & ATA_LFLAG_NO_LPM) || (ap && !ap->ops->set_lpm))
+ return 0;
+
+ /*
+ * DIPM is enabled only for MIN_POWER as some devices
+ * misbehave when the host NACKs transition to SLUMBER. Order
+ * device and link configurations such that the host always
+ * allows DIPM requests.
+ */
+ ata_for_each_dev(dev, link, ENABLED) {
+ bool hipm = ata_id_has_hipm(dev->id);
+ bool dipm = ata_id_has_dipm(dev->id) && !no_dipm;
+
+ /* find the first enabled and LPM enabled devices */
+ if (!link_dev)
+ link_dev = dev;
+
+ if (!lpm_dev && (hipm || dipm))
+ lpm_dev = dev;
+
+ hints &= ~ATA_LPM_EMPTY;
+ if (!hipm)
+ hints &= ~ATA_LPM_HIPM;
+
+ /* disable DIPM before changing link config */
+ if (policy != ATA_LPM_MIN_POWER && dipm) {
+ err_mask = ata_dev_set_feature(dev,
+ SETFEATURES_SATA_DISABLE, SATA_DIPM);
+ if (err_mask && err_mask != AC_ERR_DEV) {
+ ata_dev_warn(dev,
+ "failed to disable DIPM, Emask 0x%x\n",
+ err_mask);
+ rc = -EIO;
+ goto fail;
+ }
+ }
+ }
+
+ if (ap) {
+ rc = ap->ops->set_lpm(link, policy, hints);
+ if (!rc && ap->slave_link)
+ rc = ap->ops->set_lpm(ap->slave_link, policy, hints);
+ } else
+ rc = sata_pmp_set_lpm(link, policy, hints);
+
+ /*
+ * Attribute link config failure to the first (LPM) enabled
+ * device on the link.
+ */
+ if (rc) {
+ if (rc == -EOPNOTSUPP) {
+ link->flags |= ATA_LFLAG_NO_LPM;
+ return 0;
+ }
+ dev = lpm_dev ? lpm_dev : link_dev;
+ goto fail;
+ }
+
+ /*
+ * Low level driver acked the transition. Issue DIPM command
+ * with the new policy set.
+ */
+ link->lpm_policy = policy;
+ if (ap && ap->slave_link)
+ ap->slave_link->lpm_policy = policy;
+
+ /* host config updated, enable DIPM if transitioning to MIN_POWER */
+ ata_for_each_dev(dev, link, ENABLED) {
+ if (policy == ATA_LPM_MIN_POWER && !no_dipm &&
+ ata_id_has_dipm(dev->id)) {
+ err_mask = ata_dev_set_feature(dev,
+ SETFEATURES_SATA_ENABLE, SATA_DIPM);
+ if (err_mask && err_mask != AC_ERR_DEV) {
+ ata_dev_warn(dev,
+ "failed to enable DIPM, Emask 0x%x\n",
+ err_mask);
+ rc = -EIO;
+ goto fail;
+ }
+ }
+ }
+
+ return 0;
+
+fail:
+ /* restore the old policy */
+ link->lpm_policy = old_policy;
+ if (ap && ap->slave_link)
+ ap->slave_link->lpm_policy = old_policy;
+
+ /* if no device or only one more chance is left, disable LPM */
+ if (!dev || ehc->tries[dev->devno] <= 2) {
+ ata_link_warn(link, "disabling LPM on the link\n");
+ link->flags |= ATA_LFLAG_NO_LPM;
+ }
+ if (r_failed_dev)
+ *r_failed_dev = dev;
+ return rc;
+}
+
+int ata_link_nr_enabled(struct ata_link *link)
{
struct ata_device *dev;
int cnt = 0;
- ata_link_for_each_dev(dev, link)
- if (ata_dev_enabled(dev))
- cnt++;
+ ata_for_each_dev(dev, link, ENABLED)
+ cnt++;
return cnt;
}
@@ -2461,7 +3523,7 @@ static int ata_link_nr_vacant(struct ata_link *link)
struct ata_device *dev;
int cnt = 0;
- ata_link_for_each_dev(dev, link)
+ ata_for_each_dev(dev, link, ALL)
if (dev->class == ATA_DEV_UNKNOWN)
cnt++;
return cnt;
@@ -2477,6 +3539,10 @@ static int ata_eh_skip_recovery(struct ata_link *link)
if (link->flags & ATA_LFLAG_DISABLED)
return 1;
+ /* skip if explicitly requested */
+ if (ehc->i.flags & ATA_EHI_NO_RECOVERY)
+ return 1;
+
/* thaw frozen port and recover failed devices */
if ((ap->pflags & ATA_PFLAG_FROZEN) || ata_link_nr_enabled(link))
return 0;
@@ -2487,7 +3553,7 @@ static int ata_eh_skip_recovery(struct ata_link *link)
return 0;
/* skip if class codes for all vacant slots are ATA_DEV_NONE */
- ata_link_for_each_dev(dev, link) {
+ ata_for_each_dev(dev, link, ALL) {
if (dev->class == ATA_DEV_UNKNOWN &&
ehc->classes[dev->devno] != ATA_DEV_NONE)
return 0;
@@ -2496,9 +3562,25 @@ static int ata_eh_skip_recovery(struct ata_link *link)
return 1;
}
+static int ata_count_probe_trials_cb(struct ata_ering_entry *ent, void *void_arg)
+{
+ u64 interval = msecs_to_jiffies(ATA_EH_PROBE_TRIAL_INTERVAL);
+ u64 now = get_jiffies_64();
+ int *trials = void_arg;
+
+ if ((ent->eflags & ATA_EFLAG_OLD_ER) ||
+ (ent->timestamp < now - min(now, interval)))
+ return -1;
+
+ (*trials)++;
+ return 0;
+}
+
static int ata_eh_schedule_probe(struct ata_device *dev)
{
struct ata_eh_context *ehc = &dev->link->eh_context;
+ struct ata_link *link = ata_dev_phys_link(dev);
+ int trials = 0;
if (!(ehc->i.probe_mask & (1 << dev->devno)) ||
(ehc->did_probe_mask & (1 << dev->devno)))
@@ -2511,6 +3593,35 @@ static int ata_eh_schedule_probe(struct ata_device *dev)
ehc->saved_xfer_mode[dev->devno] = 0;
ehc->saved_ncq_enabled &= ~(1 << dev->devno);
+ /* the link maybe in a deep sleep, wake it up */
+ if (link->lpm_policy > ATA_LPM_MAX_POWER) {
+ if (ata_is_host_link(link))
+ link->ap->ops->set_lpm(link, ATA_LPM_MAX_POWER,
+ ATA_LPM_EMPTY);
+ else
+ sata_pmp_set_lpm(link, ATA_LPM_MAX_POWER,
+ ATA_LPM_EMPTY);
+ }
+
+ /* Record and count probe trials on the ering. The specific
+ * error mask used is irrelevant. Because a successful device
+ * detection clears the ering, this count accumulates only if
+ * there are consecutive failed probes.
+ *
+ * If the count is equal to or higher than ATA_EH_PROBE_TRIALS
+ * in the last ATA_EH_PROBE_TRIAL_INTERVAL, link speed is
+ * forced to 1.5Gbps.
+ *
+ * This is to work around cases where failed link speed
+ * negotiation results in device misdetection leading to
+ * infinite DEVXCHG or PHRDY CHG events.
+ */
+ ata_ering_record(&dev->ering, 0, AC_ERR_OTHER);
+ ata_ering_map(&dev->ering, ata_count_probe_trials_cb, &trials);
+
+ if (trials > ATA_EH_PROBE_TRIALS)
+ sata_down_spd_limit(link, 1);
+
return 1;
}
@@ -2518,7 +3629,11 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
{
struct ata_eh_context *ehc = &dev->link->eh_context;
- ehc->tries[dev->devno]--;
+ /* -EAGAIN from EH routine indicates retry without prejudice.
+ * The requester is responsible for ensuring forward progress.
+ */
+ if (err != -EAGAIN)
+ ehc->tries[dev->devno]--;
switch (err) {
case -ENODEV:
@@ -2528,12 +3643,13 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
/* give it just one more chance */
ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1);
case -EIO:
- if (ehc->tries[dev->devno] == 1 && dev->pio_mode > XFER_PIO_0) {
+ if (ehc->tries[dev->devno] == 1) {
/* This is the last chance, better to slow
* down than lose it.
*/
- sata_down_spd_limit(dev->link);
- ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
+ sata_down_spd_limit(ata_dev_phys_link(dev), 0);
+ if (dev->pio_mode > XFER_PIO_0)
+ ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
}
}
@@ -2542,12 +3658,15 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
ata_dev_disable(dev);
/* detach if offline */
- if (ata_link_offline(dev->link))
+ if (ata_phys_link_offline(ata_dev_phys_link(dev)))
ata_eh_detach_dev(dev);
/* schedule probe if necessary */
- if (ata_eh_schedule_probe(dev))
+ if (ata_eh_schedule_probe(dev)) {
ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+ memset(ehc->cmd_timeout_idx[dev->devno], 0,
+ sizeof(ehc->cmd_timeout_idx[dev->devno]));
+ }
return 1;
} else {
@@ -2585,14 +3704,13 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
{
struct ata_link *link;
struct ata_device *dev;
- int nr_failed_devs, nr_disabled_devs;
- int reset, rc;
- unsigned long flags;
+ int rc, nr_fails;
+ unsigned long flags, deadline;
DPRINTK("ENTER\n");
/* prep for recovery */
- ata_port_for_each_link(link, ap) {
+ ata_for_each_link(link, ap, EDGE) {
struct ata_eh_context *ehc = &link->eh_context;
/* re-enable link? */
@@ -2604,7 +3722,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK);
}
- ata_link_for_each_dev(dev, link) {
+ ata_for_each_dev(dev, link, ALL) {
if (link->flags & ATA_LFLAG_NO_RETRY)
ehc->tries[dev->devno] = 1;
else
@@ -2627,66 +3745,102 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
retry:
rc = 0;
- nr_failed_devs = 0;
- nr_disabled_devs = 0;
- reset = 0;
/* if UNLOADING, finish immediately */
if (ap->pflags & ATA_PFLAG_UNLOADING)
goto out;
/* prep for EH */
- ata_port_for_each_link(link, ap) {
+ ata_for_each_link(link, ap, EDGE) {
struct ata_eh_context *ehc = &link->eh_context;
/* skip EH if possible. */
if (ata_eh_skip_recovery(link))
ehc->i.action = 0;
- /* do we need to reset? */
- if (ehc->i.action & ATA_EH_RESET)
- reset = 1;
-
- ata_link_for_each_dev(dev, link)
+ ata_for_each_dev(dev, link, ALL)
ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
}
/* reset */
- if (reset) {
- /* if PMP is attached, this function only deals with
- * downstream links, port should stay thawed.
- */
- if (!sata_pmp_attached(ap))
- ata_eh_freeze_port(ap);
+ ata_for_each_link(link, ap, EDGE) {
+ struct ata_eh_context *ehc = &link->eh_context;
- ata_port_for_each_link(link, ap) {
- struct ata_eh_context *ehc = &link->eh_context;
+ if (!(ehc->i.action & ATA_EH_RESET))
+ continue;
- if (!(ehc->i.action & ATA_EH_RESET))
- continue;
+ rc = ata_eh_reset(link, ata_link_nr_vacant(link),
+ prereset, softreset, hardreset, postreset);
+ if (rc) {
+ ata_link_err(link, "reset failed, giving up\n");
+ goto out;
+ }
+ }
- rc = ata_eh_reset(link, ata_link_nr_vacant(link),
- prereset, softreset, hardreset,
- postreset);
- if (rc) {
- ata_link_printk(link, KERN_ERR,
- "reset failed, giving up\n");
- goto out;
+ do {
+ unsigned long now;
+
+ /*
+ * clears ATA_EH_PARK in eh_info and resets
+ * ap->park_req_pending
+ */
+ ata_eh_pull_park_action(ap);
+
+ deadline = jiffies;
+ ata_for_each_link(link, ap, EDGE) {
+ ata_for_each_dev(dev, link, ALL) {
+ struct ata_eh_context *ehc = &link->eh_context;
+ unsigned long tmp;
+
+ if (dev->class != ATA_DEV_ATA)
+ continue;
+ if (!(ehc->i.dev_action[dev->devno] &
+ ATA_EH_PARK))
+ continue;
+ tmp = dev->unpark_deadline;
+ if (time_before(deadline, tmp))
+ deadline = tmp;
+ else if (time_before_eq(tmp, jiffies))
+ continue;
+ if (ehc->unloaded_mask & (1 << dev->devno))
+ continue;
+
+ ata_eh_park_issue_cmd(dev, 1);
}
}
- if (!sata_pmp_attached(ap))
- ata_eh_thaw_port(ap);
+ now = jiffies;
+ if (time_before_eq(deadline, now))
+ break;
+
+ ata_eh_release(ap);
+ deadline = wait_for_completion_timeout(&ap->park_req_pending,
+ deadline - now);
+ ata_eh_acquire(ap);
+ } while (deadline);
+ ata_for_each_link(link, ap, EDGE) {
+ ata_for_each_dev(dev, link, ALL) {
+ if (!(link->eh_context.unloaded_mask &
+ (1 << dev->devno)))
+ continue;
+
+ ata_eh_park_issue_cmd(dev, 0);
+ ata_eh_done(link, dev, ATA_EH_PARK);
+ }
}
/* the rest */
- ata_port_for_each_link(link, ap) {
+ nr_fails = 0;
+ ata_for_each_link(link, ap, PMP_FIRST) {
struct ata_eh_context *ehc = &link->eh_context;
+ if (sata_pmp_attached(ap) && ata_is_host_link(link))
+ goto config_lpm;
+
/* revalidate existing devices and attach new ones */
rc = ata_eh_revalidate_and_attach(link, &dev);
if (rc)
- goto dev_fail;
+ goto rest_fail;
/* if PMP got attached, return, pmp EH will take care of it */
if (link->device->class == ATA_DEV_PMP) {
@@ -2698,22 +3852,50 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
if (ehc->i.flags & ATA_EHI_SETMODE) {
rc = ata_set_mode(link, &dev);
if (rc)
- goto dev_fail;
+ goto rest_fail;
ehc->i.flags &= ~ATA_EHI_SETMODE;
}
- if (ehc->i.action & ATA_EH_LPM)
- ata_link_for_each_dev(dev, link)
- ata_dev_enable_pm(dev, ap->pm_policy);
+ /* If reset has been issued, clear UA to avoid
+ * disrupting the current users of the device.
+ */
+ if (ehc->i.flags & ATA_EHI_DID_RESET) {
+ ata_for_each_dev(dev, link, ALL) {
+ if (dev->class != ATA_DEV_ATAPI)
+ continue;
+ rc = atapi_eh_clear_ua(dev);
+ if (rc)
+ goto rest_fail;
+ if (zpodd_dev_enabled(dev))
+ zpodd_post_poweron(dev);
+ }
+ }
+
+ /* retry flush if necessary */
+ ata_for_each_dev(dev, link, ALL) {
+ if (dev->class != ATA_DEV_ATA)
+ continue;
+ rc = ata_eh_maybe_retry_flush(dev);
+ if (rc)
+ goto rest_fail;
+ }
+
+ config_lpm:
+ /* configure link power saving */
+ if (link->lpm_policy != ap->target_lpm_policy) {
+ rc = ata_eh_set_lpm(link, ap->target_lpm_policy, &dev);
+ if (rc)
+ goto rest_fail;
+ }
/* this link is okay now */
ehc->i.flags = 0;
continue;
-dev_fail:
- nr_failed_devs++;
- if (ata_eh_handle_dev_fail(dev, rc))
- nr_disabled_devs++;
+ rest_fail:
+ nr_fails++;
+ if (dev)
+ ata_eh_handle_dev_fail(dev, rc);
if (ap->pflags & ATA_PFLAG_FROZEN) {
/* PMP reset requires working host port.
@@ -2725,18 +3907,8 @@ dev_fail:
}
}
- if (nr_failed_devs) {
- if (nr_failed_devs != nr_disabled_devs) {
- ata_port_printk(ap, KERN_WARNING, "failed to recover "
- "some devices, retrying in 5 secs\n");
- ssleep(5);
- } else {
- /* no device left to recover, repeat fast */
- msleep(500);
- }
-
+ if (nr_fails)
goto retry;
- }
out:
if (rc && r_failed_link)
@@ -2819,7 +3991,7 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset,
NULL);
if (rc) {
- ata_link_for_each_dev(dev, &ap->link)
+ ata_for_each_dev(dev, &ap->link, ALL)
ata_dev_disable(dev);
}
@@ -2841,7 +4013,7 @@ void ata_std_error_handler(struct ata_port *ap)
ata_reset_fn_t hardreset = ops->hardreset;
/* ignore built-in hardreset if SCR access is not available */
- if (ata_is_builtin_hardreset(hardreset) && !sata_scr_valid(&ap->link))
+ if (hardreset == sata_std_hardreset && !sata_scr_valid(&ap->link))
hardreset = NULL;
ata_do_eh(ap, ops->prereset, ops->softreset, hardreset, ops->postreset);
@@ -2861,11 +4033,12 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
{
unsigned long flags;
int rc = 0;
+ struct ata_device *dev;
/* are we suspending? */
spin_lock_irqsave(ap->lock, flags);
if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
- ap->pm_mesg.event == PM_EVENT_ON) {
+ ap->pm_mesg.event & PM_EVENT_RESUME) {
spin_unlock_irqrestore(ap->lock, flags);
return;
}
@@ -2873,6 +4046,18 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
+ /*
+ * If we have a ZPODD attached, check its zero
+ * power ready status before the port is frozen.
+ * Only needed for runtime suspend.
+ */
+ if (PMSG_IS_AUTO(ap->pm_mesg)) {
+ ata_for_each_dev(dev, &ap->link, ENABLED) {
+ if (zpodd_dev_enabled(dev))
+ zpodd_on_suspend(dev);
+ }
+ }
+
/* tell ACPI we're suspending */
rc = ata_acpi_on_suspend(ap);
if (rc)
@@ -2884,9 +4069,9 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
if (ap->ops->port_suspend)
rc = ap->ops->port_suspend(ap, ap->pm_mesg);
- ata_acpi_set_state(ap, PMSG_SUSPEND);
+ ata_acpi_set_state(ap, ap->pm_mesg);
out:
- /* report result */
+ /* update the flags */
spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~ATA_PFLAG_PM_PENDING;
@@ -2895,11 +4080,6 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
else if (ap->pflags & ATA_PFLAG_FROZEN)
ata_port_schedule_eh(ap);
- if (ap->pm_result) {
- *ap->pm_result = rc;
- ap->pm_result = NULL;
- }
-
spin_unlock_irqrestore(ap->lock, flags);
return;
@@ -2916,13 +4096,15 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
*/
static void ata_eh_handle_port_resume(struct ata_port *ap)
{
+ struct ata_link *link;
+ struct ata_device *dev;
unsigned long flags;
int rc = 0;
/* are we resuming? */
spin_lock_irqsave(ap->lock, flags);
if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
- ap->pm_mesg.event != PM_EVENT_ON) {
+ !(ap->pm_mesg.event & PM_EVENT_RESUME)) {
spin_unlock_irqrestore(ap->lock, flags);
return;
}
@@ -2930,7 +4112,18 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
WARN_ON(!(ap->pflags & ATA_PFLAG_SUSPENDED));
- ata_acpi_set_state(ap, PMSG_ON);
+ /*
+ * Error timestamps are in jiffies which doesn't run while
+ * suspended and PHY events during resume isn't too uncommon.
+ * When the two are combined, it can lead to unnecessary speed
+ * downs if the machine is suspended and resumed repeatedly.
+ * Clear error history.
+ */
+ ata_for_each_link(link, ap, HOST_FIRST)
+ ata_for_each_dev(dev, link, ALL)
+ ata_ering_clear(&dev->ering);
+
+ ata_acpi_set_state(ap, ap->pm_mesg);
if (ap->ops->port_resume)
rc = ap->ops->port_resume(ap);
@@ -2938,13 +4131,9 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
/* tell ACPI that we're resuming */
ata_acpi_on_resume(ap);
- /* report result */
+ /* update the flags */
spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
- if (ap->pm_result) {
- *ap->pm_result = rc;
- ap->pm_result = NULL;
- }
spin_unlock_irqrestore(ap->lock, flags);
}
#endif /* CONFIG_PM */
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
index ff1822a7da3..7ccc084bf1d 100644
--- a/drivers/ata/libata-pmp.c
+++ b/drivers/ata/libata-pmp.c
@@ -8,8 +8,11 @@
*/
#include <linux/kernel.h>
+#include <linux/export.h>
#include <linux/libata.h>
+#include <linux/slab.h>
#include "libata.h"
+#include "libata-transport.h"
const struct ata_port_operations sata_pmp_port_ops = {
.inherits = &sata_port_ops,
@@ -48,7 +51,7 @@ static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
tf.device = link->pmp;
err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
- SATA_PMP_SCR_TIMEOUT);
+ SATA_PMP_RW_TIMEOUT);
if (err_mask)
return err_mask;
@@ -88,7 +91,7 @@ static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val)
tf.lbah = (val >> 24) & 0xff;
return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
- SATA_PMP_SCR_TIMEOUT);
+ SATA_PMP_RW_TIMEOUT);
}
/**
@@ -145,8 +148,8 @@ int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val)
err_mask = sata_pmp_read(link, reg, r_val);
if (err_mask) {
- ata_link_printk(link, KERN_WARNING, "failed to read SCR %d "
- "(Emask=0x%x)\n", reg, err_mask);
+ ata_link_warn(link, "failed to read SCR %d (Emask=0x%x)\n",
+ reg, err_mask);
return -EIO;
}
return 0;
@@ -176,14 +179,35 @@ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
err_mask = sata_pmp_write(link, reg, val);
if (err_mask) {
- ata_link_printk(link, KERN_WARNING, "failed to write SCR %d "
- "(Emask=0x%x)\n", reg, err_mask);
+ ata_link_warn(link, "failed to write SCR %d (Emask=0x%x)\n",
+ reg, err_mask);
return -EIO;
}
return 0;
}
/**
+ * sata_pmp_set_lpm - configure LPM for a PMP link
+ * @link: PMP link to configure LPM for
+ * @policy: target LPM policy
+ * @hints: LPM hints
+ *
+ * Configure LPM for @link. This function will contain any PMP
+ * specific workarounds if necessary.
+ *
+ * LOCKING:
+ * EH context.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+ unsigned hints)
+{
+ return sata_link_scr_lpm(link, policy, true);
+}
+
+/**
* sata_pmp_read_gscr - read GSCR block of SATA PMP
* @dev: PMP device
* @gscr: buffer to read GSCR block into
@@ -208,8 +232,8 @@ static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr)
err_mask = sata_pmp_read(dev->link, reg, &gscr[reg]);
if (err_mask) {
- ata_dev_printk(dev, KERN_ERR, "failed to read PMP "
- "GSCR[%d] (Emask=0x%x)\n", reg, err_mask);
+ ata_dev_err(dev, "failed to read PMP GSCR[%d] (Emask=0x%x)\n",
+ reg, err_mask);
return -EIO;
}
}
@@ -221,6 +245,8 @@ static const char *sata_pmp_spec_rev_str(const u32 *gscr)
{
u32 rev = gscr[SATA_PMP_GSCR_REV];
+ if (rev & (1 << 3))
+ return "1.2";
if (rev & (1 << 2))
return "1.1";
if (rev & (1 << 1))
@@ -228,10 +254,14 @@ static const char *sata_pmp_spec_rev_str(const u32 *gscr)
return "<unknown>";
}
+#define PMP_GSCR_SII_POL 129
+
static int sata_pmp_configure(struct ata_device *dev, int print_info)
{
struct ata_port *ap = dev->link->ap;
u32 *gscr = dev->gscr;
+ u16 vendor = sata_pmp_gscr_vendor(gscr);
+ u16 devid = sata_pmp_gscr_devid(gscr);
unsigned int err_mask = 0;
const char *reason;
int nr_ports, rc;
@@ -257,49 +287,57 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info)
goto fail;
}
- /* turn off notification till fan-out ports are reset and configured */
- if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
- gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
+ /* Disable sending Early R_OK.
+ * With "cached read" HDD testing and multiple ports busy on a SATA
+ * host controller, 3x26 PMP will very rarely drop a deferred
+ * R_OK that was intended for the host. Symptom will be all
+ * 5 drives under test will timeout, get reset, and recover.
+ */
+ if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) {
+ u32 reg;
- err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN,
- gscr[SATA_PMP_GSCR_FEAT_EN]);
+ err_mask = sata_pmp_read(&ap->link, PMP_GSCR_SII_POL, &reg);
+ if (err_mask) {
+ rc = -EIO;
+ reason = "failed to read Sil3x26 Private Register";
+ goto fail;
+ }
+ reg &= ~0x1;
+ err_mask = sata_pmp_write(&ap->link, PMP_GSCR_SII_POL, reg);
if (err_mask) {
rc = -EIO;
- reason = "failed to write GSCR_FEAT_EN";
+ reason = "failed to write Sil3x26 Private Register";
goto fail;
}
}
if (print_info) {
- ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, "
- "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n",
- sata_pmp_spec_rev_str(gscr),
- sata_pmp_gscr_vendor(gscr),
- sata_pmp_gscr_devid(gscr),
- sata_pmp_gscr_rev(gscr),
- nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN],
- gscr[SATA_PMP_GSCR_FEAT]);
+ ata_dev_info(dev, "Port Multiplier %s, "
+ "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n",
+ sata_pmp_spec_rev_str(gscr), vendor, devid,
+ sata_pmp_gscr_rev(gscr),
+ nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN],
+ gscr[SATA_PMP_GSCR_FEAT]);
if (!(dev->flags & ATA_DFLAG_AN))
- ata_dev_printk(dev, KERN_INFO,
+ ata_dev_info(dev,
"Asynchronous notification not supported, "
- "hotplug won't\n work on fan-out "
- "ports. Use warm-plug instead.\n");
+ "hotplug won't work on fan-out ports. Use warm-plug instead.\n");
}
return 0;
fail:
- ata_dev_printk(dev, KERN_ERR,
- "failed to configure Port Multiplier (%s, Emask=0x%x)\n",
- reason, err_mask);
+ ata_dev_err(dev,
+ "failed to configure Port Multiplier (%s, Emask=0x%x)\n",
+ reason, err_mask);
return rc;
}
-static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
+static int sata_pmp_init_links (struct ata_port *ap, int nr_ports)
{
struct ata_link *pmp_link = ap->pmp_link;
- int i;
+ int i, err;
if (!pmp_link) {
pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS,
@@ -311,6 +349,13 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
ata_link_init(ap, &pmp_link[i], i);
ap->pmp_link = pmp_link;
+
+ for (i = 0; i < SATA_PMP_MAX_PORTS; i++) {
+ err = ata_tlink_add(&pmp_link[i]);
+ if (err) {
+ goto err_tlink;
+ }
+ }
}
for (i = 0; i < nr_ports; i++) {
@@ -323,6 +368,12 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
}
return 0;
+ err_tlink:
+ while (--i >= 0)
+ ata_tlink_delete(&pmp_link[i]);
+ kfree(pmp_link);
+ ap->pmp_link = NULL;
+ return err;
}
static void sata_pmp_quirks(struct ata_port *ap)
@@ -332,12 +383,19 @@ static void sata_pmp_quirks(struct ata_port *ap)
u16 devid = sata_pmp_gscr_devid(gscr);
struct ata_link *link;
- if (vendor == 0x1095 && devid == 0x3726) {
- /* sil3726 quirks */
- ata_port_for_each_link(link, ap) {
- /* class code report is unreliable */
+ if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) {
+ /* sil3x26 quirks */
+ ata_for_each_link(link, ap, EDGE) {
+ /* link reports offline after LPM */
+ link->flags |= ATA_LFLAG_NO_LPM;
+
+ /*
+ * Class code report is unreliable and SRST times
+ * out under certain configurations.
+ */
if (link->pmp < 5)
- link->flags |= ATA_LFLAG_ASSUME_ATA;
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
/* port 5 is for SEMB device and it doesn't like SRST */
if (link->pmp == 5)
@@ -345,20 +403,23 @@ static void sata_pmp_quirks(struct ata_port *ap)
ATA_LFLAG_ASSUME_SEMB;
}
} else if (vendor == 0x1095 && devid == 0x4723) {
- /* sil4723 quirks */
- ata_port_for_each_link(link, ap) {
- /* class code report is unreliable */
- if (link->pmp < 2)
- link->flags |= ATA_LFLAG_ASSUME_ATA;
-
- /* the config device at port 2 locks up on SRST */
- if (link->pmp == 2)
- link->flags |= ATA_LFLAG_NO_SRST |
- ATA_LFLAG_ASSUME_ATA;
- }
+ /*
+ * sil4723 quirks
+ *
+ * Link reports offline after LPM. Class code report is
+ * unreliable. SIMG PMPs never got SRST reliable and the
+ * config device at port 2 locks up on SRST.
+ */
+ ata_for_each_link(link, ap, EDGE)
+ link->flags |= ATA_LFLAG_NO_LPM |
+ ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
} else if (vendor == 0x1095 && devid == 0x4726) {
/* sil4726 quirks */
- ata_port_for_each_link(link, ap) {
+ ata_for_each_link(link, ap, EDGE) {
+ /* link reports offline after LPM */
+ link->flags |= ATA_LFLAG_NO_LPM;
+
/* Class code report is unreliable and SRST
* times out under certain configurations.
* Config device can be at port 0 or 5 and
@@ -386,6 +447,19 @@ static void sata_pmp_quirks(struct ata_port *ap)
* otherwise. Don't try hard to recover it.
*/
ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
+ } else if (vendor == 0x197b && (devid == 0x2352 || devid == 0x0325)) {
+ /*
+ * 0x2352: found in Thermaltake BlackX Duet, jmicron JMB350?
+ * 0x0325: jmicron JMB394.
+ */
+ ata_for_each_link(link, ap, EDGE) {
+ /* SRST breaks detection and disks get misclassified
+ * LPM disabled to avoid potential problems
+ */
+ link->flags |= ATA_LFLAG_NO_LPM |
+ ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
+ }
}
}
@@ -412,20 +486,17 @@ int sata_pmp_attach(struct ata_device *dev)
/* is it hanging off the right place? */
if (!sata_pmp_supported(ap)) {
- ata_dev_printk(dev, KERN_ERR,
- "host does not support Port Multiplier\n");
+ ata_dev_err(dev, "host does not support Port Multiplier\n");
return -EINVAL;
}
if (!ata_is_host_link(link)) {
- ata_dev_printk(dev, KERN_ERR,
- "Port Multipliers cannot be nested\n");
+ ata_dev_err(dev, "Port Multipliers cannot be nested\n");
return -EINVAL;
}
if (dev->devno) {
- ata_dev_printk(dev, KERN_ERR,
- "Port Multiplier must be the first device\n");
+ ata_dev_err(dev, "Port Multiplier must be the first device\n");
return -EINVAL;
}
@@ -444,8 +515,7 @@ int sata_pmp_attach(struct ata_device *dev)
rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr));
if (rc) {
- ata_dev_printk(dev, KERN_INFO,
- "failed to initialize PMP links\n");
+ ata_dev_info(dev, "failed to initialize PMP links\n");
goto fail;
}
@@ -460,11 +530,9 @@ int sata_pmp_attach(struct ata_device *dev)
if (ap->ops->pmp_attach)
ap->ops->pmp_attach(ap);
- ata_port_for_each_link(tlink, ap)
+ ata_for_each_link(tlink, ap, EDGE)
sata_link_init_spd(tlink);
- ata_acpi_associate_sata_port(ap);
-
return 0;
fail:
@@ -489,7 +557,7 @@ static void sata_pmp_detach(struct ata_device *dev)
struct ata_link *tlink;
unsigned long flags;
- ata_dev_printk(dev, KERN_INFO, "Port Multiplier detaching\n");
+ ata_dev_info(dev, "Port Multiplier detaching\n");
WARN_ON(!ata_is_host_link(link) || dev->devno ||
link->pmp != SATA_PMP_CTRL_PORT);
@@ -497,15 +565,13 @@ static void sata_pmp_detach(struct ata_device *dev)
if (ap->ops->pmp_detach)
ap->ops->pmp_detach(ap);
- ata_port_for_each_link(tlink, ap)
+ ata_for_each_link(tlink, ap, EDGE)
ata_eh_detach_dev(tlink->device);
spin_lock_irqsave(ap->lock, flags);
ap->nr_pmp_links = 0;
link->pmp = 0;
spin_unlock_irqrestore(ap->lock, flags);
-
- ata_acpi_associate_sata_port(ap);
}
/**
@@ -536,23 +602,23 @@ static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr)
new_nr_ports = sata_pmp_gscr_ports(new_gscr);
if (old_vendor != new_vendor) {
- ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
- "vendor mismatch '0x%x' != '0x%x'\n",
- old_vendor, new_vendor);
+ ata_dev_info(dev,
+ "Port Multiplier vendor mismatch '0x%x' != '0x%x'\n",
+ old_vendor, new_vendor);
return 0;
}
if (old_devid != new_devid) {
- ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
- "device ID mismatch '0x%x' != '0x%x'\n",
- old_devid, new_devid);
+ ata_dev_info(dev,
+ "Port Multiplier device ID mismatch '0x%x' != '0x%x'\n",
+ old_devid, new_devid);
return 0;
}
if (old_nr_ports != new_nr_ports) {
- ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
- "nr_ports mismatch '0x%x' != '0x%x'\n",
- old_nr_ports, new_nr_ports);
+ ata_dev_info(dev,
+ "Port Multiplier nr_ports mismatch '0x%x' != '0x%x'\n",
+ old_nr_ports, new_nr_ports);
return 0;
}
@@ -618,8 +684,7 @@ static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class)
return 0;
fail:
- ata_dev_printk(dev, KERN_ERR,
- "PMP revalidation failed (errno=%d)\n", rc);
+ ata_dev_err(dev, "PMP revalidation failed (errno=%d)\n", rc);
DPRINTK("EXIT, rc=%d\n", rc);
return rc;
}
@@ -643,13 +708,14 @@ static int sata_pmp_revalidate_quick(struct ata_device *dev)
err_mask = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id);
if (err_mask) {
- ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID "
- "(Emask=0x%x)\n", err_mask);
+ ata_dev_err(dev,
+ "failed to read PMP product ID (Emask=0x%x)\n",
+ err_mask);
return -EIO;
}
if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) {
- ata_dev_printk(dev, KERN_ERR, "PMP product ID mismatch\n");
+ ata_dev_err(dev, "PMP product ID mismatch\n");
/* something weird is going on, request full PMP recovery */
return -EIO;
}
@@ -700,21 +766,16 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
if (ehc->i.action & ATA_EH_RESET) {
struct ata_link *tlink;
- ata_eh_freeze_port(ap);
-
/* reset */
rc = ata_eh_reset(link, 0, prereset, softreset, hardreset,
postreset);
if (rc) {
- ata_link_printk(link, KERN_ERR,
- "failed to reset PMP, giving up\n");
+ ata_link_err(link, "failed to reset PMP, giving up\n");
goto fail;
}
- ata_eh_thaw_port(ap);
-
/* PMP is reset, SErrors cannot be trusted, scan all */
- ata_port_for_each_link(tlink, ap) {
+ ata_for_each_link(tlink, ap, EDGE) {
struct ata_eh_context *ehc = &tlink->eh_context;
ehc->i.probe_mask |= ATA_ALL_DEVICES;
@@ -741,25 +802,18 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
}
if (tries) {
- int sleep = ehc->i.flags & ATA_EHI_DID_RESET;
-
/* consecutive revalidation failures? speed down */
if (reval_failed)
- sata_down_spd_limit(link);
+ sata_down_spd_limit(link, 0);
else
reval_failed = 1;
- ata_dev_printk(dev, KERN_WARNING,
- "retrying reset%s\n",
- sleep ? " in 5 secs" : "");
- if (sleep)
- ssleep(5);
ehc->i.action |= ATA_EH_RESET;
goto retry;
} else {
- ata_dev_printk(dev, KERN_ERR, "failed to recover PMP "
- "after %d tries, giving up\n",
- ATA_EH_PMP_TRIES);
+ ata_dev_err(dev,
+ "failed to recover PMP after %d tries, giving up\n",
+ ATA_EH_PMP_TRIES);
goto fail;
}
}
@@ -789,7 +843,7 @@ static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap)
spin_lock_irqsave(ap->lock, flags);
- ata_port_for_each_link(link, ap) {
+ ata_for_each_link(link, ap, EDGE) {
if (!(link->flags & ATA_LFLAG_DISABLED))
continue;
@@ -799,13 +853,15 @@ static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap)
* SError.N working.
*/
sata_link_hardreset(link, sata_deb_timing_normal,
- jiffies + ATA_TMOUT_INTERNAL_QUICK, NULL, NULL);
+ ata_deadline(jiffies, ATA_TMOUT_INTERNAL_QUICK),
+ NULL, NULL);
/* unconditionally clear SError.N */
rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
if (rc) {
- ata_link_printk(link, KERN_ERR, "failed to clear "
- "SError.N (errno=%d)\n", rc);
+ ata_link_err(link,
+ "failed to clear SError.N (errno=%d)\n",
+ rc);
return rc;
}
@@ -827,7 +883,7 @@ static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries)
/* disable this link */
if (!(link->flags & ATA_LFLAG_DISABLED)) {
- ata_link_printk(link, KERN_WARNING,
+ ata_link_warn(link,
"failed to recover link after %d tries, disabling\n",
ATA_EH_PMP_LINK_TRIES);
@@ -864,6 +920,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
struct ata_link *pmp_link = &ap->link;
struct ata_device *pmp_dev = pmp_link->device;
struct ata_eh_context *pmp_ehc = &pmp_link->eh_context;
+ u32 *gscr = pmp_dev->gscr;
struct ata_link *link;
struct ata_device *dev;
unsigned int err_mask;
@@ -871,7 +928,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
int cnt, rc;
pmp_tries = ATA_EH_PMP_TRIES;
- ata_port_for_each_link(link, ap)
+ ata_for_each_link(link, ap, EDGE)
link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
retry:
@@ -880,7 +937,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
rc = ata_eh_recover(ap, ops->prereset, ops->softreset,
ops->hardreset, ops->postreset, NULL);
if (rc) {
- ata_link_for_each_dev(dev, &ap->link)
+ ata_for_each_dev(dev, &ap->link, ALL)
ata_dev_disable(dev);
return rc;
}
@@ -889,7 +946,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
return 0;
/* new PMP online */
- ata_port_for_each_link(link, ap)
+ ata_for_each_link(link, ap, EDGE)
link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
/* fall through */
@@ -901,6 +958,22 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
if (rc)
goto pmp_fail;
+ /* PHY event notification can disturb reset and other recovery
+ * operations. Turn it off.
+ */
+ if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
+ gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
+
+ err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN,
+ gscr[SATA_PMP_GSCR_FEAT_EN]);
+ if (err_mask) {
+ ata_link_warn(pmp_link,
+ "failed to disable NOTIFY (err_mask=0x%x)\n",
+ err_mask);
+ goto pmp_fail;
+ }
+ }
+
/* handle disabled links */
rc = sata_pmp_eh_handle_disabled_links(ap);
if (rc)
@@ -912,24 +985,35 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
if (rc)
goto link_fail;
- /* Connection status might have changed while resetting other
- * links, check SATA_PMP_GSCR_ERROR before returning.
- */
-
/* clear SNotification */
rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
if (rc == 0)
sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+ /*
+ * If LPM is active on any fan-out port, hotplug wouldn't
+ * work. Return w/ PHY event notification disabled.
+ */
+ ata_for_each_link(link, ap, EDGE)
+ if (link->lpm_policy > ATA_LPM_MAX_POWER)
+ return 0;
+
+ /*
+ * Connection status might have changed while resetting other
+ * links, enable notification and check SATA_PMP_GSCR_ERROR
+ * before returning.
+ */
+
/* enable notification */
if (pmp_dev->flags & ATA_DFLAG_AN) {
- pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
+ gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
- err_mask = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN,
- pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]);
+ err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN,
+ gscr[SATA_PMP_GSCR_FEAT_EN]);
if (err_mask) {
- ata_dev_printk(pmp_dev, KERN_ERR, "failed to write "
- "PMP_FEAT_EN (Emask=0x%x)\n", err_mask);
+ ata_dev_err(pmp_dev,
+ "failed to write PMP_FEAT_EN (Emask=0x%x)\n",
+ err_mask);
rc = -EIO;
goto pmp_fail;
}
@@ -938,14 +1022,15 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
/* check GSCR_ERROR */
err_mask = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error);
if (err_mask) {
- ata_dev_printk(pmp_dev, KERN_ERR, "failed to read "
- "PMP_GSCR_ERROR (Emask=0x%x)\n", err_mask);
+ ata_dev_err(pmp_dev,
+ "failed to read PMP_GSCR_ERROR (Emask=0x%x)\n",
+ err_mask);
rc = -EIO;
goto pmp_fail;
}
cnt = 0;
- ata_port_for_each_link(link, ap) {
+ ata_for_each_link(link, ap, EDGE) {
if (!(gscr_error & (1 << link->pmp)))
continue;
@@ -953,17 +1038,16 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
ata_ehi_hotplugged(&link->eh_context.i);
cnt++;
} else {
- ata_link_printk(link, KERN_WARNING,
- "PHY status changed but maxed out on retries, "
- "giving up\n");
- ata_link_printk(link, KERN_WARNING,
- "Manully issue scan to resume this link\n");
+ ata_link_warn(link,
+ "PHY status changed but maxed out on retries, giving up\n");
+ ata_link_warn(link,
+ "Manually issue scan to resume this link\n");
}
}
if (cnt) {
- ata_port_printk(ap, KERN_INFO, "PMP SError.N set for some "
- "ports, repeating recovery\n");
+ ata_port_info(ap,
+ "PMP SError.N set for some ports, repeating recovery\n");
goto retry;
}
@@ -987,16 +1071,12 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
goto retry;
if (--pmp_tries) {
- ata_port_printk(ap, KERN_WARNING,
- "failed to recover PMP, retrying in 5 secs\n");
pmp_ehc->i.action |= ATA_EH_RESET;
- ssleep(5);
goto retry;
}
- ata_port_printk(ap, KERN_ERR,
- "failed to recover PMP after %d tries, giving up\n",
- ATA_EH_PMP_TRIES);
+ ata_port_err(ap, "failed to recover PMP after %d tries, giving up\n",
+ ATA_EH_PMP_TRIES);
sata_pmp_detach(pmp_dev);
ata_dev_disable(pmp_dev);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index a34f32442ed..72691fd9394 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1,7 +1,7 @@
/*
* libata-scsi.c - helper library for ATA
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -33,9 +33,11 @@
*
*/
+#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/blkdev.h>
#include <linux/spinlock.h>
+#include <linux/export.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
@@ -46,10 +48,16 @@
#include <linux/libata.h>
#include <linux/hdreg.h>
#include <linux/uaccess.h>
+#include <linux/suspend.h>
+#include <asm/unaligned.h>
#include "libata.h"
+#include "libata-transport.h"
-#define SECTOR_SIZE 512
+#define ATA_SCSI_RBUF_SIZE 4096
+
+static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
+static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE];
typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc);
@@ -57,9 +65,6 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
const struct scsi_device *scsidev);
static struct ata_device *ata_scsi_find_dev(struct ata_port *ap,
const struct scsi_device *scsidev);
-static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
- unsigned int id, unsigned int lun);
-
#define RW_RECOVERY_MPAGE 0x1
#define RW_RECOVERY_MPAGE_LEN 12
@@ -99,92 +104,270 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
0, 30 /* extended self test time, see 05-359r1 */
};
-/*
- * libata transport template. libata doesn't do real transport stuff.
- * It just needs the eh_timed_out hook.
- */
-static struct scsi_transport_template ata_scsi_transport_template = {
- .eh_strategy_handler = ata_scsi_error,
- .eh_timed_out = ata_scsi_timed_out,
- .user_scan = ata_scsi_user_scan,
+static const char *ata_lpm_policy_names[] = {
+ [ATA_LPM_UNKNOWN] = "max_performance",
+ [ATA_LPM_MAX_POWER] = "max_performance",
+ [ATA_LPM_MED_POWER] = "medium_power",
+ [ATA_LPM_MIN_POWER] = "min_power",
};
+static ssize_t ata_scsi_lpm_store(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(device);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ata_link *link;
+ struct ata_device *dev;
+ enum ata_lpm_policy policy;
+ unsigned long flags;
-static const struct {
- enum link_pm value;
- const char *name;
-} link_pm_policy[] = {
- { NOT_AVAILABLE, "max_performance" },
- { MIN_POWER, "min_power" },
- { MAX_PERFORMANCE, "max_performance" },
- { MEDIUM_POWER, "medium_power" },
-};
+ /* UNKNOWN is internal state, iterate from MAX_POWER */
+ for (policy = ATA_LPM_MAX_POWER;
+ policy < ARRAY_SIZE(ata_lpm_policy_names); policy++) {
+ const char *name = ata_lpm_policy_names[policy];
-static const char *ata_scsi_lpm_get(enum link_pm policy)
-{
- int i;
+ if (strncmp(name, buf, strlen(name)) == 0)
+ break;
+ }
+ if (policy == ARRAY_SIZE(ata_lpm_policy_names))
+ return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(link_pm_policy); i++)
- if (link_pm_policy[i].value == policy)
- return link_pm_policy[i].name;
+ spin_lock_irqsave(ap->lock, flags);
- return NULL;
+ ata_for_each_link(link, ap, EDGE) {
+ ata_for_each_dev(dev, &ap->link, ENABLED) {
+ if (dev->horkage & ATA_HORKAGE_NOLPM) {
+ count = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ }
+ }
+
+ ap->target_lpm_policy = policy;
+ ata_port_schedule_eh(ap);
+out_unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
+ return count;
}
-static ssize_t ata_scsi_lpm_put(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t ata_scsi_lpm_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
- enum link_pm policy = 0;
- int i;
- /*
- * we are skipping array location 0 on purpose - this
- * is because a value of NOT_AVAILABLE is displayed
- * to the user as max_performance, but when the user
- * writes "max_performance", they actually want the
- * value to match MAX_PERFORMANCE.
- */
- for (i = 1; i < ARRAY_SIZE(link_pm_policy); i++) {
- const int len = strlen(link_pm_policy[i].name);
- if (strncmp(link_pm_policy[i].name, buf, len) == 0 &&
- buf[len] == '\n') {
- policy = link_pm_policy[i].value;
+ if (ap->target_lpm_policy >= ARRAY_SIZE(ata_lpm_policy_names))
+ return -EINVAL;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ ata_lpm_policy_names[ap->target_lpm_policy]);
+}
+DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
+ ata_scsi_lpm_show, ata_scsi_lpm_store);
+EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
+
+static ssize_t ata_scsi_park_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(device);
+ struct ata_port *ap;
+ struct ata_link *link;
+ struct ata_device *dev;
+ unsigned long flags, now;
+ unsigned int uninitialized_var(msecs);
+ int rc = 0;
+
+ ap = ata_shost_to_port(sdev->host);
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev = ata_scsi_find_dev(ap, sdev);
+ if (!dev) {
+ rc = -ENODEV;
+ goto unlock;
+ }
+ if (dev->flags & ATA_DFLAG_NO_UNLOAD) {
+ rc = -EOPNOTSUPP;
+ goto unlock;
+ }
+
+ link = dev->link;
+ now = jiffies;
+ if (ap->pflags & ATA_PFLAG_EH_IN_PROGRESS &&
+ link->eh_context.unloaded_mask & (1 << dev->devno) &&
+ time_after(dev->unpark_deadline, now))
+ msecs = jiffies_to_msecs(dev->unpark_deadline - now);
+ else
+ msecs = 0;
+
+unlock:
+ spin_unlock_irq(ap->lock);
+
+ return rc ? rc : snprintf(buf, 20, "%u\n", msecs);
+}
+
+static ssize_t ata_scsi_park_store(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct scsi_device *sdev = to_scsi_device(device);
+ struct ata_port *ap;
+ struct ata_device *dev;
+ long int input;
+ unsigned long flags;
+ int rc;
+
+ rc = kstrtol(buf, 10, &input);
+ if (rc)
+ return rc;
+ if (input < -2)
+ return -EINVAL;
+ if (input > ATA_TMOUT_MAX_PARK) {
+ rc = -EOVERFLOW;
+ input = ATA_TMOUT_MAX_PARK;
+ }
+
+ ap = ata_shost_to_port(sdev->host);
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev = ata_scsi_find_dev(ap, sdev);
+ if (unlikely(!dev)) {
+ rc = -ENODEV;
+ goto unlock;
+ }
+ if (dev->class != ATA_DEV_ATA) {
+ rc = -EOPNOTSUPP;
+ goto unlock;
+ }
+
+ if (input >= 0) {
+ if (dev->flags & ATA_DFLAG_NO_UNLOAD) {
+ rc = -EOPNOTSUPP;
+ goto unlock;
+ }
+
+ dev->unpark_deadline = ata_deadline(jiffies, input);
+ dev->link->eh_info.dev_action[dev->devno] |= ATA_EH_PARK;
+ ata_port_schedule_eh(ap);
+ complete(&ap->park_req_pending);
+ } else {
+ switch (input) {
+ case -1:
+ dev->flags &= ~ATA_DFLAG_NO_UNLOAD;
+ break;
+ case -2:
+ dev->flags |= ATA_DFLAG_NO_UNLOAD;
break;
}
}
- if (!policy)
- return -EINVAL;
+unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
- ata_lpm_schedule(ap, policy);
- return count;
+ return rc ? rc : len;
+}
+DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR,
+ ata_scsi_park_show, ata_scsi_park_store);
+EXPORT_SYMBOL_GPL(dev_attr_unload_heads);
+
+static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
+{
+ cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+ scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq);
}
static ssize_t
-ata_scsi_lpm_show(struct device *dev, struct device_attribute *attr, char *buf)
+ata_scsi_em_message_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
- const char *policy =
- ata_scsi_lpm_get(ap->pm_policy);
+ if (ap->ops->em_store && (ap->flags & ATA_FLAG_EM))
+ return ap->ops->em_store(ap, buf, count);
+ return -EINVAL;
+}
- if (!policy)
- return -EINVAL;
+static ssize_t
+ata_scsi_em_message_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
- return snprintf(buf, 23, "%s\n", policy);
+ if (ap->ops->em_show && (ap->flags & ATA_FLAG_EM))
+ return ap->ops->em_show(ap, buf);
+ return -EINVAL;
}
-DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
- ata_scsi_lpm_show, ata_scsi_lpm_put);
-EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
+DEVICE_ATTR(em_message, S_IRUGO | S_IWUSR,
+ ata_scsi_em_message_show, ata_scsi_em_message_store);
+EXPORT_SYMBOL_GPL(dev_attr_em_message);
+
+static ssize_t
+ata_scsi_em_message_type_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+
+ return snprintf(buf, 23, "%d\n", ap->em_message_type);
+}
+DEVICE_ATTR(em_message_type, S_IRUGO,
+ ata_scsi_em_message_type_show, NULL);
+EXPORT_SYMBOL_GPL(dev_attr_em_message_type);
-static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
+static ssize_t
+ata_scsi_activity_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *atadev = ata_scsi_find_dev(ap, sdev);
+
+ if (atadev && ap->ops->sw_activity_show &&
+ (ap->flags & ATA_FLAG_SW_ACTIVITY))
+ return ap->ops->sw_activity_show(atadev, buf);
+ return -EINVAL;
+}
+
+static ssize_t
+ata_scsi_activity_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *atadev = ata_scsi_find_dev(ap, sdev);
+ enum sw_activity val;
+ int rc;
+
+ if (atadev && ap->ops->sw_activity_store &&
+ (ap->flags & ATA_FLAG_SW_ACTIVITY)) {
+ val = simple_strtoul(buf, NULL, 0);
+ switch (val) {
+ case OFF: case BLINK_ON: case BLINK_OFF:
+ rc = ap->ops->sw_activity_store(atadev, val);
+ if (!rc)
+ return count;
+ else
+ return rc;
+ }
+ }
+ return -EINVAL;
+}
+DEVICE_ATTR(sw_activity, S_IWUSR | S_IRUGO, ata_scsi_activity_show,
+ ata_scsi_activity_store);
+EXPORT_SYMBOL_GPL(dev_attr_sw_activity);
+
+struct device_attribute *ata_common_sdev_attrs[] = {
+ &dev_attr_unload_heads,
+ NULL
+};
+EXPORT_SYMBOL_GPL(ata_common_sdev_attrs);
+
+static void ata_scsi_invalid_field(struct scsi_cmnd *cmd)
{
ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);
/* "Invalid field in cbd" */
- done(cmd);
+ cmd->scsi_done(cmd);
}
/**
@@ -217,7 +400,37 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
}
/**
+ * ata_scsi_unlock_native_capacity - unlock native capacity
+ * @sdev: SCSI device to adjust device capacity for
+ *
+ * This function is called if a partition on @sdev extends beyond
+ * the end of the device. It requests EH to unlock HPA.
+ *
+ * LOCKING:
+ * Defined by the SCSI layer. Might sleep.
+ */
+void ata_scsi_unlock_native_capacity(struct scsi_device *sdev)
+{
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ dev = ata_scsi_find_dev(ap, sdev);
+ if (dev && dev->n_sectors < dev->n_native_sectors) {
+ dev->flags |= ATA_DFLAG_UNLOCK_HPA;
+ dev->link->eh_info.action |= ATA_EH_RESET;
+ ata_port_schedule_eh(ap);
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+ ata_port_wait_eh(ap);
+}
+
+/**
* ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl
+ * @ap: target port
* @sdev: SCSI device to get identify data for
* @arg: User buffer area for identify data
*
@@ -227,9 +440,9 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
* RETURNS:
* Zero on success, negative errno on error.
*/
-static int ata_get_identity(struct scsi_device *sdev, void __user *arg)
+static int ata_get_identity(struct ata_port *ap, struct scsi_device *sdev,
+ void __user *arg)
{
- struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
u16 __user *dst = arg;
char buf[40];
@@ -288,7 +501,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
memset(scsi_cmd, 0, sizeof(scsi_cmd));
if (args[3]) {
- argsize = SECTOR_SIZE * args[3];
+ argsize = ATA_SECT_SIZE * args[3];
argbuf = kmalloc(argsize, GFP_KERNEL);
if (argbuf == NULL) {
rc = -ENOMEM;
@@ -308,7 +521,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
scsi_cmd[0] = ATA_16;
scsi_cmd[4] = args[2];
- if (args[0] == WIN_SMART) { /* hack -- ide driver does this too... */
+ if (args[0] == ATA_CMD_SMART) { /* hack -- ide driver does this too */
scsi_cmd[6] = args[3];
scsi_cmd[8] = args[1];
scsi_cmd[10] = 0x4f;
@@ -321,7 +534,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
/* Good values for timeout and retries? Values below
from scsi_ioctl_send_command() for default case... */
cmd_result = scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, argsize,
- sensebuf, (10*HZ), 5, 0);
+ sensebuf, (10*HZ), 5, 0, NULL);
if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */
u8 *desc = sensebuf + 8;
@@ -333,8 +546,8 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
struct scsi_sense_hdr sshdr;
scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE,
&sshdr);
- if (sshdr.sense_key == 0 &&
- sshdr.asc == 0 && sshdr.ascq == 0)
+ if (sshdr.sense_key == RECOVERED_ERROR &&
+ sshdr.asc == 0 && sshdr.ascq == 0x1d)
cmd_result &= ~SAM_STAT_CHECK_CONDITION;
}
@@ -407,7 +620,7 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
/* Good values for timeout and retries? Values below
from scsi_ioctl_send_command() for default case... */
cmd_result = scsi_execute(scsidev, scsi_cmd, DMA_NONE, NULL, 0,
- sensebuf, (10*HZ), 5, 0);
+ sensebuf, (10*HZ), 5, 0, NULL);
if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */
u8 *desc = sensebuf + 8;
@@ -419,8 +632,8 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
struct scsi_sense_hdr sshdr;
scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE,
&sshdr);
- if (sshdr.sense_key == 0 &&
- sshdr.asc == 0 && sshdr.ascq == 0)
+ if (sshdr.sense_key == RECOVERED_ERROR &&
+ sshdr.asc == 0 && sshdr.ascq == 0x1d)
cmd_result &= ~SAM_STAT_CHECK_CONDITION;
}
@@ -449,25 +662,48 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
return rc;
}
-int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
+static int ata_ioc32(struct ata_port *ap)
+{
+ if (ap->flags & ATA_FLAG_PIO_DMA)
+ return 1;
+ if (ap->pflags & ATA_PFLAG_PIO32)
+ return 1;
+ return 0;
+}
+
+int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev,
+ int cmd, void __user *arg)
{
int val = -EINVAL, rc = -EINVAL;
+ unsigned long flags;
switch (cmd) {
case ATA_IOC_GET_IO32:
- val = 0;
+ spin_lock_irqsave(ap->lock, flags);
+ val = ata_ioc32(ap);
+ spin_unlock_irqrestore(ap->lock, flags);
if (copy_to_user(arg, &val, 1))
return -EFAULT;
return 0;
case ATA_IOC_SET_IO32:
val = (unsigned long) arg;
- if (val != 0)
- return -EINVAL;
- return 0;
+ rc = 0;
+ spin_lock_irqsave(ap->lock, flags);
+ if (ap->pflags & ATA_PFLAG_PIO32CHANGE) {
+ if (val)
+ ap->pflags |= ATA_PFLAG_PIO32;
+ else
+ ap->pflags &= ~ATA_PFLAG_PIO32;
+ } else {
+ if (val != ata_ioc32(ap))
+ rc = -EINVAL;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+ return rc;
case HDIO_GET_IDENTITY:
- return ata_get_identity(scsidev, arg);
+ return ata_get_identity(ap, scsidev, arg);
case HDIO_DRIVE_CMD:
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
@@ -486,12 +722,19 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
return rc;
}
+EXPORT_SYMBOL_GPL(ata_sas_scsi_ioctl);
+
+int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
+{
+ return ata_sas_scsi_ioctl(ata_shost_to_port(scsidev->host),
+ scsidev, cmd, arg);
+}
+EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
/**
* ata_scsi_qc_new - acquire new ata_queued_cmd reference
* @dev: ATA device to which the new command is attached
* @cmd: SCSI command that originated this ATA command
- * @done: SCSI command completion function
*
* Obtain a reference to an unused ata_queued_cmd structure,
* which is the basic libata structure representing a single
@@ -508,21 +751,20 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
* Command allocated, or %NULL if none available.
*/
static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
- struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
+ struct scsi_cmnd *cmd)
{
struct ata_queued_cmd *qc;
qc = ata_qc_new_init(dev);
if (qc) {
qc->scsicmd = cmd;
- qc->scsidone = done;
+ qc->scsidone = cmd->scsi_done;
qc->sg = scsi_sglist(cmd);
qc->n_elem = scsi_sg_count(cmd);
} else {
cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
- done(cmd);
+ cmd->scsi_done(cmd);
}
return qc;
@@ -620,25 +862,24 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
/* Bad address mark */
{0x01, MEDIUM_ERROR, 0x13, 0x00}, // Address mark not found Address mark not found for data field
/* TRK0 */
- {0x02, HARDWARE_ERROR, 0x00, 0x00}, // Track 0 not found Hardware error
- /* Abort & !ICRC */
- {0x04, ABORTED_COMMAND, 0x00, 0x00}, // Aborted command Aborted command
+ {0x02, HARDWARE_ERROR, 0x00, 0x00}, // Track 0 not found Hardware error
+ /* Abort: 0x04 is not translated here, see below */
/* Media change request */
{0x08, NOT_READY, 0x04, 0x00}, // Media change request FIXME: faking offline
- /* SRV */
- {0x10, ABORTED_COMMAND, 0x14, 0x00}, // ID not found Recorded entity not found
- /* Media change */
- {0x08, NOT_READY, 0x04, 0x00}, // Media change FIXME: faking offline
+ /* SRV/IDNF */
+ {0x10, ILLEGAL_REQUEST, 0x21, 0x00}, // ID not found Logical address out of range
+ /* MC */
+ {0x20, UNIT_ATTENTION, 0x28, 0x00}, // Media Changed Not ready to ready change, medium may have changed
/* ECC */
{0x40, MEDIUM_ERROR, 0x11, 0x04}, // Uncorrectable ECC error Unrecovered read error
/* BBD - block marked bad */
- {0x80, MEDIUM_ERROR, 0x11, 0x04}, // Block marked bad Medium error, unrecovered read error
+ {0x80, MEDIUM_ERROR, 0x11, 0x04}, // Block marked bad Medium error, unrecovered read error
{0xFF, 0xFF, 0xFF, 0xFF}, // END mark
};
static const unsigned char stat_table[][4] = {
/* Must be first because BUSY means no other bits valid */
{0x80, ABORTED_COMMAND, 0x47, 0x00}, // Busy, fake parity for now
- {0x20, HARDWARE_ERROR, 0x00, 0x00}, // Device fault
+ {0x20, HARDWARE_ERROR, 0x44, 0x00}, // Device fault, internal target failure
{0x08, ABORTED_COMMAND, 0x47, 0x00}, // Timed out in xfer, fake parity for now
{0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered
{0xFF, 0xFF, 0xFF, 0xFF}, // END mark
@@ -663,13 +904,13 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
goto translate_done;
}
}
- /* No immediate match */
- if (verbose)
- printk(KERN_WARNING "ata%u: no sense translation for "
- "error 0x%02x\n", id, drv_err);
}
- /* Fall back to interpreting status bits */
+ /*
+ * Fall back to interpreting status bits. Note that if the drv_err
+ * has only the ABRT bit set, we decode drv_stat. ABRT by itself
+ * is not descriptive enough.
+ */
for (i = 0; stat_table[i][0] != 0xFF; i++) {
if (stat_table[i][0] & drv_stat) {
*sk = stat_table[i][1];
@@ -678,13 +919,11 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
goto translate_done;
}
}
- /* No error? Undecoded? */
- if (verbose)
- printk(KERN_WARNING "ata%u: no sense translation for "
- "status: 0x%02x\n", id, drv_stat);
- /* We need a sensible error return here, which is tricky, and one
- that won't cause people to do things like return a disk wrongly */
+ /*
+ * We need a sensible error return here, which is tricky, and one
+ * that won't cause people to do things like return a disk wrongly.
+ */
*sk = ABORTED_COMMAND;
*asc = 0x00;
*ascq = 0x00;
@@ -705,7 +944,11 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
* block specified for the ATA pass through commands. Regardless
* of whether the command errored or not, return a sense
* block. Copy all controller registers into the sense
- * block. Clear sense key, ASC & ASCQ if there is no error.
+ * block. If there was no error, we get the request from an ATA
+ * passthrough command, so we use the following sense data:
+ * sk = RECOVERED ERROR
+ * asc,ascq = ATA PASS-THROUGH INFORMATION AVAILABLE
+ *
*
* LOCKING:
* None.
@@ -731,6 +974,10 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc)
ata_to_sense_error(qc->ap->print_id, tf->command, tf->feature,
&sb[1], &sb[2], &sb[3], verbose);
sb[1] &= 0x0f;
+ } else {
+ sb[1] = RECOVERED_ERROR;
+ sb[2] = 0;
+ sb[3] = 0x1D;
}
/*
@@ -774,7 +1021,7 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc)
* @qc: Command that we are erroring out
*
* Generate sense block for a failed ATA command @qc. Descriptor
- * format is used to accomodate LBA48 block address.
+ * format is used to accommodate LBA48 block address.
*
* LOCKING:
* None.
@@ -826,6 +1073,8 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
{
sdev->use_10_for_rw = 1;
sdev->use_10_for_ms = 1;
+ sdev->no_report_opcodes = 1;
+ sdev->no_write_same = 1;
/* Schedule policy is determined by ->qc_defer() callback and
* it needs to see every deferred qc. Set dev_blocked to 1 to
@@ -852,10 +1101,10 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
*/
static int atapi_drain_needed(struct request *rq)
{
- if (likely(!blk_pc_request(rq)))
+ if (likely(rq->cmd_type != REQ_TYPE_BLOCK_PC))
return 0;
- if (!rq->data_len || (rq->cmd_flags & REQ_RW))
+ if (!blk_rq_bytes(rq) || (rq->cmd_flags & REQ_WRITE))
return 0;
return atapi_cmd_type(rq->cmd[0]) == ATAPI_MISC;
@@ -864,34 +1113,49 @@ static int atapi_drain_needed(struct request *rq)
static int ata_scsi_dev_config(struct scsi_device *sdev,
struct ata_device *dev)
{
+ struct request_queue *q = sdev->request_queue;
+
+ if (!ata_id_has_unload(dev->id))
+ dev->flags |= ATA_DFLAG_NO_UNLOAD;
+
/* configure max sectors */
- blk_queue_max_sectors(sdev->request_queue, dev->max_sectors);
+ blk_queue_max_hw_sectors(q, dev->max_sectors);
if (dev->class == ATA_DEV_ATAPI) {
- struct request_queue *q = sdev->request_queue;
void *buf;
- /* set the min alignment and padding */
- blk_queue_update_dma_alignment(sdev->request_queue,
- ATA_DMA_PAD_SZ - 1);
- blk_queue_dma_pad(sdev->request_queue, ATA_DMA_PAD_SZ - 1);
+ sdev->sector_size = ATA_SECT_SIZE;
+
+ /* set DMA padding */
+ blk_queue_update_dma_pad(q, ATA_DMA_PAD_SZ - 1);
/* configure draining */
buf = kmalloc(ATAPI_MAX_DRAIN, q->bounce_gfp | GFP_KERNEL);
if (!buf) {
- ata_dev_printk(dev, KERN_ERR,
- "drain buffer allocation failed\n");
+ ata_dev_err(dev, "drain buffer allocation failed\n");
return -ENOMEM;
}
blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
} else {
- /* ATA devices must be sector aligned */
- blk_queue_update_dma_alignment(sdev->request_queue,
- ATA_SECT_SIZE - 1);
+ sdev->sector_size = ata_id_logical_sector_size(dev->id);
sdev->manage_start_stop = 1;
}
+ /*
+ * ata_pio_sectors() expects buffer for each sector to not cross
+ * page boundary. Enforce it by requiring buffers to be sector
+ * aligned, which works iff sector_size is not larger than
+ * PAGE_SIZE. ATAPI devices also need the alignment as
+ * IDENTIFY_PACKET is executed as ATA_PROT_PIO.
+ */
+ if (sdev->sector_size > PAGE_SIZE)
+ ata_dev_warn(dev,
+ "sector_size=%u > PAGE_SIZE, PIO may malfunction\n",
+ sdev->sector_size);
+
+ blk_queue_update_dma_alignment(q, sdev->sector_size - 1);
+
if (dev->flags & ATA_DFLAG_AN)
set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events);
@@ -903,6 +1167,9 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
}
+ blk_queue_flush_queueable(q, false);
+
+ dev->sdev = sdev;
return 0;
}
@@ -972,26 +1239,25 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev)
}
/**
- * ata_scsi_change_queue_depth - SCSI callback for queue depth config
+ * __ata_change_queue_depth - helper for ata_scsi_change_queue_depth
+ * @ap: ATA port to which the device change the queue depth
* @sdev: SCSI device to configure queue depth for
* @queue_depth: new queue depth
+ * @reason: calling context
*
- * This is libata standard hostt->change_queue_depth callback.
- * SCSI will call into this callback when user tries to set queue
- * depth via sysfs.
- *
- * LOCKING:
- * SCSI layer (we don't care)
+ * libsas and libata have different approaches for associating a sdev to
+ * its ata_port.
*
- * RETURNS:
- * Newly configured queue depth.
*/
-int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
+ int queue_depth, int reason)
{
- struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev;
unsigned long flags;
+ if (reason != SCSI_QDEPTH_DEFAULT)
+ return -EOPNOTSUPP;
+
if (queue_depth < 1 || queue_depth == sdev->queue_depth)
return sdev->queue_depth;
@@ -1020,21 +1286,28 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
return queue_depth;
}
-/* XXX: for spindown warning */
-static void ata_delayed_done_timerfn(unsigned long arg)
-{
- struct scsi_cmnd *scmd = (void *)arg;
-
- scmd->scsi_done(scmd);
-}
-
-/* XXX: for spindown warning */
-static void ata_delayed_done(struct scsi_cmnd *scmd)
+/**
+ * ata_scsi_change_queue_depth - SCSI callback for queue depth config
+ * @sdev: SCSI device to configure queue depth for
+ * @queue_depth: new queue depth
+ * @reason: calling context
+ *
+ * This is libata standard hostt->change_queue_depth callback.
+ * SCSI will call into this callback when user tries to set queue
+ * depth via sysfs.
+ *
+ * LOCKING:
+ * SCSI layer (we don't care)
+ *
+ * RETURNS:
+ * Newly configured queue depth.
+ */
+int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth,
+ int reason)
{
- static struct timer_list timer;
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
- setup_timer(&timer, ata_delayed_done_timerfn, (unsigned long)scmd);
- mod_timer(&timer, jiffies + 5 * HZ);
+ return __ata_change_queue_depth(ap, sdev, queue_depth, reason);
}
/**
@@ -1071,12 +1344,6 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
if (((cdb[4] >> 4) & 0xf) != 0)
goto invalid_fld; /* power conditions not supported */
- if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) {
- /* the device lacks PM support, finish without doing anything */
- scmd->result = SAM_STAT_GOOD;
- return 1;
- }
-
if (cdb[4] & 0x1) {
tf->nsect = 1; /* 1 sector, lba=0 */
@@ -1096,32 +1363,16 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
tf->command = ATA_CMD_VERIFY; /* READ VERIFY */
} else {
- /* XXX: This is for backward compatibility, will be
- * removed. Read Documentation/feature-removal-schedule.txt
- * for more info.
+ /* Some odd clown BIOSen issue spindown on power off (ACPI S4
+ * or S5) causing some drives to spin up and down again.
*/
- if ((qc->dev->flags & ATA_DFLAG_SPUNDOWN) &&
- (system_state == SYSTEM_HALT ||
- system_state == SYSTEM_POWER_OFF)) {
- static unsigned long warned;
-
- if (!test_and_set_bit(0, &warned)) {
- ata_dev_printk(qc->dev, KERN_WARNING,
- "DISK MIGHT NOT BE SPUN DOWN PROPERLY. "
- "UPDATE SHUTDOWN UTILITY\n");
- ata_dev_printk(qc->dev, KERN_WARNING,
- "For more info, visit "
- "http://linux-ata.org/shutdown.html\n");
-
- /* ->scsi_done is not used, use it for
- * delayed completion.
- */
- scmd->scsi_done = qc->scsidone;
- qc->scsidone = ata_delayed_done;
- }
- scmd->result = SAM_STAT_GOOD;
- return 1;
- }
+ if ((qc->ap->flags & ATA_FLAG_NO_POWEROFF_SPINDOWN) &&
+ system_state == SYSTEM_POWER_OFF)
+ goto skip;
+
+ if ((qc->ap->flags & ATA_FLAG_NO_HIBERNATE_SPINDOWN) &&
+ system_entering_hibernation())
+ goto skip;
/* Issue ATA STANDBY IMMEDIATE command */
tf->command = ATA_CMD_STANDBYNOW1;
@@ -1136,10 +1387,13 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
return 0;
-invalid_fld:
+ invalid_fld:
ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0);
/* "Invalid field in cbd" */
return 1;
+ skip:
+ scmd->result = SAM_STAT_GOOD;
+ return 1;
}
@@ -1424,7 +1678,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
if (unlikely(scmd->cmd_len < 10))
goto invalid_fld;
scsi_10_lba_len(cdb, &block, &n_block);
- if (unlikely(cdb[1] & (1 << 3)))
+ if (cdb[1] & (1 << 3))
tf_flags |= ATA_TFLAG_FUA;
break;
case READ_6:
@@ -1444,7 +1698,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
if (unlikely(scmd->cmd_len < 16))
goto invalid_fld;
scsi_16_lba_len(cdb, &block, &n_block);
- if (unlikely(cdb[1] & (1 << 3)))
+ if (cdb[1] & (1 << 3))
tf_flags |= ATA_TFLAG_FUA;
break;
default:
@@ -1464,7 +1718,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
goto nothing_to_do;
qc->flags |= ATA_QCFLAG_IO;
- qc->nbytes = n_block * ATA_SECT_SIZE;
+ qc->nbytes = n_block * scmd->device->sector_size;
rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags,
qc->tag);
@@ -1498,10 +1752,12 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
/* For ATA pass thru (SAT) commands, generate a sense block if
* user mandated it or if there's an error. Note that if we
- * generate because the user forced us to, a check condition
- * is generated and the ATA register values are returned
+ * generate because the user forced us to [CK_COND =1], a check
+ * condition is generated and the ATA register values are returned
* whether the command completed successfully or not. If there
- * was no error, SK, ASC and ASCQ will all be zero.
+ * was no error, we use the following sense data:
+ * sk = RECOVERED ERROR
+ * asc,ascq = ATA PASS-THROUGH INFORMATION AVAILABLE
*/
if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
((cdb[2] & 0x20) || need_sense)) {
@@ -1520,14 +1776,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
}
}
- /* XXX: track spindown state for spindown skipping and warning */
- if (unlikely(qc->tf.command == ATA_CMD_STANDBY ||
- qc->tf.command == ATA_CMD_STANDBYNOW1))
- qc->dev->flags |= ATA_DFLAG_SPUNDOWN;
- else if (likely(system_state != SYSTEM_HALT &&
- system_state != SYSTEM_POWER_OFF))
- qc->dev->flags &= ~ATA_DFLAG_SPUNDOWN;
-
if (need_sense && !ap->ops->error_handler)
ata_dump_status(ap->print_id, &qc->result_tf);
@@ -1540,7 +1788,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
* ata_scsi_translate - Translate then issue SCSI command to ATA device
* @dev: ATA device to which the command is addressed
* @cmd: SCSI command to execute
- * @done: SCSI command completion function
* @xlat_func: Actor which translates @cmd to an ATA taskfile
*
* Our ->queuecommand() function has decided that the SCSI
@@ -1564,7 +1811,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
* needs to be deferred.
*/
static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *),
ata_xlat_func_t xlat_func)
{
struct ata_port *ap = dev->link->ap;
@@ -1573,7 +1819,7 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
VPRINTK("ENTER\n");
- qc = ata_scsi_qc_new(dev, cmd, done);
+ qc = ata_scsi_qc_new(dev, cmd);
if (!qc)
goto err_mem;
@@ -1581,8 +1827,7 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
cmd->sc_data_direction == DMA_TO_DEVICE) {
if (unlikely(scsi_bufflen(cmd) < 1)) {
- ata_dev_printk(dev, KERN_WARNING,
- "WARNING: zero len r/w req\n");
+ ata_dev_warn(dev, "WARNING: zero len r/w req\n");
goto err_did;
}
@@ -1609,14 +1854,14 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
early_finish:
ata_qc_free(qc);
- qc->scsidone(cmd);
+ cmd->scsi_done(cmd);
DPRINTK("EXIT - early finish (good or error)\n");
return 0;
err_did:
ata_qc_free(qc);
cmd->result = (DID_ERROR << 16);
- qc->scsidone(cmd);
+ cmd->scsi_done(cmd);
err_mem:
DPRINTK("EXIT - internal\n");
return 0;
@@ -1633,52 +1878,48 @@ defer:
/**
* ata_scsi_rbuf_get - Map response buffer.
* @cmd: SCSI command containing buffer to be mapped.
- * @buf_out: Pointer to mapped area.
+ * @flags: unsigned long variable to store irq enable status
+ * @copy_in: copy in from user buffer
*
- * Maps buffer contained within SCSI command @cmd.
+ * Prepare buffer for simulated SCSI commands.
*
* LOCKING:
- * spin_lock_irqsave(host lock)
+ * spin_lock_irqsave(ata_scsi_rbuf_lock) on success
*
* RETURNS:
- * Length of response buffer.
+ * Pointer to response buffer.
*/
-
-static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
+static void *ata_scsi_rbuf_get(struct scsi_cmnd *cmd, bool copy_in,
+ unsigned long *flags)
{
- u8 *buf;
- unsigned int buflen;
-
- struct scatterlist *sg = scsi_sglist(cmd);
-
- if (sg) {
- buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
- buflen = sg->length;
- } else {
- buf = NULL;
- buflen = 0;
- }
+ spin_lock_irqsave(&ata_scsi_rbuf_lock, *flags);
- *buf_out = buf;
- return buflen;
+ memset(ata_scsi_rbuf, 0, ATA_SCSI_RBUF_SIZE);
+ if (copy_in)
+ sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
+ ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE);
+ return ata_scsi_rbuf;
}
/**
* ata_scsi_rbuf_put - Unmap response buffer.
* @cmd: SCSI command containing buffer to be unmapped.
- * @buf: buffer to unmap
+ * @copy_out: copy out result
+ * @flags: @flags passed to ata_scsi_rbuf_get()
*
- * Unmaps response buffer contained within @cmd.
+ * Returns rbuf buffer. The result is copied to @cmd's buffer if
+ * @copy_back is true.
*
* LOCKING:
- * spin_lock_irqsave(host lock)
+ * Unlocks ata_scsi_rbuf_lock.
*/
-
-static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
+static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, bool copy_out,
+ unsigned long *flags)
{
- struct scatterlist *sg = scsi_sglist(cmd);
- if (sg)
- kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ if (copy_out)
+ sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
+ ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE);
+ spin_unlock_irqrestore(&ata_scsi_rbuf_lock, *flags);
}
/**
@@ -1696,24 +1937,17 @@ static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
- unsigned int (*actor) (struct ata_scsi_args *args,
- u8 *rbuf, unsigned int buflen))
+static void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
+ unsigned int (*actor)(struct ata_scsi_args *args, u8 *rbuf))
{
u8 *rbuf;
- unsigned int buflen, rc;
+ unsigned int rc;
struct scsi_cmnd *cmd = args->cmd;
unsigned long flags;
- local_irq_save(flags);
-
- buflen = ata_scsi_rbuf_get(cmd, &rbuf);
- memset(rbuf, 0, buflen);
- rc = actor(args, rbuf, buflen);
- ata_scsi_rbuf_put(cmd, rbuf);
-
- local_irq_restore(flags);
+ rbuf = ata_scsi_rbuf_get(cmd, false, &flags);
+ rc = actor(args, rbuf);
+ ata_scsi_rbuf_put(cmd, rc == 0, &flags);
if (rc == 0)
cmd->result = SAM_STAT_GOOD;
@@ -1721,26 +1955,9 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
}
/**
- * ATA_SCSI_RBUF_SET - helper to set values in SCSI response buffer
- * @idx: byte index into SCSI response buffer
- * @val: value to set
- *
- * To be used by SCSI command simulator functions. This macros
- * expects two local variables, u8 *rbuf and unsigned int buflen,
- * are in scope.
- *
- * LOCKING:
- * None.
- */
-#define ATA_SCSI_RBUF_SET(idx, val) do { \
- if ((idx) < buflen) rbuf[(idx)] = (u8)(val); \
- } while (0)
-
-/**
* ata_scsiop_inq_std - Simulate INQUIRY command
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Returns standard device identification data associated
* with non-VPD INQUIRY command output.
@@ -1748,10 +1965,17 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
{
+ const u8 versions[] = {
+ 0x60, /* SAM-3 (no version claimed) */
+
+ 0x03,
+ 0x20, /* SBC-2 (no version claimed) */
+
+ 0x02,
+ 0x60 /* SPC-3 (no version claimed) */
+ };
u8 hdr[] = {
TYPE_DISK,
0,
@@ -1760,35 +1984,25 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
95 - 4
};
+ VPRINTK("ENTER\n");
+
/* set scsi removeable (RMB) bit per ata bit */
if (ata_id_removeable(args->id))
hdr[1] |= (1 << 7);
- VPRINTK("ENTER\n");
-
memcpy(rbuf, hdr, sizeof(hdr));
+ memcpy(&rbuf[8], "ATA ", 8);
+ ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16);
- if (buflen > 35) {
- memcpy(&rbuf[8], "ATA ", 8);
- ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16);
+ /* From SAT, use last 2 words from fw rev unless they are spaces */
+ ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV + 2, 4);
+ if (strncmp(&rbuf[32], " ", 4) == 0)
ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);
- if (rbuf[32] == 0 || rbuf[32] == ' ')
- memcpy(&rbuf[32], "n/a ", 4);
- }
-
- if (buflen > 63) {
- const u8 versions[] = {
- 0x60, /* SAM-3 (no version claimed) */
- 0x03,
- 0x20, /* SBC-2 (no version claimed) */
+ if (rbuf[32] == 0 || rbuf[32] == ' ')
+ memcpy(&rbuf[32], "n/a ", 4);
- 0x02,
- 0x60 /* SPC-3 (no version claimed) */
- };
-
- memcpy(rbuf + 59, versions, sizeof(versions));
- }
+ memcpy(rbuf + 59, versions, sizeof(versions));
return 0;
}
@@ -1797,27 +2011,26 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
* ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Returns list of inquiry VPD pages available.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)
{
const u8 pages[] = {
0x00, /* page 0x00, this page */
0x80, /* page 0x80, unit serial no page */
- 0x83 /* page 0x83, device ident page */
+ 0x83, /* page 0x83, device ident page */
+ 0x89, /* page 0x89, ata info page */
+ 0xb0, /* page 0xb0, block limits page */
+ 0xb1, /* page 0xb1, block device characteristics page */
+ 0xb2, /* page 0xb2, thin provisioning page */
};
- rbuf[3] = sizeof(pages); /* number of supported VPD pages */
-
- if (buflen > 6)
- memcpy(rbuf + 4, pages, sizeof(pages));
+ rbuf[3] = sizeof(pages); /* number of supported VPD pages */
+ memcpy(rbuf + 4, pages, sizeof(pages));
return 0;
}
@@ -1825,16 +2038,13 @@ unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
* ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Returns ATA device serial number.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf)
{
const u8 hdr[] = {
0,
@@ -1842,12 +2052,10 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
0,
ATA_ID_SERNO_LEN, /* page len */
};
- memcpy(rbuf, hdr, sizeof(hdr));
-
- if (buflen > (ATA_ID_SERNO_LEN + 4 - 1))
- ata_id_string(args->id, (unsigned char *) &rbuf[4],
- ATA_ID_SERNO, ATA_ID_SERNO_LEN);
+ memcpy(rbuf, hdr, sizeof(hdr));
+ ata_id_string(args->id, (unsigned char *) &rbuf[4],
+ ATA_ID_SERNO, ATA_ID_SERNO_LEN);
return 0;
}
@@ -1855,7 +2063,6 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
* ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Yields two logical unit device identification designators:
* - vendor specific ASCII containing the ATA serial number
@@ -1865,40 +2072,47 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf)
{
- int num;
const int sat_model_serial_desc_len = 68;
+ int num;
rbuf[1] = 0x83; /* this page code */
num = 4;
- if (buflen > (ATA_ID_SERNO_LEN + num + 3)) {
- /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */
- rbuf[num + 0] = 2;
- rbuf[num + 3] = ATA_ID_SERNO_LEN;
- num += 4;
- ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_SERNO, ATA_ID_SERNO_LEN);
- num += ATA_ID_SERNO_LEN;
- }
- if (buflen > (sat_model_serial_desc_len + num + 3)) {
- /* SAT defined lu model and serial numbers descriptor */
- /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */
- rbuf[num + 0] = 2;
- rbuf[num + 1] = 1;
- rbuf[num + 3] = sat_model_serial_desc_len;
+ /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */
+ rbuf[num + 0] = 2;
+ rbuf[num + 3] = ATA_ID_SERNO_LEN;
+ num += 4;
+ ata_id_string(args->id, (unsigned char *) rbuf + num,
+ ATA_ID_SERNO, ATA_ID_SERNO_LEN);
+ num += ATA_ID_SERNO_LEN;
+
+ /* SAT defined lu model and serial numbers descriptor */
+ /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */
+ rbuf[num + 0] = 2;
+ rbuf[num + 1] = 1;
+ rbuf[num + 3] = sat_model_serial_desc_len;
+ num += 4;
+ memcpy(rbuf + num, "ATA ", 8);
+ num += 8;
+ ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_PROD,
+ ATA_ID_PROD_LEN);
+ num += ATA_ID_PROD_LEN;
+ ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_SERNO,
+ ATA_ID_SERNO_LEN);
+ num += ATA_ID_SERNO_LEN;
+
+ if (ata_id_has_wwn(args->id)) {
+ /* SAT defined lu world wide name */
+ /* piv=0, assoc=lu, code_set=binary, designator=NAA */
+ rbuf[num + 0] = 1;
+ rbuf[num + 1] = 3;
+ rbuf[num + 3] = ATA_ID_WWN_LEN;
num += 4;
- memcpy(rbuf + num, "ATA ", 8);
- num += 8;
ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_PROD, ATA_ID_PROD_LEN);
- num += ATA_ID_PROD_LEN;
- ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_SERNO, ATA_ID_SERNO_LEN);
- num += ATA_ID_SERNO_LEN;
+ ATA_ID_WWN, ATA_ID_WWN_LEN);
+ num += ATA_ID_WWN_LEN;
}
rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */
return 0;
@@ -1908,35 +2122,25 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
* ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Yields SAT-specified ATA VPD page.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)
{
- u8 pbuf[60];
struct ata_taskfile tf;
- unsigned int i;
- if (!buflen)
- return 0;
-
- memset(&pbuf, 0, sizeof(pbuf));
memset(&tf, 0, sizeof(tf));
- pbuf[1] = 0x89; /* our page code */
- pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */
- pbuf[3] = (0x238 & 0xff);
+ rbuf[1] = 0x89; /* our page code */
+ rbuf[2] = (0x238 >> 8); /* page size fixed at 238h */
+ rbuf[3] = (0x238 & 0xff);
- memcpy(&pbuf[8], "linux ", 8);
- memcpy(&pbuf[16], "libata ", 16);
- memcpy(&pbuf[32], DRV_VERSION, 4);
- ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4);
+ memcpy(&rbuf[8], "linux ", 8);
+ memcpy(&rbuf[16], "libata ", 16);
+ memcpy(&rbuf[32], DRV_VERSION, 4);
/* we don't store the ATA device signature, so we fake it */
@@ -1944,19 +2148,70 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
tf.lbal = 0x1;
tf.nsect = 0x1;
- ata_tf_to_fis(&tf, 0, 1, &pbuf[36]); /* TODO: PMP? */
- pbuf[36] = 0x34; /* force D2H Reg FIS (34h) */
+ ata_tf_to_fis(&tf, 0, 1, &rbuf[36]); /* TODO: PMP? */
+ rbuf[36] = 0x34; /* force D2H Reg FIS (34h) */
- pbuf[56] = ATA_CMD_ID_ATA;
+ rbuf[56] = ATA_CMD_ID_ATA;
- i = min(buflen, 60U);
- memcpy(rbuf, &pbuf[0], i);
- buflen -= i;
+ memcpy(&rbuf[60], &args->id[0], 512);
+ return 0;
+}
- if (!buflen)
- return 0;
+static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
+{
+ u16 min_io_sectors;
+
+ rbuf[1] = 0xb0;
+ rbuf[3] = 0x3c; /* required VPD size with unmap support */
+
+ /*
+ * Optimal transfer length granularity.
+ *
+ * This is always one physical block, but for disks with a smaller
+ * logical than physical sector size we need to figure out what the
+ * latter is.
+ */
+ min_io_sectors = 1 << ata_id_log2_per_physical_sector(args->id);
+ put_unaligned_be16(min_io_sectors, &rbuf[6]);
+
+ /*
+ * Optimal unmap granularity.
+ *
+ * The ATA spec doesn't even know about a granularity or alignment
+ * for the TRIM command. We can leave away most of the unmap related
+ * VPD page entries, but we have specifify a granularity to signal
+ * that we support some form of unmap - in thise case via WRITE SAME
+ * with the unmap bit set.
+ */
+ if (ata_id_has_trim(args->id)) {
+ put_unaligned_be64(65535 * 512 / 8, &rbuf[36]);
+ put_unaligned_be32(1, &rbuf[28]);
+ }
+
+ return 0;
+}
+
+static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf)
+{
+ int form_factor = ata_id_form_factor(args->id);
+ int media_rotation_rate = ata_id_rotation_rate(args->id);
+
+ rbuf[1] = 0xb1;
+ rbuf[3] = 0x3c;
+ rbuf[4] = media_rotation_rate >> 8;
+ rbuf[5] = media_rotation_rate;
+ rbuf[7] = form_factor;
+
+ return 0;
+}
+
+static unsigned int ata_scsiop_inq_b2(struct ata_scsi_args *args, u8 *rbuf)
+{
+ /* SCSI Thin Provisioning VPD page: SBC-3 rev 22 or later */
+ rbuf[1] = 0xb2;
+ rbuf[3] = 0x4;
+ rbuf[5] = 1 << 6; /* TPWS */
- memcpy(&rbuf[60], &args->id[0], min(buflen, 512U));
return 0;
}
@@ -1964,7 +2219,6 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
* ata_scsiop_noop - Command handler that simply returns success.
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* No operation. Simply returns success to caller, to indicate
* that the caller should successfully complete this SCSI command.
@@ -1972,47 +2226,40 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf)
{
VPRINTK("ENTER\n");
return 0;
}
/**
- * ata_msense_push - Push data onto MODE SENSE data output buffer
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
- * @buf: Pointer to BLOB being added to output buffer
- * @buflen: Length of BLOB
+ * modecpy - Prepare response for MODE SENSE
+ * @dest: output buffer
+ * @src: data being copied
+ * @n: length of mode page
+ * @changeable: whether changeable parameters are requested
*
- * Store MODE SENSE data on an output buffer.
+ * Generate a generic MODE SENSE page for either current or changeable
+ * parameters.
*
* LOCKING:
* None.
*/
-
-static void ata_msense_push(u8 **ptr_io, const u8 *last,
- const u8 *buf, unsigned int buflen)
+static void modecpy(u8 *dest, const u8 *src, int n, bool changeable)
{
- u8 *ptr = *ptr_io;
-
- if ((ptr + buflen - 1) > last)
- return;
-
- memcpy(ptr, buf, buflen);
-
- ptr += buflen;
-
- *ptr_io = ptr;
+ if (changeable) {
+ memcpy(dest, src, 2);
+ memset(dest + 2, 0, n - 2);
+ } else {
+ memcpy(dest, src, n);
+ }
}
/**
* ata_msense_caching - Simulate MODE SENSE caching info page
* @id: device IDENTIFY data
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
+ * @buf: output buffer
+ * @changeable: whether changeable parameters are requested
*
* Generate a caching info page, which conditionally indicates
* write caching to the SCSI layer, depending on device
@@ -2021,58 +2268,46 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last,
* LOCKING:
* None.
*/
-
-static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io,
- const u8 *last)
+static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable)
{
- u8 page[CACHE_MPAGE_LEN];
-
- memcpy(page, def_cache_mpage, sizeof(page));
- if (ata_id_wcache_enabled(id))
- page[2] |= (1 << 2); /* write cache enable */
- if (!ata_id_rahead_enabled(id))
- page[12] |= (1 << 5); /* disable read ahead */
-
- ata_msense_push(ptr_io, last, page, sizeof(page));
- return sizeof(page);
+ modecpy(buf, def_cache_mpage, sizeof(def_cache_mpage), changeable);
+ if (changeable || ata_id_wcache_enabled(id))
+ buf[2] |= (1 << 2); /* write cache enable */
+ if (!changeable && !ata_id_rahead_enabled(id))
+ buf[12] |= (1 << 5); /* disable read ahead */
+ return sizeof(def_cache_mpage);
}
/**
* ata_msense_ctl_mode - Simulate MODE SENSE control mode page
- * @dev: Device associated with this MODE SENSE command
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
+ * @buf: output buffer
+ * @changeable: whether changeable parameters are requested
*
* Generate a generic MODE SENSE control mode page.
*
* LOCKING:
* None.
*/
-
-static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last)
+static unsigned int ata_msense_ctl_mode(u8 *buf, bool changeable)
{
- ata_msense_push(ptr_io, last, def_control_mpage,
- sizeof(def_control_mpage));
+ modecpy(buf, def_control_mpage, sizeof(def_control_mpage), changeable);
return sizeof(def_control_mpage);
}
/**
* ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page
- * @dev: Device associated with this MODE SENSE command
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
+ * @buf: output buffer
+ * @changeable: whether changeable parameters are requested
*
* Generate a generic MODE SENSE r/w error recovery page.
*
* LOCKING:
* None.
*/
-
-static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
+static unsigned int ata_msense_rw_recovery(u8 *buf, bool changeable)
{
-
- ata_msense_push(ptr_io, last, def_rw_recovery_mpage,
- sizeof(def_rw_recovery_mpage));
+ modecpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage),
+ changeable);
return sizeof(def_rw_recovery_mpage);
}
@@ -2104,7 +2339,6 @@ static int ata_dev_supports_fua(u16 *id)
* ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Simulate MODE SENSE commands. Assume this is invoked for direct
* access devices (e.g. disks) only. There should be no block
@@ -2113,19 +2347,17 @@ static int ata_dev_supports_fua(u16 *id)
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
{
struct ata_device *dev = args->dev;
- u8 *scsicmd = args->cmd->cmnd, *p, *last;
+ u8 *scsicmd = args->cmd->cmnd, *p = rbuf;
const u8 sat_blk_desc[] = {
0, 0, 0, 0, /* number of blocks: sat unspecified */
0,
0, 0x2, 0x0 /* block length: 512 bytes */
};
u8 pg, spg;
- unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen;
+ unsigned int ebd, page_control, six_byte;
u8 dpofua;
VPRINTK("ENTER\n");
@@ -2139,26 +2371,19 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
page_control = scsicmd[2] >> 6;
switch (page_control) {
case 0: /* current */
+ case 1: /* changeable */
+ case 2: /* defaults */
break; /* supported */
case 3: /* saved */
goto saving_not_supp;
- case 1: /* changeable */
- case 2: /* defaults */
default:
goto invalid_fld;
}
- if (six_byte) {
- output_len = 4 + (ebd ? 8 : 0);
- alloc_len = scsicmd[4];
- } else {
- output_len = 8 + (ebd ? 8 : 0);
- alloc_len = (scsicmd[7] << 8) + scsicmd[8];
- }
- minlen = (alloc_len < buflen) ? alloc_len : buflen;
-
- p = rbuf + output_len;
- last = rbuf + minlen - 1;
+ if (six_byte)
+ p += 4 + (ebd ? 8 : 0);
+ else
+ p += 8 + (ebd ? 8 : 0);
pg = scsicmd[2] & 0x3f;
spg = scsicmd[3];
@@ -2171,61 +2396,48 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
switch(pg) {
case RW_RECOVERY_MPAGE:
- output_len += ata_msense_rw_recovery(&p, last);
+ p += ata_msense_rw_recovery(p, page_control == 1);
break;
case CACHE_MPAGE:
- output_len += ata_msense_caching(args->id, &p, last);
+ p += ata_msense_caching(args->id, p, page_control == 1);
break;
- case CONTROL_MPAGE: {
- output_len += ata_msense_ctl_mode(&p, last);
+ case CONTROL_MPAGE:
+ p += ata_msense_ctl_mode(p, page_control == 1);
break;
- }
case ALL_MPAGES:
- output_len += ata_msense_rw_recovery(&p, last);
- output_len += ata_msense_caching(args->id, &p, last);
- output_len += ata_msense_ctl_mode(&p, last);
+ p += ata_msense_rw_recovery(p, page_control == 1);
+ p += ata_msense_caching(args->id, p, page_control == 1);
+ p += ata_msense_ctl_mode(p, page_control == 1);
break;
default: /* invalid page code */
goto invalid_fld;
}
- if (minlen < 1)
- return 0;
-
dpofua = 0;
if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) &&
(!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count))
dpofua = 1 << 4;
if (six_byte) {
- output_len--;
- rbuf[0] = output_len;
- if (minlen > 2)
- rbuf[2] |= dpofua;
+ rbuf[0] = p - rbuf - 1;
+ rbuf[2] |= dpofua;
if (ebd) {
- if (minlen > 3)
- rbuf[3] = sizeof(sat_blk_desc);
- if (minlen > 11)
- memcpy(rbuf + 4, sat_blk_desc,
- sizeof(sat_blk_desc));
+ rbuf[3] = sizeof(sat_blk_desc);
+ memcpy(rbuf + 4, sat_blk_desc, sizeof(sat_blk_desc));
}
} else {
- output_len -= 2;
+ unsigned int output_len = p - rbuf - 2;
+
rbuf[0] = output_len >> 8;
- if (minlen > 1)
- rbuf[1] = output_len;
- if (minlen > 3)
- rbuf[3] |= dpofua;
+ rbuf[1] = output_len;
+ rbuf[3] |= dpofua;
if (ebd) {
- if (minlen > 7)
- rbuf[7] = sizeof(sat_blk_desc);
- if (minlen > 15)
- memcpy(rbuf + 8, sat_blk_desc,
- sizeof(sat_blk_desc));
+ rbuf[7] = sizeof(sat_blk_desc);
+ memcpy(rbuf + 8, sat_blk_desc, sizeof(sat_blk_desc));
}
}
return 0;
@@ -2245,17 +2457,23 @@ saving_not_supp:
* ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Simulate READ CAPACITY commands.
*
* LOCKING:
* None.
*/
-unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
{
- u64 last_lba = args->dev->n_sectors - 1; /* LBA of the last block */
+ struct ata_device *dev = args->dev;
+ u64 last_lba = dev->n_sectors - 1; /* LBA of the last block */
+ u32 sector_size; /* physical sector size in bytes */
+ u8 log2_per_phys;
+ u16 lowest_aligned;
+
+ sector_size = ata_id_logical_sector_size(dev->id);
+ log2_per_phys = ata_id_log2_per_physical_sector(dev->id);
+ lowest_aligned = ata_id_logical_sector_offset(dev->id, log2_per_phys);
VPRINTK("ENTER\n");
@@ -2264,28 +2482,44 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
last_lba = 0xffffffff;
/* sector count, 32-bit */
- ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 3));
- ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 2));
- ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 1));
- ATA_SCSI_RBUF_SET(3, last_lba);
+ rbuf[0] = last_lba >> (8 * 3);
+ rbuf[1] = last_lba >> (8 * 2);
+ rbuf[2] = last_lba >> (8 * 1);
+ rbuf[3] = last_lba;
/* sector size */
- ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8);
- ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE & 0xff);
+ rbuf[4] = sector_size >> (8 * 3);
+ rbuf[5] = sector_size >> (8 * 2);
+ rbuf[6] = sector_size >> (8 * 1);
+ rbuf[7] = sector_size;
} else {
/* sector count, 64-bit */
- ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7));
- ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 6));
- ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 5));
- ATA_SCSI_RBUF_SET(3, last_lba >> (8 * 4));
- ATA_SCSI_RBUF_SET(4, last_lba >> (8 * 3));
- ATA_SCSI_RBUF_SET(5, last_lba >> (8 * 2));
- ATA_SCSI_RBUF_SET(6, last_lba >> (8 * 1));
- ATA_SCSI_RBUF_SET(7, last_lba);
+ rbuf[0] = last_lba >> (8 * 7);
+ rbuf[1] = last_lba >> (8 * 6);
+ rbuf[2] = last_lba >> (8 * 5);
+ rbuf[3] = last_lba >> (8 * 4);
+ rbuf[4] = last_lba >> (8 * 3);
+ rbuf[5] = last_lba >> (8 * 2);
+ rbuf[6] = last_lba >> (8 * 1);
+ rbuf[7] = last_lba;
/* sector size */
- ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8);
- ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE & 0xff);
+ rbuf[ 8] = sector_size >> (8 * 3);
+ rbuf[ 9] = sector_size >> (8 * 2);
+ rbuf[10] = sector_size >> (8 * 1);
+ rbuf[11] = sector_size;
+
+ rbuf[12] = 0;
+ rbuf[13] = log2_per_phys;
+ rbuf[14] = (lowest_aligned >> 8) & 0x3f;
+ rbuf[15] = lowest_aligned;
+
+ if (ata_id_has_trim(args->id)) {
+ rbuf[14] |= 0x80; /* TPE */
+
+ if (ata_id_has_zero_after_trim(args->id))
+ rbuf[14] |= 0x40; /* TPRZ */
+ }
}
return 0;
@@ -2295,16 +2529,13 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
* ata_scsiop_report_luns - Simulate REPORT LUNS command
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Simulate REPORT LUNS command.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf)
{
VPRINTK("ENTER\n");
rbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */
@@ -2312,53 +2543,6 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
return 0;
}
-/**
- * ata_scsi_set_sense - Set SCSI sense data and status
- * @cmd: SCSI request to be handled
- * @sk: SCSI-defined sense key
- * @asc: SCSI-defined additional sense code
- * @ascq: SCSI-defined additional sense code qualifier
- *
- * Helper function that builds a valid fixed format, current
- * response code and the given sense key (sk), additional sense
- * code (asc) and additional sense code qualifier (ascq) with
- * a SCSI command status of %SAM_STAT_CHECK_CONDITION and
- * DRIVER_SENSE set in the upper bits of scsi_cmnd::result .
- *
- * LOCKING:
- * Not required
- */
-
-void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
-{
- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
-
- scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq);
-}
-
-/**
- * ata_scsi_badcmd - End a SCSI request with an error
- * @cmd: SCSI request to be handled
- * @done: SCSI command completion function
- * @asc: SCSI-defined additional sense code
- * @ascq: SCSI-defined additional sense code qualifier
- *
- * Helper function that completes a SCSI command with
- * %SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST
- * and the specified additional sense codes.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-
-void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq)
-{
- DPRINTK("ENTER\n");
- ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq);
-
- done(cmd);
-}
-
static void atapi_sense_complete(struct ata_queued_cmd *qc)
{
if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) {
@@ -2459,8 +2643,11 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
*
* If door lock fails, always clear sdev->locked to
* avoid this infinite loop.
+ *
+ * This may happen before SCSI scan is complete. Make
+ * sure qc->dev->sdev isn't NULL before dereferencing.
*/
- if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL)
+ if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL && qc->dev->sdev)
qc->dev->sdev->locked = 0;
qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
@@ -2485,13 +2672,10 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
u8 *scsicmd = cmd->cmnd;
if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) {
- u8 *buf = NULL;
- unsigned int buflen;
unsigned long flags;
+ u8 *buf;
- local_irq_save(flags);
-
- buflen = ata_scsi_rbuf_get(cmd, &buf);
+ buf = ata_scsi_rbuf_get(cmd, true, &flags);
/* ATAPI devices typically report zero for their SCSI version,
* and sometimes deviate from the spec WRT response data
@@ -2506,9 +2690,7 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
buf[3] = 0x32;
}
- ata_scsi_rbuf_put(cmd, buf);
-
- local_irq_restore(flags);
+ ata_scsi_rbuf_put(cmd, true, &flags);
}
cmd->result = SAM_STAT_GOOD;
@@ -2531,8 +2713,8 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *scmd = qc->scsicmd;
struct ata_device *dev = qc->dev;
- int using_pio = (dev->flags & ATA_DFLAG_PIO);
int nodata = (scmd->sc_data_direction == DMA_NONE);
+ int using_pio = !nodata && (dev->flags & ATA_DFLAG_PIO);
unsigned int nbytes;
memset(qc->cdb, 0, dev->cdb_len);
@@ -2550,7 +2732,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
ata_qc_set_pc_nbytes(qc);
/* check whether ATAPI DMA is safe */
- if (!using_pio && ata_check_atapi_dma(qc))
+ if (!nodata && !using_pio && atapi_check_dma(qc))
using_pio = 1;
/* Some controller variants snoop this value for Packet
@@ -2590,13 +2772,11 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
qc->tf.lbam = (nbytes & 0xFF);
qc->tf.lbah = (nbytes >> 8);
- if (using_pio || nodata) {
- /* no data, or PIO data xfer */
- if (nodata)
- qc->tf.protocol = ATAPI_PROT_NODATA;
- else
- qc->tf.protocol = ATAPI_PROT_PIO;
- } else {
+ if (nodata)
+ qc->tf.protocol = ATAPI_PROT_NODATA;
+ else if (using_pio)
+ qc->tf.protocol = ATAPI_PROT_PIO;
+ else {
/* DMA data xfer */
qc->tf.protocol = ATAPI_PROT_DMA;
qc->tf.feature |= ATAPI_PKT_DMA;
@@ -2646,36 +2826,6 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
}
/**
- * ata_scsi_dev_enabled - determine if device is enabled
- * @dev: ATA device
- *
- * Determine if commands should be sent to the specified device.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- *
- * RETURNS:
- * 0 if commands are not allowed / 1 if commands are allowed
- */
-
-static int ata_scsi_dev_enabled(struct ata_device *dev)
-{
- if (unlikely(!ata_dev_enabled(dev)))
- return 0;
-
- if (!atapi_enabled || (dev->link->ap->flags & ATA_FLAG_NO_ATAPI)) {
- if (unlikely(dev->class == ATA_DEV_ATAPI)) {
- ata_dev_printk(dev, KERN_WARNING,
- "WARNING: ATAPI is %s, device ignored.\n",
- atapi_enabled ? "not supported with this driver" : "disabled");
- return 0;
- }
- }
-
- return 1;
-}
-
-/**
* ata_scsi_find_dev - lookup ata_device from scsi_cmnd
* @ap: ATA port to which the device is attached
* @scsidev: SCSI device from which we derive the ATA device
@@ -2696,7 +2846,7 @@ ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev)
{
struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev);
- if (unlikely(!dev || !ata_scsi_dev_enabled(dev)))
+ if (unlikely(!dev || !ata_dev_enabled(dev)))
return NULL;
return dev;
@@ -2759,28 +2909,6 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
goto invalid_fld;
/*
- * Filter TPM commands by default. These provide an
- * essentially uncontrolled encrypted "back door" between
- * applications and the disk. Set libata.allow_tpm=1 if you
- * have a real reason for wanting to use them. This ensures
- * that installed software cannot easily mess stuff up without
- * user intent. DVR type users will probably ship with this enabled
- * for movie content management.
- *
- * Note that for ATA8 we can issue a DCS change and DCS freeze lock
- * for this and should do in future but that it is not sufficient as
- * DCS is an optional feature set. Thus we also do the software filter
- * so that we comply with the TC consortium stated goal that the user
- * can turn off TC features of their system.
- */
- if (tf->command >= 0x5C && tf->command <= 0x5F && !libata_allow_tpm)
- goto invalid_fld;
-
- /* We may not issue DMA commands if no DMA mode is set */
- if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
- goto invalid_fld;
-
- /*
* 12 and 16 byte CDBs use different offsets to
* provide the various register values.
*/
@@ -2829,6 +2957,79 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
tf->device = dev->devno ?
tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
+ switch (tf->command) {
+ /* READ/WRITE LONG use a non-standard sect_size */
+ case ATA_CMD_READ_LONG:
+ case ATA_CMD_READ_LONG_ONCE:
+ case ATA_CMD_WRITE_LONG:
+ case ATA_CMD_WRITE_LONG_ONCE:
+ if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
+ goto invalid_fld;
+ qc->sect_size = scsi_bufflen(scmd);
+ break;
+
+ /* commands using reported Logical Block size (e.g. 512 or 4K) */
+ case ATA_CMD_CFA_WRITE_NE:
+ case ATA_CMD_CFA_TRANS_SECT:
+ case ATA_CMD_CFA_WRITE_MULT_NE:
+ /* XXX: case ATA_CMD_CFA_WRITE_SECTORS_WITHOUT_ERASE: */
+ case ATA_CMD_READ:
+ case ATA_CMD_READ_EXT:
+ case ATA_CMD_READ_QUEUED:
+ /* XXX: case ATA_CMD_READ_QUEUED_EXT: */
+ case ATA_CMD_FPDMA_READ:
+ case ATA_CMD_READ_MULTI:
+ case ATA_CMD_READ_MULTI_EXT:
+ case ATA_CMD_PIO_READ:
+ case ATA_CMD_PIO_READ_EXT:
+ case ATA_CMD_READ_STREAM_DMA_EXT:
+ case ATA_CMD_READ_STREAM_EXT:
+ case ATA_CMD_VERIFY:
+ case ATA_CMD_VERIFY_EXT:
+ case ATA_CMD_WRITE:
+ case ATA_CMD_WRITE_EXT:
+ case ATA_CMD_WRITE_FUA_EXT:
+ case ATA_CMD_WRITE_QUEUED:
+ case ATA_CMD_WRITE_QUEUED_FUA_EXT:
+ case ATA_CMD_FPDMA_WRITE:
+ case ATA_CMD_WRITE_MULTI:
+ case ATA_CMD_WRITE_MULTI_EXT:
+ case ATA_CMD_WRITE_MULTI_FUA_EXT:
+ case ATA_CMD_PIO_WRITE:
+ case ATA_CMD_PIO_WRITE_EXT:
+ case ATA_CMD_WRITE_STREAM_DMA_EXT:
+ case ATA_CMD_WRITE_STREAM_EXT:
+ qc->sect_size = scmd->device->sector_size;
+ break;
+
+ /* Everything else uses 512 byte "sectors" */
+ default:
+ qc->sect_size = ATA_SECT_SIZE;
+ }
+
+ /*
+ * Set flags so that all registers will be written, pass on
+ * write indication (used for PIO/DMA setup), result TF is
+ * copied back and we don't whine too much about its failure.
+ */
+ tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ if (scmd->sc_data_direction == DMA_TO_DEVICE)
+ tf->flags |= ATA_TFLAG_WRITE;
+
+ qc->flags |= ATA_QCFLAG_RESULT_TF | ATA_QCFLAG_QUIET;
+
+ /*
+ * Set transfer length.
+ *
+ * TODO: find out if we need to do more here to
+ * cover scatter/gather case.
+ */
+ ata_qc_set_pc_nbytes(qc);
+
+ /* We may not issue DMA commands if no DMA mode is set */
+ if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
+ goto invalid_fld;
+
/* sanity check for pio multi commands */
if ((cdb[1] & 0xe0) && !is_multi_taskfile(tf))
goto invalid_fld;
@@ -2840,21 +3041,8 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
* with the cached multi_count of libata
*/
if (multi_count != dev->multi_count)
- ata_dev_printk(dev, KERN_WARNING,
- "invalid multi_count %u ignored\n",
- multi_count);
- }
-
- /* READ/WRITE LONG use a non-standard sect_size */
- qc->sect_size = ATA_SECT_SIZE;
- switch (tf->command) {
- case ATA_CMD_READ_LONG:
- case ATA_CMD_READ_LONG_ONCE:
- case ATA_CMD_WRITE_LONG:
- case ATA_CMD_WRITE_LONG_ONCE:
- if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
- goto invalid_fld;
- qc->sect_size = scsi_bufflen(scmd);
+ ata_dev_warn(dev, "invalid multi_count %u ignored\n",
+ multi_count);
}
/*
@@ -2864,30 +3052,92 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
* controller (i.e. the reason for ->set_piomode(),
* ->set_dmamode(), and ->post_set_mode() hooks).
*/
- if ((tf->command == ATA_CMD_SET_FEATURES)
- && (tf->feature == SETFEATURES_XFER))
+ if (tf->command == ATA_CMD_SET_FEATURES &&
+ tf->feature == SETFEATURES_XFER)
goto invalid_fld;
/*
- * Set flags so that all registers will be written,
- * and pass on write indication (used for PIO/DMA
- * setup.)
+ * Filter TPM commands by default. These provide an
+ * essentially uncontrolled encrypted "back door" between
+ * applications and the disk. Set libata.allow_tpm=1 if you
+ * have a real reason for wanting to use them. This ensures
+ * that installed software cannot easily mess stuff up without
+ * user intent. DVR type users will probably ship with this enabled
+ * for movie content management.
+ *
+ * Note that for ATA8 we can issue a DCS change and DCS freeze lock
+ * for this and should do in future but that it is not sufficient as
+ * DCS is an optional feature set. Thus we also do the software filter
+ * so that we comply with the TC consortium stated goal that the user
+ * can turn off TC features of their system.
*/
- tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE);
+ if (tf->command >= 0x5C && tf->command <= 0x5F && !libata_allow_tpm)
+ goto invalid_fld;
- if (scmd->sc_data_direction == DMA_TO_DEVICE)
- tf->flags |= ATA_TFLAG_WRITE;
+ return 0;
+
+ invalid_fld:
+ ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x00);
+ /* "Invalid field in cdb" */
+ return 1;
+}
+
+static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
+{
+ struct ata_taskfile *tf = &qc->tf;
+ struct scsi_cmnd *scmd = qc->scsicmd;
+ struct ata_device *dev = qc->dev;
+ const u8 *cdb = scmd->cmnd;
+ u64 block;
+ u32 n_block;
+ u32 size;
+ void *buf;
+
+ /* we may not issue DMA commands if no DMA mode is set */
+ if (unlikely(!dev->dma_mode))
+ goto invalid_fld;
+
+ if (unlikely(scmd->cmd_len < 16))
+ goto invalid_fld;
+ scsi_16_lba_len(cdb, &block, &n_block);
+
+ /* for now we only support WRITE SAME with the unmap bit set */
+ if (unlikely(!(cdb[1] & 0x8)))
+ goto invalid_fld;
/*
- * Set transfer length.
- *
- * TODO: find out if we need to do more here to
- * cover scatter/gather case.
+ * WRITE SAME always has a sector sized buffer as payload, this
+ * should never be a multiple entry S/G list.
*/
- ata_qc_set_pc_nbytes(qc);
+ if (!scsi_sg_count(scmd))
+ goto invalid_fld;
- /* request result TF and be quiet about device error */
- qc->flags |= ATA_QCFLAG_RESULT_TF | ATA_QCFLAG_QUIET;
+ buf = page_address(sg_page(scsi_sglist(scmd)));
+ size = ata_set_lba_range_entries(buf, 512, block, n_block);
+
+ if (ata_ncq_enabled(dev) && ata_fpdma_dsm_supported(dev)) {
+ /* Newer devices support queued TRIM commands */
+ tf->protocol = ATA_PROT_NCQ;
+ tf->command = ATA_CMD_FPDMA_SEND;
+ tf->hob_nsect = ATA_SUBCMD_FPDMA_SEND_DSM & 0x1f;
+ tf->nsect = qc->tag << 3;
+ tf->hob_feature = (size / 512) >> 8;
+ tf->feature = size / 512;
+
+ tf->auxiliary = 1;
+ } else {
+ tf->protocol = ATA_PROT_DMA;
+ tf->hob_feature = 0;
+ tf->feature = ATA_DSM_TRIM;
+ tf->hob_nsect = (size / 512) >> 8;
+ tf->nsect = size / 512;
+ tf->command = ATA_CMD_DSM;
+ }
+
+ tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 |
+ ATA_TFLAG_WRITE;
+
+ ata_qc_set_pc_nbytes(qc);
return 0;
@@ -2898,6 +3148,188 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
}
/**
+ * ata_mselect_caching - Simulate MODE SELECT for caching info page
+ * @qc: Storage for translated ATA taskfile
+ * @buf: input buffer
+ * @len: number of valid bytes in the input buffer
+ *
+ * Prepare a taskfile to modify caching information for the device.
+ *
+ * LOCKING:
+ * None.
+ */
+static int ata_mselect_caching(struct ata_queued_cmd *qc,
+ const u8 *buf, int len)
+{
+ struct ata_taskfile *tf = &qc->tf;
+ struct ata_device *dev = qc->dev;
+ char mpage[CACHE_MPAGE_LEN];
+ u8 wce;
+
+ /*
+ * The first two bytes of def_cache_mpage are a header, so offsets
+ * in mpage are off by 2 compared to buf. Same for len.
+ */
+
+ if (len != CACHE_MPAGE_LEN - 2)
+ return -EINVAL;
+
+ wce = buf[0] & (1 << 2);
+
+ /*
+ * Check that read-only bits are not modified.
+ */
+ ata_msense_caching(dev->id, mpage, false);
+ mpage[2] &= ~(1 << 2);
+ mpage[2] |= wce;
+ if (memcmp(mpage + 2, buf, CACHE_MPAGE_LEN - 2) != 0)
+ return -EINVAL;
+
+ tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+ tf->protocol = ATA_PROT_NODATA;
+ tf->nsect = 0;
+ tf->command = ATA_CMD_SET_FEATURES;
+ tf->feature = wce ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF;
+ return 0;
+}
+
+/**
+ * ata_scsiop_mode_select - Simulate MODE SELECT 6, 10 commands
+ * @qc: Storage for translated ATA taskfile
+ *
+ * Converts a MODE SELECT command to an ATA SET FEATURES taskfile.
+ * Assume this is invoked for direct access devices (e.g. disks) only.
+ * There should be no block descriptor for other device types.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *scmd = qc->scsicmd;
+ const u8 *cdb = scmd->cmnd;
+ const u8 *p;
+ u8 pg, spg;
+ unsigned six_byte, pg_len, hdr_len, bd_len;
+ int len;
+
+ VPRINTK("ENTER\n");
+
+ six_byte = (cdb[0] == MODE_SELECT);
+ if (six_byte) {
+ if (scmd->cmd_len < 5)
+ goto invalid_fld;
+
+ len = cdb[4];
+ hdr_len = 4;
+ } else {
+ if (scmd->cmd_len < 9)
+ goto invalid_fld;
+
+ len = (cdb[7] << 8) + cdb[8];
+ hdr_len = 8;
+ }
+
+ /* We only support PF=1, SP=0. */
+ if ((cdb[1] & 0x11) != 0x10)
+ goto invalid_fld;
+
+ /* Test early for possible overrun. */
+ if (!scsi_sg_count(scmd) || scsi_sglist(scmd)->length < len)
+ goto invalid_param_len;
+
+ p = page_address(sg_page(scsi_sglist(scmd)));
+
+ /* Move past header and block descriptors. */
+ if (len < hdr_len)
+ goto invalid_param_len;
+
+ if (six_byte)
+ bd_len = p[3];
+ else
+ bd_len = (p[6] << 8) + p[7];
+
+ len -= hdr_len;
+ p += hdr_len;
+ if (len < bd_len)
+ goto invalid_param_len;
+ if (bd_len != 0 && bd_len != 8)
+ goto invalid_param;
+
+ len -= bd_len;
+ p += bd_len;
+ if (len == 0)
+ goto skip;
+
+ /* Parse both possible formats for the mode page headers. */
+ pg = p[0] & 0x3f;
+ if (p[0] & 0x40) {
+ if (len < 4)
+ goto invalid_param_len;
+
+ spg = p[1];
+ pg_len = (p[2] << 8) | p[3];
+ p += 4;
+ len -= 4;
+ } else {
+ if (len < 2)
+ goto invalid_param_len;
+
+ spg = 0;
+ pg_len = p[1];
+ p += 2;
+ len -= 2;
+ }
+
+ /*
+ * No mode subpages supported (yet) but asking for _all_
+ * subpages may be valid
+ */
+ if (spg && (spg != ALL_SUB_MPAGES))
+ goto invalid_param;
+ if (pg_len > len)
+ goto invalid_param_len;
+
+ switch (pg) {
+ case CACHE_MPAGE:
+ if (ata_mselect_caching(qc, p, pg_len) < 0)
+ goto invalid_param;
+ break;
+
+ default: /* invalid page code */
+ goto invalid_param;
+ }
+
+ /*
+ * Only one page has changeable data, so we only support setting one
+ * page at a time.
+ */
+ if (len > pg_len)
+ goto invalid_param;
+
+ return 0;
+
+ invalid_fld:
+ /* "Invalid field in CDB" */
+ ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0);
+ return 1;
+
+ invalid_param:
+ /* "Invalid field in parameter list" */
+ ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x26, 0x0);
+ return 1;
+
+ invalid_param_len:
+ /* "Parameter list length error" */
+ ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x1a, 0x0);
+ return 1;
+
+ skip:
+ scmd->result = SAM_STAT_GOOD;
+ return 1;
+}
+
+/**
* ata_get_xlat_func - check if SCSI to ATA translation is possible
* @dev: ATA device
* @cmd: SCSI command opcode to consider
@@ -2921,6 +3353,9 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
case WRITE_16:
return ata_scsi_rw_xlat;
+ case WRITE_SAME_16:
+ return ata_scsi_write_same_xlat;
+
case SYNCHRONIZE_CACHE:
if (ata_try_flush_cache(dev))
return ata_scsi_flush_xlat;
@@ -2934,6 +3369,11 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
case ATA_16:
return ata_scsi_pass_thru;
+ case MODE_SELECT:
+ case MODE_SELECT_10:
+ return ata_scsi_mode_select_xlat;
+ break;
+
case START_STOP:
return ata_scsi_start_stop_xlat;
}
@@ -2966,7 +3406,6 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap,
}
static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
- void (*done)(struct scsi_cmnd *),
struct ata_device *dev)
{
u8 scsi_op = scmd->cmnd[0];
@@ -3000,9 +3439,9 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
}
if (xlat_func)
- rc = ata_scsi_translate(dev, scmd, done, xlat_func);
+ rc = ata_scsi_translate(dev, scmd, xlat_func);
else
- ata_scsi_simulate(dev, scmd, done);
+ ata_scsi_simulate(dev, scmd);
return rc;
@@ -3010,14 +3449,14 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
DPRINTK("bad CDB len=%u, scsi_op=0x%02x, max=%u\n",
scmd->cmd_len, scsi_op, dev->cdb_len);
scmd->result = DID_ERROR << 16;
- done(scmd);
+ scmd->scsi_done(scmd);
return 0;
}
/**
* ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device
+ * @shost: SCSI host of command to be sent
* @cmd: SCSI command to be sent
- * @done: Completion function, called when command is complete
*
* In some cases, this function translates SCSI commands into
* ATA taskfiles, and queues the taskfiles to be sent to
@@ -3027,37 +3466,36 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
* ATA and ATAPI devices appearing as SCSI devices.
*
* LOCKING:
- * Releases scsi-layer-held lock, and obtains host lock.
+ * ATA host lock
*
* RETURNS:
* Return value from __ata_scsi_queuecmd() if @cmd can be queued,
* 0 otherwise.
*/
-int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
{
struct ata_port *ap;
struct ata_device *dev;
struct scsi_device *scsidev = cmd->device;
- struct Scsi_Host *shost = scsidev->host;
int rc = 0;
+ unsigned long irq_flags;
ap = ata_shost_to_port(shost);
- spin_unlock(shost->host_lock);
- spin_lock(ap->lock);
+ spin_lock_irqsave(ap->lock, irq_flags);
ata_scsi_dump_cdb(ap, cmd);
dev = ata_scsi_find_dev(ap, scsidev);
if (likely(dev))
- rc = __ata_scsi_queuecmd(cmd, done, dev);
+ rc = __ata_scsi_queuecmd(cmd, dev);
else {
cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
+ cmd->scsi_done(cmd);
}
- spin_unlock(ap->lock);
- spin_lock(shost->host_lock);
+ spin_unlock_irqrestore(ap->lock, irq_flags);
+
return rc;
}
@@ -3065,7 +3503,6 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
* ata_scsi_simulate - simulate SCSI command on ATA device
* @dev: the target device
* @cmd: SCSI command being sent to device.
- * @done: SCSI command completion function.
*
* Interprets and directly executes a select list of SCSI commands
* that can be handled internally.
@@ -3074,8 +3511,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
* spin_lock_irqsave(host lock)
*/
-void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
+void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
{
struct ata_scsi_args args;
const u8 *scsicmd = cmd->cmnd;
@@ -3084,17 +3520,17 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
args.dev = dev;
args.id = dev->id;
args.cmd = cmd;
- args.done = done;
+ args.done = cmd->scsi_done;
switch(scsicmd[0]) {
/* TODO: worth improving? */
case FORMAT_UNIT:
- ata_scsi_invalid_field(cmd, done);
+ ata_scsi_invalid_field(cmd);
break;
case INQUIRY:
if (scsicmd[1] & 2) /* is CmdDt set? */
- ata_scsi_invalid_field(cmd, done);
+ ata_scsi_invalid_field(cmd);
else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
else switch (scsicmd[2]) {
@@ -3110,8 +3546,17 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
case 0x89:
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89);
break;
+ case 0xb0:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b0);
+ break;
+ case 0xb1:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b1);
+ break;
+ case 0xb2:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2);
+ break;
default:
- ata_scsi_invalid_field(cmd, done);
+ ata_scsi_invalid_field(cmd);
break;
}
break;
@@ -3121,11 +3566,6 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
break;
- case MODE_SELECT: /* unconditionally return */
- case MODE_SELECT_10: /* bad-field-in-cdb */
- ata_scsi_invalid_field(cmd, done);
- break;
-
case READ_CAPACITY:
ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
break;
@@ -3134,7 +3574,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
else
- ata_scsi_invalid_field(cmd, done);
+ ata_scsi_invalid_field(cmd);
break;
case REPORT_LUNS:
@@ -3144,7 +3584,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
case REQUEST_SENSE:
ata_scsi_set_sense(cmd, 0, 0, 0);
cmd->result = (DRIVER_SENSE << 24);
- done(cmd);
+ cmd->scsi_done(cmd);
break;
/* if we reach this, then writeback caching is disabled,
@@ -3166,14 +3606,14 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4]))
ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
else
- ata_scsi_invalid_field(cmd, done);
+ ata_scsi_invalid_field(cmd);
break;
/* all other commands */
default:
ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
/* "Invalid command operation code" */
- done(cmd);
+ cmd->scsi_done(cmd);
break;
}
}
@@ -3191,15 +3631,17 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
if (!shost)
goto err_alloc;
+ shost->eh_noresume = 1;
*(struct ata_port **)&shost->hostdata[0] = ap;
ap->scsi_host = shost;
- shost->transportt = &ata_scsi_transport_template;
+ shost->transportt = ata_scsi_transport_template;
shost->unique_id = ap->print_id;
shost->max_id = 16;
shost->max_lun = 1;
shost->max_channel = 1;
shost->max_cmd_len = 16;
+ shost->no_write_same = 1;
/* Schedule policy is determined by ->qc_defer()
* callback and it needs to see every deferred qc.
@@ -3208,7 +3650,8 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
*/
shost->max_host_blocked = 1;
- rc = scsi_add_host(ap->scsi_host, ap->host->dev);
+ rc = scsi_add_host_with_dma(ap->scsi_host,
+ &ap->tdev, ap->host->dev);
if (rc)
goto err_add;
}
@@ -3234,16 +3677,13 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
struct ata_link *link;
struct ata_device *dev;
- if (ap->flags & ATA_FLAG_DISABLED)
- return;
-
repeat:
- ata_port_for_each_link(link, ap) {
- ata_link_for_each_dev(dev, link) {
+ ata_for_each_link(link, ap, EDGE) {
+ ata_for_each_dev(dev, link, ENABLED) {
struct scsi_device *sdev;
int channel = 0, id = 0;
- if (!ata_dev_enabled(dev) || dev->sdev)
+ if (dev->sdev)
continue;
if (ata_is_host_link(link))
@@ -3256,6 +3696,8 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
if (!IS_ERR(sdev)) {
dev->sdev = sdev;
scsi_device_put(sdev);
+ } else {
+ dev->sdev = NULL;
}
}
}
@@ -3264,9 +3706,9 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
* failure occurred, scan would have failed silently. Check
* whether all devices are attached.
*/
- ata_port_for_each_link(link, ap) {
- ata_link_for_each_dev(dev, link) {
- if (ata_dev_enabled(dev) && !dev->sdev)
+ ata_for_each_link(link, ap, EDGE) {
+ ata_for_each_dev(dev, link, ENABLED) {
+ if (!dev->sdev)
goto exit_loop;
}
}
@@ -3293,12 +3735,11 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
goto repeat;
}
- ata_port_printk(ap, KERN_ERR, "WARNING: synchronous SCSI scan "
- "failed without making any progress,\n"
- " switching to async\n");
+ ata_port_err(ap,
+ "WARNING: synchronous SCSI scan failed without making any progress, switching to async\n");
}
- queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
+ queue_delayed_work(system_long_wq, &ap->hotplug_task,
round_jiffies_relative(HZ));
}
@@ -3377,8 +3818,8 @@ static void ata_scsi_remove_dev(struct ata_device *dev)
mutex_unlock(&ap->scsi_host->scan_mutex);
if (sdev) {
- ata_dev_printk(dev, KERN_INFO, "detaching (SCSI %s)\n",
- sdev->sdev_gendev.bus_id);
+ ata_dev_info(dev, "detaching (SCSI %s)\n",
+ dev_name(&sdev->sdev_gendev));
scsi_remove_device(sdev);
scsi_device_put(sdev);
@@ -3390,7 +3831,7 @@ static void ata_scsi_handle_link_detach(struct ata_link *link)
struct ata_port *ap = link->ap;
struct ata_device *dev;
- ata_link_for_each_dev(dev, link) {
+ ata_for_each_dev(dev, link, ALL) {
unsigned long flags;
if (!(dev->flags & ATA_DFLAG_DETACHED))
@@ -3400,6 +3841,9 @@ static void ata_scsi_handle_link_detach(struct ata_link *link)
dev->flags &= ~ATA_DFLAG_DETACHED;
spin_unlock_irqrestore(ap->lock, flags);
+ if (zpodd_dev_enabled(dev))
+ zpodd_exit(dev);
+
ata_scsi_remove_dev(dev);
}
}
@@ -3444,7 +3888,29 @@ void ata_scsi_hotplug(struct work_struct *work)
return;
}
+ /*
+ * XXX - UGLY HACK
+ *
+ * The block layer suspend/resume path is fundamentally broken due
+ * to freezable kthreads and workqueue and may deadlock if a block
+ * device gets removed while resume is in progress. I don't know
+ * what the solution is short of removing freezable kthreads and
+ * workqueues altogether.
+ *
+ * The following is an ugly hack to avoid kicking off device
+ * removal while freezer is active. This is a joke but does avoid
+ * this particular deadlock scenario.
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=62801
+ * http://marc.info/?l=linux-kernel&m=138695698516487
+ */
+#ifdef CONFIG_FREEZER
+ while (pm_freezing)
+ msleep(10);
+#endif
+
DPRINTK("ENTER\n");
+ mutex_lock(&ap->scsi_scan_mutex);
/* Unplug detached devices. We cannot use link iterator here
* because PMP links have to be scanned even if PMP is
@@ -3458,6 +3924,7 @@ void ata_scsi_hotplug(struct work_struct *work)
/* scan for new ones */
ata_scsi_scan_host(ap, 0);
+ mutex_unlock(&ap->scsi_scan_mutex);
DPRINTK("EXIT\n");
}
@@ -3477,8 +3944,8 @@ void ata_scsi_hotplug(struct work_struct *work)
* RETURNS:
* Zero.
*/
-static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
- unsigned int id, unsigned int lun)
+int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+ unsigned int id, unsigned int lun)
{
struct ata_port *ap = ata_shost_to_port(shost);
unsigned long flags;
@@ -3505,7 +3972,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
if (devno == SCAN_WILD_CARD) {
struct ata_link *link;
- ata_port_for_each_link(link, ap) {
+ ata_for_each_link(link, ap, EDGE) {
struct ata_eh_info *ehi = &link->eh_info;
ehi->probe_mask |= ATA_ALL_DEVICES;
ehi->action |= ATA_EH_RESET;
@@ -3536,9 +4003,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
* @work: Pointer to ATA port to perform scsi_rescan_device()
*
* After ATA pass thru (SAT) commands are executed successfully,
- * libata need to propagate the changes to SCSI layer. This
- * function must be executed from ata_aux_wq such that sdev
- * attach/detach don't race with rescan.
+ * libata need to propagate the changes to SCSI layer.
*
* LOCKING:
* Kernel thread context (may sleep).
@@ -3551,13 +4016,14 @@ void ata_scsi_dev_rescan(struct work_struct *work)
struct ata_device *dev;
unsigned long flags;
+ mutex_lock(&ap->scsi_scan_mutex);
spin_lock_irqsave(ap->lock, flags);
- ata_port_for_each_link(link, ap) {
- ata_link_for_each_dev(dev, link) {
+ ata_for_each_link(link, ap, EDGE) {
+ ata_for_each_dev(dev, link, ENABLED) {
struct scsi_device *sdev = dev->sdev;
- if (!ata_dev_enabled(dev) || !sdev)
+ if (!sdev)
continue;
if (scsi_device_get(sdev))
continue;
@@ -3570,6 +4036,7 @@ void ata_scsi_dev_rescan(struct work_struct *work)
}
spin_unlock_irqrestore(ap->lock, flags);
+ mutex_unlock(&ap->scsi_scan_mutex);
}
/**
@@ -3596,7 +4063,7 @@ struct ata_port *ata_sas_port_alloc(struct ata_host *host,
return NULL;
ap->port_no = 0;
- ap->lock = shost->host_lock;
+ ap->lock = &host->lock;
ap->pio_mask = port_info->pio_mask;
ap->mwdma_mask = port_info->mwdma_mask;
ap->udma_mask = port_info->udma_mask;
@@ -3622,6 +4089,12 @@ EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
*/
int ata_sas_port_start(struct ata_port *ap)
{
+ /*
+ * the port is marked as frozen at allocation time, but if we don't
+ * have new eh, we won't thaw it
+ */
+ if (!ap->ops->error_handler)
+ ap->pflags &= ~ATA_PFLAG_FROZEN;
return 0;
}
EXPORT_SYMBOL_GPL(ata_sas_port_start);
@@ -3642,6 +4115,26 @@ void ata_sas_port_stop(struct ata_port *ap)
EXPORT_SYMBOL_GPL(ata_sas_port_stop);
/**
+ * ata_sas_async_probe - simply schedule probing and return
+ * @ap: Port to probe
+ *
+ * For batch scheduling of probe for sas attached ata devices, assumes
+ * the port has already been through ata_sas_port_init()
+ */
+void ata_sas_async_probe(struct ata_port *ap)
+{
+ __ata_port_probe(ap);
+}
+EXPORT_SYMBOL_GPL(ata_sas_async_probe);
+
+int ata_sas_sync_probe(struct ata_port *ap)
+{
+ return ata_port_probe(ap);
+}
+EXPORT_SYMBOL_GPL(ata_sas_sync_probe);
+
+
+/**
* ata_sas_port_init - Initialize a SATA device
* @ap: SATA port to initialize
*
@@ -3656,12 +4149,10 @@ int ata_sas_port_init(struct ata_port *ap)
{
int rc = ap->ops->port_start(ap);
- if (!rc) {
- ap->print_id = ata_print_id++;
- rc = ata_bus_probe(ap);
- }
-
- return rc;
+ if (rc)
+ return rc;
+ ap->print_id = atomic_inc_return(&ata_print_id);
+ return 0;
}
EXPORT_SYMBOL_GPL(ata_sas_port_init);
@@ -3699,7 +4190,6 @@ EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
/**
* ata_sas_queuecmd - Issue SCSI cdb to libata-managed device
* @cmd: SCSI command to be sent
- * @done: Completion function, called when command is complete
* @ap: ATA port to which the command is being sent
*
* RETURNS:
@@ -3707,18 +4197,17 @@ EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
* 0 otherwise.
*/
-int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
- struct ata_port *ap)
+int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
{
int rc = 0;
ata_scsi_dump_cdb(ap, cmd);
- if (likely(ata_scsi_dev_enabled(ap->link.device)))
- rc = __ata_scsi_queuecmd(cmd, done, ap->link.device);
+ if (likely(ata_dev_enabled(ap->link.device)))
+ rc = __ata_scsi_queuecmd(cmd, ap->link.device);
else {
cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
+ cmd->scsi_done(cmd);
}
return rc;
}
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 15499522e64..1121153f1ec 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1,7 +1,7 @@
/*
* libata-sff.c - helper library for PCI IDE BMDMA
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -33,16 +33,20 @@
*/
#include <linux/kernel.h>
+#include <linux/gfp.h>
#include <linux/pci.h>
+#include <linux/module.h>
#include <linux/libata.h>
#include <linux/highmem.h>
#include "libata.h"
+static struct workqueue_struct *ata_sff_wq;
+
const struct ata_port_operations ata_sff_port_ops = {
.inherits = &ata_base_port_ops,
- .qc_prep = ata_sff_qc_prep,
+ .qc_prep = ata_noop_qc_prep,
.qc_issue = ata_sff_qc_issue,
.qc_fill_rtf = ata_sff_qc_fill_rtf,
@@ -53,7 +57,6 @@ const struct ata_port_operations ata_sff_port_ops = {
.hardreset = sata_sff_hardreset,
.postreset = ata_sff_postreset,
.error_handler = ata_sff_error_handler,
- .post_internal_cmd = ata_sff_post_internal_cmd,
.sff_dev_select = ata_sff_dev_select,
.sff_check_status = ata_sff_check_status,
@@ -61,205 +64,144 @@ const struct ata_port_operations ata_sff_port_ops = {
.sff_tf_read = ata_sff_tf_read,
.sff_exec_command = ata_sff_exec_command,
.sff_data_xfer = ata_sff_data_xfer,
- .sff_irq_on = ata_sff_irq_on,
- .sff_irq_clear = ata_sff_irq_clear,
-
- .port_start = ata_sff_port_start,
-};
-
-const struct ata_port_operations ata_bmdma_port_ops = {
- .inherits = &ata_sff_port_ops,
+ .sff_drain_fifo = ata_sff_drain_fifo,
- .mode_filter = ata_bmdma_mode_filter,
-
- .bmdma_setup = ata_bmdma_setup,
- .bmdma_start = ata_bmdma_start,
- .bmdma_stop = ata_bmdma_stop,
- .bmdma_status = ata_bmdma_status,
+ .lost_interrupt = ata_sff_lost_interrupt,
};
+EXPORT_SYMBOL_GPL(ata_sff_port_ops);
/**
- * ata_fill_sg - Fill PCI IDE PRD table
- * @qc: Metadata associated with taskfile to be transferred
+ * ata_sff_check_status - Read device status reg & clear interrupt
+ * @ap: port where the device is
*
- * Fill PCI IDE PRD (scatter-gather) table with segments
- * associated with the current disk command.
+ * Reads ATA taskfile status register for currently-selected device
+ * and return its value. This also clears pending interrupts
+ * from this device
*
* LOCKING:
- * spin_lock_irqsave(host lock)
- *
+ * Inherited from caller.
*/
-static void ata_fill_sg(struct ata_queued_cmd *qc)
+u8 ata_sff_check_status(struct ata_port *ap)
{
- struct ata_port *ap = qc->ap;
- struct scatterlist *sg;
- unsigned int si, pi;
-
- pi = 0;
- for_each_sg(qc->sg, sg, qc->n_elem, si) {
- u32 addr, offset;
- u32 sg_len, len;
-
- /* determine if physical DMA addr spans 64K boundary.
- * Note h/w doesn't support 64-bit, so we unconditionally
- * truncate dma_addr_t to u32.
- */
- addr = (u32) sg_dma_address(sg);
- sg_len = sg_dma_len(sg);
-
- while (sg_len) {
- offset = addr & 0xffff;
- len = sg_len;
- if ((offset + sg_len) > 0x10000)
- len = 0x10000 - offset;
-
- ap->prd[pi].addr = cpu_to_le32(addr);
- ap->prd[pi].flags_len = cpu_to_le32(len & 0xffff);
- VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
-
- pi++;
- sg_len -= len;
- addr += len;
- }
- }
-
- ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+ return ioread8(ap->ioaddr.status_addr);
}
+EXPORT_SYMBOL_GPL(ata_sff_check_status);
/**
- * ata_fill_sg_dumb - Fill PCI IDE PRD table
- * @qc: Metadata associated with taskfile to be transferred
+ * ata_sff_altstatus - Read device alternate status reg
+ * @ap: port where the device is
*
- * Fill PCI IDE PRD (scatter-gather) table with segments
- * associated with the current disk command. Perform the fill
- * so that we avoid writing any length 64K records for
- * controllers that don't follow the spec.
+ * Reads ATA taskfile alternate status register for
+ * currently-selected device and return its value.
*
- * LOCKING:
- * spin_lock_irqsave(host lock)
+ * Note: may NOT be used as the check_altstatus() entry in
+ * ata_port_operations.
*
+ * LOCKING:
+ * Inherited from caller.
*/
-static void ata_fill_sg_dumb(struct ata_queued_cmd *qc)
+static u8 ata_sff_altstatus(struct ata_port *ap)
{
- struct ata_port *ap = qc->ap;
- struct scatterlist *sg;
- unsigned int si, pi;
-
- pi = 0;
- for_each_sg(qc->sg, sg, qc->n_elem, si) {
- u32 addr, offset;
- u32 sg_len, len, blen;
-
- /* determine if physical DMA addr spans 64K boundary.
- * Note h/w doesn't support 64-bit, so we unconditionally
- * truncate dma_addr_t to u32.
- */
- addr = (u32) sg_dma_address(sg);
- sg_len = sg_dma_len(sg);
-
- while (sg_len) {
- offset = addr & 0xffff;
- len = sg_len;
- if ((offset + sg_len) > 0x10000)
- len = 0x10000 - offset;
-
- blen = len & 0xffff;
- ap->prd[pi].addr = cpu_to_le32(addr);
- if (blen == 0) {
- /* Some PATA chipsets like the CS5530 can't
- cope with 0x0000 meaning 64K as the spec says */
- ap->prd[pi].flags_len = cpu_to_le32(0x8000);
- blen = 0x8000;
- ap->prd[++pi].addr = cpu_to_le32(addr + 0x8000);
- }
- ap->prd[pi].flags_len = cpu_to_le32(blen);
- VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
-
- pi++;
- sg_len -= len;
- addr += len;
- }
- }
+ if (ap->ops->sff_check_altstatus)
+ return ap->ops->sff_check_altstatus(ap);
- ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+ return ioread8(ap->ioaddr.altstatus_addr);
}
/**
- * ata_sff_qc_prep - Prepare taskfile for submission
- * @qc: Metadata associated with taskfile to be prepared
+ * ata_sff_irq_status - Check if the device is busy
+ * @ap: port where the device is
*
- * Prepare ATA taskfile for submission.
+ * Determine if the port is currently busy. Uses altstatus
+ * if available in order to avoid clearing shared IRQ status
+ * when finding an IRQ source. Non ctl capable devices don't
+ * share interrupt lines fortunately for us.
*
* LOCKING:
- * spin_lock_irqsave(host lock)
+ * Inherited from caller.
*/
-void ata_sff_qc_prep(struct ata_queued_cmd *qc)
+static u8 ata_sff_irq_status(struct ata_port *ap)
{
- if (!(qc->flags & ATA_QCFLAG_DMAMAP))
- return;
+ u8 status;
- ata_fill_sg(qc);
+ if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) {
+ status = ata_sff_altstatus(ap);
+ /* Not us: We are busy */
+ if (status & ATA_BUSY)
+ return status;
+ }
+ /* Clear INTRQ latch */
+ status = ap->ops->sff_check_status(ap);
+ return status;
}
/**
- * ata_sff_dumb_qc_prep - Prepare taskfile for submission
- * @qc: Metadata associated with taskfile to be prepared
+ * ata_sff_sync - Flush writes
+ * @ap: Port to wait for.
*
- * Prepare ATA taskfile for submission.
+ * CAUTION:
+ * If we have an mmio device with no ctl and no altstatus
+ * method this will fail. No such devices are known to exist.
*
* LOCKING:
- * spin_lock_irqsave(host lock)
+ * Inherited from caller.
*/
-void ata_sff_dumb_qc_prep(struct ata_queued_cmd *qc)
-{
- if (!(qc->flags & ATA_QCFLAG_DMAMAP))
- return;
- ata_fill_sg_dumb(qc);
+static void ata_sff_sync(struct ata_port *ap)
+{
+ if (ap->ops->sff_check_altstatus)
+ ap->ops->sff_check_altstatus(ap);
+ else if (ap->ioaddr.altstatus_addr)
+ ioread8(ap->ioaddr.altstatus_addr);
}
/**
- * ata_sff_check_status - Read device status reg & clear interrupt
- * @ap: port where the device is
+ * ata_sff_pause - Flush writes and wait 400nS
+ * @ap: Port to pause for.
*
- * Reads ATA taskfile status register for currently-selected device
- * and return its value. This also clears pending interrupts
- * from this device
+ * CAUTION:
+ * If we have an mmio device with no ctl and no altstatus
+ * method this will fail. No such devices are known to exist.
*
* LOCKING:
* Inherited from caller.
*/
-u8 ata_sff_check_status(struct ata_port *ap)
+
+void ata_sff_pause(struct ata_port *ap)
{
- return ioread8(ap->ioaddr.status_addr);
+ ata_sff_sync(ap);
+ ndelay(400);
}
+EXPORT_SYMBOL_GPL(ata_sff_pause);
/**
- * ata_sff_altstatus - Read device alternate status reg
- * @ap: port where the device is
- *
- * Reads ATA taskfile alternate status register for
- * currently-selected device and return its value.
- *
- * Note: may NOT be used as the check_altstatus() entry in
- * ata_port_operations.
+ * ata_sff_dma_pause - Pause before commencing DMA
+ * @ap: Port to pause for.
*
- * LOCKING:
- * Inherited from caller.
+ * Perform I/O fencing and ensure sufficient cycle delays occur
+ * for the HDMA1:0 transition
*/
-u8 ata_sff_altstatus(struct ata_port *ap)
-{
- if (ap->ops->sff_check_altstatus)
- return ap->ops->sff_check_altstatus(ap);
- return ioread8(ap->ioaddr.altstatus_addr);
+void ata_sff_dma_pause(struct ata_port *ap)
+{
+ if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) {
+ /* An altstatus read will cause the needed delay without
+ messing up the IRQ status */
+ ata_sff_altstatus(ap);
+ return;
+ }
+ /* There are no DMA controllers without ctl. BUG here to ensure
+ we never violate the HDMA1:0 transition timing and risk
+ corruption. */
+ BUG();
}
+EXPORT_SYMBOL_GPL(ata_sff_dma_pause);
/**
* ata_sff_busy_sleep - sleep until BSY clears, or timeout
* @ap: port containing status register to be polled
- * @tmout_pat: impatience timeout
- * @tmout: overall timeout
+ * @tmout_pat: impatience timeout in msecs
+ * @tmout: overall timeout in msecs
*
* Sleep until ATA Status register bit BSY clears,
* or a timeout occurs.
@@ -278,22 +220,22 @@ int ata_sff_busy_sleep(struct ata_port *ap,
status = ata_sff_busy_wait(ap, ATA_BUSY, 300);
timer_start = jiffies;
- timeout = timer_start + tmout_pat;
+ timeout = ata_deadline(timer_start, tmout_pat);
while (status != 0xff && (status & ATA_BUSY) &&
time_before(jiffies, timeout)) {
- msleep(50);
+ ata_msleep(ap, 50);
status = ata_sff_busy_wait(ap, ATA_BUSY, 3);
}
if (status != 0xff && (status & ATA_BUSY))
- ata_port_printk(ap, KERN_WARNING,
- "port is slow to respond, please be patient "
- "(Status 0x%x)\n", status);
+ ata_port_warn(ap,
+ "port is slow to respond, please be patient (Status 0x%x)\n",
+ status);
- timeout = timer_start + tmout;
+ timeout = ata_deadline(timer_start, tmout);
while (status != 0xff && (status & ATA_BUSY) &&
time_before(jiffies, timeout)) {
- msleep(50);
+ ata_msleep(ap, 50);
status = ap->ops->sff_check_status(ap);
}
@@ -301,24 +243,21 @@ int ata_sff_busy_sleep(struct ata_port *ap,
return -ENODEV;
if (status & ATA_BUSY) {
- ata_port_printk(ap, KERN_ERR, "port failed to respond "
- "(%lu secs, Status 0x%x)\n",
- tmout / HZ, status);
+ ata_port_err(ap,
+ "port failed to respond (%lu secs, Status 0x%x)\n",
+ DIV_ROUND_UP(tmout, 1000), status);
return -EBUSY;
}
return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_busy_sleep);
static int ata_sff_check_ready(struct ata_link *link)
{
u8 status = link->ap->ops->sff_check_status(link->ap);
- if (!(status & ATA_BUSY))
- return 1;
- if (status == 0xff)
- return -ENODEV;
- return 0;
+ return ata_check_ready(status);
}
/**
@@ -339,6 +278,28 @@ int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline)
{
return ata_wait_ready(link, deadline, ata_sff_check_ready);
}
+EXPORT_SYMBOL_GPL(ata_sff_wait_ready);
+
+/**
+ * ata_sff_set_devctl - Write device control reg
+ * @ap: port where the device is
+ * @ctl: value to write
+ *
+ * Writes ATA taskfile device control register.
+ *
+ * Note: may NOT be used as the sff_set_devctl() entry in
+ * ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void ata_sff_set_devctl(struct ata_port *ap, u8 ctl)
+{
+ if (ap->ops->sff_set_devctl)
+ ap->ops->sff_set_devctl(ap, ctl);
+ else
+ iowrite8(ctl, ap->ioaddr.ctl_addr);
+}
/**
* ata_sff_dev_select - Select device 0/1 on ATA bus
@@ -366,6 +327,7 @@ void ata_sff_dev_select(struct ata_port *ap, unsigned int device)
iowrite8(tmp, ap->ioaddr.device_addr);
ata_sff_pause(ap); /* needed; also flushes, for mmio */
}
+EXPORT_SYMBOL_GPL(ata_sff_dev_select);
/**
* ata_dev_select - Select device 0/1 on ATA bus
@@ -385,12 +347,12 @@ void ata_sff_dev_select(struct ata_port *ap, unsigned int device)
* LOCKING:
* caller.
*/
-void ata_dev_select(struct ata_port *ap, unsigned int device,
+static void ata_dev_select(struct ata_port *ap, unsigned int device,
unsigned int wait, unsigned int can_sleep)
{
if (ata_msg_probe(ap))
- ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, "
- "device %u, wait %u\n", device, wait);
+ ata_port_info(ap, "ata_dev_select: ENTER, device %u, wait %u\n",
+ device, wait);
if (wait)
ata_wait_idle(ap);
@@ -399,7 +361,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device,
if (wait) {
if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI)
- msleep(150);
+ ata_msleep(ap, 150);
ata_wait_idle(ap);
}
}
@@ -411,46 +373,32 @@ void ata_dev_select(struct ata_port *ap, unsigned int device,
* Enable interrupts on a legacy IDE device using MMIO or PIO,
* wait for idle, clear any pending interrupts.
*
+ * Note: may NOT be used as the sff_irq_on() entry in
+ * ata_port_operations.
+ *
* LOCKING:
* Inherited from caller.
*/
-u8 ata_sff_irq_on(struct ata_port *ap)
+void ata_sff_irq_on(struct ata_port *ap)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
- u8 tmp;
+
+ if (ap->ops->sff_irq_on) {
+ ap->ops->sff_irq_on(ap);
+ return;
+ }
ap->ctl &= ~ATA_NIEN;
ap->last_ctl = ap->ctl;
- if (ioaddr->ctl_addr)
- iowrite8(ap->ctl, ioaddr->ctl_addr);
- tmp = ata_wait_idle(ap);
-
- ap->ops->sff_irq_clear(ap);
-
- return tmp;
-}
-
-/**
- * ata_sff_irq_clear - Clear PCI IDE BMDMA interrupt.
- * @ap: Port associated with this ATA transaction.
- *
- * Clear interrupt and error flags in DMA status register.
- *
- * May be used as the irq_clear() entry in ata_port_operations.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-void ata_sff_irq_clear(struct ata_port *ap)
-{
- void __iomem *mmio = ap->ioaddr.bmdma_addr;
-
- if (!mmio)
- return;
+ if (ap->ops->sff_set_devctl || ioaddr->ctl_addr)
+ ata_sff_set_devctl(ap, ap->ctl);
+ ata_wait_idle(ap);
- iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS);
+ if (ap->ops->sff_irq_clear)
+ ap->ops->sff_irq_clear(ap);
}
+EXPORT_SYMBOL_GPL(ata_sff_irq_on);
/**
* ata_sff_tf_load - send taskfile registers to host controller
@@ -475,7 +423,7 @@ void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
}
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- WARN_ON(!ioaddr->ctl_addr);
+ WARN_ON_ONCE(!ioaddr->ctl_addr);
iowrite8(tf->hob_feature, ioaddr->feature_addr);
iowrite8(tf->hob_nsect, ioaddr->nsect_addr);
iowrite8(tf->hob_lbal, ioaddr->lbal_addr);
@@ -510,6 +458,7 @@ void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
ata_wait_idle(ap);
}
+EXPORT_SYMBOL_GPL(ata_sff_tf_load);
/**
* ata_sff_tf_read - input device's ATA taskfile shadow registers
@@ -547,9 +496,10 @@ void ata_sff_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
iowrite8(tf->ctl, ioaddr->ctl_addr);
ap->last_ctl = tf->ctl;
} else
- WARN_ON(1);
+ WARN_ON_ONCE(1);
}
}
+EXPORT_SYMBOL_GPL(ata_sff_tf_read);
/**
* ata_sff_exec_command - issue ATA command to host controller
@@ -569,6 +519,7 @@ void ata_sff_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
iowrite8(tf->command, ap->ioaddr.command_addr);
ata_sff_pause(ap);
}
+EXPORT_SYMBOL_GPL(ata_sff_exec_command);
/**
* ata_tf_to_host - issue ATA taskfile to host controller
@@ -617,23 +568,93 @@ unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf,
else
iowrite16_rep(data_addr, buf, words);
- /* Transfer trailing 1 byte, if any. */
+ /* Transfer trailing byte, if any. */
if (unlikely(buflen & 0x01)) {
- __le16 align_buf[1] = { 0 };
- unsigned char *trailing_buf = buf + buflen - 1;
+ unsigned char pad[2] = { };
+
+ /* Point buf to the tail of buffer */
+ buf += buflen - 1;
+ /*
+ * Use io*16_rep() accessors here as well to avoid pointlessly
+ * swapping bytes to and from on the big endian machines...
+ */
if (rw == READ) {
- align_buf[0] = cpu_to_le16(ioread16(data_addr));
- memcpy(trailing_buf, align_buf, 1);
+ ioread16_rep(data_addr, pad, 1);
+ *buf = pad[0];
} else {
- memcpy(align_buf, trailing_buf, 1);
- iowrite16(le16_to_cpu(align_buf[0]), data_addr);
+ pad[0] = *buf;
+ iowrite16_rep(data_addr, pad, 1);
}
words++;
}
return words << 1;
}
+EXPORT_SYMBOL_GPL(ata_sff_data_xfer);
+
+/**
+ * ata_sff_data_xfer32 - Transfer data by PIO
+ * @dev: device to target
+ * @buf: data buffer
+ * @buflen: buffer length
+ * @rw: read/write
+ *
+ * Transfer data from/to the device data register by PIO using 32bit
+ * I/O operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * Bytes consumed.
+ */
+
+unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw)
+{
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned int words = buflen >> 2;
+ int slop = buflen & 3;
+
+ if (!(ap->pflags & ATA_PFLAG_PIO32))
+ return ata_sff_data_xfer(dev, buf, buflen, rw);
+
+ /* Transfer multiple of 4 bytes */
+ if (rw == READ)
+ ioread32_rep(data_addr, buf, words);
+ else
+ iowrite32_rep(data_addr, buf, words);
+
+ /* Transfer trailing bytes, if any */
+ if (unlikely(slop)) {
+ unsigned char pad[4] = { };
+
+ /* Point buf to the tail of buffer */
+ buf += buflen - slop;
+
+ /*
+ * Use io*_rep() accessors here as well to avoid pointlessly
+ * swapping bytes to and from on the big endian machines...
+ */
+ if (rw == READ) {
+ if (slop < 3)
+ ioread16_rep(data_addr, pad, 1);
+ else
+ ioread32_rep(data_addr, pad, 1);
+ memcpy(buf, pad, slop);
+ } else {
+ memcpy(pad, buf, slop);
+ if (slop < 3)
+ iowrite16_rep(data_addr, pad, 1);
+ else
+ iowrite32_rep(data_addr, pad, 1);
+ }
+ }
+ return (buflen + 1) & ~1;
+}
+EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
/**
* ata_sff_data_xfer_noirq - Transfer data by PIO
@@ -658,11 +679,12 @@ unsigned int ata_sff_data_xfer_noirq(struct ata_device *dev, unsigned char *buf,
unsigned int consumed;
local_irq_save(flags);
- consumed = ata_sff_data_xfer(dev, buf, buflen, rw);
+ consumed = ata_sff_data_xfer32(dev, buf, buflen, rw);
local_irq_restore(flags);
return consumed;
}
+EXPORT_SYMBOL_GPL(ata_sff_data_xfer_noirq);
/**
* ata_pio_sector - Transfer a sector of data.
@@ -698,13 +720,13 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
/* FIXME: use a bounce buffer */
local_irq_save(flags);
- buf = kmap_atomic(page, KM_IRQ0);
+ buf = kmap_atomic(page);
/* do the actual data transfer */
ap->ops->sff_data_xfer(qc->dev, buf + offset, qc->sect_size,
do_write);
- kunmap_atomic(buf, KM_IRQ0);
+ kunmap_atomic(buf);
local_irq_restore(flags);
} else {
buf = page_address(page);
@@ -712,6 +734,9 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
do_write);
}
+ if (!do_write && !PageSlab(page))
+ flush_dcache_page(page);
+
qc->curbytes += qc->sect_size;
qc->cursg_ofs += qc->sect_size;
@@ -737,7 +762,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
/* READ/WRITE MULTIPLE */
unsigned int nsect;
- WARN_ON(qc->dev->multi_count == 0);
+ WARN_ON_ONCE(qc->dev->multi_count == 0);
nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size,
qc->dev->multi_count);
@@ -746,7 +771,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
} else
ata_pio_sector(qc);
- ata_sff_altstatus(qc->ap); /* flush */
+ ata_sff_sync(qc->ap); /* flush */
}
/**
@@ -764,11 +789,12 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
{
/* send SCSI cdb */
DPRINTK("send cdb\n");
- WARN_ON(qc->dev->cdb_len < 12);
+ WARN_ON_ONCE(qc->dev->cdb_len < 12);
ap->ops->sff_data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
- ata_sff_altstatus(ap); /* flush */
-
+ ata_sff_sync(ap);
+ /* FIXME: If the CDB is for DMA do we need to do the transition delay
+ or is bmdma_start guaranteed to do it ? */
switch (qc->tf.protocol) {
case ATAPI_PROT_PIO:
ap->hsm_task_state = HSM_ST;
@@ -776,11 +802,15 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
case ATAPI_PROT_NODATA:
ap->hsm_task_state = HSM_ST_LAST;
break;
+#ifdef CONFIG_ATA_BMDMA
case ATAPI_PROT_DMA:
ap->hsm_task_state = HSM_ST_LAST;
/* initiate bmdma */
ap->ops->bmdma_start(qc);
break;
+#endif /* CONFIG_ATA_BMDMA */
+ default:
+ BUG();
}
}
@@ -835,16 +865,18 @@ next_sg:
/* FIXME: use bounce buffer */
local_irq_save(flags);
- buf = kmap_atomic(page, KM_IRQ0);
+ buf = kmap_atomic(page);
/* do the actual data transfer */
- consumed = ap->ops->sff_data_xfer(dev, buf + offset, count, rw);
+ consumed = ap->ops->sff_data_xfer(dev, buf + offset,
+ count, rw);
- kunmap_atomic(buf, KM_IRQ0);
+ kunmap_atomic(buf);
local_irq_restore(flags);
} else {
buf = page_address(page);
- consumed = ap->ops->sff_data_xfer(dev, buf + offset, count, rw);
+ consumed = ap->ops->sff_data_xfer(dev, buf + offset,
+ count, rw);
}
bytes -= min(bytes, consumed);
@@ -856,9 +888,12 @@ next_sg:
qc->cursg_ofs = 0;
}
- /* consumed can be larger than count only for the last transfer */
- WARN_ON(qc->cursg && count != consumed);
-
+ /*
+ * There used to be a WARN_ON_ONCE(qc->cursg && count != consumed);
+ * Unfortunately __atapi_pio_bytes doesn't know enough to do the WARN
+ * check correctly as it doesn't know if it is the last request being
+ * made. Somebody should implement a proper sanity check.
+ */
if (bytes)
goto next_sg;
return 0;
@@ -894,11 +929,11 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
bytes = (bc_hi << 8) | bc_lo;
/* shall be cleared to zero, indicating xfer of data */
- if (unlikely(ireason & (1 << 0)))
+ if (unlikely(ireason & ATAPI_COD))
goto atapi_check;
/* make sure transfer direction matches expected */
- i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0;
+ i_write = ((ireason & ATAPI_IO) == 0) ? 1 : 0;
if (unlikely(do_write != i_write))
goto atapi_check;
@@ -909,7 +944,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
if (unlikely(__atapi_pio_bytes(qc, bytes)))
goto err_out;
- ata_sff_altstatus(ap); /* flush */
+ ata_sff_sync(ap); /* flush */
return;
@@ -929,18 +964,19 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
* RETURNS:
* 1 if ok in workqueue, 0 otherwise.
*/
-static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc)
+static inline int ata_hsm_ok_in_wq(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
{
if (qc->tf.flags & ATA_TFLAG_POLLING)
return 1;
if (ap->hsm_task_state == HSM_ST_FIRST) {
if (qc->tf.protocol == ATA_PROT_PIO &&
- (qc->tf.flags & ATA_TFLAG_WRITE))
+ (qc->tf.flags & ATA_TFLAG_WRITE))
return 1;
if (ata_is_atapi(qc->tf.protocol) &&
- !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
return 1;
}
@@ -973,7 +1009,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
qc = ata_qc_from_tag(ap, qc->tag);
if (qc) {
if (likely(!(qc->err_mask & AC_ERR_HSM))) {
- ap->ops->sff_irq_on(ap);
+ ata_sff_irq_on(ap);
ata_qc_complete(qc);
} else
ata_port_freeze(ap);
@@ -989,7 +1025,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
} else {
if (in_wq) {
spin_lock_irqsave(ap->lock, flags);
- ap->ops->sff_irq_on(ap);
+ ata_sff_irq_on(ap);
ata_qc_complete(qc);
spin_unlock_irqrestore(ap->lock, flags);
} else
@@ -1010,16 +1046,18 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
u8 status, int in_wq)
{
+ struct ata_link *link = qc->dev->link;
+ struct ata_eh_info *ehi = &link->eh_info;
unsigned long flags = 0;
int poll_next;
- WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
+ WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
/* Make sure ata_sff_qc_issue() does not throw things
* like DMA polling into the workqueue. Notice that
* in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING).
*/
- WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc));
+ WARN_ON_ONCE(in_wq != ata_hsm_ok_in_wq(ap, qc));
fsm_start:
DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
@@ -1041,9 +1079,12 @@ fsm_start:
if (likely(status & (ATA_ERR | ATA_DF)))
/* device stops HSM for abort/error */
qc->err_mask |= AC_ERR_DEV;
- else
+ else {
/* HSM violation. Let EH handle this */
+ ata_ehi_push_desc(ehi,
+ "ST_FIRST: !(DRQ|ERR|DF)");
qc->err_mask |= AC_ERR_HSM;
+ }
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -1062,9 +1103,9 @@ fsm_start:
* the CDB.
*/
if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) {
- ata_port_printk(ap, KERN_WARNING,
- "DRQ=1 with device error, "
- "dev_stat 0x%X\n", status);
+ ata_ehi_push_desc(ehi, "ST_FIRST: "
+ "DRQ=1 with device error, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -1097,7 +1138,7 @@ fsm_start:
if (in_wq)
spin_unlock_irqrestore(ap->lock, flags);
- /* if polling, ata_pio_task() handles the rest.
+ /* if polling, ata_sff_pio_task() handles the rest.
* otherwise, interrupt handler takes over from here.
*/
break;
@@ -1121,9 +1162,9 @@ fsm_start:
* let the EH abort the command or reset the device.
*/
if (unlikely(status & (ATA_ERR | ATA_DF))) {
- ata_port_printk(ap, KERN_WARNING, "DRQ=1 with "
- "device error, dev_stat 0x%X\n",
- status);
+ ata_ehi_push_desc(ehi, "ST-ATAPI: "
+ "DRQ=1 with device error, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -1139,16 +1180,29 @@ fsm_start:
/* ATA PIO protocol */
if (unlikely((status & ATA_DRQ) == 0)) {
/* handle BSY=0, DRQ=0 as error */
- if (likely(status & (ATA_ERR | ATA_DF)))
+ if (likely(status & (ATA_ERR | ATA_DF))) {
/* device stops HSM for abort/error */
qc->err_mask |= AC_ERR_DEV;
- else
+
+ /* If diagnostic failed and this is
+ * IDENTIFY, it's likely a phantom
+ * device. Mark hint.
+ */
+ if (qc->dev->horkage &
+ ATA_HORKAGE_DIAGNOSTIC)
+ qc->err_mask |=
+ AC_ERR_NODEV_HINT;
+ } else {
/* HSM violation. Let EH handle this.
* Phantom devices also trigger this
* condition. Mark hint.
*/
+ ata_ehi_push_desc(ehi, "ST-ATA: "
+ "DRQ=0 without device error, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM |
AC_ERR_NODEV_HINT;
+ }
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -1173,8 +1227,22 @@ fsm_start:
status = ata_wait_idle(ap);
}
- if (status & (ATA_BUSY | ATA_DRQ))
+ if (status & (ATA_BUSY | ATA_DRQ)) {
+ ata_ehi_push_desc(ehi, "ST-ATA: "
+ "BUSY|DRQ persists on ERR|DF, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM;
+ }
+
+ /* There are oddball controllers with
+ * status register stuck at 0x7f and
+ * lbal/m/h at zero which makes it
+ * pass all other presence detection
+ * mechanisms we have. Set NODEV_HINT
+ * for it. Kernel bz#7241.
+ */
+ if (status == 0x7f)
+ qc->err_mask |= AC_ERR_NODEV_HINT;
/* ata_pio_sectors() might change the
* state to HSM_ST_LAST. so, the state
@@ -1208,7 +1276,7 @@ fsm_start:
DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n",
ap->print_id, qc->dev->devno, status);
- WARN_ON(qc->err_mask);
+ WARN_ON_ONCE(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM));
ap->hsm_task_state = HSM_ST_IDLE;
@@ -1219,11 +1287,6 @@ fsm_start:
break;
case HSM_ST_ERR:
- /* make sure qc->err_mask is available to
- * know what's wrong and recover
- */
- WARN_ON(qc->err_mask == 0);
-
ap->hsm_task_state = HSM_ST_IDLE;
/* complete taskfile transaction */
@@ -1238,17 +1301,64 @@ fsm_start:
return poll_next;
}
+EXPORT_SYMBOL_GPL(ata_sff_hsm_move);
+
+void ata_sff_queue_work(struct work_struct *work)
+{
+ queue_work(ata_sff_wq, work);
+}
+EXPORT_SYMBOL_GPL(ata_sff_queue_work);
+
+void ata_sff_queue_delayed_work(struct delayed_work *dwork, unsigned long delay)
+{
+ queue_delayed_work(ata_sff_wq, dwork, delay);
+}
+EXPORT_SYMBOL_GPL(ata_sff_queue_delayed_work);
+
+void ata_sff_queue_pio_task(struct ata_link *link, unsigned long delay)
+{
+ struct ata_port *ap = link->ap;
+
+ WARN_ON((ap->sff_pio_task_link != NULL) &&
+ (ap->sff_pio_task_link != link));
+ ap->sff_pio_task_link = link;
+
+ /* may fail if ata_sff_flush_pio_task() in progress */
+ ata_sff_queue_delayed_work(&ap->sff_pio_task, msecs_to_jiffies(delay));
+}
+EXPORT_SYMBOL_GPL(ata_sff_queue_pio_task);
-void ata_pio_task(struct work_struct *work)
+void ata_sff_flush_pio_task(struct ata_port *ap)
+{
+ DPRINTK("ENTER\n");
+
+ cancel_delayed_work_sync(&ap->sff_pio_task);
+ ap->hsm_task_state = HSM_ST_IDLE;
+ ap->sff_pio_task_link = NULL;
+
+ if (ata_msg_ctl(ap))
+ ata_port_dbg(ap, "%s: EXIT\n", __func__);
+}
+
+static void ata_sff_pio_task(struct work_struct *work)
{
struct ata_port *ap =
- container_of(work, struct ata_port, port_task.work);
- struct ata_queued_cmd *qc = ap->port_task_data;
+ container_of(work, struct ata_port, sff_pio_task.work);
+ struct ata_link *link = ap->sff_pio_task_link;
+ struct ata_queued_cmd *qc;
u8 status;
int poll_next;
+ BUG_ON(ap->sff_pio_task_link == NULL);
+ /* qc can be NULL if timeout occurred */
+ qc = ata_qc_from_tag(ap, link->active_tag);
+ if (!qc) {
+ ap->sff_pio_task_link = NULL;
+ return;
+ }
+
fsm_start:
- WARN_ON(ap->hsm_task_state == HSM_ST_IDLE);
+ WARN_ON_ONCE(ap->hsm_task_state == HSM_ST_IDLE);
/*
* This is purely heuristic. This is a fast path.
@@ -1259,14 +1369,19 @@ fsm_start:
*/
status = ata_sff_busy_wait(ap, ATA_BUSY, 5);
if (status & ATA_BUSY) {
- msleep(2);
+ ata_msleep(ap, 2);
status = ata_sff_busy_wait(ap, ATA_BUSY, 10);
if (status & ATA_BUSY) {
- ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE);
+ ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE);
return;
}
}
+ /*
+ * hsm_move() may trigger another command to be processed.
+ * clean the link beforehand.
+ */
+ ap->sff_pio_task_link = NULL;
/* move the HSM */
poll_next = ata_sff_hsm_move(ap, qc, status, 1);
@@ -1278,15 +1393,11 @@ fsm_start:
}
/**
- * ata_sff_qc_issue - issue taskfile to device in proto-dependent manner
+ * ata_sff_qc_issue - issue taskfile to a SFF controller
* @qc: command to issue to device
*
- * Using various libata functions and hooks, this function
- * starts an ATA command. ATA commands are grouped into
- * classes called "protocols", and issuing each type of protocol
- * is slightly different.
- *
- * May be used as the qc_issue() entry in ata_port_operations.
+ * This function issues a PIO or NODATA command to a SFF
+ * controller.
*
* LOCKING:
* spin_lock_irqsave(host lock)
@@ -1297,27 +1408,13 @@ fsm_start:
unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ struct ata_link *link = qc->dev->link;
/* Use polling pio if the LLD doesn't handle
* interrupt driven pio and atapi CDB interrupt.
*/
- if (ap->flags & ATA_FLAG_PIO_POLLING) {
- switch (qc->tf.protocol) {
- case ATA_PROT_PIO:
- case ATA_PROT_NODATA:
- case ATAPI_PROT_PIO:
- case ATAPI_PROT_NODATA:
- qc->tf.flags |= ATA_TFLAG_POLLING;
- break;
- case ATAPI_PROT_DMA:
- if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
- /* see ata_dma_blacklisted() */
- BUG();
- break;
- default:
- break;
- }
- }
+ if (ap->flags & ATA_FLAG_PIO_POLLING)
+ qc->tf.flags |= ATA_TFLAG_POLLING;
/* select the device */
ata_dev_select(ap, qc->dev->devno, 1, 0);
@@ -1332,19 +1429,10 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc)
ap->hsm_task_state = HSM_ST_LAST;
if (qc->tf.flags & ATA_TFLAG_POLLING)
- ata_pio_queue_task(ap, qc, 0);
+ ata_sff_queue_pio_task(link, 0);
break;
- case ATA_PROT_DMA:
- WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
-
- ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */
- ap->ops->bmdma_setup(qc); /* set up bmdma */
- ap->ops->bmdma_start(qc); /* initiate bmdma */
- ap->hsm_task_state = HSM_ST_LAST;
- break;
-
case ATA_PROT_PIO:
if (qc->tf.flags & ATA_TFLAG_POLLING)
ata_qc_set_polling(qc);
@@ -1354,20 +1442,21 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc)
if (qc->tf.flags & ATA_TFLAG_WRITE) {
/* PIO data out protocol */
ap->hsm_task_state = HSM_ST_FIRST;
- ata_pio_queue_task(ap, qc, 0);
+ ata_sff_queue_pio_task(link, 0);
- /* always send first data block using
- * the ata_pio_task() codepath.
+ /* always send first data block using the
+ * ata_sff_pio_task() codepath.
*/
} else {
/* PIO data in protocol */
ap->hsm_task_state = HSM_ST;
if (qc->tf.flags & ATA_TFLAG_POLLING)
- ata_pio_queue_task(ap, qc, 0);
+ ata_sff_queue_pio_task(link, 0);
- /* if polling, ata_pio_task() handles the rest.
- * otherwise, interrupt handler takes over from here.
+ /* if polling, ata_sff_pio_task() handles the
+ * rest. otherwise, interrupt handler takes
+ * over from here.
*/
}
@@ -1385,28 +1474,17 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc)
/* send cdb by polling if no cdb interrupt */
if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
(qc->tf.flags & ATA_TFLAG_POLLING))
- ata_pio_queue_task(ap, qc, 0);
- break;
-
- case ATAPI_PROT_DMA:
- WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
-
- ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */
- ap->ops->bmdma_setup(qc); /* set up bmdma */
- ap->hsm_task_state = HSM_ST_FIRST;
-
- /* send cdb by polling if no cdb interrupt */
- if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
- ata_pio_queue_task(ap, qc, 0);
+ ata_sff_queue_pio_task(link, 0);
break;
default:
- WARN_ON(1);
+ WARN_ON_ONCE(1);
return AC_ERR_SYSTEM;
}
return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_qc_issue);
/**
* ata_sff_qc_fill_rtf - fill result TF using ->sff_tf_read
@@ -1426,27 +1504,29 @@ bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc)
qc->ap->ops->sff_tf_read(qc->ap, &qc->result_tf);
return true;
}
+EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf);
-/**
- * ata_sff_host_intr - Handle host interrupt for given (port, task)
- * @ap: Port on which interrupt arrived (possibly...)
- * @qc: Taskfile currently active in engine
- *
- * Handle host interrupt for given queued command. Currently,
- * only DMA interrupts are handled. All other commands are
- * handled via polling with interrupts disabled (nIEN bit).
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- *
- * RETURNS:
- * One if interrupt was handled, zero if not (shared irq).
- */
-inline unsigned int ata_sff_host_intr(struct ata_port *ap,
- struct ata_queued_cmd *qc)
+static unsigned int ata_sff_idle_irq(struct ata_port *ap)
{
- struct ata_eh_info *ehi = &ap->link.eh_info;
- u8 status, host_stat = 0;
+ ap->stats.idle_irq++;
+
+#ifdef ATA_IRQ_TRAP
+ if ((ap->stats.idle_irq % 1000) == 0) {
+ ap->ops->sff_check_status(ap);
+ if (ap->ops->sff_irq_clear)
+ ap->ops->sff_irq_clear(ap);
+ ata_port_warn(ap, "irq trap\n");
+ return 1;
+ }
+#endif
+ return 0; /* irq not handled */
+}
+
+static unsigned int __ata_sff_port_intr(struct ata_port *ap,
+ struct ata_queued_cmd *qc,
+ bool hsmv_on_idle)
+{
+ u8 status;
VPRINTK("ata%u: protocol %d task_state %d\n",
ap->print_id, qc->tf.protocol, ap->hsm_task_state);
@@ -1463,107 +1543,117 @@ inline unsigned int ata_sff_host_intr(struct ata_port *ap,
* need to check ata_is_atapi(qc->tf.protocol) again.
*/
if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
- goto idle_irq;
- break;
- case HSM_ST_LAST:
- if (qc->tf.protocol == ATA_PROT_DMA ||
- qc->tf.protocol == ATAPI_PROT_DMA) {
- /* check status of DMA engine */
- host_stat = ap->ops->bmdma_status(ap);
- VPRINTK("ata%u: host_stat 0x%X\n",
- ap->print_id, host_stat);
-
- /* if it's not our irq... */
- if (!(host_stat & ATA_DMA_INTR))
- goto idle_irq;
-
- /* before we do anything else, clear DMA-Start bit */
- ap->ops->bmdma_stop(qc);
-
- if (unlikely(host_stat & ATA_DMA_ERR)) {
- /* error when transfering data to/from memory */
- qc->err_mask |= AC_ERR_HOST_BUS;
- ap->hsm_task_state = HSM_ST_ERR;
- }
- }
- break;
- case HSM_ST:
+ return ata_sff_idle_irq(ap);
break;
+ case HSM_ST_IDLE:
+ return ata_sff_idle_irq(ap);
default:
- goto idle_irq;
+ break;
}
- /* check altstatus */
- status = ata_sff_altstatus(ap);
- if (status & ATA_BUSY)
- goto idle_irq;
-
- /* check main status, clearing INTRQ */
- status = ap->ops->sff_check_status(ap);
- if (unlikely(status & ATA_BUSY))
- goto idle_irq;
+ /* check main status, clearing INTRQ if needed */
+ status = ata_sff_irq_status(ap);
+ if (status & ATA_BUSY) {
+ if (hsmv_on_idle) {
+ /* BMDMA engine is already stopped, we're screwed */
+ qc->err_mask |= AC_ERR_HSM;
+ ap->hsm_task_state = HSM_ST_ERR;
+ } else
+ return ata_sff_idle_irq(ap);
+ }
- /* ack bmdma irq events */
- ap->ops->sff_irq_clear(ap);
+ /* clear irq events */
+ if (ap->ops->sff_irq_clear)
+ ap->ops->sff_irq_clear(ap);
ata_sff_hsm_move(ap, qc, status, 0);
- if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
- qc->tf.protocol == ATAPI_PROT_DMA))
- ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
-
return 1; /* irq handled */
-
-idle_irq:
- ap->stats.idle_irq++;
-
-#ifdef ATA_IRQ_TRAP
- if ((ap->stats.idle_irq % 1000) == 0) {
- ap->ops->sff_check_status(ap);
- ap->ops->sff_irq_clear(ap);
- ata_port_printk(ap, KERN_WARNING, "irq trap\n");
- return 1;
- }
-#endif
- return 0; /* irq not handled */
}
/**
- * ata_sff_interrupt - Default ATA host interrupt handler
- * @irq: irq line (unused)
- * @dev_instance: pointer to our ata_host information structure
+ * ata_sff_port_intr - Handle SFF port interrupt
+ * @ap: Port on which interrupt arrived (possibly...)
+ * @qc: Taskfile currently active in engine
*
- * Default interrupt handler for PCI IDE devices. Calls
- * ata_sff_host_intr() for each port that is not disabled.
+ * Handle port interrupt for given queued command.
*
* LOCKING:
- * Obtains host lock during operation.
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
- * IRQ_NONE or IRQ_HANDLED.
+ * One if interrupt was handled, zero if not (shared irq).
*/
-irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
+unsigned int ata_sff_port_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ return __ata_sff_port_intr(ap, qc, false);
+}
+EXPORT_SYMBOL_GPL(ata_sff_port_intr);
+
+static inline irqreturn_t __ata_sff_interrupt(int irq, void *dev_instance,
+ unsigned int (*port_intr)(struct ata_port *, struct ata_queued_cmd *))
{
struct ata_host *host = dev_instance;
+ bool retried = false;
unsigned int i;
- unsigned int handled = 0;
+ unsigned int handled, idle, polling;
unsigned long flags;
/* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
spin_lock_irqsave(&host->lock, flags);
+retry:
+ handled = idle = polling = 0;
for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap;
+ struct ata_port *ap = host->ports[i];
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc) {
+ if (!(qc->tf.flags & ATA_TFLAG_POLLING))
+ handled |= port_intr(ap, qc);
+ else
+ polling |= 1 << i;
+ } else
+ idle |= 1 << i;
+ }
- ap = host->ports[i];
- if (ap &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
+ /*
+ * If no port was expecting IRQ but the controller is actually
+ * asserting IRQ line, nobody cared will ensue. Check IRQ
+ * pending status if available and clear spurious IRQ.
+ */
+ if (!handled && !retried) {
+ bool retry = false;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (polling & (1 << i))
+ continue;
+
+ if (!ap->ops->sff_irq_check ||
+ !ap->ops->sff_irq_check(ap))
+ continue;
+
+ if (idle & (1 << i)) {
+ ap->ops->sff_check_status(ap);
+ if (ap->ops->sff_irq_clear)
+ ap->ops->sff_irq_clear(ap);
+ } else {
+ /* clear INTRQ and check if BUSY cleared */
+ if (!(ap->ops->sff_check_status(ap) & ATA_BUSY))
+ retry |= true;
+ /*
+ * With command in flight, we can't do
+ * sff_irq_clear() w/o racing with completion.
+ */
+ }
+ }
- qc = ata_qc_from_tag(ap, ap->link.active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
- (qc->flags & ATA_QCFLAG_ACTIVE))
- handled |= ata_sff_host_intr(ap, qc);
+ if (retry) {
+ retried = true;
+ goto retry;
}
}
@@ -1573,23 +1663,80 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
}
/**
+ * ata_sff_interrupt - Default SFF ATA host interrupt handler
+ * @irq: irq line (unused)
+ * @dev_instance: pointer to our ata_host information structure
+ *
+ * Default interrupt handler for PCI IDE devices. Calls
+ * ata_sff_port_intr() for each port that is not disabled.
+ *
+ * LOCKING:
+ * Obtains host lock during operation.
+ *
+ * RETURNS:
+ * IRQ_NONE or IRQ_HANDLED.
+ */
+irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
+{
+ return __ata_sff_interrupt(irq, dev_instance, ata_sff_port_intr);
+}
+EXPORT_SYMBOL_GPL(ata_sff_interrupt);
+
+/**
+ * ata_sff_lost_interrupt - Check for an apparent lost interrupt
+ * @ap: port that appears to have timed out
+ *
+ * Called from the libata error handlers when the core code suspects
+ * an interrupt has been lost. If it has complete anything we can and
+ * then return. Interface must support altstatus for this faster
+ * recovery to occur.
+ *
+ * Locking:
+ * Caller holds host lock
+ */
+
+void ata_sff_lost_interrupt(struct ata_port *ap)
+{
+ u8 status;
+ struct ata_queued_cmd *qc;
+
+ /* Only one outstanding command per SFF channel */
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ /* We cannot lose an interrupt on a non-existent or polled command */
+ if (!qc || qc->tf.flags & ATA_TFLAG_POLLING)
+ return;
+ /* See if the controller thinks it is still busy - if so the command
+ isn't a lost IRQ but is still in progress */
+ status = ata_sff_altstatus(ap);
+ if (status & ATA_BUSY)
+ return;
+
+ /* There was a command running, we are no longer busy and we have
+ no interrupt. */
+ ata_port_warn(ap, "lost interrupt (Status 0x%x)\n",
+ status);
+ /* Run the host interrupt logic as if the interrupt had not been
+ lost */
+ ata_sff_port_intr(ap, qc);
+}
+EXPORT_SYMBOL_GPL(ata_sff_lost_interrupt);
+
+/**
* ata_sff_freeze - Freeze SFF controller port
* @ap: port to freeze
*
- * Freeze BMDMA controller port.
+ * Freeze SFF controller port.
*
* LOCKING:
* Inherited from caller.
*/
void ata_sff_freeze(struct ata_port *ap)
{
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
ap->ctl |= ATA_NIEN;
ap->last_ctl = ap->ctl;
- if (ioaddr->ctl_addr)
- iowrite8(ap->ctl, ioaddr->ctl_addr);
+ if (ap->ops->sff_set_devctl || ap->ioaddr.ctl_addr)
+ ata_sff_set_devctl(ap, ap->ctl);
/* Under certain circumstances, some controllers raise IRQ on
* ATA_NIEN manipulation. Also, many controllers fail to mask
@@ -1597,8 +1744,10 @@ void ata_sff_freeze(struct ata_port *ap)
*/
ap->ops->sff_check_status(ap);
- ap->ops->sff_irq_clear(ap);
+ if (ap->ops->sff_irq_clear)
+ ap->ops->sff_irq_clear(ap);
}
+EXPORT_SYMBOL_GPL(ata_sff_freeze);
/**
* ata_sff_thaw - Thaw SFF controller port
@@ -1613,9 +1762,11 @@ void ata_sff_thaw(struct ata_port *ap)
{
/* clear & re-enable interrupts */
ap->ops->sff_check_status(ap);
- ap->ops->sff_irq_clear(ap);
- ap->ops->sff_irq_on(ap);
+ if (ap->ops->sff_irq_clear)
+ ap->ops->sff_irq_clear(ap);
+ ata_sff_irq_on(ap);
}
+EXPORT_SYMBOL_GPL(ata_sff_thaw);
/**
* ata_sff_prereset - prepare SFF link for reset
@@ -1649,14 +1800,16 @@ int ata_sff_prereset(struct ata_link *link, unsigned long deadline)
if (!ata_link_offline(link)) {
rc = ata_sff_wait_ready(link, deadline);
if (rc && rc != -ENODEV) {
- ata_link_printk(link, KERN_WARNING, "device not ready "
- "(errno=%d), forcing hardreset\n", rc);
+ ata_link_warn(link,
+ "device not ready (errno=%d), forcing hardreset\n",
+ rc);
ehc->i.action |= ATA_EH_HARDRESET;
}
}
return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_prereset);
/**
* ata_devchk - PATA device presence detection
@@ -1769,6 +1922,7 @@ unsigned int ata_sff_dev_classify(struct ata_device *dev, int present,
return class;
}
+EXPORT_SYMBOL_GPL(ata_sff_dev_classify);
/**
* ata_sff_wait_after_reset - wait for devices to become ready after reset
@@ -1796,7 +1950,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask,
unsigned int dev1 = devmask & (1 << 1);
int rc, ret = 0;
- msleep(ATA_WAIT_AFTER_RESET_MSECS);
+ ata_msleep(ap, ATA_WAIT_AFTER_RESET);
/* always check readiness of the master device */
rc = ata_sff_wait_ready(link, deadline);
@@ -1825,7 +1979,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask,
lbal = ioread8(ioaddr->lbal_addr);
if ((nsect == 1) && (lbal == 1))
break;
- msleep(50); /* give drive a breather */
+ ata_msleep(ap, 50); /* give drive a breather */
}
rc = ata_sff_wait_ready(link, deadline);
@@ -1845,6 +1999,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask,
return ret;
}
+EXPORT_SYMBOL_GPL(ata_sff_wait_after_reset);
static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
unsigned long deadline)
@@ -1859,6 +2014,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
udelay(20); /* FIXME: flush */
iowrite8(ap->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = ap->ctl;
/* wait the port to become ready */
return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
@@ -1903,7 +2059,7 @@ int ata_sff_softreset(struct ata_link *link, unsigned int *classes,
rc = ata_bus_softreset(ap, devmask, deadline);
/* if link is occupied, -ENODEV too is an error */
if (rc && (rc != -ENODEV || sata_scr_valid(link))) {
- ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc);
+ ata_link_err(link, "SRST failed (errno=%d)\n", rc);
return rc;
}
@@ -1917,6 +2073,7 @@ int ata_sff_softreset(struct ata_link *link, unsigned int *classes,
DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_softreset);
/**
* sata_sff_hardreset - reset host port via SATA phy reset
@@ -1949,6 +2106,7 @@ int sata_sff_hardreset(struct ata_link *link, unsigned int *class,
DPRINTK("EXIT, class=%u\n", *class);
return rc;
}
+EXPORT_SYMBOL_GPL(sata_sff_hardreset);
/**
* ata_sff_postreset - SFF postreset callback
@@ -1981,12 +2139,47 @@ void ata_sff_postreset(struct ata_link *link, unsigned int *classes)
}
/* set up device control */
- if (ap->ioaddr.ctl_addr)
- iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
+ if (ap->ops->sff_set_devctl || ap->ioaddr.ctl_addr) {
+ ata_sff_set_devctl(ap, ap->ctl);
+ ap->last_ctl = ap->ctl;
+ }
+}
+EXPORT_SYMBOL_GPL(ata_sff_postreset);
+
+/**
+ * ata_sff_drain_fifo - Stock FIFO drain logic for SFF controllers
+ * @qc: command
+ *
+ * Drain the FIFO and device of any stuck data following a command
+ * failing to complete. In some cases this is necessary before a
+ * reset will recover the device.
+ *
+ */
+
+void ata_sff_drain_fifo(struct ata_queued_cmd *qc)
+{
+ int count;
+ struct ata_port *ap;
+
+ /* We only need to flush incoming data when a command was running */
+ if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
+ return;
+
+ ap = qc->ap;
+ /* Drain up to 64K of data before we give up this recovery method */
+ for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ)
+ && count < 65536; count += 2)
+ ioread16(ap->ioaddr.data_addr);
+
+ /* Can become DEBUG later */
+ if (count)
+ ata_port_dbg(ap, "drained %d bytes to clear DRQ\n", count);
+
}
+EXPORT_SYMBOL_GPL(ata_sff_drain_fifo);
/**
- * ata_sff_error_handler - Stock error handler for BMDMA controller
+ * ata_sff_error_handler - Stock error handler for SFF controller
* @ap: port to handle error for
*
* Stock error handler for SFF controller. It can handle both
@@ -2003,92 +2196,38 @@ void ata_sff_error_handler(struct ata_port *ap)
ata_reset_fn_t hardreset = ap->ops->hardreset;
struct ata_queued_cmd *qc;
unsigned long flags;
- int thaw = 0;
qc = __ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
qc = NULL;
- /* reset PIO HSM and stop DMA engine */
spin_lock_irqsave(ap->lock, flags);
- ap->hsm_task_state = HSM_ST_IDLE;
-
- if (ap->ioaddr.bmdma_addr &&
- qc && (qc->tf.protocol == ATA_PROT_DMA ||
- qc->tf.protocol == ATAPI_PROT_DMA)) {
- u8 host_stat;
-
- host_stat = ap->ops->bmdma_status(ap);
-
- /* BMDMA controllers indicate host bus error by
- * setting DMA_ERR bit and timing out. As it wasn't
- * really a timeout event, adjust error mask and
- * cancel frozen state.
- */
- if (qc->err_mask == AC_ERR_TIMEOUT && (host_stat & ATA_DMA_ERR)) {
- qc->err_mask = AC_ERR_HOST_BUS;
- thaw = 1;
- }
-
- ap->ops->bmdma_stop(qc);
- }
-
- ata_sff_altstatus(ap);
- ap->ops->sff_check_status(ap);
- ap->ops->sff_irq_clear(ap);
+ /*
+ * We *MUST* do FIFO draining before we issue a reset as
+ * several devices helpfully clear their internal state and
+ * will lock solid if we touch the data port post reset. Pass
+ * qc in case anyone wants to do different PIO/DMA recovery or
+ * has per command fixups
+ */
+ if (ap->ops->sff_drain_fifo)
+ ap->ops->sff_drain_fifo(qc);
spin_unlock_irqrestore(ap->lock, flags);
- if (thaw)
- ata_eh_thaw_port(ap);
-
- /* PIO and DMA engines have been stopped, perform recovery */
-
- /* Ignore ata_sff_softreset if ctl isn't accessible and
- * built-in hardresets if SCR access isn't available.
- */
+ /* ignore ata_sff_softreset if ctl isn't accessible */
if (softreset == ata_sff_softreset && !ap->ioaddr.ctl_addr)
softreset = NULL;
- if (ata_is_builtin_hardreset(hardreset) && !sata_scr_valid(&ap->link))
+
+ /* ignore built-in hardresets if SCR access is not available */
+ if ((hardreset == sata_std_hardreset ||
+ hardreset == sata_sff_hardreset) && !sata_scr_valid(&ap->link))
hardreset = NULL;
ata_do_eh(ap, ap->ops->prereset, softreset, hardreset,
ap->ops->postreset);
}
-
-/**
- * ata_sff_post_internal_cmd - Stock post_internal_cmd for SFF controller
- * @qc: internal command to clean up
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- */
-void ata_sff_post_internal_cmd(struct ata_queued_cmd *qc)
-{
- if (qc->ap->ioaddr.bmdma_addr)
- ata_bmdma_stop(qc);
-}
-
-/**
- * ata_sff_port_start - Set port up for dma.
- * @ap: Port to initialize
- *
- * Called just after data structures for each port are
- * initialized. Allocates space for PRD table if the device
- * is DMA capable SFF.
- *
- * May be used as the port_start() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-int ata_sff_port_start(struct ata_port *ap)
-{
- if (ap->ioaddr.bmdma_addr)
- return ata_port_start(ap);
- return 0;
-}
+EXPORT_SYMBOL_GPL(ata_sff_error_handler);
/**
* ata_sff_std_ports - initialize ioaddr with standard port offsets.
@@ -2114,300 +2253,17 @@ void ata_sff_std_ports(struct ata_ioports *ioaddr)
ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS;
ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
}
-
-unsigned long ata_bmdma_mode_filter(struct ata_device *adev,
- unsigned long xfer_mask)
-{
- /* Filter out DMA modes if the device has been configured by
- the BIOS as PIO only */
-
- if (adev->link->ap->ioaddr.bmdma_addr == NULL)
- xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
- return xfer_mask;
-}
-
-/**
- * ata_bmdma_setup - Set up PCI IDE BMDMA transaction
- * @qc: Info associated with this ATA transaction.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-void ata_bmdma_setup(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
- u8 dmactl;
-
- /* load PRD table addr. */
- mb(); /* make sure PRD table writes are visible to controller */
- iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
-
- /* specify data direction, triple-check start bit is clear */
- dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
- if (!rw)
- dmactl |= ATA_DMA_WR;
- iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-
- /* issue r/w command */
- ap->ops->sff_exec_command(ap, &qc->tf);
-}
-
-/**
- * ata_bmdma_start - Start a PCI IDE BMDMA transaction
- * @qc: Info associated with this ATA transaction.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-void ata_bmdma_start(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- u8 dmactl;
-
- /* start host DMA transaction */
- dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-
- /* Strictly, one may wish to issue an ioread8() here, to
- * flush the mmio write. However, control also passes
- * to the hardware at this point, and it will interrupt
- * us when we are to resume control. So, in effect,
- * we don't care when the mmio write flushes.
- * Further, a read of the DMA status register _immediately_
- * following the write may not be what certain flaky hardware
- * is expected, so I think it is best to not add a readb()
- * without first all the MMIO ATA cards/mobos.
- * Or maybe I'm just being paranoid.
- *
- * FIXME: The posting of this write means I/O starts are
- * unneccessarily delayed for MMIO
- */
-}
-
-/**
- * ata_bmdma_stop - Stop PCI IDE BMDMA transfer
- * @qc: Command we are ending DMA for
- *
- * Clears the ATA_DMA_START flag in the dma control register
- *
- * May be used as the bmdma_stop() entry in ata_port_operations.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-void ata_bmdma_stop(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- void __iomem *mmio = ap->ioaddr.bmdma_addr;
-
- /* clear start/stop bit */
- iowrite8(ioread8(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
- mmio + ATA_DMA_CMD);
-
- /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
- ata_sff_altstatus(ap); /* dummy read */
-}
-
-/**
- * ata_bmdma_status - Read PCI IDE BMDMA status
- * @ap: Port associated with this ATA transaction.
- *
- * Read and return BMDMA status register.
- *
- * May be used as the bmdma_status() entry in ata_port_operations.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-u8 ata_bmdma_status(struct ata_port *ap)
-{
- return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-}
-
-/**
- * ata_bus_reset - reset host port and associated ATA channel
- * @ap: port to reset
- *
- * This is typically the first time we actually start issuing
- * commands to the ATA channel. We wait for BSY to clear, then
- * issue EXECUTE DEVICE DIAGNOSTIC command, polling for its
- * result. Determine what devices, if any, are on the channel
- * by looking at the device 0/1 error register. Look at the signature
- * stored in each device's taskfile registers, to determine if
- * the device is ATA or ATAPI.
- *
- * LOCKING:
- * PCI/etc. bus probe sem.
- * Obtains host lock.
- *
- * SIDE EFFECTS:
- * Sets ATA_FLAG_DISABLED if bus reset fails.
- *
- * DEPRECATED:
- * This function is only for drivers which still use old EH and
- * will be removed soon.
- */
-void ata_bus_reset(struct ata_port *ap)
-{
- struct ata_device *device = ap->link.device;
- struct ata_ioports *ioaddr = &ap->ioaddr;
- unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
- u8 err;
- unsigned int dev0, dev1 = 0, devmask = 0;
- int rc;
-
- DPRINTK("ENTER, host %u, port %u\n", ap->print_id, ap->port_no);
-
- /* determine if device 0/1 are present */
- if (ap->flags & ATA_FLAG_SATA_RESET)
- dev0 = 1;
- else {
- dev0 = ata_devchk(ap, 0);
- if (slave_possible)
- dev1 = ata_devchk(ap, 1);
- }
-
- if (dev0)
- devmask |= (1 << 0);
- if (dev1)
- devmask |= (1 << 1);
-
- /* select device 0 again */
- ap->ops->sff_dev_select(ap, 0);
-
- /* issue bus reset */
- if (ap->flags & ATA_FLAG_SRST) {
- rc = ata_bus_softreset(ap, devmask, jiffies + 40 * HZ);
- if (rc && rc != -ENODEV)
- goto err_out;
- }
-
- /*
- * determine by signature whether we have ATA or ATAPI devices
- */
- device[0].class = ata_sff_dev_classify(&device[0], dev0, &err);
- if ((slave_possible) && (err != 0x81))
- device[1].class = ata_sff_dev_classify(&device[1], dev1, &err);
-
- /* is double-select really necessary? */
- if (device[1].class != ATA_DEV_NONE)
- ap->ops->sff_dev_select(ap, 1);
- if (device[0].class != ATA_DEV_NONE)
- ap->ops->sff_dev_select(ap, 0);
-
- /* if no devices were detected, disable this port */
- if ((device[0].class == ATA_DEV_NONE) &&
- (device[1].class == ATA_DEV_NONE))
- goto err_out;
-
- if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
- /* set up device control for ATA_FLAG_SATA_RESET */
- iowrite8(ap->ctl, ioaddr->ctl_addr);
- }
-
- DPRINTK("EXIT\n");
- return;
-
-err_out:
- ata_port_printk(ap, KERN_ERR, "disabling port\n");
- ata_port_disable(ap);
-
- DPRINTK("EXIT\n");
-}
+EXPORT_SYMBOL_GPL(ata_sff_std_ports);
#ifdef CONFIG_PCI
-/**
- * ata_pci_bmdma_clear_simplex - attempt to kick device out of simplex
- * @pdev: PCI device
- *
- * Some PCI ATA devices report simplex mode but in fact can be told to
- * enter non simplex mode. This implements the necessary logic to
- * perform the task on such devices. Calling it on other devices will
- * have -undefined- behaviour.
- */
-int ata_pci_bmdma_clear_simplex(struct pci_dev *pdev)
-{
- unsigned long bmdma = pci_resource_start(pdev, 4);
- u8 simplex;
-
- if (bmdma == 0)
- return -ENOENT;
-
- simplex = inb(bmdma + 0x02);
- outb(simplex & 0x60, bmdma + 0x02);
- simplex = inb(bmdma + 0x02);
- if (simplex & 0x80)
- return -EOPNOTSUPP;
- return 0;
-}
-
-/**
- * ata_pci_bmdma_init - acquire PCI BMDMA resources and init ATA host
- * @host: target ATA host
- *
- * Acquire PCI BMDMA resources and initialize @host accordingly.
- *
- * LOCKING:
- * Inherited from calling layer (may sleep).
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
-int ata_pci_bmdma_init(struct ata_host *host)
-{
- struct device *gdev = host->dev;
- struct pci_dev *pdev = to_pci_dev(gdev);
- int i, rc;
-
- /* No BAR4 allocation: No DMA */
- if (pci_resource_start(pdev, 4) == 0)
- return 0;
-
- /* TODO: If we get no DMA mask we should fall back to PIO */
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
-
- /* request and iomap DMA region */
- rc = pcim_iomap_regions(pdev, 1 << 4, dev_driver_string(gdev));
- if (rc) {
- dev_printk(KERN_ERR, gdev, "failed to request/iomap BAR4\n");
- return -ENOMEM;
- }
- host->iomap = pcim_iomap_table(pdev);
-
- for (i = 0; i < 2; i++) {
- struct ata_port *ap = host->ports[i];
- void __iomem *bmdma = host->iomap[4] + 8 * i;
-
- if (ata_port_is_dummy(ap))
- continue;
-
- ap->ioaddr.bmdma_addr = bmdma;
- if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) &&
- (ioread8(bmdma + 2) & 0x80))
- host->flags |= ATA_HOST_SIMPLEX;
-
- ata_port_desc(ap, "bmdma 0x%llx",
- (unsigned long long)pci_resource_start(pdev, 4) + 8 * i);
- }
-
- return 0;
-}
-
static int ata_resources_present(struct pci_dev *pdev, int port)
{
int i;
/* Check the PCI resources for this channel are enabled */
port = port * 2;
- for (i = 0; i < 2; i ++) {
+ for (i = 0; i < 2; i++) {
if (pci_resource_start(pdev, port + i) == 0 ||
pci_resource_len(pdev, port + i) == 0)
return 0;
@@ -2462,9 +2318,9 @@ int ata_pci_sff_init_host(struct ata_host *host)
rc = pcim_iomap_regions(pdev, 0x3 << base,
dev_driver_string(gdev));
if (rc) {
- dev_printk(KERN_WARNING, gdev,
- "failed to request/iomap BARs for port %d "
- "(errno=%d)\n", i, rc);
+ dev_warn(gdev,
+ "failed to request/iomap BARs for port %d (errno=%d)\n",
+ i, rc);
if (rc == -EBUSY)
pcim_pin_device(pdev);
ap->ops = &ata_dummy_port_ops;
@@ -2486,21 +2342,22 @@ int ata_pci_sff_init_host(struct ata_host *host)
}
if (!mask) {
- dev_printk(KERN_ERR, gdev, "no available native port\n");
+ dev_err(gdev, "no available native port\n");
return -ENODEV;
}
return 0;
}
+EXPORT_SYMBOL_GPL(ata_pci_sff_init_host);
/**
- * ata_pci_sff_prepare_host - helper to prepare native PCI ATA host
+ * ata_pci_sff_prepare_host - helper to prepare PCI PIO-only SFF ATA host
* @pdev: target PCI device
* @ppi: array of port_info, must be enough for two ports
* @r_host: out argument for the initialized ATA host
*
- * Helper to allocate ATA host for @pdev, acquire all native PCI
- * resources and initialize it accordingly in one go.
+ * Helper to allocate PIO-only SFF ATA host for @pdev, acquire
+ * all PCI resources and initialize it accordingly in one go.
*
* LOCKING:
* Inherited from calling layer (may sleep).
@@ -2509,7 +2366,7 @@ int ata_pci_sff_init_host(struct ata_host *host)
* 0 on success, -errno otherwise.
*/
int ata_pci_sff_prepare_host(struct pci_dev *pdev,
- const struct ata_port_info * const * ppi,
+ const struct ata_port_info * const *ppi,
struct ata_host **r_host)
{
struct ata_host *host;
@@ -2520,8 +2377,7 @@ int ata_pci_sff_prepare_host(struct pci_dev *pdev,
host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
if (!host) {
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to allocate ATA host\n");
+ dev_err(&pdev->dev, "failed to allocate ATA host\n");
rc = -ENOMEM;
goto err_out;
}
@@ -2530,26 +2386,15 @@ int ata_pci_sff_prepare_host(struct pci_dev *pdev,
if (rc)
goto err_out;
- /* init DMA related stuff */
- rc = ata_pci_bmdma_init(host);
- if (rc)
- goto err_bmdma;
-
devres_remove_group(&pdev->dev, NULL);
*r_host = host;
return 0;
- err_bmdma:
- /* This is necessary because PCI and iomap resources are
- * merged and releasing the top group won't release the
- * acquired resources if some of those have been acquired
- * before entering this function.
- */
- pcim_iounmap_regions(pdev, 0xf);
- err_out:
+err_out:
devres_release_group(&pdev->dev, NULL);
return rc;
}
+EXPORT_SYMBOL_GPL(ata_pci_sff_prepare_host);
/**
* ata_pci_sff_activate_host - start SFF host, request IRQ and register it
@@ -2588,28 +2433,24 @@ int ata_pci_sff_activate_host(struct ata_host *host,
mask = (1 << 2) | (1 << 0);
if ((tmp8 & mask) != mask)
legacy_mode = 1;
-#if defined(CONFIG_NO_ATA_LEGACY)
- /* Some platforms with PCI limits cannot address compat
- port space. In that case we punt if their firmware has
- left a device in compatibility mode */
- if (legacy_mode) {
- printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
- return -EOPNOTSUPP;
- }
-#endif
}
if (!devres_open_group(dev, NULL, GFP_KERNEL))
return -ENOMEM;
if (!legacy_mode && pdev->irq) {
+ int i;
+
rc = devm_request_irq(dev, pdev->irq, irq_handler,
IRQF_SHARED, drv_name, host);
if (rc)
goto out;
- ata_port_desc(host->ports[0], "irq %d", pdev->irq);
- ata_port_desc(host->ports[1], "irq %d", pdev->irq);
+ for (i = 0; i < 2; i++) {
+ if (ata_port_is_dummy(host->ports[i]))
+ continue;
+ ata_port_desc(host->ports[i], "irq %d", pdev->irq);
+ }
} else if (legacy_mode) {
if (!ata_port_is_dummy(host->ports[0])) {
rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
@@ -2635,7 +2476,7 @@ int ata_pci_sff_activate_host(struct ata_host *host,
}
rc = ata_host_register(host, sht);
- out:
+out:
if (rc == 0)
devres_remove_group(dev, NULL);
else
@@ -2643,21 +2484,86 @@ int ata_pci_sff_activate_host(struct ata_host *host,
return rc;
}
+EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host);
+
+static const struct ata_port_info *ata_sff_find_valid_pi(
+ const struct ata_port_info * const *ppi)
+{
+ int i;
+
+ /* look up the first valid port_info */
+ for (i = 0; i < 2 && ppi[i]; i++)
+ if (ppi[i]->port_ops != &ata_dummy_port_ops)
+ return ppi[i];
+
+ return NULL;
+}
+
+static int ata_pci_init_one(struct pci_dev *pdev,
+ const struct ata_port_info * const *ppi,
+ struct scsi_host_template *sht, void *host_priv,
+ int hflags, bool bmdma)
+{
+ struct device *dev = &pdev->dev;
+ const struct ata_port_info *pi;
+ struct ata_host *host = NULL;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ pi = ata_sff_find_valid_pi(ppi);
+ if (!pi) {
+ dev_err(&pdev->dev, "no valid port_info specified\n");
+ return -EINVAL;
+ }
+
+ if (!devres_open_group(dev, NULL, GFP_KERNEL))
+ return -ENOMEM;
+
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ goto out;
+
+#ifdef CONFIG_ATA_BMDMA
+ if (bmdma)
+ /* prepare and activate BMDMA host */
+ rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
+ else
+#endif
+ /* prepare and activate SFF host */
+ rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+ if (rc)
+ goto out;
+ host->private_data = host_priv;
+ host->flags |= hflags;
+
+#ifdef CONFIG_ATA_BMDMA
+ if (bmdma) {
+ pci_set_master(pdev);
+ rc = ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht);
+ } else
+#endif
+ rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht);
+out:
+ if (rc == 0)
+ devres_remove_group(&pdev->dev, NULL);
+ else
+ devres_release_group(&pdev->dev, NULL);
+
+ return rc;
+}
/**
- * ata_pci_sff_init_one - Initialize/register PCI IDE host controller
+ * ata_pci_sff_init_one - Initialize/register PIO-only PCI IDE controller
* @pdev: Controller to be initialized
* @ppi: array of port_info, must be enough for two ports
* @sht: scsi_host_template to use when registering the host
* @host_priv: host private_data
+ * @hflag: host flags
*
* This is a helper function which can be called from a driver's
* xxx_init_one() probe function if the hardware uses traditional
- * IDE taskfile registers.
- *
- * This function calls pci_enable_device(), reserves its register
- * regions, sets the dma mask, enables bus master mode, and calls
- * ata_device_add()
+ * IDE taskfile registers and is PIO only.
*
* ASSUMPTION:
* Nobody makes a single channel controller that appears solely as
@@ -2670,100 +2576,762 @@ int ata_pci_sff_activate_host(struct ata_host *host,
* Zero on success, negative on errno-based value on error.
*/
int ata_pci_sff_init_one(struct pci_dev *pdev,
- const struct ata_port_info * const * ppi,
- struct scsi_host_template *sht, void *host_priv)
+ const struct ata_port_info * const *ppi,
+ struct scsi_host_template *sht, void *host_priv, int hflag)
{
- struct device *dev = &pdev->dev;
- const struct ata_port_info *pi = NULL;
- struct ata_host *host = NULL;
- int i, rc;
+ return ata_pci_init_one(pdev, ppi, sht, host_priv, hflag, 0);
+}
+EXPORT_SYMBOL_GPL(ata_pci_sff_init_one);
- DPRINTK("ENTER\n");
+#endif /* CONFIG_PCI */
- /* look up the first valid port_info */
- for (i = 0; i < 2 && ppi[i]; i++) {
- if (ppi[i]->port_ops != &ata_dummy_port_ops) {
- pi = ppi[i];
- break;
+/*
+ * BMDMA support
+ */
+
+#ifdef CONFIG_ATA_BMDMA
+
+const struct ata_port_operations ata_bmdma_port_ops = {
+ .inherits = &ata_sff_port_ops,
+
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_bmdma_qc_prep,
+ .qc_issue = ata_bmdma_qc_issue,
+
+ .sff_irq_clear = ata_bmdma_irq_clear,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .port_start = ata_bmdma_port_start,
+};
+EXPORT_SYMBOL_GPL(ata_bmdma_port_ops);
+
+const struct ata_port_operations ata_bmdma32_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+
+ .sff_data_xfer = ata_sff_data_xfer32,
+ .port_start = ata_bmdma_port_start32,
+};
+EXPORT_SYMBOL_GPL(ata_bmdma32_port_ops);
+
+/**
+ * ata_bmdma_fill_sg - Fill PCI IDE PRD table
+ * @qc: Metadata associated with taskfile to be transferred
+ *
+ * Fill PCI IDE PRD (scatter-gather) table with segments
+ * associated with the current disk command.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ */
+static void ata_bmdma_fill_sg(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_bmdma_prd *prd = ap->bmdma_prd;
+ struct scatterlist *sg;
+ unsigned int si, pi;
+
+ pi = 0;
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ u32 addr, offset;
+ u32 sg_len, len;
+
+ /* determine if physical DMA addr spans 64K boundary.
+ * Note h/w doesn't support 64-bit, so we unconditionally
+ * truncate dma_addr_t to u32.
+ */
+ addr = (u32) sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ while (sg_len) {
+ offset = addr & 0xffff;
+ len = sg_len;
+ if ((offset + sg_len) > 0x10000)
+ len = 0x10000 - offset;
+
+ prd[pi].addr = cpu_to_le32(addr);
+ prd[pi].flags_len = cpu_to_le32(len & 0xffff);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
+
+ pi++;
+ sg_len -= len;
+ addr += len;
}
}
- if (!pi) {
- dev_printk(KERN_ERR, &pdev->dev,
- "no valid port_info specified\n");
- return -EINVAL;
+ prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+}
+
+/**
+ * ata_bmdma_fill_sg_dumb - Fill PCI IDE PRD table
+ * @qc: Metadata associated with taskfile to be transferred
+ *
+ * Fill PCI IDE PRD (scatter-gather) table with segments
+ * associated with the current disk command. Perform the fill
+ * so that we avoid writing any length 64K records for
+ * controllers that don't follow the spec.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ */
+static void ata_bmdma_fill_sg_dumb(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_bmdma_prd *prd = ap->bmdma_prd;
+ struct scatterlist *sg;
+ unsigned int si, pi;
+
+ pi = 0;
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ u32 addr, offset;
+ u32 sg_len, len, blen;
+
+ /* determine if physical DMA addr spans 64K boundary.
+ * Note h/w doesn't support 64-bit, so we unconditionally
+ * truncate dma_addr_t to u32.
+ */
+ addr = (u32) sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ while (sg_len) {
+ offset = addr & 0xffff;
+ len = sg_len;
+ if ((offset + sg_len) > 0x10000)
+ len = 0x10000 - offset;
+
+ blen = len & 0xffff;
+ prd[pi].addr = cpu_to_le32(addr);
+ if (blen == 0) {
+ /* Some PATA chipsets like the CS5530 can't
+ cope with 0x0000 meaning 64K as the spec
+ says */
+ prd[pi].flags_len = cpu_to_le32(0x8000);
+ blen = 0x8000;
+ prd[++pi].addr = cpu_to_le32(addr + 0x8000);
+ }
+ prd[pi].flags_len = cpu_to_le32(blen);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
+
+ pi++;
+ sg_len -= len;
+ addr += len;
+ }
}
- if (!devres_open_group(dev, NULL, GFP_KERNEL))
- return -ENOMEM;
+ prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+}
- rc = pcim_enable_device(pdev);
- if (rc)
- goto out;
+/**
+ * ata_bmdma_qc_prep - Prepare taskfile for submission
+ * @qc: Metadata associated with taskfile to be prepared
+ *
+ * Prepare ATA taskfile for submission.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_bmdma_qc_prep(struct ata_queued_cmd *qc)
+{
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
- /* prepare and activate SFF host */
- rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
- if (rc)
- goto out;
- host->private_data = host_priv;
+ ata_bmdma_fill_sg(qc);
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_qc_prep);
- pci_set_master(pdev);
- rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht);
- out:
- if (rc == 0)
- devres_remove_group(&pdev->dev, NULL);
- else
- devres_release_group(&pdev->dev, NULL);
+/**
+ * ata_bmdma_dumb_qc_prep - Prepare taskfile for submission
+ * @qc: Metadata associated with taskfile to be prepared
+ *
+ * Prepare ATA taskfile for submission.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_bmdma_dumb_qc_prep(struct ata_queued_cmd *qc)
+{
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
- return rc;
+ ata_bmdma_fill_sg_dumb(qc);
}
+EXPORT_SYMBOL_GPL(ata_bmdma_dumb_qc_prep);
-#endif /* CONFIG_PCI */
+/**
+ * ata_bmdma_qc_issue - issue taskfile to a BMDMA controller
+ * @qc: command to issue to device
+ *
+ * This function issues a PIO, NODATA or DMA command to a
+ * SFF/BMDMA controller. PIO and NODATA are handled by
+ * ata_sff_qc_issue().
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Zero on success, AC_ERR_* mask on failure
+ */
+unsigned int ata_bmdma_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_link *link = qc->dev->link;
-EXPORT_SYMBOL_GPL(ata_sff_port_ops);
-EXPORT_SYMBOL_GPL(ata_bmdma_port_ops);
-EXPORT_SYMBOL_GPL(ata_sff_qc_prep);
-EXPORT_SYMBOL_GPL(ata_sff_dumb_qc_prep);
-EXPORT_SYMBOL_GPL(ata_sff_dev_select);
-EXPORT_SYMBOL_GPL(ata_sff_check_status);
-EXPORT_SYMBOL_GPL(ata_sff_altstatus);
-EXPORT_SYMBOL_GPL(ata_sff_busy_sleep);
-EXPORT_SYMBOL_GPL(ata_sff_wait_ready);
-EXPORT_SYMBOL_GPL(ata_sff_tf_load);
-EXPORT_SYMBOL_GPL(ata_sff_tf_read);
-EXPORT_SYMBOL_GPL(ata_sff_exec_command);
-EXPORT_SYMBOL_GPL(ata_sff_data_xfer);
-EXPORT_SYMBOL_GPL(ata_sff_data_xfer_noirq);
-EXPORT_SYMBOL_GPL(ata_sff_irq_on);
-EXPORT_SYMBOL_GPL(ata_sff_irq_clear);
-EXPORT_SYMBOL_GPL(ata_sff_hsm_move);
-EXPORT_SYMBOL_GPL(ata_sff_qc_issue);
-EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf);
-EXPORT_SYMBOL_GPL(ata_sff_host_intr);
-EXPORT_SYMBOL_GPL(ata_sff_interrupt);
-EXPORT_SYMBOL_GPL(ata_sff_freeze);
-EXPORT_SYMBOL_GPL(ata_sff_thaw);
-EXPORT_SYMBOL_GPL(ata_sff_prereset);
-EXPORT_SYMBOL_GPL(ata_sff_dev_classify);
-EXPORT_SYMBOL_GPL(ata_sff_wait_after_reset);
-EXPORT_SYMBOL_GPL(ata_sff_softreset);
-EXPORT_SYMBOL_GPL(sata_sff_hardreset);
-EXPORT_SYMBOL_GPL(ata_sff_postreset);
-EXPORT_SYMBOL_GPL(ata_sff_error_handler);
-EXPORT_SYMBOL_GPL(ata_sff_post_internal_cmd);
-EXPORT_SYMBOL_GPL(ata_sff_port_start);
-EXPORT_SYMBOL_GPL(ata_sff_std_ports);
-EXPORT_SYMBOL_GPL(ata_bmdma_mode_filter);
+ /* defer PIO handling to sff_qc_issue */
+ if (!ata_is_dma(qc->tf.protocol))
+ return ata_sff_qc_issue(qc);
+
+ /* select the device */
+ ata_dev_select(ap, qc->dev->devno, 1, 0);
+
+ /* start the command */
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ WARN_ON_ONCE(qc->tf.flags & ATA_TFLAG_POLLING);
+
+ ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */
+ ap->ops->bmdma_setup(qc); /* set up bmdma */
+ ap->ops->bmdma_start(qc); /* initiate bmdma */
+ ap->hsm_task_state = HSM_ST_LAST;
+ break;
+
+ case ATAPI_PROT_DMA:
+ WARN_ON_ONCE(qc->tf.flags & ATA_TFLAG_POLLING);
+
+ ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */
+ ap->ops->bmdma_setup(qc); /* set up bmdma */
+ ap->hsm_task_state = HSM_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ ata_sff_queue_pio_task(link, 0);
+ break;
+
+ default:
+ WARN_ON(1);
+ return AC_ERR_SYSTEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_qc_issue);
+
+/**
+ * ata_bmdma_port_intr - Handle BMDMA port interrupt
+ * @ap: Port on which interrupt arrived (possibly...)
+ * @qc: Taskfile currently active in engine
+ *
+ * Handle port interrupt for given queued command.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * One if interrupt was handled, zero if not (shared irq).
+ */
+unsigned int ata_bmdma_port_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ u8 host_stat = 0;
+ bool bmdma_stopped = false;
+ unsigned int handled;
+
+ if (ap->hsm_task_state == HSM_ST_LAST && ata_is_dma(qc->tf.protocol)) {
+ /* check status of DMA engine */
+ host_stat = ap->ops->bmdma_status(ap);
+ VPRINTK("ata%u: host_stat 0x%X\n", ap->print_id, host_stat);
+
+ /* if it's not our irq... */
+ if (!(host_stat & ATA_DMA_INTR))
+ return ata_sff_idle_irq(ap);
+
+ /* before we do anything else, clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+ bmdma_stopped = true;
+
+ if (unlikely(host_stat & ATA_DMA_ERR)) {
+ /* error when transferring data to/from memory */
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ ap->hsm_task_state = HSM_ST_ERR;
+ }
+ }
+
+ handled = __ata_sff_port_intr(ap, qc, bmdma_stopped);
+
+ if (unlikely(qc->err_mask) && ata_is_dma(qc->tf.protocol))
+ ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
+
+ return handled;
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_port_intr);
+
+/**
+ * ata_bmdma_interrupt - Default BMDMA ATA host interrupt handler
+ * @irq: irq line (unused)
+ * @dev_instance: pointer to our ata_host information structure
+ *
+ * Default interrupt handler for PCI IDE devices. Calls
+ * ata_bmdma_port_intr() for each port that is not disabled.
+ *
+ * LOCKING:
+ * Obtains host lock during operation.
+ *
+ * RETURNS:
+ * IRQ_NONE or IRQ_HANDLED.
+ */
+irqreturn_t ata_bmdma_interrupt(int irq, void *dev_instance)
+{
+ return __ata_sff_interrupt(irq, dev_instance, ata_bmdma_port_intr);
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_interrupt);
+
+/**
+ * ata_bmdma_error_handler - Stock error handler for BMDMA controller
+ * @ap: port to handle error for
+ *
+ * Stock error handler for BMDMA controller. It can handle both
+ * PATA and SATA controllers. Most BMDMA controllers should be
+ * able to use this EH as-is or with some added handling before
+ * and after.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_bmdma_error_handler(struct ata_port *ap)
+{
+ struct ata_queued_cmd *qc;
+ unsigned long flags;
+ bool thaw = false;
+
+ qc = __ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
+ qc = NULL;
+
+ /* reset PIO HSM and stop DMA engine */
+ spin_lock_irqsave(ap->lock, flags);
+
+ if (qc && ata_is_dma(qc->tf.protocol)) {
+ u8 host_stat;
+
+ host_stat = ap->ops->bmdma_status(ap);
+
+ /* BMDMA controllers indicate host bus error by
+ * setting DMA_ERR bit and timing out. As it wasn't
+ * really a timeout event, adjust error mask and
+ * cancel frozen state.
+ */
+ if (qc->err_mask == AC_ERR_TIMEOUT && (host_stat & ATA_DMA_ERR)) {
+ qc->err_mask = AC_ERR_HOST_BUS;
+ thaw = true;
+ }
+
+ ap->ops->bmdma_stop(qc);
+
+ /* if we're gonna thaw, make sure IRQ is clear */
+ if (thaw) {
+ ap->ops->sff_check_status(ap);
+ if (ap->ops->sff_irq_clear)
+ ap->ops->sff_irq_clear(ap);
+ }
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ if (thaw)
+ ata_eh_thaw_port(ap);
+
+ ata_sff_error_handler(ap);
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_error_handler);
+
+/**
+ * ata_bmdma_post_internal_cmd - Stock post_internal_cmd for BMDMA
+ * @qc: internal command to clean up
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned long flags;
+
+ if (ata_is_dma(qc->tf.protocol)) {
+ spin_lock_irqsave(ap->lock, flags);
+ ap->ops->bmdma_stop(qc);
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
+
+/**
+ * ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
+ * @ap: Port associated with this ATA transaction.
+ *
+ * Clear interrupt and error flags in DMA status register.
+ *
+ * May be used as the irq_clear() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_bmdma_irq_clear(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ if (!mmio)
+ return;
+
+ iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS);
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
+
+/**
+ * ata_bmdma_setup - Set up PCI IDE BMDMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+ u8 dmactl;
+
+ /* load PRD table addr. */
+ mb(); /* make sure PRD table writes are visible to controller */
+ iowrite32(ap->bmdma_prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+
+ /* specify data direction, triple-check start bit is clear */
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+ if (!rw)
+ dmactl |= ATA_DMA_WR;
+ iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+ /* issue r/w command */
+ ap->ops->sff_exec_command(ap, &qc->tf);
+}
EXPORT_SYMBOL_GPL(ata_bmdma_setup);
+
+/**
+ * ata_bmdma_start - Start a PCI IDE BMDMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ u8 dmactl;
+
+ /* start host DMA transaction */
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+ /* Strictly, one may wish to issue an ioread8() here, to
+ * flush the mmio write. However, control also passes
+ * to the hardware at this point, and it will interrupt
+ * us when we are to resume control. So, in effect,
+ * we don't care when the mmio write flushes.
+ * Further, a read of the DMA status register _immediately_
+ * following the write may not be what certain flaky hardware
+ * is expected, so I think it is best to not add a readb()
+ * without first all the MMIO ATA cards/mobos.
+ * Or maybe I'm just being paranoid.
+ *
+ * FIXME: The posting of this write means I/O starts are
+ * unnecessarily delayed for MMIO
+ */
+}
EXPORT_SYMBOL_GPL(ata_bmdma_start);
+
+/**
+ * ata_bmdma_stop - Stop PCI IDE BMDMA transfer
+ * @qc: Command we are ending DMA for
+ *
+ * Clears the ATA_DMA_START flag in the dma control register
+ *
+ * May be used as the bmdma_stop() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ /* clear start/stop bit */
+ iowrite8(ioread8(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
+ mmio + ATA_DMA_CMD);
+
+ /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+ ata_sff_dma_pause(ap);
+}
EXPORT_SYMBOL_GPL(ata_bmdma_stop);
+
+/**
+ * ata_bmdma_status - Read PCI IDE BMDMA status
+ * @ap: Port associated with this ATA transaction.
+ *
+ * Read and return BMDMA status register.
+ *
+ * May be used as the bmdma_status() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+u8 ata_bmdma_status(struct ata_port *ap)
+{
+ return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+}
EXPORT_SYMBOL_GPL(ata_bmdma_status);
-EXPORT_SYMBOL_GPL(ata_bus_reset);
+
+
+/**
+ * ata_bmdma_port_start - Set port up for bmdma.
+ * @ap: Port to initialize
+ *
+ * Called just after data structures for each port are
+ * initialized. Allocates space for PRD table.
+ *
+ * May be used as the port_start() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+int ata_bmdma_port_start(struct ata_port *ap)
+{
+ if (ap->mwdma_mask || ap->udma_mask) {
+ ap->bmdma_prd =
+ dmam_alloc_coherent(ap->host->dev, ATA_PRD_TBL_SZ,
+ &ap->bmdma_prd_dma, GFP_KERNEL);
+ if (!ap->bmdma_prd)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_port_start);
+
+/**
+ * ata_bmdma_port_start32 - Set port up for dma.
+ * @ap: Port to initialize
+ *
+ * Called just after data structures for each port are
+ * initialized. Enables 32bit PIO and allocates space for PRD
+ * table.
+ *
+ * May be used as the port_start() entry in ata_port_operations for
+ * devices that are capable of 32bit PIO.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+int ata_bmdma_port_start32(struct ata_port *ap)
+{
+ ap->pflags |= ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE;
+ return ata_bmdma_port_start(ap);
+}
+EXPORT_SYMBOL_GPL(ata_bmdma_port_start32);
+
#ifdef CONFIG_PCI
+
+/**
+ * ata_pci_bmdma_clear_simplex - attempt to kick device out of simplex
+ * @pdev: PCI device
+ *
+ * Some PCI ATA devices report simplex mode but in fact can be told to
+ * enter non simplex mode. This implements the necessary logic to
+ * perform the task on such devices. Calling it on other devices will
+ * have -undefined- behaviour.
+ */
+int ata_pci_bmdma_clear_simplex(struct pci_dev *pdev)
+{
+ unsigned long bmdma = pci_resource_start(pdev, 4);
+ u8 simplex;
+
+ if (bmdma == 0)
+ return -ENOENT;
+
+ simplex = inb(bmdma + 0x02);
+ outb(simplex & 0x60, bmdma + 0x02);
+ simplex = inb(bmdma + 0x02);
+ if (simplex & 0x80)
+ return -EOPNOTSUPP;
+ return 0;
+}
EXPORT_SYMBOL_GPL(ata_pci_bmdma_clear_simplex);
+
+static void ata_bmdma_nodma(struct ata_host *host, const char *reason)
+{
+ int i;
+
+ dev_err(host->dev, "BMDMA: %s, falling back to PIO\n", reason);
+
+ for (i = 0; i < 2; i++) {
+ host->ports[i]->mwdma_mask = 0;
+ host->ports[i]->udma_mask = 0;
+ }
+}
+
+/**
+ * ata_pci_bmdma_init - acquire PCI BMDMA resources and init ATA host
+ * @host: target ATA host
+ *
+ * Acquire PCI BMDMA resources and initialize @host accordingly.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ */
+void ata_pci_bmdma_init(struct ata_host *host)
+{
+ struct device *gdev = host->dev;
+ struct pci_dev *pdev = to_pci_dev(gdev);
+ int i, rc;
+
+ /* No BAR4 allocation: No DMA */
+ if (pci_resource_start(pdev, 4) == 0) {
+ ata_bmdma_nodma(host, "BAR4 is zero");
+ return;
+ }
+
+ /*
+ * Some controllers require BMDMA region to be initialized
+ * even if DMA is not in use to clear IRQ status via
+ * ->sff_irq_clear method. Try to initialize bmdma_addr
+ * regardless of dma masks.
+ */
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ ata_bmdma_nodma(host, "failed to set dma mask");
+ if (!rc) {
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ ata_bmdma_nodma(host,
+ "failed to set consistent dma mask");
+ }
+
+ /* request and iomap DMA region */
+ rc = pcim_iomap_regions(pdev, 1 << 4, dev_driver_string(gdev));
+ if (rc) {
+ ata_bmdma_nodma(host, "failed to request/iomap BAR4");
+ return;
+ }
+ host->iomap = pcim_iomap_table(pdev);
+
+ for (i = 0; i < 2; i++) {
+ struct ata_port *ap = host->ports[i];
+ void __iomem *bmdma = host->iomap[4] + 8 * i;
+
+ if (ata_port_is_dummy(ap))
+ continue;
+
+ ap->ioaddr.bmdma_addr = bmdma;
+ if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) &&
+ (ioread8(bmdma + 2) & 0x80))
+ host->flags |= ATA_HOST_SIMPLEX;
+
+ ata_port_desc(ap, "bmdma 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, 4) + 8 * i);
+ }
+}
EXPORT_SYMBOL_GPL(ata_pci_bmdma_init);
-EXPORT_SYMBOL_GPL(ata_pci_sff_init_host);
-EXPORT_SYMBOL_GPL(ata_pci_sff_prepare_host);
-EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host);
-EXPORT_SYMBOL_GPL(ata_pci_sff_init_one);
+
+/**
+ * ata_pci_bmdma_prepare_host - helper to prepare PCI BMDMA ATA host
+ * @pdev: target PCI device
+ * @ppi: array of port_info, must be enough for two ports
+ * @r_host: out argument for the initialized ATA host
+ *
+ * Helper to allocate BMDMA ATA host for @pdev, acquire all PCI
+ * resources and initialize it accordingly in one go.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_pci_bmdma_prepare_host(struct pci_dev *pdev,
+ const struct ata_port_info * const * ppi,
+ struct ata_host **r_host)
+{
+ int rc;
+
+ rc = ata_pci_sff_prepare_host(pdev, ppi, r_host);
+ if (rc)
+ return rc;
+
+ ata_pci_bmdma_init(*r_host);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ata_pci_bmdma_prepare_host);
+
+/**
+ * ata_pci_bmdma_init_one - Initialize/register BMDMA PCI IDE controller
+ * @pdev: Controller to be initialized
+ * @ppi: array of port_info, must be enough for two ports
+ * @sht: scsi_host_template to use when registering the host
+ * @host_priv: host private_data
+ * @hflags: host flags
+ *
+ * This function is similar to ata_pci_sff_init_one() but also
+ * takes care of BMDMA initialization.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, negative on errno-based value on error.
+ */
+int ata_pci_bmdma_init_one(struct pci_dev *pdev,
+ const struct ata_port_info * const * ppi,
+ struct scsi_host_template *sht, void *host_priv,
+ int hflags)
+{
+ return ata_pci_init_one(pdev, ppi, sht, host_priv, hflags, 1);
+}
+EXPORT_SYMBOL_GPL(ata_pci_bmdma_init_one);
+
#endif /* CONFIG_PCI */
+#endif /* CONFIG_ATA_BMDMA */
+
+/**
+ * ata_sff_port_init - Initialize SFF/BMDMA ATA port
+ * @ap: Port to initialize
+ *
+ * Called on port allocation to initialize SFF/BMDMA specific
+ * fields.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_sff_port_init(struct ata_port *ap)
+{
+ INIT_DELAYED_WORK(&ap->sff_pio_task, ata_sff_pio_task);
+ ap->ctl = ATA_DEVCTL_OBS;
+ ap->last_ctl = 0xFF;
+}
+
+int __init ata_sff_init(void)
+{
+ ata_sff_wq = alloc_workqueue("ata_sff", WQ_MEM_RECLAIM, WQ_MAX_ACTIVE);
+ if (!ata_sff_wq)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void ata_sff_exit(void)
+{
+ destroy_workqueue(ata_sff_wq);
+}
diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
new file mode 100644
index 00000000000..e3741322822
--- /dev/null
+++ b/drivers/ata/libata-transport.c
@@ -0,0 +1,785 @@
+/*
+ * Copyright 2008 ioogle, Inc. All rights reserved.
+ * Released under GPL v2.
+ *
+ * Libata transport class.
+ *
+ * The ATA transport class contains common code to deal with ATA HBAs,
+ * an approximated representation of ATA topologies in the driver model,
+ * and various sysfs attributes to expose these topologies and management
+ * interfaces to user-space.
+ *
+ * There are 3 objects defined in in this class:
+ * - ata_port
+ * - ata_link
+ * - ata_device
+ * Each port has a link object. Each link can have up to two devices for PATA
+ * and generally one for SATA.
+ * If there is SATA port multiplier [PMP], 15 additional ata_link object are
+ * created.
+ *
+ * These objects are created when the ata host is initialized and when a PMP is
+ * found. They are removed only when the HBA is removed, cleaned before the
+ * error handler runs.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <scsi/scsi_transport.h>
+#include <linux/libata.h>
+#include <linux/hdreg.h>
+#include <linux/uaccess.h>
+#include <linux/pm_runtime.h>
+
+#include "libata.h"
+#include "libata-transport.h"
+
+#define ATA_PORT_ATTRS 3
+#define ATA_LINK_ATTRS 3
+#define ATA_DEV_ATTRS 9
+
+struct scsi_transport_template;
+struct scsi_transport_template *ata_scsi_transport_template;
+
+struct ata_internal {
+ struct scsi_transport_template t;
+
+ struct device_attribute private_port_attrs[ATA_PORT_ATTRS];
+ struct device_attribute private_link_attrs[ATA_LINK_ATTRS];
+ struct device_attribute private_dev_attrs[ATA_DEV_ATTRS];
+
+ struct transport_container link_attr_cont;
+ struct transport_container dev_attr_cont;
+
+ /*
+ * The array of null terminated pointers to attributes
+ * needed by scsi_sysfs.c
+ */
+ struct device_attribute *link_attrs[ATA_LINK_ATTRS + 1];
+ struct device_attribute *port_attrs[ATA_PORT_ATTRS + 1];
+ struct device_attribute *dev_attrs[ATA_DEV_ATTRS + 1];
+};
+#define to_ata_internal(tmpl) container_of(tmpl, struct ata_internal, t)
+
+
+#define tdev_to_device(d) \
+ container_of((d), struct ata_device, tdev)
+#define transport_class_to_dev(dev) \
+ tdev_to_device((dev)->parent)
+
+#define tdev_to_link(d) \
+ container_of((d), struct ata_link, tdev)
+#define transport_class_to_link(dev) \
+ tdev_to_link((dev)->parent)
+
+#define tdev_to_port(d) \
+ container_of((d), struct ata_port, tdev)
+#define transport_class_to_port(dev) \
+ tdev_to_port((dev)->parent)
+
+
+/* Device objects are always created whit link objects */
+static int ata_tdev_add(struct ata_device *dev);
+static void ata_tdev_delete(struct ata_device *dev);
+
+
+/*
+ * Hack to allow attributes of the same name in different objects.
+ */
+#define ATA_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
+ struct device_attribute device_attr_##_prefix##_##_name = \
+ __ATTR(_name,_mode,_show,_store)
+
+#define ata_bitfield_name_match(title, table) \
+static ssize_t \
+get_ata_##title##_names(u32 table_key, char *buf) \
+{ \
+ char *prefix = ""; \
+ ssize_t len = 0; \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(table); i++) { \
+ if (table[i].value & table_key) { \
+ len += sprintf(buf + len, "%s%s", \
+ prefix, table[i].name); \
+ prefix = ", "; \
+ } \
+ } \
+ len += sprintf(buf + len, "\n"); \
+ return len; \
+}
+
+#define ata_bitfield_name_search(title, table) \
+static ssize_t \
+get_ata_##title##_names(u32 table_key, char *buf) \
+{ \
+ ssize_t len = 0; \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(table); i++) { \
+ if (table[i].value == table_key) { \
+ len += sprintf(buf + len, "%s", \
+ table[i].name); \
+ break; \
+ } \
+ } \
+ len += sprintf(buf + len, "\n"); \
+ return len; \
+}
+
+static struct {
+ u32 value;
+ char *name;
+} ata_class_names[] = {
+ { ATA_DEV_UNKNOWN, "unknown" },
+ { ATA_DEV_ATA, "ata" },
+ { ATA_DEV_ATA_UNSUP, "ata" },
+ { ATA_DEV_ATAPI, "atapi" },
+ { ATA_DEV_ATAPI_UNSUP, "atapi" },
+ { ATA_DEV_PMP, "pmp" },
+ { ATA_DEV_PMP_UNSUP, "pmp" },
+ { ATA_DEV_SEMB, "semb" },
+ { ATA_DEV_SEMB_UNSUP, "semb" },
+ { ATA_DEV_NONE, "none" }
+};
+ata_bitfield_name_search(class, ata_class_names)
+
+
+static struct {
+ u32 value;
+ char *name;
+} ata_err_names[] = {
+ { AC_ERR_DEV, "DeviceError" },
+ { AC_ERR_HSM, "HostStateMachineError" },
+ { AC_ERR_TIMEOUT, "Timeout" },
+ { AC_ERR_MEDIA, "MediaError" },
+ { AC_ERR_ATA_BUS, "BusError" },
+ { AC_ERR_HOST_BUS, "HostBusError" },
+ { AC_ERR_SYSTEM, "SystemError" },
+ { AC_ERR_INVALID, "InvalidArg" },
+ { AC_ERR_OTHER, "Unknown" },
+ { AC_ERR_NODEV_HINT, "NoDeviceHint" },
+ { AC_ERR_NCQ, "NCQError" }
+};
+ata_bitfield_name_match(err, ata_err_names)
+
+static struct {
+ u32 value;
+ char *name;
+} ata_xfer_names[] = {
+ { XFER_UDMA_7, "XFER_UDMA_7" },
+ { XFER_UDMA_6, "XFER_UDMA_6" },
+ { XFER_UDMA_5, "XFER_UDMA_5" },
+ { XFER_UDMA_4, "XFER_UDMA_4" },
+ { XFER_UDMA_3, "XFER_UDMA_3" },
+ { XFER_UDMA_2, "XFER_UDMA_2" },
+ { XFER_UDMA_1, "XFER_UDMA_1" },
+ { XFER_UDMA_0, "XFER_UDMA_0" },
+ { XFER_MW_DMA_4, "XFER_MW_DMA_4" },
+ { XFER_MW_DMA_3, "XFER_MW_DMA_3" },
+ { XFER_MW_DMA_2, "XFER_MW_DMA_2" },
+ { XFER_MW_DMA_1, "XFER_MW_DMA_1" },
+ { XFER_MW_DMA_0, "XFER_MW_DMA_0" },
+ { XFER_SW_DMA_2, "XFER_SW_DMA_2" },
+ { XFER_SW_DMA_1, "XFER_SW_DMA_1" },
+ { XFER_SW_DMA_0, "XFER_SW_DMA_0" },
+ { XFER_PIO_6, "XFER_PIO_6" },
+ { XFER_PIO_5, "XFER_PIO_5" },
+ { XFER_PIO_4, "XFER_PIO_4" },
+ { XFER_PIO_3, "XFER_PIO_3" },
+ { XFER_PIO_2, "XFER_PIO_2" },
+ { XFER_PIO_1, "XFER_PIO_1" },
+ { XFER_PIO_0, "XFER_PIO_0" },
+ { XFER_PIO_SLOW, "XFER_PIO_SLOW" }
+};
+ata_bitfield_name_match(xfer,ata_xfer_names)
+
+/*
+ * ATA Port attributes
+ */
+#define ata_port_show_simple(field, name, format_string, cast) \
+static ssize_t \
+show_ata_port_##name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct ata_port *ap = transport_class_to_port(dev); \
+ \
+ return snprintf(buf, 20, format_string, cast ap->field); \
+}
+
+#define ata_port_simple_attr(field, name, format_string, type) \
+ ata_port_show_simple(field, name, format_string, (type)) \
+static DEVICE_ATTR(name, S_IRUGO, show_ata_port_##name, NULL)
+
+ata_port_simple_attr(nr_pmp_links, nr_pmp_links, "%d\n", int);
+ata_port_simple_attr(stats.idle_irq, idle_irq, "%ld\n", unsigned long);
+ata_port_simple_attr(local_port_no, port_no, "%u\n", unsigned int);
+
+static DECLARE_TRANSPORT_CLASS(ata_port_class,
+ "ata_port", NULL, NULL, NULL);
+
+static void ata_tport_release(struct device *dev)
+{
+ put_device(dev->parent);
+}
+
+/**
+ * ata_is_port -- check if a struct device represents a ATA port
+ * @dev: device to check
+ *
+ * Returns:
+ * %1 if the device represents a ATA Port, %0 else
+ */
+static int ata_is_port(const struct device *dev)
+{
+ return dev->release == ata_tport_release;
+}
+
+static int ata_tport_match(struct attribute_container *cont,
+ struct device *dev)
+{
+ if (!ata_is_port(dev))
+ return 0;
+ return &ata_scsi_transport_template->host_attrs.ac == cont;
+}
+
+/**
+ * ata_tport_delete -- remove ATA PORT
+ * @port: ATA PORT to remove
+ *
+ * Removes the specified ATA PORT. Remove the associated link as well.
+ */
+void ata_tport_delete(struct ata_port *ap)
+{
+ struct device *dev = &ap->tdev;
+
+ ata_tlink_delete(&ap->link);
+
+ transport_remove_device(dev);
+ device_del(dev);
+ transport_destroy_device(dev);
+ put_device(dev);
+}
+
+/** ata_tport_add - initialize a transport ATA port structure
+ *
+ * @parent: parent device
+ * @ap: existing ata_port structure
+ *
+ * Initialize a ATA port structure for sysfs. It will be added to the device
+ * tree below the device specified by @parent which could be a PCI device.
+ *
+ * Returns %0 on success
+ */
+int ata_tport_add(struct device *parent,
+ struct ata_port *ap)
+{
+ int error;
+ struct device *dev = &ap->tdev;
+
+ device_initialize(dev);
+ dev->type = &ata_port_type;
+
+ dev->parent = get_device(parent);
+ dev->release = ata_tport_release;
+ dev_set_name(dev, "ata%d", ap->print_id);
+ transport_setup_device(dev);
+ ata_acpi_bind_port(ap);
+ error = device_add(dev);
+ if (error) {
+ goto tport_err;
+ }
+
+ device_enable_async_suspend(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_forbid(dev);
+
+ transport_add_device(dev);
+ transport_configure_device(dev);
+
+ error = ata_tlink_add(&ap->link);
+ if (error) {
+ goto tport_link_err;
+ }
+ return 0;
+
+ tport_link_err:
+ transport_remove_device(dev);
+ device_del(dev);
+
+ tport_err:
+ transport_destroy_device(dev);
+ put_device(dev);
+ return error;
+}
+
+
+/*
+ * ATA link attributes
+ */
+static int noop(int x) { return x; }
+
+#define ata_link_show_linkspeed(field, format) \
+static ssize_t \
+show_ata_link_##field(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct ata_link *link = transport_class_to_link(dev); \
+ \
+ return sprintf(buf, "%s\n", sata_spd_string(format(link->field))); \
+}
+
+#define ata_link_linkspeed_attr(field, format) \
+ ata_link_show_linkspeed(field, format) \
+static DEVICE_ATTR(field, S_IRUGO, show_ata_link_##field, NULL)
+
+ata_link_linkspeed_attr(hw_sata_spd_limit, fls);
+ata_link_linkspeed_attr(sata_spd_limit, fls);
+ata_link_linkspeed_attr(sata_spd, noop);
+
+
+static DECLARE_TRANSPORT_CLASS(ata_link_class,
+ "ata_link", NULL, NULL, NULL);
+
+static void ata_tlink_release(struct device *dev)
+{
+ put_device(dev->parent);
+}
+
+/**
+ * ata_is_link -- check if a struct device represents a ATA link
+ * @dev: device to check
+ *
+ * Returns:
+ * %1 if the device represents a ATA link, %0 else
+ */
+static int ata_is_link(const struct device *dev)
+{
+ return dev->release == ata_tlink_release;
+}
+
+static int ata_tlink_match(struct attribute_container *cont,
+ struct device *dev)
+{
+ struct ata_internal* i = to_ata_internal(ata_scsi_transport_template);
+ if (!ata_is_link(dev))
+ return 0;
+ return &i->link_attr_cont.ac == cont;
+}
+
+/**
+ * ata_tlink_delete -- remove ATA LINK
+ * @port: ATA LINK to remove
+ *
+ * Removes the specified ATA LINK. remove associated ATA device(s) as well.
+ */
+void ata_tlink_delete(struct ata_link *link)
+{
+ struct device *dev = &link->tdev;
+ struct ata_device *ata_dev;
+
+ ata_for_each_dev(ata_dev, link, ALL) {
+ ata_tdev_delete(ata_dev);
+ }
+
+ transport_remove_device(dev);
+ device_del(dev);
+ transport_destroy_device(dev);
+ put_device(dev);
+}
+
+/**
+ * ata_tlink_add -- initialize a transport ATA link structure
+ * @link: allocated ata_link structure.
+ *
+ * Initialize an ATA LINK structure for sysfs. It will be added in the
+ * device tree below the ATA PORT it belongs to.
+ *
+ * Returns %0 on success
+ */
+int ata_tlink_add(struct ata_link *link)
+{
+ struct device *dev = &link->tdev;
+ struct ata_port *ap = link->ap;
+ struct ata_device *ata_dev;
+ int error;
+
+ device_initialize(dev);
+ dev->parent = get_device(&ap->tdev);
+ dev->release = ata_tlink_release;
+ if (ata_is_host_link(link))
+ dev_set_name(dev, "link%d", ap->print_id);
+ else
+ dev_set_name(dev, "link%d.%d", ap->print_id, link->pmp);
+
+ transport_setup_device(dev);
+
+ error = device_add(dev);
+ if (error) {
+ goto tlink_err;
+ }
+
+ transport_add_device(dev);
+ transport_configure_device(dev);
+
+ ata_for_each_dev(ata_dev, link, ALL) {
+ error = ata_tdev_add(ata_dev);
+ if (error) {
+ goto tlink_dev_err;
+ }
+ }
+ return 0;
+ tlink_dev_err:
+ while (--ata_dev >= link->device) {
+ ata_tdev_delete(ata_dev);
+ }
+ transport_remove_device(dev);
+ device_del(dev);
+ tlink_err:
+ transport_destroy_device(dev);
+ put_device(dev);
+ return error;
+}
+
+/*
+ * ATA device attributes
+ */
+
+#define ata_dev_show_class(title, field) \
+static ssize_t \
+show_ata_dev_##field(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct ata_device *ata_dev = transport_class_to_dev(dev); \
+ \
+ return get_ata_##title##_names(ata_dev->field, buf); \
+}
+
+#define ata_dev_attr(title, field) \
+ ata_dev_show_class(title, field) \
+static DEVICE_ATTR(field, S_IRUGO, show_ata_dev_##field, NULL)
+
+ata_dev_attr(class, class);
+ata_dev_attr(xfer, pio_mode);
+ata_dev_attr(xfer, dma_mode);
+ata_dev_attr(xfer, xfer_mode);
+
+
+#define ata_dev_show_simple(field, format_string, cast) \
+static ssize_t \
+show_ata_dev_##field(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct ata_device *ata_dev = transport_class_to_dev(dev); \
+ \
+ return snprintf(buf, 20, format_string, cast ata_dev->field); \
+}
+
+#define ata_dev_simple_attr(field, format_string, type) \
+ ata_dev_show_simple(field, format_string, (type)) \
+static DEVICE_ATTR(field, S_IRUGO, \
+ show_ata_dev_##field, NULL)
+
+ata_dev_simple_attr(spdn_cnt, "%d\n", int);
+
+struct ata_show_ering_arg {
+ char* buf;
+ int written;
+};
+
+static int ata_show_ering(struct ata_ering_entry *ent, void *void_arg)
+{
+ struct ata_show_ering_arg* arg = void_arg;
+ struct timespec time;
+
+ jiffies_to_timespec(ent->timestamp,&time);
+ arg->written += sprintf(arg->buf + arg->written,
+ "[%5lu.%06lu]",
+ time.tv_sec, time.tv_nsec);
+ arg->written += get_ata_err_names(ent->err_mask,
+ arg->buf + arg->written);
+ return 0;
+}
+
+static ssize_t
+show_ata_dev_ering(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ata_device *ata_dev = transport_class_to_dev(dev);
+ struct ata_show_ering_arg arg = { buf, 0 };
+
+ ata_ering_map(&ata_dev->ering, ata_show_ering, &arg);
+ return arg.written;
+}
+
+
+static DEVICE_ATTR(ering, S_IRUGO, show_ata_dev_ering, NULL);
+
+static ssize_t
+show_ata_dev_id(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ata_device *ata_dev = transport_class_to_dev(dev);
+ int written = 0, i = 0;
+
+ if (ata_dev->class == ATA_DEV_PMP)
+ return 0;
+ for(i=0;i<ATA_ID_WORDS;i++) {
+ written += snprintf(buf+written, 20, "%04x%c",
+ ata_dev->id[i],
+ ((i+1) & 7) ? ' ' : '\n');
+ }
+ return written;
+}
+
+static DEVICE_ATTR(id, S_IRUGO, show_ata_dev_id, NULL);
+
+static ssize_t
+show_ata_dev_gscr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ata_device *ata_dev = transport_class_to_dev(dev);
+ int written = 0, i = 0;
+
+ if (ata_dev->class != ATA_DEV_PMP)
+ return 0;
+ for(i=0;i<SATA_PMP_GSCR_DWORDS;i++) {
+ written += snprintf(buf+written, 20, "%08x%c",
+ ata_dev->gscr[i],
+ ((i+1) & 3) ? ' ' : '\n');
+ }
+ if (SATA_PMP_GSCR_DWORDS & 3)
+ buf[written-1] = '\n';
+ return written;
+}
+
+static DEVICE_ATTR(gscr, S_IRUGO, show_ata_dev_gscr, NULL);
+
+static DECLARE_TRANSPORT_CLASS(ata_dev_class,
+ "ata_device", NULL, NULL, NULL);
+
+static void ata_tdev_release(struct device *dev)
+{
+ put_device(dev->parent);
+}
+
+/**
+ * ata_is_ata_dev -- check if a struct device represents a ATA device
+ * @dev: device to check
+ *
+ * Returns:
+ * %1 if the device represents a ATA device, %0 else
+ */
+static int ata_is_ata_dev(const struct device *dev)
+{
+ return dev->release == ata_tdev_release;
+}
+
+static int ata_tdev_match(struct attribute_container *cont,
+ struct device *dev)
+{
+ struct ata_internal* i = to_ata_internal(ata_scsi_transport_template);
+ if (!ata_is_ata_dev(dev))
+ return 0;
+ return &i->dev_attr_cont.ac == cont;
+}
+
+/**
+ * ata_tdev_free -- free a ATA LINK
+ * @dev: ATA PHY to free
+ *
+ * Frees the specified ATA PHY.
+ *
+ * Note:
+ * This function must only be called on a PHY that has not
+ * successfully been added using ata_tdev_add().
+ */
+static void ata_tdev_free(struct ata_device *dev)
+{
+ transport_destroy_device(&dev->tdev);
+ put_device(&dev->tdev);
+}
+
+/**
+ * ata_tdev_delete -- remove ATA device
+ * @port: ATA PORT to remove
+ *
+ * Removes the specified ATA device.
+ */
+static void ata_tdev_delete(struct ata_device *ata_dev)
+{
+ struct device *dev = &ata_dev->tdev;
+
+ transport_remove_device(dev);
+ device_del(dev);
+ ata_tdev_free(ata_dev);
+}
+
+
+/**
+ * ata_tdev_add -- initialize a transport ATA device structure.
+ * @ata_dev: ata_dev structure.
+ *
+ * Initialize an ATA device structure for sysfs. It will be added in the
+ * device tree below the ATA LINK device it belongs to.
+ *
+ * Returns %0 on success
+ */
+static int ata_tdev_add(struct ata_device *ata_dev)
+{
+ struct device *dev = &ata_dev->tdev;
+ struct ata_link *link = ata_dev->link;
+ struct ata_port *ap = link->ap;
+ int error;
+
+ device_initialize(dev);
+ dev->parent = get_device(&link->tdev);
+ dev->release = ata_tdev_release;
+ if (ata_is_host_link(link))
+ dev_set_name(dev, "dev%d.%d", ap->print_id,ata_dev->devno);
+ else
+ dev_set_name(dev, "dev%d.%d.0", ap->print_id, link->pmp);
+
+ transport_setup_device(dev);
+ ata_acpi_bind_dev(ata_dev);
+ error = device_add(dev);
+ if (error) {
+ ata_tdev_free(ata_dev);
+ return error;
+ }
+
+ transport_add_device(dev);
+ transport_configure_device(dev);
+ return 0;
+}
+
+
+/*
+ * Setup / Teardown code
+ */
+
+#define SETUP_TEMPLATE(attrb, field, perm, test) \
+ i->private_##attrb[count] = dev_attr_##field; \
+ i->private_##attrb[count].attr.mode = perm; \
+ i->attrb[count] = &i->private_##attrb[count]; \
+ if (test) \
+ count++
+
+#define SETUP_LINK_ATTRIBUTE(field) \
+ SETUP_TEMPLATE(link_attrs, field, S_IRUGO, 1)
+
+#define SETUP_PORT_ATTRIBUTE(field) \
+ SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
+
+#define SETUP_DEV_ATTRIBUTE(field) \
+ SETUP_TEMPLATE(dev_attrs, field, S_IRUGO, 1)
+
+/**
+ * ata_attach_transport -- instantiate ATA transport template
+ */
+struct scsi_transport_template *ata_attach_transport(void)
+{
+ struct ata_internal *i;
+ int count;
+
+ i = kzalloc(sizeof(struct ata_internal), GFP_KERNEL);
+ if (!i)
+ return NULL;
+
+ i->t.eh_strategy_handler = ata_scsi_error;
+ i->t.eh_timed_out = ata_scsi_timed_out;
+ i->t.user_scan = ata_scsi_user_scan;
+
+ i->t.host_attrs.ac.attrs = &i->port_attrs[0];
+ i->t.host_attrs.ac.class = &ata_port_class.class;
+ i->t.host_attrs.ac.match = ata_tport_match;
+ transport_container_register(&i->t.host_attrs);
+
+ i->link_attr_cont.ac.class = &ata_link_class.class;
+ i->link_attr_cont.ac.attrs = &i->link_attrs[0];
+ i->link_attr_cont.ac.match = ata_tlink_match;
+ transport_container_register(&i->link_attr_cont);
+
+ i->dev_attr_cont.ac.class = &ata_dev_class.class;
+ i->dev_attr_cont.ac.attrs = &i->dev_attrs[0];
+ i->dev_attr_cont.ac.match = ata_tdev_match;
+ transport_container_register(&i->dev_attr_cont);
+
+ count = 0;
+ SETUP_PORT_ATTRIBUTE(nr_pmp_links);
+ SETUP_PORT_ATTRIBUTE(idle_irq);
+ SETUP_PORT_ATTRIBUTE(port_no);
+ BUG_ON(count > ATA_PORT_ATTRS);
+ i->port_attrs[count] = NULL;
+
+ count = 0;
+ SETUP_LINK_ATTRIBUTE(hw_sata_spd_limit);
+ SETUP_LINK_ATTRIBUTE(sata_spd_limit);
+ SETUP_LINK_ATTRIBUTE(sata_spd);
+ BUG_ON(count > ATA_LINK_ATTRS);
+ i->link_attrs[count] = NULL;
+
+ count = 0;
+ SETUP_DEV_ATTRIBUTE(class);
+ SETUP_DEV_ATTRIBUTE(pio_mode);
+ SETUP_DEV_ATTRIBUTE(dma_mode);
+ SETUP_DEV_ATTRIBUTE(xfer_mode);
+ SETUP_DEV_ATTRIBUTE(spdn_cnt);
+ SETUP_DEV_ATTRIBUTE(ering);
+ SETUP_DEV_ATTRIBUTE(id);
+ SETUP_DEV_ATTRIBUTE(gscr);
+ BUG_ON(count > ATA_DEV_ATTRS);
+ i->dev_attrs[count] = NULL;
+
+ return &i->t;
+}
+
+/**
+ * ata_release_transport -- release ATA transport template instance
+ * @t: transport template instance
+ */
+void ata_release_transport(struct scsi_transport_template *t)
+{
+ struct ata_internal *i = to_ata_internal(t);
+
+ transport_container_unregister(&i->t.host_attrs);
+ transport_container_unregister(&i->link_attr_cont);
+ transport_container_unregister(&i->dev_attr_cont);
+
+ kfree(i);
+}
+
+__init int libata_transport_init(void)
+{
+ int error;
+
+ error = transport_class_register(&ata_link_class);
+ if (error)
+ goto out_unregister_transport;
+ error = transport_class_register(&ata_port_class);
+ if (error)
+ goto out_unregister_link;
+ error = transport_class_register(&ata_dev_class);
+ if (error)
+ goto out_unregister_port;
+ return 0;
+
+ out_unregister_port:
+ transport_class_unregister(&ata_port_class);
+ out_unregister_link:
+ transport_class_unregister(&ata_link_class);
+ out_unregister_transport:
+ return error;
+
+}
+
+void __exit libata_transport_exit(void)
+{
+ transport_class_unregister(&ata_link_class);
+ transport_class_unregister(&ata_port_class);
+ transport_class_unregister(&ata_dev_class);
+}
diff --git a/drivers/ata/libata-transport.h b/drivers/ata/libata-transport.h
new file mode 100644
index 00000000000..2820cf864f1
--- /dev/null
+++ b/drivers/ata/libata-transport.h
@@ -0,0 +1,18 @@
+#ifndef _LIBATA_TRANSPORT_H
+#define _LIBATA_TRANSPORT_H
+
+
+extern struct scsi_transport_template *ata_scsi_transport_template;
+
+int ata_tlink_add(struct ata_link *link);
+void ata_tlink_delete(struct ata_link *link);
+
+int ata_tport_add(struct device *parent, struct ata_port *ap);
+void ata_tport_delete(struct ata_port *ap);
+
+struct scsi_transport_template *ata_attach_transport(void);
+void ata_release_transport(struct scsi_transport_template *t);
+
+__init int libata_transport_init(void);
+void __exit libata_transport_exit(void);
+#endif
diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c
new file mode 100644
index 00000000000..f3a65a3140d
--- /dev/null
+++ b/drivers/ata/libata-zpodd.c
@@ -0,0 +1,283 @@
+#include <linux/libata.h>
+#include <linux/cdrom.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <linux/pm_qos.h>
+#include <scsi/scsi_device.h>
+
+#include "libata.h"
+
+static int zpodd_poweroff_delay = 30; /* 30 seconds for power off delay */
+module_param(zpodd_poweroff_delay, int, 0644);
+MODULE_PARM_DESC(zpodd_poweroff_delay, "Poweroff delay for ZPODD in seconds");
+
+enum odd_mech_type {
+ ODD_MECH_TYPE_SLOT,
+ ODD_MECH_TYPE_DRAWER,
+ ODD_MECH_TYPE_UNSUPPORTED,
+};
+
+struct zpodd {
+ enum odd_mech_type mech_type; /* init during probe, RO afterwards */
+ struct ata_device *dev;
+
+ /* The following fields are synchronized by PM core. */
+ bool from_notify; /* resumed as a result of
+ * acpi wake notification */
+ bool zp_ready; /* ZP ready state */
+ unsigned long last_ready; /* last ZP ready timestamp */
+ bool zp_sampled; /* ZP ready state sampled */
+ bool powered_off; /* ODD is powered off
+ * during suspend */
+};
+
+static int eject_tray(struct ata_device *dev)
+{
+ struct ata_taskfile tf;
+ const char cdb[] = { GPCMD_START_STOP_UNIT,
+ 0, 0, 0,
+ 0x02, /* LoEj */
+ 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ ata_tf_init(dev, &tf);
+ tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.command = ATA_CMD_PACKET;
+ tf.protocol = ATAPI_PROT_NODATA;
+
+ return ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
+}
+
+/* Per the spec, only slot type and drawer type ODD can be supported */
+static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
+{
+ char buf[16];
+ unsigned int ret;
+ struct rm_feature_desc *desc = (void *)(buf + 8);
+ struct ata_taskfile tf;
+ char cdb[] = { GPCMD_GET_CONFIGURATION,
+ 2, /* only 1 feature descriptor requested */
+ 0, 3, /* 3, removable medium feature */
+ 0, 0, 0,/* reserved */
+ 0, sizeof(buf),
+ 0, 0, 0,
+ };
+
+ ata_tf_init(dev, &tf);
+ tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.command = ATA_CMD_PACKET;
+ tf.protocol = ATAPI_PROT_PIO;
+ tf.lbam = sizeof(buf);
+
+ ret = ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
+ buf, sizeof(buf), 0);
+ if (ret)
+ return ODD_MECH_TYPE_UNSUPPORTED;
+
+ if (be16_to_cpu(desc->feature_code) != 3)
+ return ODD_MECH_TYPE_UNSUPPORTED;
+
+ if (desc->mech_type == 0 && desc->load == 0 && desc->eject == 1)
+ return ODD_MECH_TYPE_SLOT;
+ else if (desc->mech_type == 1 && desc->load == 0 && desc->eject == 1)
+ return ODD_MECH_TYPE_DRAWER;
+ else
+ return ODD_MECH_TYPE_UNSUPPORTED;
+}
+
+/* Test if ODD is zero power ready by sense code */
+static bool zpready(struct ata_device *dev)
+{
+ u8 sense_key, *sense_buf;
+ unsigned int ret, asc, ascq, add_len;
+ struct zpodd *zpodd = dev->zpodd;
+
+ ret = atapi_eh_tur(dev, &sense_key);
+
+ if (!ret || sense_key != NOT_READY)
+ return false;
+
+ sense_buf = dev->link->ap->sector_buf;
+ ret = atapi_eh_request_sense(dev, sense_buf, sense_key);
+ if (ret)
+ return false;
+
+ /* sense valid */
+ if ((sense_buf[0] & 0x7f) != 0x70)
+ return false;
+
+ add_len = sense_buf[7];
+ /* has asc and ascq */
+ if (add_len < 6)
+ return false;
+
+ asc = sense_buf[12];
+ ascq = sense_buf[13];
+
+ if (zpodd->mech_type == ODD_MECH_TYPE_SLOT)
+ /* no media inside */
+ return asc == 0x3a;
+ else
+ /* no media inside and door closed */
+ return asc == 0x3a && ascq == 0x01;
+}
+
+/*
+ * Update the zpodd->zp_ready field. This field will only be set
+ * if the ODD has stayed in ZP ready state for zpodd_poweroff_delay
+ * time, and will be used to decide if power off is allowed. If it
+ * is set, it will be cleared during resume from powered off state.
+ */
+void zpodd_on_suspend(struct ata_device *dev)
+{
+ struct zpodd *zpodd = dev->zpodd;
+ unsigned long expires;
+
+ if (!zpready(dev)) {
+ zpodd->zp_sampled = false;
+ zpodd->zp_ready = false;
+ return;
+ }
+
+ if (!zpodd->zp_sampled) {
+ zpodd->zp_sampled = true;
+ zpodd->last_ready = jiffies;
+ return;
+ }
+
+ expires = zpodd->last_ready +
+ msecs_to_jiffies(zpodd_poweroff_delay * 1000);
+ if (time_before(jiffies, expires))
+ return;
+
+ zpodd->zp_ready = true;
+}
+
+bool zpodd_zpready(struct ata_device *dev)
+{
+ struct zpodd *zpodd = dev->zpodd;
+ return zpodd->zp_ready;
+}
+
+/*
+ * Enable runtime wake capability through ACPI and set the powered_off flag,
+ * this flag will be used during resume to decide what operations are needed
+ * to take.
+ *
+ * Also, media poll needs to be silenced, so that it doesn't bring the ODD
+ * back to full power state every few seconds.
+ */
+void zpodd_enable_run_wake(struct ata_device *dev)
+{
+ struct zpodd *zpodd = dev->zpodd;
+
+ sdev_disable_disk_events(dev->sdev);
+
+ zpodd->powered_off = true;
+ device_set_run_wake(&dev->tdev, true);
+ acpi_pm_device_run_wake(&dev->tdev, true);
+}
+
+/* Disable runtime wake capability if it is enabled */
+void zpodd_disable_run_wake(struct ata_device *dev)
+{
+ struct zpodd *zpodd = dev->zpodd;
+
+ if (zpodd->powered_off) {
+ acpi_pm_device_run_wake(&dev->tdev, false);
+ device_set_run_wake(&dev->tdev, false);
+ }
+}
+
+/*
+ * Post power on processing after the ODD has been recovered. If the
+ * ODD wasn't powered off during suspend, it doesn't do anything.
+ *
+ * For drawer type ODD, if it is powered on due to user pressed the
+ * eject button, the tray needs to be ejected. This can only be done
+ * after the ODD has been recovered, i.e. link is initialized and
+ * device is able to process NON_DATA PIO command, as eject needs to
+ * send command for the ODD to process.
+ *
+ * The from_notify flag set in wake notification handler function
+ * zpodd_wake_dev represents if power on is due to user's action.
+ *
+ * For both types of ODD, several fields need to be reset.
+ */
+void zpodd_post_poweron(struct ata_device *dev)
+{
+ struct zpodd *zpodd = dev->zpodd;
+
+ if (!zpodd->powered_off)
+ return;
+
+ zpodd->powered_off = false;
+
+ if (zpodd->from_notify) {
+ zpodd->from_notify = false;
+ if (zpodd->mech_type == ODD_MECH_TYPE_DRAWER)
+ eject_tray(dev);
+ }
+
+ zpodd->zp_sampled = false;
+ zpodd->zp_ready = false;
+
+ sdev_enable_disk_events(dev->sdev);
+}
+
+static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context)
+{
+ struct ata_device *ata_dev = context;
+ struct zpodd *zpodd = ata_dev->zpodd;
+ struct device *dev = &ata_dev->sdev->sdev_gendev;
+
+ if (event == ACPI_NOTIFY_DEVICE_WAKE && pm_runtime_suspended(dev)) {
+ zpodd->from_notify = true;
+ pm_runtime_resume(dev);
+ }
+}
+
+static void ata_acpi_add_pm_notifier(struct ata_device *dev)
+{
+ acpi_handle handle = ata_dev_acpi_handle(dev);
+ acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ zpodd_wake_dev, dev);
+}
+
+static void ata_acpi_remove_pm_notifier(struct ata_device *dev)
+{
+ acpi_handle handle = ata_dev_acpi_handle(dev);
+ acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, zpodd_wake_dev);
+}
+
+void zpodd_init(struct ata_device *dev)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&dev->tdev);
+ enum odd_mech_type mech_type;
+ struct zpodd *zpodd;
+
+ if (dev->zpodd || !adev || !acpi_device_can_poweroff(adev))
+ return;
+
+ mech_type = zpodd_get_mech_type(dev);
+ if (mech_type == ODD_MECH_TYPE_UNSUPPORTED)
+ return;
+
+ zpodd = kzalloc(sizeof(struct zpodd), GFP_KERNEL);
+ if (!zpodd)
+ return;
+
+ zpodd->mech_type = mech_type;
+
+ ata_acpi_add_pm_notifier(dev);
+ zpodd->dev = dev;
+ dev->zpodd = zpodd;
+ dev_pm_qos_expose_flags(&dev->tdev, 0);
+}
+
+void zpodd_exit(struct ata_device *dev)
+{
+ ata_acpi_remove_pm_notifier(dev);
+ kfree(dev->zpodd);
+ dev->zpodd = NULL;
+}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 4aeeabb10a4..45b5ab3a95d 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -38,17 +38,6 @@ struct ata_scsi_args {
void (*done)(struct scsi_cmnd *);
};
-static inline int ata_is_builtin_hardreset(ata_reset_fn_t reset)
-{
- if (reset == sata_std_hardreset)
- return 1;
-#ifdef CONFIG_ATA_SFF
- if (reset == sata_sff_hardreset)
- return 1;
-#endif
- return 0;
-}
-
/* libata-core.c */
enum {
/* flags for ata_dev_read_id() */
@@ -64,13 +53,13 @@ enum {
ATA_DNXFER_QUIET = (1 << 31),
};
-extern unsigned int ata_print_id;
-extern struct workqueue_struct *ata_aux_wq;
-extern int atapi_enabled;
+extern atomic_t ata_print_id;
extern int atapi_passthru16;
extern int libata_fua;
extern int libata_noacpi;
extern int libata_allow_tpm;
+extern struct device_type ata_port_type;
+extern struct ata_link *ata_dev_phys_link(struct ata_device *dev);
extern void ata_force_cbl(struct ata_port *ap);
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
@@ -79,10 +68,6 @@ extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
u64 block, u32 n_block, unsigned int tf_flags,
unsigned int tag);
extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev);
-extern void ata_dev_disable(struct ata_device *dev);
-extern void ata_pio_queue_task(struct ata_port *ap, void *data,
- unsigned long delay);
-extern void ata_port_flush_task(struct ata_port *ap);
extern unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, void *buf, unsigned int buflen,
@@ -100,37 +85,43 @@ extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags);
extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
unsigned int readid_flags);
extern int ata_dev_configure(struct ata_device *dev);
-extern int sata_down_spd_limit(struct ata_link *link);
-extern int sata_set_spd_needed(struct ata_link *link);
+extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
+extern unsigned int ata_dev_set_feature(struct ata_device *dev,
+ u8 enable, u8 feature);
extern void ata_sg_clean(struct ata_queued_cmd *qc);
extern void ata_qc_free(struct ata_queued_cmd *qc);
extern void ata_qc_issue(struct ata_queued_cmd *qc);
extern void __ata_qc_complete(struct ata_queued_cmd *qc);
-extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
+extern int atapi_check_dma(struct ata_queued_cmd *qc);
extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
+extern bool ata_phys_link_online(struct ata_link *link);
+extern bool ata_phys_link_offline(struct ata_link *link);
extern void ata_dev_init(struct ata_device *dev);
extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
extern int sata_link_init_spd(struct ata_link *link);
extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
extern struct ata_port *ata_port_alloc(struct ata_host *host);
-extern void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy);
-extern void ata_lpm_schedule(struct ata_port *ap, enum link_pm);
+extern const char *sata_spd_string(unsigned int spd);
+extern int ata_port_probe(struct ata_port *ap);
+extern void __ata_port_probe(struct ata_port *ap);
+
+#define to_ata_port(d) container_of(d, struct ata_port, tdev)
/* libata-acpi.c */
#ifdef CONFIG_ATA_ACPI
-extern void ata_acpi_associate_sata_port(struct ata_port *ap);
-extern void ata_acpi_associate(struct ata_host *host);
+extern unsigned int ata_acpi_gtf_filter;
extern void ata_acpi_dissociate(struct ata_host *host);
extern int ata_acpi_on_suspend(struct ata_port *ap);
extern void ata_acpi_on_resume(struct ata_port *ap);
extern int ata_acpi_on_devcfg(struct ata_device *dev);
extern void ata_acpi_on_disable(struct ata_device *dev);
extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state);
+extern void ata_acpi_bind_port(struct ata_port *ap);
+extern void ata_acpi_bind_dev(struct ata_device *dev);
+extern acpi_handle ata_dev_acpi_handle(struct ata_device *dev);
#else
-static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { }
-static inline void ata_acpi_associate(struct ata_host *host) { }
static inline void ata_acpi_dissociate(struct ata_host *host) { }
static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
static inline void ata_acpi_on_resume(struct ata_port *ap) { }
@@ -138,6 +129,8 @@ static inline int ata_acpi_on_devcfg(struct ata_device *dev) { return 0; }
static inline void ata_acpi_on_disable(struct ata_device *dev) { }
static inline void ata_acpi_set_state(struct ata_port *ap,
pm_message_t state) { }
+static inline void ata_acpi_bind_port(struct ata_port *ap) {}
+static inline void ata_acpi_bind_dev(struct ata_device *dev) {}
#endif
/* libata-scsi.c */
@@ -147,50 +140,32 @@ extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
extern int ata_scsi_offline_dev(struct ata_device *dev);
extern void ata_scsi_media_change_notify(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work);
-extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-
-extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-
-extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern void ata_scsi_badcmd(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *),
- u8 asc, u8 ascq);
-extern void ata_scsi_set_sense(struct scsi_cmnd *cmd,
- u8 sk, u8 asc, u8 ascq);
-extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
- unsigned int (*actor) (struct ata_scsi_args *args,
- u8 *rbuf, unsigned int buflen));
extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
extern void ata_scsi_dev_rescan(struct work_struct *work);
extern int ata_bus_probe(struct ata_port *ap);
+extern int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+ unsigned int id, unsigned int lun);
+
/* libata-eh.c */
-extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
+extern unsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd);
+extern void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd);
+extern void ata_eh_acquire(struct ata_port *ap);
+extern void ata_eh_release(struct ata_port *ap);
+extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
extern void ata_scsi_error(struct Scsi_Host *host);
-extern void ata_port_wait_eh(struct ata_port *ap);
extern void ata_eh_fastdrain_timerfn(unsigned long arg);
extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
+extern void ata_dev_disable(struct ata_device *dev);
extern void ata_eh_detach_dev(struct ata_device *dev);
extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
unsigned int action);
extern void ata_eh_done(struct ata_link *link, struct ata_device *dev,
unsigned int action);
+extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
+ u8 page, void *buf, unsigned int sectors);
extern void ata_eh_autopsy(struct ata_port *ap);
+const char *ata_get_cmd_descript(u8 command);
extern void ata_eh_report(struct ata_port *ap);
extern int ata_eh_reset(struct ata_link *link, int classify,
ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
@@ -201,11 +176,19 @@ extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_postreset_fn_t postreset,
struct ata_link **r_failed_disk);
extern void ata_eh_finish(struct ata_port *ap);
+extern int ata_ering_map(struct ata_ering *ering,
+ int (*map_fn)(struct ata_ering_entry *, void *),
+ void *arg);
+extern unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key);
+extern unsigned int atapi_eh_request_sense(struct ata_device *dev,
+ u8 *sense_buf, u8 dfl_sense_key);
/* libata-pmp.c */
#ifdef CONFIG_SATA_PMP
extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val);
extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val);
+extern int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+ unsigned hints);
extern int sata_pmp_attach(struct ata_device *dev);
#else /* CONFIG_SATA_PMP */
static inline int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val)
@@ -218,6 +201,12 @@ static inline int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
return -EINVAL;
}
+static inline int sata_pmp_set_lpm(struct ata_link *link,
+ enum ata_lpm_policy policy, unsigned hints)
+{
+ return -EINVAL;
+}
+
static inline int sata_pmp_attach(struct ata_device *dev)
{
return -EINVAL;
@@ -226,10 +215,43 @@ static inline int sata_pmp_attach(struct ata_device *dev)
/* libata-sff.c */
#ifdef CONFIG_ATA_SFF
-extern void ata_dev_select(struct ata_port *ap, unsigned int device,
- unsigned int wait, unsigned int can_sleep);
-extern u8 ata_irq_on(struct ata_port *ap);
-extern void ata_pio_task(struct work_struct *work);
+extern void ata_sff_flush_pio_task(struct ata_port *ap);
+extern void ata_sff_port_init(struct ata_port *ap);
+extern int ata_sff_init(void);
+extern void ata_sff_exit(void);
+#else /* CONFIG_ATA_SFF */
+static inline void ata_sff_flush_pio_task(struct ata_port *ap)
+{ }
+static inline void ata_sff_port_init(struct ata_port *ap)
+{ }
+static inline int ata_sff_init(void)
+{ return 0; }
+static inline void ata_sff_exit(void)
+{ }
#endif /* CONFIG_ATA_SFF */
+/* libata-zpodd.c */
+#ifdef CONFIG_SATA_ZPODD
+void zpodd_init(struct ata_device *dev);
+void zpodd_exit(struct ata_device *dev);
+static inline bool zpodd_dev_enabled(struct ata_device *dev)
+{
+ return dev->zpodd != NULL;
+}
+void zpodd_on_suspend(struct ata_device *dev);
+bool zpodd_zpready(struct ata_device *dev);
+void zpodd_enable_run_wake(struct ata_device *dev);
+void zpodd_disable_run_wake(struct ata_device *dev);
+void zpodd_post_poweron(struct ata_device *dev);
+#else /* CONFIG_SATA_ZPODD */
+static inline void zpodd_init(struct ata_device *dev) {}
+static inline void zpodd_exit(struct ata_device *dev) {}
+static inline bool zpodd_dev_enabled(struct ata_device *dev) { return false; }
+static inline void zpodd_on_suspend(struct ata_device *dev) {}
+static inline bool zpodd_zpready(struct ata_device *dev) { return false; }
+static inline void zpodd_enable_run_wake(struct ata_device *dev) {}
+static inline void zpodd_disable_run_wake(struct ata_device *dev) {}
+static inline void zpodd_post_poweron(struct ata_device *dev) {}
+#endif /* CONFIG_SATA_ZPODD */
+
#endif /* __LIBATA_H__ */
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
index c5f91e62994..b70fce2a38e 100644
--- a/drivers/ata/pata_acpi.c
+++ b/drivers/ata/pata_acpi.c
@@ -1,27 +1,20 @@
/*
* ACPI PATA driver
*
- * (c) 2007 Red Hat <alan@redhat.com>
+ * (c) 2007 Red Hat
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acnames.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acparser.h>
-#include <acpi/acexcep.h>
-#include <acpi/acmacros.h>
-#include <acpi/actypes.h>
-
+#include <linux/gfp.h>
+#include <linux/acpi.h>
#include <linux/libata.h>
#include <linux/ata.h>
+#include <scsi/scsi_host.h>
#define DRV_NAME "pata_acpi"
#define DRV_VERSION "0.2.3"
@@ -44,7 +37,7 @@ static int pacpi_pre_reset(struct ata_link *link, unsigned long deadline)
{
struct ata_port *ap = link->ap;
struct pata_acpi *acpi = ap->private_data;
- if (ap->acpi_handle == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0)
+ if (ACPI_HANDLE(&ap->tdev) == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0)
return -ENODEV;
return ata_sff_prereset(link, deadline);
@@ -106,7 +99,7 @@ static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device
static unsigned long pacpi_mode_filter(struct ata_device *adev, unsigned long mask)
{
struct pata_acpi *acpi = adev->link->ap->private_data;
- return ata_bmdma_mode_filter(adev, mask & acpi->mask[adev->devno]);
+ return mask & acpi->mask[adev->devno];
}
/**
@@ -167,7 +160,7 @@ static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev)
*
* Called when the libata layer is about to issue a command. We wrap
* this interface so that we can load the correct ATA timings if
- * neccessary.
+ * necessary.
*/
static unsigned int pacpi_qc_issue(struct ata_queued_cmd *qc)
@@ -177,15 +170,15 @@ static unsigned int pacpi_qc_issue(struct ata_queued_cmd *qc)
struct pata_acpi *acpi = ap->private_data;
if (acpi->gtm.flags & 0x10)
- return ata_sff_qc_issue(qc);
+ return ata_bmdma_qc_issue(qc);
if (adev != acpi->last) {
pacpi_set_piomode(ap, adev);
- if (adev->dma_mode)
+ if (ata_dma_enabled(adev))
pacpi_set_dmamode(ap, adev);
acpi->last = adev;
}
- return ata_sff_qc_issue(qc);
+ return ata_bmdma_qc_issue(qc);
}
/**
@@ -200,9 +193,7 @@ static int pacpi_port_start(struct ata_port *ap)
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct pata_acpi *acpi;
- int ret;
-
- if (ap->acpi_handle == NULL)
+ if (ACPI_HANDLE(&ap->tdev) == NULL)
return -ENODEV;
acpi = ap->private_data = devm_kzalloc(&pdev->dev, sizeof(struct pata_acpi), GFP_KERNEL);
@@ -210,11 +201,7 @@ static int pacpi_port_start(struct ata_port *ap)
return -ENOMEM;
acpi->mask[0] = pacpi_discover_modes(ap, &ap->link.device[0]);
acpi->mask[1] = pacpi_discover_modes(ap, &ap->link.device[1]);
- ret = ata_sff_port_start(ap);
- if (ret < 0)
- return ret;
-
- return ret;
+ return ata_bmdma_port_start(ap);
}
static struct scsi_host_template pacpi_sht = {
@@ -250,16 +237,22 @@ static struct ata_port_operations pacpi_ops = {
static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
{
static const struct ata_port_info info = {
- .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = 0x7f,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
.port_ops = &pacpi_ops,
};
const struct ata_port_info *ppi[] = { &info, NULL };
- return ata_pci_sff_init_one(pdev, ppi, &pacpi_sht, NULL);
+ if (pdev->vendor == PCI_VENDOR_ID_ATI) {
+ int rc = pcim_enable_device(pdev);
+ if (rc < 0)
+ return rc;
+ pcim_pin_device(pdev);
+ }
+ return ata_pci_bmdma_init_one(pdev, ppi, &pacpi_sht, NULL, 0);
}
static const struct pci_device_id pacpi_pci_tbl[] = {
@@ -272,28 +265,16 @@ static struct pci_driver pacpi_pci_driver = {
.id_table = pacpi_pci_tbl,
.probe = pacpi_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init pacpi_init(void)
-{
- return pci_register_driver(&pacpi_pci_driver);
-}
-
-static void __exit pacpi_exit(void)
-{
- pci_unregister_driver(&pacpi_pci_driver);
-}
-
-module_init(pacpi_init);
-module_exit(pacpi_exit);
+module_pci_driver(pacpi_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("SCSI low-level driver for ATA in ACPI mode");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, pacpi_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index fcabe46f262..d19cd88ed2d 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -1,7 +1,6 @@
/*
* pata_ali.c - ALI 15x3 PATA for new ATA layer
* (C) 2005 Red Hat Inc
- * Alan Cox <alan@redhat.com>
*
* based in part upon
* linux/drivers/ide/pci/alim15x3.c Version 0.17 2003/01/02
@@ -20,7 +19,9 @@
*
* TODO/CHECK
* Cannot have ATAPI on both master & slave for rev < c2 (???) but
- * otherwise should do atapi DMA.
+ * otherwise should do atapi DMA (For now for old we do PIO only for
+ * ATAPI)
+ * Review Sunblade workaround.
*/
#include <linux/kernel.h>
@@ -34,12 +35,14 @@
#include <linux/dmi.h>
#define DRV_NAME "pata_ali"
-#define DRV_VERSION "0.7.5"
+#define DRV_VERSION "0.7.8"
static int ali_atapi_dma = 0;
module_param_named(atapi_dma, ali_atapi_dma, int, 0644);
MODULE_PARM_DESC(atapi_dma, "Enable ATAPI DMA (0=disable, 1=enable)");
+static struct pci_dev *ali_isa_bridge;
+
/*
* Cable special cases
*/
@@ -53,7 +56,7 @@ static const struct dmi_system_id cable_dmi_table[] = {
},
},
{
- .ident = "Toshiba Satelite S1800-814",
+ .ident = "Toshiba Satellite S1800-814",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "S1800-814"),
@@ -121,7 +124,7 @@ static unsigned long ali_20_filter(struct ata_device *adev, unsigned long mask)
ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
if (strstr(model_num, "WDC"))
return mask &= ~ATA_MASK_UDMA;
- return ata_bmdma_mode_filter(adev, mask);
+ return mask;
}
/**
@@ -148,8 +151,7 @@ static void ali_fifo_control(struct ata_port *ap, struct ata_device *adev, int o
pci_read_config_byte(pdev, pio_fifo, &fifo);
fifo &= ~(0x0F << shift);
- if (on)
- fifo |= (on << shift);
+ fifo |= (on << shift);
pci_write_config_byte(pdev, pio_fifo, fifo);
}
@@ -157,8 +159,7 @@ static void ali_fifo_control(struct ata_port *ap, struct ata_device *adev, int o
* ali_program_modes - load mode registers
* @ap: ALi channel to load
* @adev: Device the timing is for
- * @cmd: Command timing
- * @data: Data timing
+ * @t: timing data
* @ultra: UDMA timing or zero for off
*
* Loads the timing registers for cmd/data and disable UDMA if
@@ -177,11 +178,11 @@ static void ali_program_modes(struct ata_port *ap, struct ata_device *adev, stru
u8 udma;
if (t != NULL) {
- t->setup = FIT(t->setup, 1, 8) & 7;
- t->act8b = FIT(t->act8b, 1, 8) & 7;
- t->rec8b = FIT(t->rec8b, 1, 16) & 15;
- t->active = FIT(t->active, 1, 8) & 7;
- t->recover = FIT(t->recover, 1, 16) & 15;
+ t->setup = clamp_val(t->setup, 1, 8) & 7;
+ t->act8b = clamp_val(t->act8b, 1, 8) & 7;
+ t->rec8b = clamp_val(t->rec8b, 1, 16) & 15;
+ t->active = clamp_val(t->active, 1, 8) & 7;
+ t->recover = clamp_val(t->recover, 1, 16) & 15;
pci_write_config_byte(pdev, cas, t->setup);
pci_write_config_byte(pdev, cbt, (t->act8b << 4) | t->rec8b);
@@ -200,8 +201,7 @@ static void ali_program_modes(struct ata_port *ap, struct ata_device *adev, stru
* @ap: ATA interface
* @adev: ATA device
*
- * Program the ALi registers for PIO mode. FIXME: add timings for
- * PIO5.
+ * Program the ALi registers for PIO mode.
*/
static void ali_set_piomode(struct ata_port *ap, struct ata_device *adev)
@@ -235,7 +235,7 @@ static void ali_set_piomode(struct ata_port *ap, struct ata_device *adev)
* @ap: ATA interface
* @adev: ATA device
*
- * FIXME: MWDMA timings
+ * Program the ALi registers for DMA mode.
*/
static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev)
@@ -287,10 +287,10 @@ static void ali_warn_atapi_dma(struct ata_device *adev)
int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
if (print_info && adev->class == ATA_DEV_ATAPI && !ali_atapi_dma) {
- ata_dev_printk(adev, KERN_WARNING,
- "WARNING: ATAPI DMA disabled for reliablity issues. It can be enabled\n");
- ata_dev_printk(adev, KERN_WARNING,
- "WARNING: via pata_ali.atapi_dma modparam or corresponding sysfs node.\n");
+ ata_dev_warn(adev,
+ "WARNING: ATAPI DMA disabled for reliability issues. It can be enabled\n");
+ ata_dev_warn(adev,
+ "WARNING: via pata_ali.atapi_dma modparam or corresponding sysfs node.\n");
}
}
@@ -338,6 +338,23 @@ static int ali_check_atapi_dma(struct ata_queued_cmd *qc)
return 0;
}
+static void ali_c2_c3_postreset(struct ata_link *link, unsigned int *classes)
+{
+ u8 r;
+ int port_bit = 4 << link->ap->port_no;
+
+ /* If our bridge is an ALI 1533 then do the extra work */
+ if (ali_isa_bridge) {
+ /* Tristate and re-enable the bus signals */
+ pci_read_config_byte(ali_isa_bridge, 0x58, &r);
+ r &= ~port_bit;
+ pci_write_config_byte(ali_isa_bridge, 0x58, r);
+ r |= port_bit;
+ pci_write_config_byte(ali_isa_bridge, 0x58, r);
+ }
+ ata_sff_postreset(link, classes);
+}
+
static struct scsi_host_template ali_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
@@ -350,10 +367,11 @@ static struct ata_port_operations ali_early_port_ops = {
.inherits = &ata_sff_port_ops,
.cable_detect = ata_cable_40wire,
.set_piomode = ali_set_piomode,
+ .sff_data_xfer = ata_sff_data_xfer32,
};
static const struct ata_port_operations ali_dma_base_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma32_port_ops,
.set_piomode = ali_set_piomode,
.set_dmamode = ali_set_dmamode,
};
@@ -378,6 +396,17 @@ static struct ata_port_operations ali_c2_port_ops = {
.check_atapi_dma = ali_check_atapi_dma,
.cable_detect = ali_c2_cable_detect,
.dev_config = ali_lock_sectors,
+ .postreset = ali_c2_c3_postreset,
+};
+
+/*
+ * Port operations for DMA capable ALi with cable detect
+ */
+static struct ata_port_operations ali_c4_port_ops = {
+ .inherits = &ali_dma_base_ops,
+ .check_atapi_dma = ali_check_atapi_dma,
+ .cable_detect = ali_c2_cable_detect,
+ .dev_config = ali_lock_sectors,
};
/*
@@ -402,52 +431,51 @@ static struct ata_port_operations ali_c5_port_ops = {
static void ali_init_chipset(struct pci_dev *pdev)
{
u8 tmp;
- struct pci_dev *north, *isa_bridge;
+ struct pci_dev *north;
/*
* The chipset revision selects the driver operations and
* mode data.
*/
- if (pdev->revision >= 0x20 && pdev->revision < 0xC2) {
- /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */
- pci_read_config_byte(pdev, 0x4B, &tmp);
- /* Clear CD-ROM DMA write bit */
- tmp &= 0x7F;
- pci_write_config_byte(pdev, 0x4B, tmp);
- } else if (pdev->revision >= 0xC2) {
- /* Enable cable detection logic */
+ if (pdev->revision <= 0x20) {
+ pci_read_config_byte(pdev, 0x53, &tmp);
+ tmp |= 0x03;
+ pci_write_config_byte(pdev, 0x53, tmp);
+ } else {
+ pci_read_config_byte(pdev, 0x4a, &tmp);
+ pci_write_config_byte(pdev, 0x4a, tmp | 0x20);
pci_read_config_byte(pdev, 0x4B, &tmp);
+ if (pdev->revision < 0xC2)
+ /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */
+ /* Clear CD-ROM DMA write bit */
+ tmp &= 0x7F;
+ /* Cable and UDMA */
+ if (pdev->revision >= 0xc2)
+ tmp |= 0x01;
pci_write_config_byte(pdev, 0x4B, tmp | 0x08);
- }
- north = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
- isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
-
- if (north && north->vendor == PCI_VENDOR_ID_AL && isa_bridge) {
- /* Configure the ALi bridge logic. For non ALi rely on BIOS.
- Set the south bridge enable bit */
- pci_read_config_byte(isa_bridge, 0x79, &tmp);
- if (pdev->revision == 0xC2)
- pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04);
- else if (pdev->revision > 0xC2 && pdev->revision < 0xC5)
- pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02);
- }
- if (pdev->revision >= 0x20) {
/*
* CD_ROM DMA on (0x53 bit 0). Enable this even if we want
* to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control
* via 0x54/55.
*/
pci_read_config_byte(pdev, 0x53, &tmp);
- if (pdev->revision <= 0x20)
- tmp &= ~0x02;
if (pdev->revision >= 0xc7)
tmp |= 0x03;
else
tmp |= 0x01; /* CD_ROM enable for DMA */
pci_write_config_byte(pdev, 0x53, tmp);
}
- pci_dev_put(isa_bridge);
+ north = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
+ if (north && north->vendor == PCI_VENDOR_ID_AL && ali_isa_bridge) {
+ /* Configure the ALi bridge logic. For non ALi rely on BIOS.
+ Set the south bridge enable bit */
+ pci_read_config_byte(ali_isa_bridge, 0x79, &tmp);
+ if (pdev->revision == 0xC2)
+ pci_write_config_byte(ali_isa_bridge, 0x79, tmp | 0x04);
+ else if (pdev->revision > 0xC2 && pdev->revision < 0xC5)
+ pci_write_config_byte(ali_isa_bridge, 0x79, tmp | 0x02);
+ }
pci_dev_put(north);
ata_pci_bmdma_clear_simplex(pdev);
}
@@ -464,60 +492,64 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
static const struct ata_port_info info_early = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
+ .pio_mask = ATA_PIO4,
.port_ops = &ali_early_port_ops
};
/* Revision 0x20 added DMA */
static const struct ata_port_info info_20 = {
- .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48 |
+ ATA_FLAG_IGN_SIMPLEX,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.port_ops = &ali_20_port_ops
};
/* Revision 0x20 with support logic added UDMA */
static const struct ata_port_info info_20_udma = {
- .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = 0x07, /* UDMA33 */
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48 |
+ ATA_FLAG_IGN_SIMPLEX,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
.port_ops = &ali_20_port_ops
};
/* Revision 0xC2 adds UDMA66 */
static const struct ata_port_info info_c2 = {
- .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48 |
+ ATA_FLAG_IGN_SIMPLEX,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA4,
.port_ops = &ali_c2_port_ops
};
/* Revision 0xC3 is UDMA66 for now */
static const struct ata_port_info info_c3 = {
- .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48 |
+ ATA_FLAG_IGN_SIMPLEX,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA4,
.port_ops = &ali_c2_port_ops
};
/* Revision 0xC4 is UDMA100 */
static const struct ata_port_info info_c4 = {
- .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48 |
+ ATA_FLAG_IGN_SIMPLEX,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
- .port_ops = &ali_c2_port_ops
+ .port_ops = &ali_c4_port_ops
};
/* Revision 0xC5 is UDMA133 with LBA48 DMA */
static const struct ata_port_info info_c5 = {
- .flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_IGN_SIMPLEX,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &ali_c5_port_ops
};
const struct ata_port_info *ppi[] = { NULL, NULL };
u8 tmp;
- struct pci_dev *isa_bridge;
int rc;
rc = pcim_enable_device(pdev);
@@ -544,21 +576,23 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
ali_init_chipset(pdev);
- isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
- if (isa_bridge && pdev->revision >= 0x20 && pdev->revision < 0xC2) {
+ if (ali_isa_bridge && pdev->revision >= 0x20 && pdev->revision < 0xC2) {
/* Are we paired with a UDMA capable chip */
- pci_read_config_byte(isa_bridge, 0x5E, &tmp);
+ pci_read_config_byte(ali_isa_bridge, 0x5E, &tmp);
if ((tmp & 0x1E) == 0x12)
ppi[0] = &info_20_udma;
- pci_dev_put(isa_bridge);
}
- return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL);
+
+ if (!ppi[0]->mwdma_mask && !ppi[0]->udma_mask)
+ return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL, 0);
+ else
+ return ata_pci_bmdma_init_one(pdev, ppi, &ali_sht, NULL, 0);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ali_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -582,7 +616,7 @@ static struct pci_driver ali_pci_driver = {
.id_table = ali,
.probe = ali_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ali_reinit_one,
#endif
@@ -590,13 +624,20 @@ static struct pci_driver ali_pci_driver = {
static int __init ali_init(void)
{
- return pci_register_driver(&ali_pci_driver);
+ int ret;
+ ali_isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+
+ ret = pci_register_driver(&ali_pci_driver);
+ if (ret < 0)
+ pci_dev_put(ali_isa_bridge);
+ return ret;
}
static void __exit ali_exit(void)
{
pci_unregister_driver(&ali_pci_driver);
+ pci_dev_put(ali_isa_bridge);
}
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 26665c39648..8d4d959a821 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -1,7 +1,6 @@
/*
* pata_amd.c - AMD PATA for new ATA layer
* (C) 2005-2006 Red Hat Inc
- * Alan Cox <alan@redhat.com>
*
* Based on pata-sil680. Errata information is taken from data sheets
* and the amd74xx.c driver by Vojtech Pavlik. Nvidia SATA devices are
@@ -12,20 +11,19 @@
* Power management on ports
*
*
- * Documentation publically available.
+ * Documentation publicly available.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "pata_amd"
-#define DRV_VERSION "0.3.10"
+#define DRV_VERSION "0.4.1"
/**
* timing_setup - shared timing computation and load
@@ -61,7 +59,7 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse
UT = T / 2;
if (ata_timing_compute(adev, speed, &at, T, UT) < 0) {
- dev_printk(KERN_ERR, &pdev->dev, "unknown mode %d.\n", speed);
+ dev_err(&pdev->dev, "unknown mode %d\n", speed);
return;
}
@@ -84,32 +82,32 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse
/* Configure the address set up timing */
pci_read_config_byte(pdev, offset + 0x0C, &t);
- t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(at.setup, 1, 4) - 1) << ((3 - dn) << 1));
+ t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(at.setup, 1, 4) - 1) << ((3 - dn) << 1));
pci_write_config_byte(pdev, offset + 0x0C , t);
/* Configure the 8bit I/O timing */
pci_write_config_byte(pdev, offset + 0x0E + (1 - (dn >> 1)),
- ((FIT(at.act8b, 1, 16) - 1) << 4) | (FIT(at.rec8b, 1, 16) - 1));
+ ((clamp_val(at.act8b, 1, 16) - 1) << 4) | (clamp_val(at.rec8b, 1, 16) - 1));
/* Drive timing */
pci_write_config_byte(pdev, offset + 0x08 + (3 - dn),
- ((FIT(at.active, 1, 16) - 1) << 4) | (FIT(at.recover, 1, 16) - 1));
+ ((clamp_val(at.active, 1, 16) - 1) << 4) | (clamp_val(at.recover, 1, 16) - 1));
switch (clock) {
case 1:
- t = at.udma ? (0xc0 | (FIT(at.udma, 2, 5) - 2)) : 0x03;
+ t = at.udma ? (0xc0 | (clamp_val(at.udma, 2, 5) - 2)) : 0x03;
break;
case 2:
- t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 2, 10)]) : 0x03;
+ t = at.udma ? (0xc0 | amd_cyc2udma[clamp_val(at.udma, 2, 10)]) : 0x03;
break;
case 3:
- t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 10)]) : 0x03;
+ t = at.udma ? (0xc0 | amd_cyc2udma[clamp_val(at.udma, 1, 10)]) : 0x03;
break;
case 4:
- t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 15)]) : 0x03;
+ t = at.udma ? (0xc0 | amd_cyc2udma[clamp_val(at.udma, 1, 15)]) : 0x03;
break;
default:
@@ -146,6 +144,13 @@ static int amd_pre_reset(struct ata_link *link, unsigned long deadline)
return ata_sff_prereset(link, deadline);
}
+/**
+ * amd_cable_detect - report cable type
+ * @ap: port
+ *
+ * AMD controller/BIOS setups record the cable type in word 0x42
+ */
+
static int amd_cable_detect(struct ata_port *ap)
{
static const u32 bitmask[2] = {0x03, 0x0C};
@@ -159,6 +164,40 @@ static int amd_cable_detect(struct ata_port *ap)
}
/**
+ * amd_fifo_setup - set the PIO FIFO for ATA/ATAPI
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Set the PCI fifo for this device according to the devices present
+ * on the bus at this point in time. We need to turn the post write buffer
+ * off for ATAPI devices as we may need to issue a word sized write to the
+ * device as the final I/O
+ */
+
+static void amd_fifo_setup(struct ata_port *ap)
+{
+ struct ata_device *adev;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const u8 fifobit[2] = { 0xC0, 0x30};
+ u8 fifo = fifobit[ap->port_no];
+ u8 r;
+
+
+ ata_for_each_dev(adev, &ap->link, ENABLED) {
+ if (adev->class == ATA_DEV_ATAPI)
+ fifo = 0;
+ }
+ if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7411) /* FIFO is broken */
+ fifo = 0;
+
+ /* On the later chips the read prefetch bits become no-op bits */
+ pci_read_config_byte(pdev, 0x41, &r);
+ r &= ~fifobit[ap->port_no];
+ r |= fifo;
+ pci_write_config_byte(pdev, 0x41, r);
+}
+
+/**
* amd33_set_piomode - set initial PIO mode data
* @ap: ATA interface
* @adev: ATA device
@@ -168,21 +207,25 @@ static int amd_cable_detect(struct ata_port *ap)
static void amd33_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
+ amd_fifo_setup(ap);
timing_setup(ap, adev, 0x40, adev->pio_mode, 1);
}
static void amd66_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
+ amd_fifo_setup(ap);
timing_setup(ap, adev, 0x40, adev->pio_mode, 2);
}
static void amd100_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
+ amd_fifo_setup(ap);
timing_setup(ap, adev, 0x40, adev->pio_mode, 3);
}
static void amd133_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
+ amd_fifo_setup(ap);
timing_setup(ap, adev, 0x40, adev->pio_mode, 4);
}
@@ -263,8 +306,11 @@ static unsigned long nv_mode_filter(struct ata_device *dev,
limit |= ATA_MASK_PIO;
if (!(limit & (ATA_MASK_MWDMA | ATA_MASK_UDMA)))
limit |= ATA_MASK_MWDMA | ATA_MASK_UDMA;
+ /* PIO4, MWDMA2, UDMA2 should always be supported regardless of
+ cable detection result */
+ limit |= ata_pack_xfermask(ATA_PIO4, ATA_MWDMA2, ATA_UDMA2);
- ata_port_printk(ap, KERN_DEBUG, "nv_mode_filter: 0x%lx&0x%lx->0x%lx, "
+ ata_port_dbg(ap, "nv_mode_filter: 0x%lx&0x%lx->0x%lx, "
"BIOS=0x%lx (0x%x) ACPI=0x%lx%s\n",
xfer_mask, limit, xfer_mask & limit, bios_limit,
saved_udma, acpi_limit, acpi_str);
@@ -346,7 +392,7 @@ static struct scsi_host_template amd_sht = {
};
static const struct ata_port_operations amd_base_port_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma32_port_ops,
.prereset = amd_pre_reset,
};
@@ -398,89 +444,97 @@ static struct ata_port_operations nv133_port_ops = {
.set_dmamode = nv133_set_dmamode,
};
+static void amd_clear_fifo(struct pci_dev *pdev)
+{
+ u8 fifo;
+ /* Disable the FIFO, the FIFO logic will re-enable it as
+ appropriate */
+ pci_read_config_byte(pdev, 0x41, &fifo);
+ fifo &= 0x0F;
+ pci_write_config_byte(pdev, 0x41, fifo);
+}
+
static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
static const struct ata_port_info info[10] = {
- { /* 0: AMD 7401 */
+ { /* 0: AMD 7401 - no swdma */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07, /* No SWDMA */
- .udma_mask = 0x07, /* UDMA 33 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
.port_ops = &amd33_port_ops
},
{ /* 1: Early AMD7409 - no swdma */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA4, /* UDMA 66 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
.port_ops = &amd66_port_ops
},
- { /* 2: AMD 7409, no swdma errata */
+ { /* 2: AMD 7409 */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA4, /* UDMA 66 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
.port_ops = &amd66_port_ops
},
{ /* 3: AMD 7411 */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA5, /* UDMA 100 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
.port_ops = &amd100_port_ops
},
{ /* 4: AMD 7441 */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA5, /* UDMA 100 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
.port_ops = &amd100_port_ops
},
- { /* 5: AMD 8111*/
+ { /* 5: AMD 8111 - no swdma */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA6, /* UDMA 133, no swdma */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
.port_ops = &amd133_port_ops
},
- { /* 6: AMD 8111 UDMA 100 (Serenade) */
+ { /* 6: AMD 8111 UDMA 100 (Serenade) - no swdma */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA5, /* UDMA 100, no swdma */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
.port_ops = &amd133_port_ops
},
{ /* 7: Nvidia Nforce */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA5, /* UDMA 100 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
.port_ops = &nv100_port_ops
},
- { /* 8: Nvidia Nforce2 and later */
+ { /* 8: Nvidia Nforce2 and later - no swdma */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA6, /* UDMA 133, no swdma */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
.port_ops = &nv133_port_ops
},
{ /* 9: AMD CS5536 (Geode companion) */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA5, /* UDMA 100 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
.port_ops = &amd100_port_ops
}
};
const struct ata_port_info *ppi[] = { NULL, NULL };
- static int printed_version;
int type = id->driver_data;
void *hpriv = NULL;
u8 fifo;
int rc;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
rc = pcim_enable_device(pdev);
if (rc)
@@ -504,14 +558,8 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (type < 3)
ata_pci_bmdma_clear_simplex(pdev);
-
- /* Check for AMD7411 */
- if (type == 3)
- /* FIFO is broken */
- pci_write_config_byte(pdev, 0x41, fifo & 0x0F);
- else
- pci_write_config_byte(pdev, 0x41, fifo | 0xF0);
-
+ if (pdev->vendor == PCI_VENDOR_ID_AMD)
+ amd_clear_fifo(pdev);
/* Cable detection on Nvidia chips doesn't work too well,
* cache BIOS programmed UDMA mode.
*/
@@ -523,13 +571,13 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* And fire it up */
- return ata_pci_sff_init_one(pdev, ppi, &amd_sht, hpriv);
+ return ata_pci_bmdma_init_one(pdev, ppi, &amd_sht, hpriv, 0);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int amd_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -537,18 +585,11 @@ static int amd_reinit_one(struct pci_dev *pdev)
return rc;
if (pdev->vendor == PCI_VENDOR_ID_AMD) {
- u8 fifo;
- pci_read_config_byte(pdev, 0x41, &fifo);
- if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7411)
- /* FIFO is broken */
- pci_write_config_byte(pdev, 0x41, fifo & 0x0F);
- else
- pci_write_config_byte(pdev, 0x41, fifo | 0xF0);
+ amd_clear_fifo(pdev);
if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7409 ||
pdev->device == PCI_DEVICE_ID_AMD_COBRA_7401)
ata_pci_bmdma_clear_simplex(pdev);
}
-
ata_host_resume(host);
return 0;
}
@@ -584,27 +625,16 @@ static struct pci_driver amd_pci_driver = {
.id_table = amd,
.probe = amd_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = amd_reinit_one,
#endif
};
-static int __init amd_init(void)
-{
- return pci_register_driver(&amd_pci_driver);
-}
-
-static void __exit amd_exit(void)
-{
- pci_unregister_driver(&amd_pci_driver);
-}
+module_pci_driver(amd_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for AMD and Nvidia PATA IDE");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, amd);
MODULE_VERSION(DRV_VERSION);
-
-module_init(amd_init);
-module_exit(amd_exit);
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
new file mode 100644
index 00000000000..4edb1a81f63
--- /dev/null
+++ b/drivers/ata/pata_arasan_cf.c
@@ -0,0 +1,976 @@
+/*
+ * drivers/ata/pata_arasan_cf.c
+ *
+ * Arasan Compact Flash host controller source file
+ *
+ * Copyright (C) 2011 ST Microelectronics
+ * Viresh Kumar <viresh.linux@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/*
+ * The Arasan CompactFlash Device Controller IP core has three basic modes of
+ * operation: PC card ATA using I/O mode, PC card ATA using memory mode, PC card
+ * ATA using true IDE modes. This driver supports only True IDE mode currently.
+ *
+ * Arasan CF Controller shares global irq register with Arasan XD Controller.
+ *
+ * Tested on arch/arm/mach-spear13xx
+ */
+
+#include <linux/ata.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/libata.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pata_arasan_cf_data.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#define DRIVER_NAME "arasan_cf"
+#define TIMEOUT msecs_to_jiffies(3000)
+
+/* Registers */
+/* CompactFlash Interface Status */
+#define CFI_STS 0x000
+ #define STS_CHG (1)
+ #define BIN_AUDIO_OUT (1 << 1)
+ #define CARD_DETECT1 (1 << 2)
+ #define CARD_DETECT2 (1 << 3)
+ #define INP_ACK (1 << 4)
+ #define CARD_READY (1 << 5)
+ #define IO_READY (1 << 6)
+ #define B16_IO_PORT_SEL (1 << 7)
+/* IRQ */
+#define IRQ_STS 0x004
+/* Interrupt Enable */
+#define IRQ_EN 0x008
+ #define CARD_DETECT_IRQ (1)
+ #define STATUS_CHNG_IRQ (1 << 1)
+ #define MEM_MODE_IRQ (1 << 2)
+ #define IO_MODE_IRQ (1 << 3)
+ #define TRUE_IDE_MODE_IRQ (1 << 8)
+ #define PIO_XFER_ERR_IRQ (1 << 9)
+ #define BUF_AVAIL_IRQ (1 << 10)
+ #define XFER_DONE_IRQ (1 << 11)
+ #define IGNORED_IRQS (STATUS_CHNG_IRQ | MEM_MODE_IRQ | IO_MODE_IRQ |\
+ TRUE_IDE_MODE_IRQ)
+ #define TRUE_IDE_IRQS (CARD_DETECT_IRQ | PIO_XFER_ERR_IRQ |\
+ BUF_AVAIL_IRQ | XFER_DONE_IRQ)
+/* Operation Mode */
+#define OP_MODE 0x00C
+ #define CARD_MODE_MASK (0x3)
+ #define MEM_MODE (0x0)
+ #define IO_MODE (0x1)
+ #define TRUE_IDE_MODE (0x2)
+
+ #define CARD_TYPE_MASK (1 << 2)
+ #define CF_CARD (0)
+ #define CF_PLUS_CARD (1 << 2)
+
+ #define CARD_RESET (1 << 3)
+ #define CFHOST_ENB (1 << 4)
+ #define OUTPUTS_TRISTATE (1 << 5)
+ #define ULTRA_DMA_ENB (1 << 8)
+ #define MULTI_WORD_DMA_ENB (1 << 9)
+ #define DRQ_BLOCK_SIZE_MASK (0x3 << 11)
+ #define DRQ_BLOCK_SIZE_512 (0)
+ #define DRQ_BLOCK_SIZE_1024 (1 << 11)
+ #define DRQ_BLOCK_SIZE_2048 (2 << 11)
+ #define DRQ_BLOCK_SIZE_4096 (3 << 11)
+/* CF Interface Clock Configuration */
+#define CLK_CFG 0x010
+ #define CF_IF_CLK_MASK (0XF)
+/* CF Timing Mode Configuration */
+#define TM_CFG 0x014
+ #define MEM_MODE_TIMING_MASK (0x3)
+ #define MEM_MODE_TIMING_250NS (0x0)
+ #define MEM_MODE_TIMING_120NS (0x1)
+ #define MEM_MODE_TIMING_100NS (0x2)
+ #define MEM_MODE_TIMING_80NS (0x3)
+
+ #define IO_MODE_TIMING_MASK (0x3 << 2)
+ #define IO_MODE_TIMING_250NS (0x0 << 2)
+ #define IO_MODE_TIMING_120NS (0x1 << 2)
+ #define IO_MODE_TIMING_100NS (0x2 << 2)
+ #define IO_MODE_TIMING_80NS (0x3 << 2)
+
+ #define TRUEIDE_PIO_TIMING_MASK (0x7 << 4)
+ #define TRUEIDE_PIO_TIMING_SHIFT 4
+
+ #define TRUEIDE_MWORD_DMA_TIMING_MASK (0x7 << 7)
+ #define TRUEIDE_MWORD_DMA_TIMING_SHIFT 7
+
+ #define ULTRA_DMA_TIMING_MASK (0x7 << 10)
+ #define ULTRA_DMA_TIMING_SHIFT 10
+/* CF Transfer Address */
+#define XFER_ADDR 0x014
+ #define XFER_ADDR_MASK (0x7FF)
+ #define MAX_XFER_COUNT 0x20000u
+/* Transfer Control */
+#define XFER_CTR 0x01C
+ #define XFER_COUNT_MASK (0x3FFFF)
+ #define ADDR_INC_DISABLE (1 << 24)
+ #define XFER_WIDTH_MASK (1 << 25)
+ #define XFER_WIDTH_8B (0)
+ #define XFER_WIDTH_16B (1 << 25)
+
+ #define MEM_TYPE_MASK (1 << 26)
+ #define MEM_TYPE_COMMON (0)
+ #define MEM_TYPE_ATTRIBUTE (1 << 26)
+
+ #define MEM_IO_XFER_MASK (1 << 27)
+ #define MEM_XFER (0)
+ #define IO_XFER (1 << 27)
+
+ #define DMA_XFER_MODE (1 << 28)
+
+ #define AHB_BUS_NORMAL_PIO_OPRTN (~(1 << 29))
+ #define XFER_DIR_MASK (1 << 30)
+ #define XFER_READ (0)
+ #define XFER_WRITE (1 << 30)
+
+ #define XFER_START (1 << 31)
+/* Write Data Port */
+#define WRITE_PORT 0x024
+/* Read Data Port */
+#define READ_PORT 0x028
+/* ATA Data Port */
+#define ATA_DATA_PORT 0x030
+ #define ATA_DATA_PORT_MASK (0xFFFF)
+/* ATA Error/Features */
+#define ATA_ERR_FTR 0x034
+/* ATA Sector Count */
+#define ATA_SC 0x038
+/* ATA Sector Number */
+#define ATA_SN 0x03C
+/* ATA Cylinder Low */
+#define ATA_CL 0x040
+/* ATA Cylinder High */
+#define ATA_CH 0x044
+/* ATA Select Card/Head */
+#define ATA_SH 0x048
+/* ATA Status-Command */
+#define ATA_STS_CMD 0x04C
+/* ATA Alternate Status/Device Control */
+#define ATA_ASTS_DCTR 0x050
+/* Extended Write Data Port 0x200-0x3FC */
+#define EXT_WRITE_PORT 0x200
+/* Extended Read Data Port 0x400-0x5FC */
+#define EXT_READ_PORT 0x400
+ #define FIFO_SIZE 0x200u
+/* Global Interrupt Status */
+#define GIRQ_STS 0x800
+/* Global Interrupt Status enable */
+#define GIRQ_STS_EN 0x804
+/* Global Interrupt Signal enable */
+#define GIRQ_SGN_EN 0x808
+ #define GIRQ_CF (1)
+ #define GIRQ_XD (1 << 1)
+
+/* Compact Flash Controller Dev Structure */
+struct arasan_cf_dev {
+ /* pointer to ata_host structure */
+ struct ata_host *host;
+ /* clk structure */
+ struct clk *clk;
+
+ /* physical base address of controller */
+ dma_addr_t pbase;
+ /* virtual base address of controller */
+ void __iomem *vbase;
+ /* irq number*/
+ int irq;
+
+ /* status to be updated to framework regarding DMA transfer */
+ u8 dma_status;
+ /* Card is present or Not */
+ u8 card_present;
+
+ /* dma specific */
+ /* Completion for transfer complete interrupt from controller */
+ struct completion cf_completion;
+ /* Completion for DMA transfer complete. */
+ struct completion dma_completion;
+ /* Dma channel allocated */
+ struct dma_chan *dma_chan;
+ /* Mask for DMA transfers */
+ dma_cap_mask_t mask;
+ /* DMA transfer work */
+ struct work_struct work;
+ /* DMA delayed finish work */
+ struct delayed_work dwork;
+ /* qc to be transferred using DMA */
+ struct ata_queued_cmd *qc;
+};
+
+static struct scsi_host_template arasan_cf_sht = {
+ ATA_BASE_SHT(DRIVER_NAME),
+ .sg_tablesize = SG_NONE,
+ .dma_boundary = 0xFFFFFFFFUL,
+};
+
+static void cf_dumpregs(struct arasan_cf_dev *acdev)
+{
+ struct device *dev = acdev->host->dev;
+
+ dev_dbg(dev, ": =========== REGISTER DUMP ===========");
+ dev_dbg(dev, ": CFI_STS: %x", readl(acdev->vbase + CFI_STS));
+ dev_dbg(dev, ": IRQ_STS: %x", readl(acdev->vbase + IRQ_STS));
+ dev_dbg(dev, ": IRQ_EN: %x", readl(acdev->vbase + IRQ_EN));
+ dev_dbg(dev, ": OP_MODE: %x", readl(acdev->vbase + OP_MODE));
+ dev_dbg(dev, ": CLK_CFG: %x", readl(acdev->vbase + CLK_CFG));
+ dev_dbg(dev, ": TM_CFG: %x", readl(acdev->vbase + TM_CFG));
+ dev_dbg(dev, ": XFER_CTR: %x", readl(acdev->vbase + XFER_CTR));
+ dev_dbg(dev, ": GIRQ_STS: %x", readl(acdev->vbase + GIRQ_STS));
+ dev_dbg(dev, ": GIRQ_STS_EN: %x", readl(acdev->vbase + GIRQ_STS_EN));
+ dev_dbg(dev, ": GIRQ_SGN_EN: %x", readl(acdev->vbase + GIRQ_SGN_EN));
+ dev_dbg(dev, ": =====================================");
+}
+
+/* Enable/Disable global interrupts shared between CF and XD ctrlr. */
+static void cf_ginterrupt_enable(struct arasan_cf_dev *acdev, bool enable)
+{
+ /* enable should be 0 or 1 */
+ writel(enable, acdev->vbase + GIRQ_STS_EN);
+ writel(enable, acdev->vbase + GIRQ_SGN_EN);
+}
+
+/* Enable/Disable CF interrupts */
+static inline void
+cf_interrupt_enable(struct arasan_cf_dev *acdev, u32 mask, bool enable)
+{
+ u32 val = readl(acdev->vbase + IRQ_EN);
+ /* clear & enable/disable irqs */
+ if (enable) {
+ writel(mask, acdev->vbase + IRQ_STS);
+ writel(val | mask, acdev->vbase + IRQ_EN);
+ } else
+ writel(val & ~mask, acdev->vbase + IRQ_EN);
+}
+
+static inline void cf_card_reset(struct arasan_cf_dev *acdev)
+{
+ u32 val = readl(acdev->vbase + OP_MODE);
+
+ writel(val | CARD_RESET, acdev->vbase + OP_MODE);
+ udelay(200);
+ writel(val & ~CARD_RESET, acdev->vbase + OP_MODE);
+}
+
+static inline void cf_ctrl_reset(struct arasan_cf_dev *acdev)
+{
+ writel(readl(acdev->vbase + OP_MODE) & ~CFHOST_ENB,
+ acdev->vbase + OP_MODE);
+ writel(readl(acdev->vbase + OP_MODE) | CFHOST_ENB,
+ acdev->vbase + OP_MODE);
+}
+
+static void cf_card_detect(struct arasan_cf_dev *acdev, bool hotplugged)
+{
+ struct ata_port *ap = acdev->host->ports[0];
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ u32 val = readl(acdev->vbase + CFI_STS);
+
+ /* Both CD1 & CD2 should be low if card inserted completely */
+ if (!(val & (CARD_DETECT1 | CARD_DETECT2))) {
+ if (acdev->card_present)
+ return;
+ acdev->card_present = 1;
+ cf_card_reset(acdev);
+ } else {
+ if (!acdev->card_present)
+ return;
+ acdev->card_present = 0;
+ }
+
+ if (hotplugged) {
+ ata_ehi_hotplugged(ehi);
+ ata_port_freeze(ap);
+ }
+}
+
+static int cf_init(struct arasan_cf_dev *acdev)
+{
+ struct arasan_cf_pdata *pdata = dev_get_platdata(acdev->host->dev);
+ unsigned int if_clk;
+ unsigned long flags;
+ int ret = 0;
+
+ ret = clk_prepare_enable(acdev->clk);
+ if (ret) {
+ dev_dbg(acdev->host->dev, "clock enable failed");
+ return ret;
+ }
+
+ ret = clk_set_rate(acdev->clk, 166000000);
+ if (ret) {
+ dev_warn(acdev->host->dev, "clock set rate failed");
+ clk_disable_unprepare(acdev->clk);
+ return ret;
+ }
+
+ spin_lock_irqsave(&acdev->host->lock, flags);
+ /* configure CF interface clock */
+ /* TODO: read from device tree */
+ if_clk = CF_IF_CLK_166M;
+ if (pdata && pdata->cf_if_clk <= CF_IF_CLK_200M)
+ if_clk = pdata->cf_if_clk;
+
+ writel(if_clk, acdev->vbase + CLK_CFG);
+
+ writel(TRUE_IDE_MODE | CFHOST_ENB, acdev->vbase + OP_MODE);
+ cf_interrupt_enable(acdev, CARD_DETECT_IRQ, 1);
+ cf_ginterrupt_enable(acdev, 1);
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
+
+ return ret;
+}
+
+static void cf_exit(struct arasan_cf_dev *acdev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&acdev->host->lock, flags);
+ cf_ginterrupt_enable(acdev, 0);
+ cf_interrupt_enable(acdev, TRUE_IDE_IRQS, 0);
+ cf_card_reset(acdev);
+ writel(readl(acdev->vbase + OP_MODE) & ~CFHOST_ENB,
+ acdev->vbase + OP_MODE);
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
+ clk_disable_unprepare(acdev->clk);
+}
+
+static void dma_callback(void *dev)
+{
+ struct arasan_cf_dev *acdev = dev;
+
+ complete(&acdev->dma_completion);
+}
+
+static inline void dma_complete(struct arasan_cf_dev *acdev)
+{
+ struct ata_queued_cmd *qc = acdev->qc;
+ unsigned long flags;
+
+ acdev->qc = NULL;
+ ata_sff_interrupt(acdev->irq, acdev->host);
+
+ spin_lock_irqsave(&acdev->host->lock, flags);
+ if (unlikely(qc->err_mask) && ata_is_dma(qc->tf.protocol))
+ ata_ehi_push_desc(&qc->ap->link.eh_info, "DMA Failed: Timeout");
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
+}
+
+static inline int wait4buf(struct arasan_cf_dev *acdev)
+{
+ if (!wait_for_completion_timeout(&acdev->cf_completion, TIMEOUT)) {
+ u32 rw = acdev->qc->tf.flags & ATA_TFLAG_WRITE;
+
+ dev_err(acdev->host->dev, "%s TimeOut", rw ? "write" : "read");
+ return -ETIMEDOUT;
+ }
+
+ /* Check if PIO Error interrupt has occurred */
+ if (acdev->dma_status & ATA_DMA_ERR)
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int
+dma_xfer(struct arasan_cf_dev *acdev, dma_addr_t src, dma_addr_t dest, u32 len)
+{
+ struct dma_async_tx_descriptor *tx;
+ struct dma_chan *chan = acdev->dma_chan;
+ dma_cookie_t cookie;
+ unsigned long flags = DMA_PREP_INTERRUPT;
+ int ret = 0;
+
+ tx = chan->device->device_prep_dma_memcpy(chan, dest, src, len, flags);
+ if (!tx) {
+ dev_err(acdev->host->dev, "device_prep_dma_memcpy failed\n");
+ return -EAGAIN;
+ }
+
+ tx->callback = dma_callback;
+ tx->callback_param = acdev;
+ cookie = tx->tx_submit(tx);
+
+ ret = dma_submit_error(cookie);
+ if (ret) {
+ dev_err(acdev->host->dev, "dma_submit_error\n");
+ return ret;
+ }
+
+ chan->device->device_issue_pending(chan);
+
+ /* Wait for DMA to complete */
+ if (!wait_for_completion_timeout(&acdev->dma_completion, TIMEOUT)) {
+ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+ dev_err(acdev->host->dev, "wait_for_completion_timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ return ret;
+}
+
+static int sg_xfer(struct arasan_cf_dev *acdev, struct scatterlist *sg)
+{
+ dma_addr_t dest = 0, src = 0;
+ u32 xfer_cnt, sglen, dma_len, xfer_ctr;
+ u32 write = acdev->qc->tf.flags & ATA_TFLAG_WRITE;
+ unsigned long flags;
+ int ret = 0;
+
+ sglen = sg_dma_len(sg);
+ if (write) {
+ src = sg_dma_address(sg);
+ dest = acdev->pbase + EXT_WRITE_PORT;
+ } else {
+ dest = sg_dma_address(sg);
+ src = acdev->pbase + EXT_READ_PORT;
+ }
+
+ /*
+ * For each sg:
+ * MAX_XFER_COUNT data will be transferred before we get transfer
+ * complete interrupt. Between after FIFO_SIZE data
+ * buffer available interrupt will be generated. At this time we will
+ * fill FIFO again: max FIFO_SIZE data.
+ */
+ while (sglen) {
+ xfer_cnt = min(sglen, MAX_XFER_COUNT);
+ spin_lock_irqsave(&acdev->host->lock, flags);
+ xfer_ctr = readl(acdev->vbase + XFER_CTR) &
+ ~XFER_COUNT_MASK;
+ writel(xfer_ctr | xfer_cnt | XFER_START,
+ acdev->vbase + XFER_CTR);
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
+
+ /* continue dma xfers until current sg is completed */
+ while (xfer_cnt) {
+ /* wait for read to complete */
+ if (!write) {
+ ret = wait4buf(acdev);
+ if (ret)
+ goto fail;
+ }
+
+ /* read/write FIFO in chunk of FIFO_SIZE */
+ dma_len = min(xfer_cnt, FIFO_SIZE);
+ ret = dma_xfer(acdev, src, dest, dma_len);
+ if (ret) {
+ dev_err(acdev->host->dev, "dma failed");
+ goto fail;
+ }
+
+ if (write)
+ src += dma_len;
+ else
+ dest += dma_len;
+
+ sglen -= dma_len;
+ xfer_cnt -= dma_len;
+
+ /* wait for write to complete */
+ if (write) {
+ ret = wait4buf(acdev);
+ if (ret)
+ goto fail;
+ }
+ }
+ }
+
+fail:
+ spin_lock_irqsave(&acdev->host->lock, flags);
+ writel(readl(acdev->vbase + XFER_CTR) & ~XFER_START,
+ acdev->vbase + XFER_CTR);
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
+
+ return ret;
+}
+
+/*
+ * This routine uses External DMA controller to read/write data to FIFO of CF
+ * controller. There are two xfer related interrupt supported by CF controller:
+ * - buf_avail: This interrupt is generated as soon as we have buffer of 512
+ * bytes available for reading or empty buffer available for writing.
+ * - xfer_done: This interrupt is generated on transfer of "xfer_size" amount of
+ * data to/from FIFO. xfer_size is programmed in XFER_CTR register.
+ *
+ * Max buffer size = FIFO_SIZE = 512 Bytes.
+ * Max xfer_size = MAX_XFER_COUNT = 256 KB.
+ */
+static void data_xfer(struct work_struct *work)
+{
+ struct arasan_cf_dev *acdev = container_of(work, struct arasan_cf_dev,
+ work);
+ struct ata_queued_cmd *qc = acdev->qc;
+ struct scatterlist *sg;
+ unsigned long flags;
+ u32 temp;
+ int ret = 0;
+
+ /* request dma channels */
+ /* dma_request_channel may sleep, so calling from process context */
+ acdev->dma_chan = dma_request_slave_channel(acdev->host->dev, "data");
+ if (!acdev->dma_chan) {
+ dev_err(acdev->host->dev, "Unable to get dma_chan\n");
+ goto chan_request_fail;
+ }
+
+ for_each_sg(qc->sg, sg, qc->n_elem, temp) {
+ ret = sg_xfer(acdev, sg);
+ if (ret)
+ break;
+ }
+
+ dma_release_channel(acdev->dma_chan);
+
+ /* data xferred successfully */
+ if (!ret) {
+ u32 status;
+
+ spin_lock_irqsave(&acdev->host->lock, flags);
+ status = ioread8(qc->ap->ioaddr.altstatus_addr);
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
+ if (status & (ATA_BUSY | ATA_DRQ)) {
+ ata_sff_queue_delayed_work(&acdev->dwork, 1);
+ return;
+ }
+
+ goto sff_intr;
+ }
+
+ cf_dumpregs(acdev);
+
+chan_request_fail:
+ spin_lock_irqsave(&acdev->host->lock, flags);
+ /* error when transferring data to/from memory */
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ qc->ap->hsm_task_state = HSM_ST_ERR;
+
+ cf_ctrl_reset(acdev);
+ spin_unlock_irqrestore(qc->ap->lock, flags);
+sff_intr:
+ dma_complete(acdev);
+}
+
+static void delayed_finish(struct work_struct *work)
+{
+ struct arasan_cf_dev *acdev = container_of(work, struct arasan_cf_dev,
+ dwork.work);
+ struct ata_queued_cmd *qc = acdev->qc;
+ unsigned long flags;
+ u8 status;
+
+ spin_lock_irqsave(&acdev->host->lock, flags);
+ status = ioread8(qc->ap->ioaddr.altstatus_addr);
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
+
+ if (status & (ATA_BUSY | ATA_DRQ))
+ ata_sff_queue_delayed_work(&acdev->dwork, 1);
+ else
+ dma_complete(acdev);
+}
+
+static irqreturn_t arasan_cf_interrupt(int irq, void *dev)
+{
+ struct arasan_cf_dev *acdev = ((struct ata_host *)dev)->private_data;
+ unsigned long flags;
+ u32 irqsts;
+
+ irqsts = readl(acdev->vbase + GIRQ_STS);
+ if (!(irqsts & GIRQ_CF))
+ return IRQ_NONE;
+
+ spin_lock_irqsave(&acdev->host->lock, flags);
+ irqsts = readl(acdev->vbase + IRQ_STS);
+ writel(irqsts, acdev->vbase + IRQ_STS); /* clear irqs */
+ writel(GIRQ_CF, acdev->vbase + GIRQ_STS); /* clear girqs */
+
+ /* handle only relevant interrupts */
+ irqsts &= ~IGNORED_IRQS;
+
+ if (irqsts & CARD_DETECT_IRQ) {
+ cf_card_detect(acdev, 1);
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ if (irqsts & PIO_XFER_ERR_IRQ) {
+ acdev->dma_status = ATA_DMA_ERR;
+ writel(readl(acdev->vbase + XFER_CTR) & ~XFER_START,
+ acdev->vbase + XFER_CTR);
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
+ complete(&acdev->cf_completion);
+ dev_err(acdev->host->dev, "pio xfer err irq\n");
+ return IRQ_HANDLED;
+ }
+
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
+
+ if (irqsts & BUF_AVAIL_IRQ) {
+ complete(&acdev->cf_completion);
+ return IRQ_HANDLED;
+ }
+
+ if (irqsts & XFER_DONE_IRQ) {
+ struct ata_queued_cmd *qc = acdev->qc;
+
+ /* Send Complete only for write */
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ complete(&acdev->cf_completion);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void arasan_cf_freeze(struct ata_port *ap)
+{
+ struct arasan_cf_dev *acdev = ap->host->private_data;
+
+ /* stop transfer and reset controller */
+ writel(readl(acdev->vbase + XFER_CTR) & ~XFER_START,
+ acdev->vbase + XFER_CTR);
+ cf_ctrl_reset(acdev);
+ acdev->dma_status = ATA_DMA_ERR;
+
+ ata_sff_dma_pause(ap);
+ ata_sff_freeze(ap);
+}
+
+static void arasan_cf_error_handler(struct ata_port *ap)
+{
+ struct arasan_cf_dev *acdev = ap->host->private_data;
+
+ /*
+ * DMA transfers using an external DMA controller may be scheduled.
+ * Abort them before handling error. Refer data_xfer() for further
+ * details.
+ */
+ cancel_work_sync(&acdev->work);
+ cancel_delayed_work_sync(&acdev->dwork);
+ return ata_sff_error_handler(ap);
+}
+
+static void arasan_cf_dma_start(struct arasan_cf_dev *acdev)
+{
+ struct ata_queued_cmd *qc = acdev->qc;
+ struct ata_port *ap = qc->ap;
+ struct ata_taskfile *tf = &qc->tf;
+ u32 xfer_ctr = readl(acdev->vbase + XFER_CTR) & ~XFER_DIR_MASK;
+ u32 write = tf->flags & ATA_TFLAG_WRITE;
+
+ xfer_ctr |= write ? XFER_WRITE : XFER_READ;
+ writel(xfer_ctr, acdev->vbase + XFER_CTR);
+
+ ap->ops->sff_exec_command(ap, tf);
+ ata_sff_queue_work(&acdev->work);
+}
+
+static unsigned int arasan_cf_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct arasan_cf_dev *acdev = ap->host->private_data;
+
+ /* defer PIO handling to sff_qc_issue */
+ if (!ata_is_dma(qc->tf.protocol))
+ return ata_sff_qc_issue(qc);
+
+ /* select the device */
+ ata_wait_idle(ap);
+ ata_sff_dev_select(ap, qc->dev->devno);
+ ata_wait_idle(ap);
+
+ /* start the command */
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ WARN_ON_ONCE(qc->tf.flags & ATA_TFLAG_POLLING);
+
+ ap->ops->sff_tf_load(ap, &qc->tf);
+ acdev->dma_status = 0;
+ acdev->qc = qc;
+ arasan_cf_dma_start(acdev);
+ ap->hsm_task_state = HSM_ST_LAST;
+ break;
+
+ default:
+ WARN_ON(1);
+ return AC_ERR_SYSTEM;
+ }
+
+ return 0;
+}
+
+static void arasan_cf_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct arasan_cf_dev *acdev = ap->host->private_data;
+ u8 pio = adev->pio_mode - XFER_PIO_0;
+ unsigned long flags;
+ u32 val;
+
+ /* Arasan ctrl supports Mode0 -> Mode6 */
+ if (pio > 6) {
+ dev_err(ap->dev, "Unknown PIO mode\n");
+ return;
+ }
+
+ spin_lock_irqsave(&acdev->host->lock, flags);
+ val = readl(acdev->vbase + OP_MODE) &
+ ~(ULTRA_DMA_ENB | MULTI_WORD_DMA_ENB | DRQ_BLOCK_SIZE_MASK);
+ writel(val, acdev->vbase + OP_MODE);
+ val = readl(acdev->vbase + TM_CFG) & ~TRUEIDE_PIO_TIMING_MASK;
+ val |= pio << TRUEIDE_PIO_TIMING_SHIFT;
+ writel(val, acdev->vbase + TM_CFG);
+
+ cf_interrupt_enable(acdev, BUF_AVAIL_IRQ | XFER_DONE_IRQ, 0);
+ cf_interrupt_enable(acdev, PIO_XFER_ERR_IRQ, 1);
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
+}
+
+static void arasan_cf_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct arasan_cf_dev *acdev = ap->host->private_data;
+ u32 opmode, tmcfg, dma_mode = adev->dma_mode;
+ unsigned long flags;
+
+ spin_lock_irqsave(&acdev->host->lock, flags);
+ opmode = readl(acdev->vbase + OP_MODE) &
+ ~(MULTI_WORD_DMA_ENB | ULTRA_DMA_ENB);
+ tmcfg = readl(acdev->vbase + TM_CFG);
+
+ if ((dma_mode >= XFER_UDMA_0) && (dma_mode <= XFER_UDMA_6)) {
+ opmode |= ULTRA_DMA_ENB;
+ tmcfg &= ~ULTRA_DMA_TIMING_MASK;
+ tmcfg |= (dma_mode - XFER_UDMA_0) << ULTRA_DMA_TIMING_SHIFT;
+ } else if ((dma_mode >= XFER_MW_DMA_0) && (dma_mode <= XFER_MW_DMA_4)) {
+ opmode |= MULTI_WORD_DMA_ENB;
+ tmcfg &= ~TRUEIDE_MWORD_DMA_TIMING_MASK;
+ tmcfg |= (dma_mode - XFER_MW_DMA_0) <<
+ TRUEIDE_MWORD_DMA_TIMING_SHIFT;
+ } else {
+ dev_err(ap->dev, "Unknown DMA mode\n");
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
+ return;
+ }
+
+ writel(opmode, acdev->vbase + OP_MODE);
+ writel(tmcfg, acdev->vbase + TM_CFG);
+ writel(DMA_XFER_MODE, acdev->vbase + XFER_CTR);
+
+ cf_interrupt_enable(acdev, PIO_XFER_ERR_IRQ, 0);
+ cf_interrupt_enable(acdev, BUF_AVAIL_IRQ | XFER_DONE_IRQ, 1);
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
+}
+
+static struct ata_port_operations arasan_cf_ops = {
+ .inherits = &ata_sff_port_ops,
+ .freeze = arasan_cf_freeze,
+ .error_handler = arasan_cf_error_handler,
+ .qc_issue = arasan_cf_qc_issue,
+ .set_piomode = arasan_cf_set_piomode,
+ .set_dmamode = arasan_cf_set_dmamode,
+};
+
+static int arasan_cf_probe(struct platform_device *pdev)
+{
+ struct arasan_cf_dev *acdev;
+ struct arasan_cf_pdata *pdata = dev_get_platdata(&pdev->dev);
+ struct ata_host *host;
+ struct ata_port *ap;
+ struct resource *res;
+ u32 quirk;
+ irq_handler_t irq_handler = NULL;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
+ DRIVER_NAME)) {
+ dev_warn(&pdev->dev, "Failed to get memory region resource\n");
+ return -ENOENT;
+ }
+
+ acdev = devm_kzalloc(&pdev->dev, sizeof(*acdev), GFP_KERNEL);
+ if (!acdev) {
+ dev_warn(&pdev->dev, "kzalloc fail\n");
+ return -ENOMEM;
+ }
+
+ if (pdata)
+ quirk = pdata->quirk;
+ else
+ quirk = CF_BROKEN_UDMA; /* as it is on spear1340 */
+
+ /* if irq is 0, support only PIO */
+ acdev->irq = platform_get_irq(pdev, 0);
+ if (acdev->irq)
+ irq_handler = arasan_cf_interrupt;
+ else
+ quirk |= CF_BROKEN_MWDMA | CF_BROKEN_UDMA;
+
+ acdev->pbase = res->start;
+ acdev->vbase = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
+ if (!acdev->vbase) {
+ dev_warn(&pdev->dev, "ioremap fail\n");
+ return -ENOMEM;
+ }
+
+ acdev->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(acdev->clk)) {
+ dev_warn(&pdev->dev, "Clock not found\n");
+ return PTR_ERR(acdev->clk);
+ }
+
+ /* allocate host */
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host) {
+ ret = -ENOMEM;
+ dev_warn(&pdev->dev, "alloc host fail\n");
+ goto free_clk;
+ }
+
+ ap = host->ports[0];
+ host->private_data = acdev;
+ acdev->host = host;
+ ap->ops = &arasan_cf_ops;
+ ap->pio_mask = ATA_PIO6;
+ ap->mwdma_mask = ATA_MWDMA4;
+ ap->udma_mask = ATA_UDMA6;
+
+ init_completion(&acdev->cf_completion);
+ init_completion(&acdev->dma_completion);
+ INIT_WORK(&acdev->work, data_xfer);
+ INIT_DELAYED_WORK(&acdev->dwork, delayed_finish);
+ dma_cap_set(DMA_MEMCPY, acdev->mask);
+
+ /* Handle platform specific quirks */
+ if (quirk) {
+ if (quirk & CF_BROKEN_PIO) {
+ ap->ops->set_piomode = NULL;
+ ap->pio_mask = 0;
+ }
+ if (quirk & CF_BROKEN_MWDMA)
+ ap->mwdma_mask = 0;
+ if (quirk & CF_BROKEN_UDMA)
+ ap->udma_mask = 0;
+ }
+ ap->flags |= ATA_FLAG_PIO_POLLING | ATA_FLAG_NO_ATAPI;
+
+ ap->ioaddr.cmd_addr = acdev->vbase + ATA_DATA_PORT;
+ ap->ioaddr.data_addr = acdev->vbase + ATA_DATA_PORT;
+ ap->ioaddr.error_addr = acdev->vbase + ATA_ERR_FTR;
+ ap->ioaddr.feature_addr = acdev->vbase + ATA_ERR_FTR;
+ ap->ioaddr.nsect_addr = acdev->vbase + ATA_SC;
+ ap->ioaddr.lbal_addr = acdev->vbase + ATA_SN;
+ ap->ioaddr.lbam_addr = acdev->vbase + ATA_CL;
+ ap->ioaddr.lbah_addr = acdev->vbase + ATA_CH;
+ ap->ioaddr.device_addr = acdev->vbase + ATA_SH;
+ ap->ioaddr.status_addr = acdev->vbase + ATA_STS_CMD;
+ ap->ioaddr.command_addr = acdev->vbase + ATA_STS_CMD;
+ ap->ioaddr.altstatus_addr = acdev->vbase + ATA_ASTS_DCTR;
+ ap->ioaddr.ctl_addr = acdev->vbase + ATA_ASTS_DCTR;
+
+ ata_port_desc(ap, "phy_addr %llx virt_addr %p",
+ (unsigned long long) res->start, acdev->vbase);
+
+ ret = cf_init(acdev);
+ if (ret)
+ goto free_clk;
+
+ cf_card_detect(acdev, 0);
+
+ ret = ata_host_activate(host, acdev->irq, irq_handler, 0,
+ &arasan_cf_sht);
+ if (!ret)
+ return 0;
+
+ cf_exit(acdev);
+free_clk:
+ clk_put(acdev->clk);
+ return ret;
+}
+
+static int arasan_cf_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct arasan_cf_dev *acdev = host->ports[0]->private_data;
+
+ ata_host_detach(host);
+ cf_exit(acdev);
+ clk_put(acdev->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int arasan_cf_suspend(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct arasan_cf_dev *acdev = host->ports[0]->private_data;
+
+ if (acdev->dma_chan)
+ acdev->dma_chan->device->device_control(acdev->dma_chan,
+ DMA_TERMINATE_ALL, 0);
+
+ cf_exit(acdev);
+ return ata_host_suspend(host, PMSG_SUSPEND);
+}
+
+static int arasan_cf_resume(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct arasan_cf_dev *acdev = host->ports[0]->private_data;
+
+ cf_init(acdev);
+ ata_host_resume(host);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(arasan_cf_pm_ops, arasan_cf_suspend, arasan_cf_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id arasan_cf_id_table[] = {
+ { .compatible = "arasan,cf-spear1340" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, arasan_cf_id_table);
+#endif
+
+static struct platform_driver arasan_cf_driver = {
+ .probe = arasan_cf_probe,
+ .remove = arasan_cf_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &arasan_cf_pm_ops,
+ .of_match_table = of_match_ptr(arasan_cf_id_table),
+ },
+};
+
+module_platform_driver(arasan_cf_driver);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
+MODULE_DESCRIPTION("Arasan ATA Compact Flash driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index 0f513bc1119..96c05c9494f 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -1,8 +1,8 @@
/*
* pata_artop.c - ARTOP ATA controller driver
*
- * (C) 2006 Red Hat <alan@redhat.com>
- * (C) 2007 Bartlomiej Zolnierkiewicz
+ * (C) 2006 Red Hat
+ * (C) 2007,2011 Bartlomiej Zolnierkiewicz
*
* Based in part on drivers/ide/pci/aec62xx.c
* Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
@@ -12,7 +12,6 @@
* performance Alessandro Zummo <alessandro.zummo@towertech.it>
*
* TODO
- * 850 serialization once the core supports it
* Investigate no_dsc on 850R
* Clock detect
*/
@@ -20,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -29,7 +27,7 @@
#include <linux/ata.h>
#define DRV_NAME "pata_artop"
-#define DRV_VERSION "0.4.4"
+#define DRV_VERSION "0.4.6"
/*
* The ARTOP has 33 Mhz and "over clocked" timing tables. Until we
@@ -40,31 +38,15 @@
static int clock = 0;
-static int artop6210_pre_reset(struct ata_link *link, unsigned long deadline)
-{
- struct ata_port *ap = link->ap;
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- const struct pci_bits artop_enable_bits[] = {
- { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
- { 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */
- };
-
- if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
- return -ENOENT;
-
- return ata_sff_prereset(link, deadline);
-}
-
/**
- * artop6260_pre_reset - check for 40/80 pin
+ * artop62x0_pre_reset - probe begin
* @link: link
* @deadline: deadline jiffies for the operation
*
- * The ARTOP hardware reports the cable detect bits in register 0x49.
* Nothing complicated needed here.
*/
-static int artop6260_pre_reset(struct ata_link *link, unsigned long deadline)
+static int artop62x0_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits artop_enable_bits[] = {
{ 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
@@ -74,8 +56,9 @@ static int artop6260_pre_reset(struct ata_link *link, unsigned long deadline)
struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- /* Odd numbered device ids are the units with enable bits (the -R cards) */
- if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
+ /* Odd numbered device ids are the units with enable bits. */
+ if ((pdev->device & 1) &&
+ !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
return -ENOENT;
return ata_sff_prereset(link, deadline);
@@ -283,6 +266,31 @@ static void artop6260_set_dmamode (struct ata_port *ap, struct ata_device *adev)
pci_write_config_byte(pdev, 0x44 + ap->port_no, ultra);
}
+/**
+ * artop_6210_qc_defer - implement serialization
+ * @qc: command
+ *
+ * Issue commands per host on this chip.
+ */
+
+static int artop6210_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_host *host = qc->ap->host;
+ struct ata_port *alt = host->ports[1 ^ qc->ap->port_no];
+ int rc;
+
+ /* First apply the usual rules */
+ rc = ata_std_qc_defer(qc);
+ if (rc != 0)
+ return rc;
+
+ /* Now apply serialization rules. Only allow a command if the
+ other channel state machine is idle */
+ if (alt && alt->qc_active)
+ return ATA_DEFER_PORT;
+ return 0;
+}
+
static struct scsi_host_template artop_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
@@ -292,7 +300,8 @@ static struct ata_port_operations artop6210_ops = {
.cable_detect = ata_cable_40wire,
.set_piomode = artop6210_set_piomode,
.set_dmamode = artop6210_set_dmamode,
- .prereset = artop6210_pre_reset,
+ .prereset = artop62x0_pre_reset,
+ .qc_defer = artop6210_qc_defer,
};
static struct ata_port_operations artop6260_ops = {
@@ -300,9 +309,36 @@ static struct ata_port_operations artop6260_ops = {
.cable_detect = artop6260_cable_detect,
.set_piomode = artop6260_set_piomode,
.set_dmamode = artop6260_set_dmamode,
- .prereset = artop6260_pre_reset,
+ .prereset = artop62x0_pre_reset,
};
+static void atp8xx_fixup(struct pci_dev *pdev)
+{
+ if (pdev->device == 0x0005)
+ /* BIOS may have left us in UDMA, clear it before libata probe */
+ pci_write_config_byte(pdev, 0x54, 0);
+ else if (pdev->device == 0x0008 || pdev->device == 0x0009) {
+ u8 reg;
+
+ /* Mac systems come up with some registers not set as we
+ will need them */
+
+ /* Clear reset & test bits */
+ pci_read_config_byte(pdev, 0x49, &reg);
+ pci_write_config_byte(pdev, 0x49, reg & ~0x30);
+
+ /* PCI latency must be > 0x80 for burst mode, tweak it
+ * if required.
+ */
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &reg);
+ if (reg <= 0x80)
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x90);
+
+ /* Enable IRQ output and burst mode */
+ pci_read_config_byte(pdev, 0x4a, &reg);
+ pci_write_config_byte(pdev, 0x4a, (reg & ~0x01) | 0x80);
+ }
+}
/**
* artop_init_one - Register ARTOP ATA PCI device with kernel services
@@ -320,87 +356,60 @@ static struct ata_port_operations artop6260_ops = {
static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
{
- static int printed_version;
static const struct ata_port_info info_6210 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA2,
.port_ops = &artop6210_ops,
};
static const struct ata_port_info info_626x = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA4,
.port_ops = &artop6260_ops,
};
static const struct ata_port_info info_628x = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &artop6260_ops,
};
static const struct ata_port_info info_628x_fast = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &artop6260_ops,
};
const struct ata_port_info *ppi[] = { NULL, NULL };
int rc;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev,
- "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- if (id->driver_data == 0) { /* 6210 variant */
+ if (id->driver_data == 0) /* 6210 variant */
ppi[0] = &info_6210;
- ppi[1] = &ata_dummy_port_info;
- /* BIOS may have left us in UDMA, clear it before libata probe */
- pci_write_config_byte(pdev, 0x54, 0);
- /* For the moment (also lacks dsc) */
- printk(KERN_WARNING "ARTOP 6210 requires serialize functionality not yet supported by libata.\n");
- printk(KERN_WARNING "Secondary ATA ports will not be activated.\n");
- }
else if (id->driver_data == 1) /* 6260 */
ppi[0] = &info_626x;
else if (id->driver_data == 2) { /* 6280 or 6280 + fast */
unsigned long io = pci_resource_start(pdev, 4);
- u8 reg;
ppi[0] = &info_628x;
if (inb(io) & 0x10)
ppi[0] = &info_628x_fast;
- /* Mac systems come up with some registers not set as we
- will need them */
-
- /* Clear reset & test bits */
- pci_read_config_byte(pdev, 0x49, &reg);
- pci_write_config_byte(pdev, 0x49, reg & ~ 0x30);
-
- /* PCI latency must be > 0x80 for burst mode, tweak it
- * if required.
- */
- pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &reg);
- if (reg <= 0x80)
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x90);
-
- /* Enable IRQ output and burst mode */
- pci_read_config_byte(pdev, 0x4a, &reg);
- pci_write_config_byte(pdev, 0x4a, (reg & ~0x01) | 0x80);
-
}
BUG_ON(ppi[0] == NULL);
- return ata_pci_sff_init_one(pdev, ppi, &artop_sht, NULL);
+ atp8xx_fixup(pdev);
+
+ return ata_pci_bmdma_init_one(pdev, ppi, &artop_sht, NULL, 0);
}
static const struct pci_device_id artop_pci_tbl[] = {
@@ -413,29 +422,38 @@ static const struct pci_device_id artop_pci_tbl[] = {
{ } /* terminate list */
};
+#ifdef CONFIG_PM_SLEEP
+static int atp8xx_reinit_one(struct pci_dev *pdev)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ atp8xx_fixup(pdev);
+
+ ata_host_resume(host);
+ return 0;
+}
+#endif
+
static struct pci_driver artop_pci_driver = {
.name = DRV_NAME,
.id_table = artop_pci_tbl,
.probe = artop_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = ata_pci_device_suspend,
+ .resume = atp8xx_reinit_one,
+#endif
};
-static int __init artop_init(void)
-{
- return pci_register_driver(&artop_pci_driver);
-}
-
-static void __exit artop_exit(void)
-{
- pci_unregister_driver(&artop_pci_driver);
-}
+module_pci_driver(artop_pci_driver);
-module_init(artop_init);
-module_exit(artop_exit);
-
-MODULE_AUTHOR("Alan Cox");
+MODULE_AUTHOR("Alan Cox, Bartlomiej Zolnierkiewicz");
MODULE_DESCRIPTION("SCSI low-level driver for ARTOP PATA");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, artop_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c
index 3e8651d7895..d59d5239405 100644
--- a/drivers/ata/pata_at32.c
+++ b/drivers/ata/pata_at32.c
@@ -18,14 +18,15 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/slab.h>
#include <scsi/scsi_host.h>
#include <linux/ata.h>
#include <linux/libata.h>
#include <linux/err.h>
#include <linux/io.h>
-#include <asm/arch/board.h>
-#include <asm/arch/smc.h>
+#include <mach/board.h>
+#include <mach/smc.h>
#define DRV_NAME "pata_at32"
#define DRV_VERSION "0.0.3"
@@ -67,7 +68,9 @@
*
* Alter PIO_MASK below according to table to set maximal PIO mode.
*/
-#define PIO_MASK (0x1f)
+enum {
+ PIO_MASK = ATA_PIO4,
+};
/*
* Struct containing private information about device.
@@ -191,7 +194,7 @@ static int __init pata_at32_init_one(struct device *dev,
/* Setup ATA bindings */
ap->ops = &at32_port_ops;
ap->pio_mask = PIO_MASK;
- ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
/*
* Since all 8-bit taskfile transfers has to go on the lower
@@ -268,7 +271,7 @@ static int __init pata_at32_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct at32_ide_info *info;
- struct ide_platform_data *board = pdev->dev.platform_data;
+ struct ide_platform_data *board = dev_get_platdata(&pdev->dev);
struct resource *res;
int irq;
@@ -291,8 +294,6 @@ static int __init pata_at32_probe(struct platform_device *pdev)
if (!info)
return -ENOMEM;
- memset(info, 0, sizeof(struct at32_ide_info));
-
info->irq = irq;
info->cs = board->cs;
@@ -381,6 +382,9 @@ static int __exit pata_at32_remove(struct platform_device *pdev)
return 0;
}
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:at32_ide");
+
static struct platform_driver pata_at32_driver = {
.remove = __exit_p(pata_at32_remove),
.driver = {
@@ -389,18 +393,7 @@ static struct platform_driver pata_at32_driver = {
},
};
-static int __init pata_at32_init(void)
-{
- return platform_driver_probe(&pata_at32_driver, pata_at32_probe);
-}
-
-static void __exit pata_at32_exit(void)
-{
- platform_driver_unregister(&pata_at32_driver);
-}
-
-module_init(pata_at32_init);
-module_exit(pata_at32_exit);
+module_platform_driver_probe(pata_at32_driver, pata_at32_probe);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("AVR32 SMC/CFC PATA Driver");
diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c
new file mode 100644
index 00000000000..8a66f23af4c
--- /dev/null
+++ b/drivers/ata/pata_at91.c
@@ -0,0 +1,457 @@
+/*
+ * PATA driver for AT91SAM9260 Static Memory Controller
+ * with CompactFlash interface in True IDE mode
+ *
+ * Copyright (C) 2009 Matyukevich Sergey
+ * 2011 Igor Plyatov
+ *
+ * Based on:
+ * * generic platform driver by Paul Mundt: drivers/ata/pata_platform.c
+ * * pata_at32 driver by Kristoffer Nyborg Gregertsen
+ * * at91_ide driver by Stanislaw Gruszka
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/gfp.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/clk.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+#include <linux/platform_data/atmel.h>
+
+#include <mach/at91sam9_smc.h>
+#include <asm/gpio.h>
+
+#define DRV_NAME "pata_at91"
+#define DRV_VERSION "0.3"
+
+#define CF_IDE_OFFSET 0x00c00000
+#define CF_ALT_IDE_OFFSET 0x00e00000
+#define CF_IDE_RES_SIZE 0x08
+#define CS_PULSE_MAXIMUM 319
+#define ER_SMC_CALC 1
+#define ER_SMC_RECALC 2
+
+struct at91_ide_info {
+ unsigned long mode;
+ unsigned int cs;
+ struct clk *mck;
+ void __iomem *ide_addr;
+ void __iomem *alt_addr;
+};
+
+/**
+ * struct smc_range - range of valid values for SMC register.
+ */
+struct smc_range {
+ int min;
+ int max;
+};
+
+/**
+ * adjust_smc_value - adjust value for one of SMC registers.
+ * @value: adjusted value
+ * @range: array of SMC ranges with valid values
+ * @size: SMC ranges array size
+ *
+ * This returns the difference between input and output value or negative
+ * in case of invalid input value.
+ * If negative returned, then output value = maximal possible from ranges.
+ */
+static int adjust_smc_value(int *value, struct smc_range *range, int size)
+{
+ int maximum = (range + size - 1)->max;
+ int remainder;
+
+ do {
+ if (*value < range->min) {
+ remainder = range->min - *value;
+ *value = range->min; /* nearest valid value */
+ return remainder;
+ } else if ((range->min <= *value) && (*value <= range->max))
+ return 0;
+
+ range++;
+ } while (--size);
+ *value = maximum;
+
+ return -1; /* invalid value */
+}
+
+/**
+ * calc_smc_vals - calculate SMC register values
+ * @dev: ATA device
+ * @setup: SMC_SETUP register value
+ * @pulse: SMC_PULSE register value
+ * @cycle: SMC_CYCLE register value
+ *
+ * This returns negative in case of invalid values for SMC registers:
+ * -ER_SMC_RECALC - recalculation required for SMC values,
+ * -ER_SMC_CALC - calculation failed (invalid input values).
+ *
+ * SMC use special coding scheme, see "Coding and Range of Timing
+ * Parameters" table from AT91SAM9 datasheets.
+ *
+ * SMC_SETUP = 128*setup[5] + setup[4:0]
+ * SMC_PULSE = 256*pulse[6] + pulse[5:0]
+ * SMC_CYCLE = 256*cycle[8:7] + cycle[6:0]
+ */
+static int calc_smc_vals(struct device *dev,
+ int *setup, int *pulse, int *cycle, int *cs_pulse)
+{
+ int ret_val;
+ int err = 0;
+ struct smc_range range_setup[] = { /* SMC_SETUP valid values */
+ {.min = 0, .max = 31}, /* first range */
+ {.min = 128, .max = 159} /* second range */
+ };
+ struct smc_range range_pulse[] = { /* SMC_PULSE valid values */
+ {.min = 0, .max = 63}, /* first range */
+ {.min = 256, .max = 319} /* second range */
+ };
+ struct smc_range range_cycle[] = { /* SMC_CYCLE valid values */
+ {.min = 0, .max = 127}, /* first range */
+ {.min = 256, .max = 383}, /* second range */
+ {.min = 512, .max = 639}, /* third range */
+ {.min = 768, .max = 895} /* fourth range */
+ };
+
+ ret_val = adjust_smc_value(setup, range_setup, ARRAY_SIZE(range_setup));
+ if (ret_val < 0)
+ dev_warn(dev, "maximal SMC Setup value\n");
+ else
+ *cycle += ret_val;
+
+ ret_val = adjust_smc_value(pulse, range_pulse, ARRAY_SIZE(range_pulse));
+ if (ret_val < 0)
+ dev_warn(dev, "maximal SMC Pulse value\n");
+ else
+ *cycle += ret_val;
+
+ ret_val = adjust_smc_value(cycle, range_cycle, ARRAY_SIZE(range_cycle));
+ if (ret_val < 0)
+ dev_warn(dev, "maximal SMC Cycle value\n");
+
+ *cs_pulse = *cycle;
+ if (*cs_pulse > CS_PULSE_MAXIMUM) {
+ dev_err(dev, "unable to calculate valid SMC settings\n");
+ return -ER_SMC_CALC;
+ }
+
+ ret_val = adjust_smc_value(cs_pulse, range_pulse,
+ ARRAY_SIZE(range_pulse));
+ if (ret_val < 0) {
+ dev_warn(dev, "maximal SMC CS Pulse value\n");
+ } else if (ret_val != 0) {
+ *cycle = *cs_pulse;
+ dev_warn(dev, "SMC Cycle extended\n");
+ err = -ER_SMC_RECALC;
+ }
+
+ return err;
+}
+
+/**
+ * to_smc_format - convert values into SMC format
+ * @setup: SETUP value of SMC Setup Register
+ * @pulse: PULSE value of SMC Pulse Register
+ * @cycle: CYCLE value of SMC Cycle Register
+ * @cs_pulse: NCS_PULSE value of SMC Pulse Register
+ */
+static void to_smc_format(int *setup, int *pulse, int *cycle, int *cs_pulse)
+{
+ *setup = (*setup & 0x1f) | ((*setup & 0x80) >> 2);
+ *pulse = (*pulse & 0x3f) | ((*pulse & 0x100) >> 2);
+ *cycle = (*cycle & 0x7f) | ((*cycle & 0x300) >> 1);
+ *cs_pulse = (*cs_pulse & 0x3f) | ((*cs_pulse & 0x100) >> 2);
+}
+
+static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz)
+{
+ unsigned long mul;
+
+ /*
+ * cycles = x [nsec] * f [Hz] / 10^9 [ns in sec] =
+ * x * (f / 1_000_000_000) =
+ * x * ((f * 65536) / 1_000_000_000) / 65536 =
+ * x * (((f / 10_000) * 65536) / 100_000) / 65536 =
+ */
+
+ mul = (mck_hz / 10000) << 16;
+ mul /= 100000;
+
+ return (ns * mul + 65536) >> 16; /* rounding */
+}
+
+/**
+ * set_smc_timing - SMC timings setup.
+ * @dev: device
+ * @info: AT91 IDE info
+ * @ata: ATA timings
+ *
+ * Its assumed that write timings are same as read timings,
+ * cs_setup = 0 and cs_pulse = cycle.
+ */
+static void set_smc_timing(struct device *dev, struct ata_device *adev,
+ struct at91_ide_info *info, const struct ata_timing *ata)
+{
+ int ret = 0;
+ int use_iordy;
+ struct sam9_smc_config smc;
+ unsigned int t6z; /* data tristate time in ns */
+ unsigned int cycle; /* SMC Cycle width in MCK ticks */
+ unsigned int setup; /* SMC Setup width in MCK ticks */
+ unsigned int pulse; /* CFIOR and CFIOW pulse width in MCK ticks */
+ unsigned int cs_pulse; /* CS4 or CS5 pulse width in MCK ticks*/
+ unsigned int tdf_cycles; /* SMC TDF MCK ticks */
+ unsigned long mck_hz; /* MCK frequency in Hz */
+
+ t6z = (ata->mode < XFER_PIO_5) ? 30 : 20;
+ mck_hz = clk_get_rate(info->mck);
+ cycle = calc_mck_cycles(ata->cyc8b, mck_hz);
+ setup = calc_mck_cycles(ata->setup, mck_hz);
+ pulse = calc_mck_cycles(ata->act8b, mck_hz);
+ tdf_cycles = calc_mck_cycles(t6z, mck_hz);
+
+ do {
+ ret = calc_smc_vals(dev, &setup, &pulse, &cycle, &cs_pulse);
+ } while (ret == -ER_SMC_RECALC);
+
+ if (ret == -ER_SMC_CALC)
+ dev_err(dev, "Interface may not operate correctly\n");
+
+ dev_dbg(dev, "SMC Setup=%u, Pulse=%u, Cycle=%u, CS Pulse=%u\n",
+ setup, pulse, cycle, cs_pulse);
+ to_smc_format(&setup, &pulse, &cycle, &cs_pulse);
+ /* disable or enable waiting for IORDY signal */
+ use_iordy = ata_pio_need_iordy(adev);
+ if (use_iordy)
+ info->mode |= AT91_SMC_EXNWMODE_READY;
+
+ if (tdf_cycles > 15) {
+ tdf_cycles = 15;
+ dev_warn(dev, "maximal SMC TDF Cycles value\n");
+ }
+
+ dev_dbg(dev, "Use IORDY=%u, TDF Cycles=%u\n", use_iordy, tdf_cycles);
+
+ /* SMC Setup Register */
+ smc.nwe_setup = smc.nrd_setup = setup;
+ smc.ncs_write_setup = smc.ncs_read_setup = 0;
+ /* SMC Pulse Register */
+ smc.nwe_pulse = smc.nrd_pulse = pulse;
+ smc.ncs_write_pulse = smc.ncs_read_pulse = cs_pulse;
+ /* SMC Cycle Register */
+ smc.write_cycle = smc.read_cycle = cycle;
+ /* SMC Mode Register*/
+ smc.tdf_cycles = tdf_cycles;
+ smc.mode = info->mode;
+
+ sam9_smc_configure(0, info->cs, &smc);
+}
+
+static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct at91_ide_info *info = ap->host->private_data;
+ struct ata_timing timing;
+ int ret;
+
+ /* Compute ATA timing and set it to SMC */
+ ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0);
+ if (ret) {
+ dev_warn(ap->dev, "Failed to compute ATA timing %d, "
+ "set PIO_0 timing\n", ret);
+ timing = *ata_timing_find_mode(XFER_PIO_0);
+ }
+ set_smc_timing(ap->dev, adev, info, &timing);
+}
+
+static unsigned int pata_at91_data_xfer_noirq(struct ata_device *dev,
+ unsigned char *buf, unsigned int buflen, int rw)
+{
+ struct at91_ide_info *info = dev->link->ap->host->private_data;
+ unsigned int consumed;
+ unsigned long flags;
+ struct sam9_smc_config smc;
+
+ local_irq_save(flags);
+ sam9_smc_read_mode(0, info->cs, &smc);
+
+ /* set 16bit mode before writing data */
+ smc.mode = (smc.mode & ~AT91_SMC_DBW) | AT91_SMC_DBW_16;
+ sam9_smc_write_mode(0, info->cs, &smc);
+
+ consumed = ata_sff_data_xfer(dev, buf, buflen, rw);
+
+ /* restore 8bit mode after data is written */
+ smc.mode = (smc.mode & ~AT91_SMC_DBW) | AT91_SMC_DBW_8;
+ sam9_smc_write_mode(0, info->cs, &smc);
+
+ local_irq_restore(flags);
+ return consumed;
+}
+
+static struct scsi_host_template pata_at91_sht = {
+ ATA_PIO_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations pata_at91_port_ops = {
+ .inherits = &ata_sff_port_ops,
+
+ .sff_data_xfer = pata_at91_data_xfer_noirq,
+ .set_piomode = pata_at91_set_piomode,
+ .cable_detect = ata_cable_40wire,
+};
+
+static int pata_at91_probe(struct platform_device *pdev)
+{
+ struct at91_cf_data *board = dev_get_platdata(&pdev->dev);
+ struct device *dev = &pdev->dev;
+ struct at91_ide_info *info;
+ struct resource *mem_res;
+ struct ata_host *host;
+ struct ata_port *ap;
+
+ int irq_flags = 0;
+ int irq = 0;
+ int ret;
+
+ /* get platform resources: IO/CTL memories and irq/rst pins */
+
+ if (pdev->num_resources != 1) {
+ dev_err(&pdev->dev, "invalid number of resources\n");
+ return -EINVAL;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!mem_res) {
+ dev_err(dev, "failed to get mem resource\n");
+ return -EINVAL;
+ }
+
+ irq = board->irq_pin;
+
+ /* init ata host */
+
+ host = ata_host_alloc(dev, 1);
+
+ if (!host)
+ return -ENOMEM;
+
+ ap = host->ports[0];
+ ap->ops = &pata_at91_port_ops;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
+ ap->pio_mask = ATA_PIO4;
+
+ if (!gpio_is_valid(irq)) {
+ ap->flags |= ATA_FLAG_PIO_POLLING;
+ ata_port_desc(ap, "no IRQ, using PIO polling");
+ }
+
+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+
+ if (!info) {
+ dev_err(dev, "failed to allocate memory for private data\n");
+ return -ENOMEM;
+ }
+
+ info->mck = clk_get(NULL, "mck");
+
+ if (IS_ERR(info->mck)) {
+ dev_err(dev, "failed to get access to mck clock\n");
+ return -ENODEV;
+ }
+
+ info->cs = board->chipselect;
+ info->mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE |
+ AT91_SMC_EXNWMODE_READY | AT91_SMC_BAT_SELECT |
+ AT91_SMC_DBW_8 | AT91_SMC_TDF_(0);
+
+ info->ide_addr = devm_ioremap(dev,
+ mem_res->start + CF_IDE_OFFSET, CF_IDE_RES_SIZE);
+
+ if (!info->ide_addr) {
+ dev_err(dev, "failed to map IO base\n");
+ ret = -ENOMEM;
+ goto err_put;
+ }
+
+ info->alt_addr = devm_ioremap(dev,
+ mem_res->start + CF_ALT_IDE_OFFSET, CF_IDE_RES_SIZE);
+
+ if (!info->alt_addr) {
+ dev_err(dev, "failed to map CTL base\n");
+ ret = -ENOMEM;
+ goto err_put;
+ }
+
+ ap->ioaddr.cmd_addr = info->ide_addr;
+ ap->ioaddr.ctl_addr = info->alt_addr + 0x06;
+ ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
+
+ ata_sff_std_ports(&ap->ioaddr);
+
+ ata_port_desc(ap, "mmio cmd 0x%llx ctl 0x%llx",
+ (unsigned long long)mem_res->start + CF_IDE_OFFSET,
+ (unsigned long long)mem_res->start + CF_ALT_IDE_OFFSET);
+
+ host->private_data = info;
+
+ ret = ata_host_activate(host, gpio_is_valid(irq) ? gpio_to_irq(irq) : 0,
+ gpio_is_valid(irq) ? ata_sff_interrupt : NULL,
+ irq_flags, &pata_at91_sht);
+ if (ret)
+ goto err_put;
+
+ return 0;
+
+err_put:
+ clk_put(info->mck);
+ return ret;
+}
+
+static int pata_at91_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct at91_ide_info *info;
+
+ if (!host)
+ return 0;
+ info = host->private_data;
+
+ ata_host_detach(host);
+
+ if (!info)
+ return 0;
+
+ clk_put(info->mck);
+
+ return 0;
+}
+
+static struct platform_driver pata_at91_driver = {
+ .probe = pata_at91_probe,
+ .remove = pata_at91_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(pata_at91_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for CF in True IDE mode on AT91SAM9260 SoC");
+MODULE_AUTHOR("Matyukevich Sergey");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 78738fb4223..970f7767e5f 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -1,7 +1,7 @@
/*
* pata_atiixp.c - ATI PATA for new ATA layer
* (C) 2005 Red Hat Inc
- * Alan Cox <alan@redhat.com>
+ * (C) 2009-2010 Bartlomiej Zolnierkiewicz
*
* Based on
*
@@ -15,11 +15,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
+#include <linux/dmi.h>
#define DRV_NAME "pata_atiixp"
#define DRV_VERSION "0.4.6"
@@ -33,26 +33,26 @@ enum {
ATIIXP_IDE_UDMA_MODE = 0x56
};
-static int atiixp_pre_reset(struct ata_link *link, unsigned long deadline)
-{
- struct ata_port *ap = link->ap;
- static const struct pci_bits atiixp_enable_bits[] = {
- { 0x48, 1, 0x01, 0x00 },
- { 0x48, 1, 0x08, 0x00 }
- };
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-
- if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
- return -ENOENT;
-
- return ata_sff_prereset(link, deadline);
-}
+static const struct dmi_system_id attixp_cable_override_dmi_table[] = {
+ {
+ /* Board has onboard PATA<->SATA converters */
+ .ident = "MSI E350DM-E33",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
+ DMI_MATCH(DMI_BOARD_NAME, "E350DM-E33(MS-7720)"),
+ },
+ },
+ { }
+};
static int atiixp_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 udma;
+ if (dmi_check_system(attixp_cable_override_dmi_table))
+ return ATA_CBL_PATA40_SHORT;
+
/* Hack from drivers/ide/pci. Really we want to know how to do the
raw detection not play follow the bios mode guess */
pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma);
@@ -61,6 +61,33 @@ static int atiixp_cable_detect(struct ata_port *ap)
return ATA_CBL_PATA40;
}
+static DEFINE_SPINLOCK(atiixp_lock);
+
+/**
+ * atiixp_prereset - perform reset handling
+ * @link: ATA link
+ * @deadline: deadline jiffies for the operation
+ *
+ * Reset sequence checking enable bits to see which ports are
+ * active.
+ */
+
+static int atiixp_prereset(struct ata_link *link, unsigned long deadline)
+{
+ static const struct pci_bits atiixp_enable_bits[] = {
+ { 0x48, 1, 0x01, 0x00 },
+ { 0x48, 1, 0x08, 0x00 }
+ };
+
+ struct ata_port *ap = link->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ return ata_sff_prereset(link, deadline);
+}
+
/**
* atiixp_set_pio_timing - set initial PIO mode data
* @ap: ATA interface
@@ -77,20 +104,19 @@ static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev,
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
int dn = 2 * ap->port_no + adev->devno;
-
- /* Check this is correct - the order is odd in both drivers */
int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1);
- u16 pio_mode_data, pio_timing_data;
+ u32 pio_timing_data;
+ u16 pio_mode_data;
pci_read_config_word(pdev, ATIIXP_IDE_PIO_MODE, &pio_mode_data);
pio_mode_data &= ~(0x7 << (4 * dn));
pio_mode_data |= pio << (4 * dn);
pci_write_config_word(pdev, ATIIXP_IDE_PIO_MODE, pio_mode_data);
- pci_read_config_word(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
- pio_mode_data &= ~(0xFF << timing_shift);
- pio_mode_data |= (pio_timings[pio] << timing_shift);
- pci_write_config_word(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
+ pci_read_config_dword(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
+ pio_timing_data &= ~(0xFF << timing_shift);
+ pio_timing_data |= (pio_timings[pio] << timing_shift);
+ pci_write_config_dword(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
}
/**
@@ -104,7 +130,10 @@ static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev,
static void atiixp_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
+ unsigned long flags;
+ spin_lock_irqsave(&atiixp_lock, flags);
atiixp_set_pio_timing(ap, adev, adev->pio_mode - XFER_PIO_0);
+ spin_unlock_irqrestore(&atiixp_lock, flags);
}
/**
@@ -124,6 +153,9 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
int dma = adev->dma_mode;
int dn = 2 * ap->port_no + adev->devno;
int wanted_pio;
+ unsigned long flags;
+
+ spin_lock_irqsave(&atiixp_lock, flags);
if (adev->dma_mode >= XFER_UDMA_0) {
u16 udma_mode_data;
@@ -135,16 +167,17 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
udma_mode_data |= dma << (4 * dn);
pci_write_config_word(pdev, ATIIXP_IDE_UDMA_MODE, udma_mode_data);
} else {
- u16 mwdma_timing_data;
- /* Check this is correct - the order is odd in both drivers */
int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1);
+ u32 mwdma_timing_data;
dma -= XFER_MW_DMA_0;
- pci_read_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, &mwdma_timing_data);
+ pci_read_config_dword(pdev, ATIIXP_IDE_MWDMA_TIMING,
+ &mwdma_timing_data);
mwdma_timing_data &= ~(0xFF << timing_shift);
mwdma_timing_data |= (mwdma_timings[dma] << timing_shift);
- pci_write_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, mwdma_timing_data);
+ pci_write_config_dword(pdev, ATIIXP_IDE_MWDMA_TIMING,
+ mwdma_timing_data);
}
/*
* We must now look at the PIO mode situation. We may need to
@@ -160,6 +193,7 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
if (adev->pio_mode != wanted_pio)
atiixp_set_pio_timing(ap, adev, wanted_pio);
+ spin_unlock_irqrestore(&atiixp_lock, flags);
}
/**
@@ -183,7 +217,7 @@ static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
u16 tmp16;
pci_read_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
- if (adev->dma_mode >= XFER_UDMA_0)
+ if (ata_using_udma(adev))
tmp16 |= (1 << dn);
else
tmp16 &= ~(1 << dn);
@@ -223,27 +257,29 @@ static struct scsi_host_template atiixp_sht = {
static struct ata_port_operations atiixp_port_ops = {
.inherits = &ata_bmdma_port_ops,
- .qc_prep = ata_sff_dumb_qc_prep,
+ .qc_prep = ata_bmdma_dumb_qc_prep,
.bmdma_start = atiixp_bmdma_start,
.bmdma_stop = atiixp_bmdma_stop,
+ .prereset = atiixp_prereset,
.cable_detect = atiixp_cable_detect,
.set_piomode = atiixp_set_piomode,
.set_dmamode = atiixp_set_dmamode,
- .prereset = atiixp_pre_reset,
};
-static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int atiixp_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x06, /* No MWDMA0 support */
- .udma_mask = 0x3F,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA12_ONLY,
+ .udma_mask = ATA_UDMA5,
.port_ops = &atiixp_port_ops
};
- const struct ata_port_info *ppi[] = { &info, NULL };
- return ata_pci_sff_init_one(dev, ppi, &atiixp_sht, NULL);
+ const struct ata_port_info *ppi[] = { &info, &info };
+
+ return ata_pci_bmdma_init_one(pdev, ppi, &atiixp_sht, NULL,
+ ATA_HOST_PARALLEL_SCAN);
}
static const struct pci_device_id atiixp[] = {
@@ -252,6 +288,7 @@ static const struct pci_device_id atiixp[] = {
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_HUDSON2_IDE), },
{ },
};
@@ -261,28 +298,16 @@ static struct pci_driver atiixp_pci_driver = {
.id_table = atiixp,
.probe = atiixp_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.resume = ata_pci_device_resume,
.suspend = ata_pci_device_suspend,
#endif
};
-static int __init atiixp_init(void)
-{
- return pci_register_driver(&atiixp_pci_driver);
-}
-
-
-static void __exit atiixp_exit(void)
-{
- pci_unregister_driver(&atiixp_pci_driver);
-}
+module_pci_driver(atiixp_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for ATI IXP200/300/400");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, atiixp);
MODULE_VERSION(DRV_VERSION);
-
-module_init(atiixp_init);
-module_exit(atiixp_exit);
diff --git a/drivers/ata/pata_atp867x.c b/drivers/ata/pata_atp867x.c
new file mode 100644
index 00000000000..a705cfca90f
--- /dev/null
+++ b/drivers/ata/pata_atp867x.c
@@ -0,0 +1,573 @@
+/*
+ * pata_atp867x.c - ARTOP 867X 64bit 4-channel UDMA133 ATA controller driver
+ *
+ * (C) 2009 Google Inc. John(Jung-Ik) Lee <jilee@google.com>
+ *
+ * Per Atp867 data sheet rev 1.2, Acard.
+ * Based in part on early ide code from
+ * 2003-2004 by Eric Uhrhane, Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * TODO:
+ * 1. RAID features [comparison, XOR, striping, mirroring, etc.]
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gfp.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_atp867x"
+#define DRV_VERSION "0.7.5"
+
+/*
+ * IO Registers
+ * Note that all runtime hot priv ports are cached in ap private_data
+ */
+
+enum {
+ ATP867X_IO_CHANNEL_OFFSET = 0x10,
+
+ /*
+ * IO Register Bitfields
+ */
+
+ ATP867X_IO_PIOSPD_ACTIVE_SHIFT = 4,
+ ATP867X_IO_PIOSPD_RECOVER_SHIFT = 0,
+
+ ATP867X_IO_DMAMODE_MSTR_SHIFT = 0,
+ ATP867X_IO_DMAMODE_MSTR_MASK = 0x07,
+ ATP867X_IO_DMAMODE_SLAVE_SHIFT = 4,
+ ATP867X_IO_DMAMODE_SLAVE_MASK = 0x70,
+
+ ATP867X_IO_DMAMODE_UDMA_6 = 0x07,
+ ATP867X_IO_DMAMODE_UDMA_5 = 0x06,
+ ATP867X_IO_DMAMODE_UDMA_4 = 0x05,
+ ATP867X_IO_DMAMODE_UDMA_3 = 0x04,
+ ATP867X_IO_DMAMODE_UDMA_2 = 0x03,
+ ATP867X_IO_DMAMODE_UDMA_1 = 0x02,
+ ATP867X_IO_DMAMODE_UDMA_0 = 0x01,
+ ATP867X_IO_DMAMODE_DISABLE = 0x00,
+
+ ATP867X_IO_SYS_INFO_66MHZ = 0x04,
+ ATP867X_IO_SYS_INFO_SLOW_UDMA5 = 0x02,
+ ATP867X_IO_SYS_MASK_RESERVED = (~0xf1),
+
+ ATP867X_IO_PORTSPD_VAL = 0x1143,
+ ATP867X_PREREAD_VAL = 0x0200,
+
+ ATP867X_NUM_PORTS = 4,
+ ATP867X_BAR_IOBASE = 0,
+ ATP867X_BAR_ROMBASE = 6,
+};
+
+#define ATP867X_IOBASE(ap) ((ap)->host->iomap[0])
+#define ATP867X_SYS_INFO(ap) (0x3F + ATP867X_IOBASE(ap))
+
+#define ATP867X_IO_PORTBASE(ap, port) (0x00 + ATP867X_IOBASE(ap) + \
+ (port) * ATP867X_IO_CHANNEL_OFFSET)
+#define ATP867X_IO_DMABASE(ap, port) (0x40 + \
+ ATP867X_IO_PORTBASE((ap), (port)))
+
+#define ATP867X_IO_STATUS(ap, port) (0x07 + \
+ ATP867X_IO_PORTBASE((ap), (port)))
+#define ATP867X_IO_ALTSTATUS(ap, port) (0x0E + \
+ ATP867X_IO_PORTBASE((ap), (port)))
+
+/*
+ * hot priv ports
+ */
+#define ATP867X_IO_MSTRPIOSPD(ap, port) (0x08 + \
+ ATP867X_IO_DMABASE((ap), (port)))
+#define ATP867X_IO_SLAVPIOSPD(ap, port) (0x09 + \
+ ATP867X_IO_DMABASE((ap), (port)))
+#define ATP867X_IO_8BPIOSPD(ap, port) (0x0A + \
+ ATP867X_IO_DMABASE((ap), (port)))
+#define ATP867X_IO_DMAMODE(ap, port) (0x0B + \
+ ATP867X_IO_DMABASE((ap), (port)))
+
+#define ATP867X_IO_PORTSPD(ap, port) (0x4A + \
+ ATP867X_IO_PORTBASE((ap), (port)))
+#define ATP867X_IO_PREREAD(ap, port) (0x4C + \
+ ATP867X_IO_PORTBASE((ap), (port)))
+
+struct atp867x_priv {
+ void __iomem *dma_mode;
+ void __iomem *mstr_piospd;
+ void __iomem *slave_piospd;
+ void __iomem *eightb_piospd;
+ int pci66mhz;
+};
+
+static void atp867x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct atp867x_priv *dp = ap->private_data;
+ u8 speed = adev->dma_mode;
+ u8 b;
+ u8 mode = speed - XFER_UDMA_0 + 1;
+
+ /*
+ * Doc 6.6.9: decrease the udma mode value by 1 for safer UDMA speed
+ * on 66MHz bus
+ * rev-A: UDMA_1~4 (5, 6 no change)
+ * rev-B: all UDMA modes
+ * UDMA_0 stays not to disable UDMA
+ */
+ if (dp->pci66mhz && mode > ATP867X_IO_DMAMODE_UDMA_0 &&
+ (pdev->device == PCI_DEVICE_ID_ARTOP_ATP867B ||
+ mode < ATP867X_IO_DMAMODE_UDMA_5))
+ mode--;
+
+ b = ioread8(dp->dma_mode);
+ if (adev->devno & 1) {
+ b = (b & ~ATP867X_IO_DMAMODE_SLAVE_MASK) |
+ (mode << ATP867X_IO_DMAMODE_SLAVE_SHIFT);
+ } else {
+ b = (b & ~ATP867X_IO_DMAMODE_MSTR_MASK) |
+ (mode << ATP867X_IO_DMAMODE_MSTR_SHIFT);
+ }
+ iowrite8(b, dp->dma_mode);
+}
+
+static int atp867x_get_active_clocks_shifted(struct ata_port *ap,
+ unsigned int clk)
+{
+ struct atp867x_priv *dp = ap->private_data;
+ unsigned char clocks = clk;
+
+ /*
+ * Doc 6.6.9: increase the clock value by 1 for safer PIO speed
+ * on 66MHz bus
+ */
+ if (dp->pci66mhz)
+ clocks++;
+
+ switch (clocks) {
+ case 0:
+ clocks = 1;
+ break;
+ case 1 ... 6:
+ break;
+ default:
+ printk(KERN_WARNING "ATP867X: active %dclk is invalid. "
+ "Using 12clk.\n", clk);
+ case 9 ... 12:
+ clocks = 7; /* 12 clk */
+ break;
+ case 7:
+ case 8: /* default 8 clk */
+ clocks = 0;
+ goto active_clock_shift_done;
+ }
+
+active_clock_shift_done:
+ return clocks << ATP867X_IO_PIOSPD_ACTIVE_SHIFT;
+}
+
+static int atp867x_get_recover_clocks_shifted(unsigned int clk)
+{
+ unsigned char clocks = clk;
+
+ switch (clocks) {
+ case 0:
+ clocks = 1;
+ break;
+ case 1 ... 11:
+ break;
+ case 13:
+ case 14:
+ --clocks; /* by the spec */
+ break;
+ case 15:
+ break;
+ default:
+ printk(KERN_WARNING "ATP867X: recover %dclk is invalid. "
+ "Using default 12clk.\n", clk);
+ case 12: /* default 12 clk */
+ clocks = 0;
+ break;
+ }
+
+ return clocks << ATP867X_IO_PIOSPD_RECOVER_SHIFT;
+}
+
+static void atp867x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_device *peer = ata_dev_pair(adev);
+ struct atp867x_priv *dp = ap->private_data;
+ u8 speed = adev->pio_mode;
+ struct ata_timing t, p;
+ int T, UT;
+ u8 b;
+
+ T = 1000000000 / 33333;
+ UT = T / 4;
+
+ ata_timing_compute(adev, speed, &t, T, UT);
+ if (peer && peer->pio_mode) {
+ ata_timing_compute(peer, peer->pio_mode, &p, T, UT);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_8BIT);
+ }
+
+ b = ioread8(dp->dma_mode);
+ if (adev->devno & 1)
+ b = (b & ~ATP867X_IO_DMAMODE_SLAVE_MASK);
+ else
+ b = (b & ~ATP867X_IO_DMAMODE_MSTR_MASK);
+ iowrite8(b, dp->dma_mode);
+
+ b = atp867x_get_active_clocks_shifted(ap, t.active) |
+ atp867x_get_recover_clocks_shifted(t.recover);
+
+ if (adev->devno & 1)
+ iowrite8(b, dp->slave_piospd);
+ else
+ iowrite8(b, dp->mstr_piospd);
+
+ b = atp867x_get_active_clocks_shifted(ap, t.act8b) |
+ atp867x_get_recover_clocks_shifted(t.rec8b);
+
+ iowrite8(b, dp->eightb_piospd);
+}
+
+static int atp867x_cable_override(struct pci_dev *pdev)
+{
+ if (pdev->subsystem_vendor == PCI_VENDOR_ID_ARTOP &&
+ (pdev->subsystem_device == PCI_DEVICE_ID_ARTOP_ATP867A ||
+ pdev->subsystem_device == PCI_DEVICE_ID_ARTOP_ATP867B)) {
+ return 1;
+ }
+ return 0;
+}
+
+static int atp867x_cable_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (atp867x_cable_override(pdev))
+ return ATA_CBL_PATA40_SHORT;
+
+ return ATA_CBL_PATA_UNK;
+}
+
+static struct scsi_host_template atp867x_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations atp867x_ops = {
+ .inherits = &ata_bmdma_port_ops,
+ .cable_detect = atp867x_cable_detect,
+ .set_piomode = atp867x_set_piomode,
+ .set_dmamode = atp867x_set_dmamode,
+};
+
+
+#ifdef ATP867X_DEBUG
+static void atp867x_check_res(struct pci_dev *pdev)
+{
+ int i;
+ unsigned long start, len;
+
+ /* Check the PCI resources for this channel are enabled */
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ start = pci_resource_start(pdev, i);
+ len = pci_resource_len(pdev, i);
+ printk(KERN_DEBUG "ATP867X: resource start:len=%lx:%lx\n",
+ start, len);
+ }
+}
+
+static void atp867x_check_ports(struct ata_port *ap, int port)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ struct atp867x_priv *dp = ap->private_data;
+
+ printk(KERN_DEBUG "ATP867X: port[%d] addresses\n"
+ " cmd_addr =0x%llx, 0x%llx\n"
+ " ctl_addr =0x%llx, 0x%llx\n"
+ " bmdma_addr =0x%llx, 0x%llx\n"
+ " data_addr =0x%llx\n"
+ " error_addr =0x%llx\n"
+ " feature_addr =0x%llx\n"
+ " nsect_addr =0x%llx\n"
+ " lbal_addr =0x%llx\n"
+ " lbam_addr =0x%llx\n"
+ " lbah_addr =0x%llx\n"
+ " device_addr =0x%llx\n"
+ " status_addr =0x%llx\n"
+ " command_addr =0x%llx\n"
+ " dp->dma_mode =0x%llx\n"
+ " dp->mstr_piospd =0x%llx\n"
+ " dp->slave_piospd =0x%llx\n"
+ " dp->eightb_piospd =0x%llx\n"
+ " dp->pci66mhz =0x%lx\n",
+ port,
+ (unsigned long long)ioaddr->cmd_addr,
+ (unsigned long long)ATP867X_IO_PORTBASE(ap, port),
+ (unsigned long long)ioaddr->ctl_addr,
+ (unsigned long long)ATP867X_IO_ALTSTATUS(ap, port),
+ (unsigned long long)ioaddr->bmdma_addr,
+ (unsigned long long)ATP867X_IO_DMABASE(ap, port),
+ (unsigned long long)ioaddr->data_addr,
+ (unsigned long long)ioaddr->error_addr,
+ (unsigned long long)ioaddr->feature_addr,
+ (unsigned long long)ioaddr->nsect_addr,
+ (unsigned long long)ioaddr->lbal_addr,
+ (unsigned long long)ioaddr->lbam_addr,
+ (unsigned long long)ioaddr->lbah_addr,
+ (unsigned long long)ioaddr->device_addr,
+ (unsigned long long)ioaddr->status_addr,
+ (unsigned long long)ioaddr->command_addr,
+ (unsigned long long)dp->dma_mode,
+ (unsigned long long)dp->mstr_piospd,
+ (unsigned long long)dp->slave_piospd,
+ (unsigned long long)dp->eightb_piospd,
+ (unsigned long)dp->pci66mhz);
+}
+#endif
+
+static int atp867x_set_priv(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct atp867x_priv *dp;
+ int port = ap->port_no;
+
+ dp = ap->private_data =
+ devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL);
+ if (dp == NULL)
+ return -ENOMEM;
+
+ dp->dma_mode = ATP867X_IO_DMAMODE(ap, port);
+ dp->mstr_piospd = ATP867X_IO_MSTRPIOSPD(ap, port);
+ dp->slave_piospd = ATP867X_IO_SLAVPIOSPD(ap, port);
+ dp->eightb_piospd = ATP867X_IO_8BPIOSPD(ap, port);
+
+ dp->pci66mhz =
+ ioread8(ATP867X_SYS_INFO(ap)) & ATP867X_IO_SYS_INFO_66MHZ;
+
+ return 0;
+}
+
+static void atp867x_fixup(struct ata_host *host)
+{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ struct ata_port *ap = host->ports[0];
+ int i;
+ u8 v;
+
+ /*
+ * Broken BIOS might not set latency high enough
+ */
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &v);
+ if (v < 0x80) {
+ v = 0x80;
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, v);
+ printk(KERN_DEBUG "ATP867X: set latency timer of device %s"
+ " to %d\n", pci_name(pdev), v);
+ }
+
+ /*
+ * init 8bit io ports speed(0aaarrrr) to 43h and
+ * init udma modes of master/slave to 0/0(11h)
+ */
+ for (i = 0; i < ATP867X_NUM_PORTS; i++)
+ iowrite16(ATP867X_IO_PORTSPD_VAL, ATP867X_IO_PORTSPD(ap, i));
+
+ /*
+ * init PreREAD counts
+ */
+ for (i = 0; i < ATP867X_NUM_PORTS; i++)
+ iowrite16(ATP867X_PREREAD_VAL, ATP867X_IO_PREREAD(ap, i));
+
+ v = ioread8(ATP867X_IOBASE(ap) + 0x28);
+ v &= 0xcf; /* Enable INTA#: bit4=0 means enable */
+ v |= 0xc0; /* Enable PCI burst, MRM & not immediate interrupts */
+ iowrite8(v, ATP867X_IOBASE(ap) + 0x28);
+
+ /*
+ * Turn off the over clocked udma5 mode, only for Rev-B
+ */
+ v = ioread8(ATP867X_SYS_INFO(ap));
+ v &= ATP867X_IO_SYS_MASK_RESERVED;
+ if (pdev->device == PCI_DEVICE_ID_ARTOP_ATP867B)
+ v |= ATP867X_IO_SYS_INFO_SLOW_UDMA5;
+ iowrite8(v, ATP867X_SYS_INFO(ap));
+}
+
+static int atp867x_ata_pci_sff_init_host(struct ata_host *host)
+{
+ struct device *gdev = host->dev;
+ struct pci_dev *pdev = to_pci_dev(gdev);
+ unsigned int mask = 0;
+ int i, rc;
+
+ /*
+ * do not map rombase
+ */
+ rc = pcim_iomap_regions(pdev, 1 << ATP867X_BAR_IOBASE, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
+ host->iomap = pcim_iomap_table(pdev);
+
+#ifdef ATP867X_DEBUG
+ atp867x_check_res(pdev);
+
+ for (i = 0; i < PCI_ROM_RESOURCE; i++)
+ printk(KERN_DEBUG "ATP867X: iomap[%d]=0x%llx\n", i,
+ (unsigned long long)(host->iomap[i]));
+#endif
+
+ /*
+ * request, iomap BARs and init port addresses accordingly
+ */
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ ioaddr->cmd_addr = ATP867X_IO_PORTBASE(ap, i);
+ ioaddr->ctl_addr = ioaddr->altstatus_addr
+ = ATP867X_IO_ALTSTATUS(ap, i);
+ ioaddr->bmdma_addr = ATP867X_IO_DMABASE(ap, i);
+
+ ata_sff_std_ports(ioaddr);
+ rc = atp867x_set_priv(ap);
+ if (rc)
+ return rc;
+
+#ifdef ATP867X_DEBUG
+ atp867x_check_ports(ap, i);
+#endif
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",
+ (unsigned long)ioaddr->cmd_addr,
+ (unsigned long)ioaddr->ctl_addr);
+ ata_port_desc(ap, "bmdma 0x%lx",
+ (unsigned long)ioaddr->bmdma_addr);
+
+ mask |= 1 << i;
+ }
+
+ if (!mask) {
+ dev_err(gdev, "no available native port\n");
+ return -ENODEV;
+ }
+
+ atp867x_fixup(host);
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ return rc;
+}
+
+static int atp867x_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ static const struct ata_port_info info_867x = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &atp867x_ops,
+ };
+
+ struct ata_host *host;
+ const struct ata_port_info *ppi[] = { &info_867x, NULL };
+ int rc;
+
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
+
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ printk(KERN_INFO "ATP867X: ATP867 ATA UDMA133 controller (rev %02X)",
+ pdev->device);
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, ATP867X_NUM_PORTS);
+ if (!host) {
+ dev_err(&pdev->dev, "failed to allocate ATA host\n");
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ rc = atp867x_ata_pci_sff_init_host(host);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to init host\n");
+ goto err_out;
+ }
+
+ pci_set_master(pdev);
+
+ rc = ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
+ IRQF_SHARED, &atp867x_sht);
+ if (rc)
+ dev_err(&pdev->dev, "failed to activate host\n");
+
+err_out:
+ return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int atp867x_reinit_one(struct pci_dev *pdev)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ atp867x_fixup(host);
+
+ ata_host_resume(host);
+ return 0;
+}
+#endif
+
+static struct pci_device_id atp867x_pci_tbl[] = {
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP867A), 0 },
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP867B), 0 },
+ { },
+};
+
+static struct pci_driver atp867x_driver = {
+ .name = DRV_NAME,
+ .id_table = atp867x_pci_tbl,
+ .probe = atp867x_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = ata_pci_device_suspend,
+ .resume = atp867x_reinit_one,
+#endif
+};
+
+module_pci_driver(atp867x_driver);
+
+MODULE_AUTHOR("John(Jung-Ik) Lee, Google Inc.");
+MODULE_DESCRIPTION("low level driver for Artop/Acard 867x ATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, atp867x_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index 0a5ad98635b..03f2f2bc83b 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -251,6 +251,8 @@ static const u32 udma_tenvmin = 20;
static const u32 udma_tackmin = 20;
static const u32 udma_tssmin = 50;
+#define BFIN_MAX_SG_SEGMENTS 4
+
/**
*
* Function: num_clocks_min
@@ -356,7 +358,6 @@ static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev)
* bfin_set_dmamode - Initialize host controller PATA DMA timings
* @ap: Port whose timings we are configuring
* @adev: um
- * @udma: udma mode, 0 - 6
*
* Set UDMA mode for device.
*
@@ -419,14 +420,6 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
(tcyc_tdvs<<8 | tdvs));
ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss));
ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah));
-
- /* Enable host ATAPI Untra DMA interrupts */
- ATAPI_SET_INT_MASK(base,
- ATAPI_GET_INT_MASK(base)
- | UDMAIN_DONE_MASK
- | UDMAOUT_DONE_MASK
- | UDMAIN_TERM_MASK
- | UDMAOUT_TERM_MASK);
}
}
}
@@ -471,10 +464,6 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td));
ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw));
ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th));
-
- /* Enable host ATAPI Multi DMA interrupts */
- ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
- | MULTI_DONE_MASK | MULTI_TERM_MASK);
SSYNC();
}
}
@@ -822,6 +811,18 @@ static void bfin_dev_select(struct ata_port *ap, unsigned int device)
}
/**
+ * bfin_set_devctl - Write device control reg
+ * @ap: port where the device is
+ * @ctl: value to write
+ */
+
+static void bfin_set_devctl(struct ata_port *ap, u8 ctl)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ write_atapi_register(base, ATA_REG_CTRL, ctl);
+}
+
+/**
* bfin_bmdma_setup - Set up IDE DMA transaction
* @qc: Info associated with this ATA transaction.
*
@@ -830,79 +831,61 @@ static void bfin_dev_select(struct ata_port *ap, unsigned int device)
static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
{
- unsigned short config = WDSIZE_16;
+ struct ata_port *ap = qc->ap;
+ struct dma_desc_array *dma_desc_cpu = (struct dma_desc_array *)ap->bmdma_prd;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned short config = DMAFLOW_ARRAY | NDSIZE_5 | RESTART | WDSIZE_16 | DMAEN;
struct scatterlist *sg;
unsigned int si;
+ unsigned int channel;
+ unsigned int dir;
+ unsigned int size = 0;
dev_dbg(qc->ap->dev, "in atapi dma setup\n");
/* Program the ATA_CTRL register with dir */
if (qc->tf.flags & ATA_TFLAG_WRITE) {
- /* fill the ATAPI DMA controller */
- set_dma_config(CH_ATAPI_TX, config);
- set_dma_x_modify(CH_ATAPI_TX, 2);
- for_each_sg(qc->sg, sg, qc->n_elem, si) {
- set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg));
- set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1);
- }
+ channel = CH_ATAPI_TX;
+ dir = DMA_TO_DEVICE;
} else {
+ channel = CH_ATAPI_RX;
+ dir = DMA_FROM_DEVICE;
config |= WNR;
- /* fill the ATAPI DMA controller */
- set_dma_config(CH_ATAPI_RX, config);
- set_dma_x_modify(CH_ATAPI_RX, 2);
- for_each_sg(qc->sg, sg, qc->n_elem, si) {
- set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg));
- set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1);
- }
}
-}
-/**
- * bfin_bmdma_start - Start an IDE DMA transaction
- * @qc: Info associated with this ATA transaction.
- *
- * Note: Original code is ata_bmdma_start().
- */
+ dma_map_sg(ap->dev, qc->sg, qc->n_elem, dir);
-static void bfin_bmdma_start(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
- struct scatterlist *sg;
- unsigned int si;
+ /* fill the ATAPI DMA controller */
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ dma_desc_cpu[si].start_addr = sg_dma_address(sg);
+ dma_desc_cpu[si].cfg = config;
+ dma_desc_cpu[si].x_count = sg_dma_len(sg) >> 1;
+ dma_desc_cpu[si].x_modify = 2;
+ size += sg_dma_len(sg);
+ }
- dev_dbg(qc->ap->dev, "in atapi dma start\n");
- if (!(ap->udma_mask || ap->mwdma_mask))
- return;
+ /* Set the last descriptor to stop mode */
+ dma_desc_cpu[qc->n_elem - 1].cfg &= ~(DMAFLOW | NDSIZE);
- /* start ATAPI DMA controller*/
- if (qc->tf.flags & ATA_TFLAG_WRITE) {
- /*
- * On blackfin arch, uncacheable memory is not
- * allocated with flag GFP_DMA. DMA buffer from
- * common kenel code should be flushed if WB
- * data cache is enabled. Otherwise, this loop
- * is an empty loop and optimized out.
- */
- for_each_sg(qc->sg, sg, qc->n_elem, si) {
- flush_dcache_range(sg_dma_address(sg),
- sg_dma_address(sg) + sg_dma_len(sg));
- }
- enable_dma(CH_ATAPI_TX);
- dev_dbg(qc->ap->dev, "enable udma write\n");
+ flush_dcache_range((unsigned int)dma_desc_cpu,
+ (unsigned int)dma_desc_cpu +
+ qc->n_elem * sizeof(struct dma_desc_array));
- /* Send ATA DMA write command */
- bfin_exec_command(ap, &qc->tf);
+ /* Enable ATA DMA operation*/
+ set_dma_curr_desc_addr(channel, (unsigned long *)ap->bmdma_prd_dma);
+ set_dma_x_count(channel, 0);
+ set_dma_x_modify(channel, 0);
+ set_dma_config(channel, config);
+ SSYNC();
+
+ /* Send ATA DMA command */
+ bfin_exec_command(ap, &qc->tf);
+
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
/* set ATA DMA write direction */
ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
| XFER_DIR));
} else {
- enable_dma(CH_ATAPI_RX);
- dev_dbg(qc->ap->dev, "enable udma read\n");
-
- /* Send ATA DMA read command */
- bfin_exec_command(ap, &qc->tf);
-
/* set ATA DMA read direction */
ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
& ~XFER_DIR));
@@ -911,12 +894,31 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
/* Reset all transfer count */
ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);
- /* Set transfer length to buffer len */
- for_each_sg(qc->sg, sg, qc->n_elem, si) {
- ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
- }
+ /* Set ATAPI state machine contorl in terminate sequence */
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | END_ON_TERM);
- /* Enable ATA DMA operation*/
+ /* Set transfer length to the total size of sg buffers */
+ ATAPI_SET_XFER_LEN(base, size >> 1);
+}
+
+/**
+ * bfin_bmdma_start - Start an IDE DMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * Note: Original code is ata_bmdma_start().
+ */
+
+static void bfin_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ dev_dbg(qc->ap->dev, "in atapi dma start\n");
+
+ if (!(ap->udma_mask || ap->mwdma_mask))
+ return;
+
+ /* start ATAPI transfer*/
if (ap->udma_mask)
ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)
| ULTRA_START);
@@ -933,34 +935,23 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- struct scatterlist *sg;
- unsigned int si;
+ unsigned int dir;
dev_dbg(qc->ap->dev, "in atapi dma stop\n");
+
if (!(ap->udma_mask || ap->mwdma_mask))
return;
/* stop ATAPI DMA controller*/
- if (qc->tf.flags & ATA_TFLAG_WRITE)
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ dir = DMA_TO_DEVICE;
disable_dma(CH_ATAPI_TX);
- else {
+ } else {
+ dir = DMA_FROM_DEVICE;
disable_dma(CH_ATAPI_RX);
- if (ap->hsm_task_state & HSM_ST_LAST) {
- /*
- * On blackfin arch, uncacheable memory is not
- * allocated with flag GFP_DMA. DMA buffer from
- * common kenel code should be invalidated if
- * data cache is enabled. Otherwise, this loop
- * is an empty loop and optimized out.
- */
- for_each_sg(qc->sg, sg, qc->n_elem, si) {
- invalidate_dcache_range(
- sg_dma_address(sg),
- sg_dma_address(sg)
- + sg_dma_len(sg));
- }
- }
}
+
+ dma_unmap_sg(ap->dev, qc->sg, qc->n_elem, dir);
}
/**
@@ -1008,7 +999,7 @@ static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
unsigned int dev0 = devmask & (1 << 0);
unsigned int dev1 = devmask & (1 << 1);
- unsigned long timeout;
+ unsigned long deadline;
/* if device 0 was found in ata_devchk, wait for its
* BSY bit to clear
@@ -1019,7 +1010,7 @@ static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
/* if device 1 was found in ata_devchk, wait for
* register access, then wait for BSY to clear
*/
- timeout = jiffies + ATA_TMOUT_BOOT;
+ deadline = ata_deadline(jiffies, ATA_TMOUT_BOOT);
while (dev1) {
u8 nsect, lbal;
@@ -1028,11 +1019,11 @@ static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
lbal = read_atapi_register(base, ATA_REG_LBAL);
if ((nsect == 1) && (lbal == 1))
break;
- if (time_after(jiffies, timeout)) {
+ if (time_after(jiffies, deadline)) {
dev1 = 0;
break;
}
- msleep(50); /* give drive a breather */
+ ata_msleep(ap, 50); /* give drive a breather */
}
if (dev1)
ata_sff_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
@@ -1073,7 +1064,7 @@ static unsigned int bfin_bus_softreset(struct ata_port *ap,
*
* Old drivers/ide uses the 2mS rule and then waits for ready
*/
- msleep(150);
+ ata_msleep(ap, 150);
/* Before we perform post reset processing we want to see if
* the bus shows 0xFF because the odd clown forgets the D7
@@ -1115,7 +1106,7 @@ static int bfin_softreset(struct ata_link *link, unsigned int *classes,
/* issue bus reset */
err_mask = bfin_bus_softreset(ap, devmask);
if (err_mask) {
- ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
+ ata_port_err(ap, "SRST failed (err_mask=0x%x)\n",
err_mask);
return -EIO;
}
@@ -1139,15 +1130,11 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)
{
unsigned char host_stat = 0;
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
- unsigned short int_status = ATAPI_GET_INT_STATUS(base);
- if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON))
+ if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON | ULTRA_XFER_ON))
host_stat |= ATA_DMA_ACTIVE;
- if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT|
- ATAPI_DEV_INT))
+ if (ATAPI_GET_INT_STATUS(base) & ATAPI_DEV_INT)
host_stat |= ATA_DMA_INTR;
- if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT))
- host_stat |= ATA_DMA_ERR|ATA_DMA_INTR;
dev_dbg(ap->dev, "ATAPI: host_stat=0x%x\n", host_stat);
@@ -1200,7 +1187,7 @@ static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf,
* bfin_irq_clear - Clear ATAPI interrupt.
* @ap: Port associated with this ATA transaction.
*
- * Note: Original code is ata_sff_irq_clear().
+ * Note: Original code is ata_bmdma_irq_clear().
*/
static void bfin_irq_clear(struct ata_port *ap)
@@ -1214,56 +1201,6 @@ static void bfin_irq_clear(struct ata_port *ap)
}
/**
- * bfin_irq_on - Enable interrupts on a port.
- * @ap: Port on which interrupts are enabled.
- *
- * Note: Original code is ata_sff_irq_on().
- */
-
-static unsigned char bfin_irq_on(struct ata_port *ap)
-{
- void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
- u8 tmp;
-
- dev_dbg(ap->dev, "in atapi irq on\n");
- ap->ctl &= ~ATA_NIEN;
- ap->last_ctl = ap->ctl;
-
- write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
- tmp = ata_wait_idle(ap);
-
- bfin_irq_clear(ap);
-
- return tmp;
-}
-
-/**
- * bfin_freeze - Freeze DMA controller port
- * @ap: port to freeze
- *
- * Note: Original code is ata_sff_freeze().
- */
-
-static void bfin_freeze(struct ata_port *ap)
-{
- void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
-
- dev_dbg(ap->dev, "in atapi dma freeze\n");
- ap->ctl |= ATA_NIEN;
- ap->last_ctl = ap->ctl;
-
- write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
-
- /* Under certain circumstances, some controllers raise IRQ on
- * ATA_NIEN manipulation. Also, many controllers fail to mask
- * previously pending IRQ on ATA_NIEN assertion. Clear it.
- */
- ap->ops->sff_check_status(ap);
-
- bfin_irq_clear(ap);
-}
-
-/**
* bfin_thaw - Thaw DMA controller port
* @ap: port to thaw
*
@@ -1272,9 +1209,9 @@ static void bfin_freeze(struct ata_port *ap)
void bfin_thaw(struct ata_port *ap)
{
+ dev_dbg(ap->dev, "in atapi dma thaw\n");
bfin_check_status(ap);
- bfin_irq_clear(ap);
- bfin_irq_on(ap);
+ ata_sff_irq_on(ap);
}
/**
@@ -1291,7 +1228,7 @@ static void bfin_postreset(struct ata_link *link, unsigned int *classes)
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
/* re-enable interrupts */
- bfin_irq_on(ap);
+ ata_sff_irq_on(ap);
/* is double-select really necessary? */
if (classes[0] != ATA_DEV_NONE)
@@ -1312,6 +1249,11 @@ static void bfin_port_stop(struct ata_port *ap)
{
dev_dbg(ap->dev, "in atapi port stop\n");
if (ap->udma_mask != 0 || ap->mwdma_mask != 0) {
+ dma_free_coherent(ap->dev,
+ BFIN_MAX_SG_SEGMENTS * sizeof(struct dma_desc_array),
+ ap->bmdma_prd,
+ ap->bmdma_prd_dma);
+
free_dma(CH_ATAPI_RX);
free_dma(CH_ATAPI_TX);
}
@@ -1323,14 +1265,29 @@ static int bfin_port_start(struct ata_port *ap)
if (!(ap->udma_mask || ap->mwdma_mask))
return 0;
+ ap->bmdma_prd = dma_alloc_coherent(ap->dev,
+ BFIN_MAX_SG_SEGMENTS * sizeof(struct dma_desc_array),
+ &ap->bmdma_prd_dma,
+ GFP_KERNEL);
+
+ if (ap->bmdma_prd == NULL) {
+ dev_info(ap->dev, "Unable to allocate DMA descriptor array.\n");
+ goto out;
+ }
+
if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) {
if (request_dma(CH_ATAPI_TX,
"BFIN ATAPI TX DMA") >= 0)
return 0;
free_dma(CH_ATAPI_RX);
+ dma_free_coherent(ap->dev,
+ BFIN_MAX_SG_SEGMENTS * sizeof(struct dma_desc_array),
+ ap->bmdma_prd,
+ ap->bmdma_prd_dma);
}
+out:
ap->udma_mask = 0;
ap->mwdma_mask = 0;
dev_err(ap->dev, "Unable to request ATAPI DMA!"
@@ -1339,14 +1296,125 @@ static int bfin_port_start(struct ata_port *ap)
return 0;
}
+static unsigned int bfin_ata_host_intr(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
+{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ u8 status, host_stat = 0;
+
+ VPRINTK("ata%u: protocol %d task_state %d\n",
+ ap->print_id, qc->tf.protocol, ap->hsm_task_state);
+
+ /* Check whether we are expecting interrupt in this state */
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
+ /* Some pre-ATAPI-4 devices assert INTRQ
+ * at this state when ready to receive CDB.
+ */
+
+ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+ * The flag was turned on only for atapi devices.
+ * No need to check is_atapi_taskfile(&qc->tf) again.
+ */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ goto idle_irq;
+ break;
+ case HSM_ST_LAST:
+ if (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATAPI_PROT_DMA) {
+ /* check status of DMA engine */
+ host_stat = ap->ops->bmdma_status(ap);
+ VPRINTK("ata%u: host_stat 0x%X\n",
+ ap->print_id, host_stat);
+
+ /* if it's not our irq... */
+ if (!(host_stat & ATA_DMA_INTR))
+ goto idle_irq;
+
+ /* before we do anything else, clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+
+ if (unlikely(host_stat & ATA_DMA_ERR)) {
+ /* error when transferring data to/from memory */
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ ap->hsm_task_state = HSM_ST_ERR;
+ }
+ }
+ break;
+ case HSM_ST:
+ break;
+ default:
+ goto idle_irq;
+ }
+
+ /* check altstatus */
+ status = ap->ops->sff_check_altstatus(ap);
+ if (status & ATA_BUSY)
+ goto busy_ata;
+
+ /* check main status, clearing INTRQ */
+ status = ap->ops->sff_check_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ goto busy_ata;
+
+ /* ack bmdma irq events */
+ ap->ops->sff_irq_clear(ap);
+
+ ata_sff_hsm_move(ap, qc, status, 0);
+
+ if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATAPI_PROT_DMA))
+ ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
+
+busy_ata:
+ return 1; /* irq handled */
+
+idle_irq:
+ ap->stats.idle_irq++;
+
+#ifdef ATA_IRQ_TRAP
+ if ((ap->stats.idle_irq % 1000) == 0) {
+ ap->ops->irq_ack(ap, 0); /* debug trap */
+ ata_port_warn(ap, "irq trap\n");
+ return 1;
+ }
+#endif
+ return 0; /* irq not handled */
+}
+
+static irqreturn_t bfin_ata_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ unsigned int i;
+ unsigned int handled = 0;
+ unsigned long flags;
+
+ /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
+ spin_lock_irqsave(&host->lock, flags);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
+ handled |= bfin_ata_host_intr(ap, qc);
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+
static struct scsi_host_template bfin_sht = {
ATA_BASE_SHT(DRV_NAME),
- .sg_tablesize = SG_NONE,
+ .sg_tablesize = BFIN_MAX_SG_SEGMENTS,
.dma_boundary = ATA_DMA_BOUNDARY,
};
-static const struct ata_port_operations bfin_pata_ops = {
- .inherits = &ata_sff_port_ops,
+static struct ata_port_operations bfin_pata_ops = {
+ .inherits = &ata_bmdma_port_ops,
.set_piomode = bfin_set_piomode,
.set_dmamode = bfin_set_dmamode,
@@ -1357,6 +1425,7 @@ static const struct ata_port_operations bfin_pata_ops = {
.sff_check_status = bfin_check_status,
.sff_check_altstatus = bfin_check_altstatus,
.sff_dev_select = bfin_dev_select,
+ .sff_set_devctl = bfin_set_devctl,
.bmdma_setup = bfin_bmdma_setup,
.bmdma_start = bfin_bmdma_start,
@@ -1366,14 +1435,11 @@ static const struct ata_port_operations bfin_pata_ops = {
.qc_prep = ata_noop_qc_prep,
- .freeze = bfin_freeze,
.thaw = bfin_thaw,
.softreset = bfin_softreset,
.postreset = bfin_postreset,
- .post_internal_cmd = bfin_bmdma_stop,
.sff_irq_clear = bfin_irq_clear,
- .sff_irq_on = bfin_irq_on,
.port_start = bfin_port_start,
.port_stop = bfin_port_stop,
@@ -1381,10 +1447,8 @@ static const struct ata_port_operations bfin_pata_ops = {
static struct ata_port_info bfin_port_info[] = {
{
- .flags = ATA_FLAG_SLAVE_POSS
- | ATA_FLAG_MMIO
- | ATA_FLAG_NO_LEGACY,
- .pio_mask = 0x1f, /* pio0-4 */
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
.mwdma_mask = 0,
.udma_mask = 0,
.port_ops = &bfin_pata_ops,
@@ -1417,7 +1481,7 @@ static int bfin_reset_controller(struct ata_host *host)
count = 10000000;
do {
status = read_atapi_register(base, ATA_REG_STATUS);
- } while (count-- && (status & ATA_BUSY));
+ } while (--count && (status & ATA_BUSY));
/* Enable only ATAPI Device interrupt */
ATAPI_SET_INT_MASK(base, 1);
@@ -1439,6 +1503,25 @@ static unsigned short atapi_io_port[] = {
P_ATAPI_DMARQ,
P_ATAPI_INTRQ,
P_ATAPI_IORDY,
+ P_ATAPI_D0A,
+ P_ATAPI_D1A,
+ P_ATAPI_D2A,
+ P_ATAPI_D3A,
+ P_ATAPI_D4A,
+ P_ATAPI_D5A,
+ P_ATAPI_D6A,
+ P_ATAPI_D7A,
+ P_ATAPI_D8A,
+ P_ATAPI_D9A,
+ P_ATAPI_D10A,
+ P_ATAPI_D11A,
+ P_ATAPI_D12A,
+ P_ATAPI_D13A,
+ P_ATAPI_D14A,
+ P_ATAPI_D15A,
+ P_ATAPI_A0A,
+ P_ATAPI_A1A,
+ P_ATAPI_A2A,
0
};
@@ -1455,7 +1538,7 @@ static unsigned short atapi_io_port[] = {
* - IRQ (IORESOURCE_IRQ)
*
*/
-static int __devinit bfin_atapi_probe(struct platform_device *pdev)
+static int bfin_atapi_probe(struct platform_device *pdev)
{
int board_idx = 0;
struct resource *res;
@@ -1496,7 +1579,7 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev)
host->ports[0]->ioaddr.ctl_addr = (void *)res->start;
if (peripheral_request_list(atapi_io_port, "atapi-io-port")) {
- dev_err(&pdev->dev, "Requesting Peripherals faild\n");
+ dev_err(&pdev->dev, "Requesting Peripherals failed\n");
return -EFAULT;
}
@@ -1507,12 +1590,14 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev)
}
if (ata_host_activate(host, platform_get_irq(pdev, 0),
- ata_sff_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
+ bfin_ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
peripheral_free_list(atapi_io_port);
dev_err(&pdev->dev, "Fail to attach ATAPI device\n");
return -ENODEV;
}
+ platform_set_drvdata(pdev, host);
+
return 0;
}
@@ -1523,10 +1608,9 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev)
* A bfin atapi device has been unplugged. Perform the needed
* cleanup. Also called on module unload for any active devices.
*/
-static int __devexit bfin_atapi_remove(struct platform_device *pdev)
+static int bfin_atapi_remove(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct ata_host *host = dev_get_drvdata(dev);
+ struct ata_host *host = platform_get_drvdata(pdev);
ata_host_detach(host);
@@ -1535,28 +1619,45 @@ static int __devexit bfin_atapi_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
{
- return 0;
+ struct ata_host *host = platform_get_drvdata(pdev);
+ if (host)
+ return ata_host_suspend(host, state);
+ else
+ return 0;
}
-int bfin_atapi_resume(struct platform_device *pdev)
+static int bfin_atapi_resume(struct platform_device *pdev)
{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ int ret;
+
+ if (host) {
+ ret = bfin_reset_controller(host);
+ if (ret) {
+ printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+ return ret;
+ }
+ ata_host_resume(host);
+ }
+
return 0;
}
+#else
+#define bfin_atapi_suspend NULL
+#define bfin_atapi_resume NULL
#endif
static struct platform_driver bfin_atapi_driver = {
.probe = bfin_atapi_probe,
- .remove = __devexit_p(bfin_atapi_remove),
+ .remove = bfin_atapi_remove,
+ .suspend = bfin_atapi_suspend,
+ .resume = bfin_atapi_resume,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .suspend = bfin_atapi_suspend,
- .resume = bfin_atapi_resume,
-#endif
},
};
@@ -1601,3 +1702,4 @@ MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c
index 2de30b99027..c47caa807fa 100644
--- a/drivers/ata/pata_cmd640.c
+++ b/drivers/ata/pata_cmd640.c
@@ -1,7 +1,6 @@
/*
* pata_cmd640.c - CMD640 PCI PATA for new ATA layer
* (C) 2007 Red Hat Inc
- * Alan Cox <alan@redhat.com>
*
* Based upon
* linux/drivers/ide/pci/cmd640.c Version 1.02 Sep 01, 1996
@@ -16,9 +15,9 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
+#include <linux/gfp.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
@@ -153,26 +152,34 @@ static int cmd640_port_start(struct ata_port *ap)
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct cmd640_reg *timing;
- int ret = ata_sff_port_start(ap);
- if (ret < 0)
- return ret;
-
timing = devm_kzalloc(&pdev->dev, sizeof(struct cmd640_reg), GFP_KERNEL);
if (timing == NULL)
return -ENOMEM;
timing->last = -1; /* Force a load */
ap->private_data = timing;
- return ret;
+ return 0;
+}
+
+static bool cmd640_sff_irq_check(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int irq_reg = ap->port_no ? ARTIM23 : CFR;
+ u8 irq_stat, irq_mask = ap->port_no ? 0x10 : 0x04;
+
+ pci_read_config_byte(pdev, irq_reg, &irq_stat);
+
+ return irq_stat & irq_mask;
}
static struct scsi_host_template cmd640_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
+ ATA_PIO_SHT(DRV_NAME),
};
static struct ata_port_operations cmd640_port_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_sff_port_ops,
/* In theory xfer_noirq is not needed once we kill the prefetcher */
.sff_data_xfer = ata_sff_data_xfer_noirq,
+ .sff_irq_check = cmd640_sff_irq_check,
.qc_issue = cmd640_qc_issue,
.cable_detect = ata_cable_40wire,
.set_piomode = cmd640_set_piomode,
@@ -181,13 +188,10 @@ static struct ata_port_operations cmd640_port_ops = {
static void cmd640_hardware_init(struct pci_dev *pdev)
{
- u8 r;
u8 ctrl;
/* CMD640 detected, commiserations */
pci_write_config_byte(pdev, 0x5B, 0x00);
- /* Get version info */
- pci_read_config_byte(pdev, CFR, &r);
/* PIO0 command cycles */
pci_write_config_byte(pdev, CMDTIM, 0);
/* 512 byte bursts (sector) */
@@ -212,7 +216,7 @@ static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
+ .pio_mask = ATA_PIO4,
.port_ops = &cmd640_port_ops
};
const struct ata_port_info *ppi[] = { &info, NULL };
@@ -224,13 +228,13 @@ static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
cmd640_hardware_init(pdev);
- return ata_pci_sff_init_one(pdev, ppi, &cmd640_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &cmd640_sht, NULL, 0);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int cmd640_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -252,27 +256,16 @@ static struct pci_driver cmd640_pci_driver = {
.id_table = cmd640,
.probe = cmd640_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = cmd640_reinit_one,
#endif
};
-static int __init cmd640_init(void)
-{
- return pci_register_driver(&cmd640_pci_driver);
-}
-
-static void __exit cmd640_exit(void)
-{
- pci_unregister_driver(&cmd640_pci_driver);
-}
+module_pci_driver(cmd640_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for CMD640 PATA controllers");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, cmd640);
MODULE_VERSION(DRV_VERSION);
-
-module_init(cmd640_init);
-module_exit(cmd640_exit);
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index ddd09b7d98c..13ca5883285 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -1,7 +1,9 @@
/*
* pata_cmd64x.c - CMD64x PATA for new ATA layer
* (C) 2005 Red Hat Inc
- * Alan Cox <alan@redhat.com>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
+ * (C) 2009-2010 Bartlomiej Zolnierkiewicz
+ * (C) 2012 MontaVista Software, LLC <source@mvista.com>
*
* Based upon
* linux/drivers/ide/pci/cmd64x.c Version 1.30 Sept 10, 2002
@@ -24,14 +26,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "pata_cmd64x"
-#define DRV_VERSION "0.2.5"
+#define DRV_VERSION "0.2.18"
/*
* CMD64x specific registers definition.
@@ -39,11 +40,10 @@
enum {
CFR = 0x50,
- CFR_INTR_CH0 = 0x02,
- CNTRL = 0x51,
- CNTRL_DIS_RA0 = 0x40,
- CNTRL_DIS_RA1 = 0x80,
- CNTRL_ENA_2ND = 0x08,
+ CFR_INTR_CH0 = 0x04,
+ CNTRL = 0x51,
+ CNTRL_CH0 = 0x04,
+ CNTRL_CH1 = 0x08,
CMDTIM = 0x52,
ARTTIM0 = 0x53,
DRWTIM0 = 0x54,
@@ -53,9 +53,6 @@ enum {
ARTTIM23_DIS_RA2 = 0x04,
ARTTIM23_DIS_RA3 = 0x08,
ARTTIM23_INTR_CH1 = 0x10,
- ARTTIM2 = 0x57,
- ARTTIM3 = 0x57,
- DRWTIM23 = 0x58,
DRWTIM2 = 0x58,
BRST = 0x59,
DRWTIM3 = 0x5b,
@@ -63,14 +60,11 @@ enum {
MRDMODE = 0x71,
MRDMODE_INTR_CH0 = 0x04,
MRDMODE_INTR_CH1 = 0x08,
- MRDMODE_BLK_CH0 = 0x10,
- MRDMODE_BLK_CH1 = 0x20,
BMIDESR0 = 0x72,
UDIDETCR0 = 0x73,
DTPR0 = 0x74,
BMIDECR1 = 0x78,
BMIDECSR = 0x79,
- BMIDESR1 = 0x7A,
UDIDETCR1 = 0x7B,
DTPR1 = 0x7C
};
@@ -88,7 +82,7 @@ static int cmd648_cable_detect(struct ata_port *ap)
}
/**
- * cmd64x_set_piomode - set PIO and MWDMA timing
+ * cmd64x_set_timing - set PIO and MWDMA timing
* @ap: ATA interface
* @adev: ATA device
* @mode: mode
@@ -147,7 +141,9 @@ static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 m
/* Now convert the clocks into values we can actually stuff into
the chip */
- if (t.recover > 1)
+ if (t.recover == 16)
+ t.recover = 0;
+ else if (t.recover > 1)
t.recover--;
else
t.recover = 15;
@@ -219,7 +215,7 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
regU |= udma_data[adev->dma_mode - XFER_UDMA_0] << shift;
/* Merge the control bits */
regU |= 1 << adev->devno; /* UDMA on */
- if (adev->dma_mode > 2) /* 15nS timing */
+ if (adev->dma_mode > XFER_UDMA_2) /* 15nS timing */
regU |= 4 << adev->devno;
} else {
regU &= ~ (1 << adev->devno); /* UDMA off */
@@ -233,28 +229,85 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
}
/**
- * cmd648_dma_stop - DMA stop callback
- * @qc: Command in progress
+ * cmd64x_sff_irq_check - check IDE interrupt
+ * @ap: ATA interface
*
- * DMA has completed.
+ * Check IDE interrupt in CFR/ARTTIM23 registers.
*/
-static void cmd648_bmdma_stop(struct ata_queued_cmd *qc)
+static bool cmd64x_sff_irq_check(struct ata_port *ap)
{
- struct ata_port *ap = qc->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u8 dma_intr;
- int dma_mask = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
- int dma_reg = ap->port_no ? ARTTIM2 : CFR;
+ int irq_mask = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
+ int irq_reg = ap->port_no ? ARTTIM23 : CFR;
+ u8 irq_stat;
- ata_bmdma_stop(qc);
+ /* NOTE: reading the register should clear the interrupt */
+ pci_read_config_byte(pdev, irq_reg, &irq_stat);
+
+ return irq_stat & irq_mask;
+}
+
+/**
+ * cmd64x_sff_irq_clear - clear IDE interrupt
+ * @ap: ATA interface
+ *
+ * Clear IDE interrupt in CFR/ARTTIM23 and DMA status registers.
+ */
+
+static void cmd64x_sff_irq_clear(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int irq_reg = ap->port_no ? ARTTIM23 : CFR;
+ u8 irq_stat;
+
+ ata_bmdma_irq_clear(ap);
+
+ /* Reading the register should be enough to clear the interrupt */
+ pci_read_config_byte(pdev, irq_reg, &irq_stat);
+}
+
+/**
+ * cmd648_sff_irq_check - check IDE interrupt
+ * @ap: ATA interface
+ *
+ * Check IDE interrupt in MRDMODE register.
+ */
+
+static bool cmd648_sff_irq_check(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned long base = pci_resource_start(pdev, 4);
+ int irq_mask = ap->port_no ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
+ u8 mrdmode = inb(base + 1);
- pci_read_config_byte(pdev, dma_reg, &dma_intr);
- pci_write_config_byte(pdev, dma_reg, dma_intr | dma_mask);
+ return mrdmode & irq_mask;
}
/**
- * cmd646r1_dma_stop - DMA stop callback
+ * cmd648_sff_irq_clear - clear IDE interrupt
+ * @ap: ATA interface
+ *
+ * Clear IDE interrupt in MRDMODE and DMA status registers.
+ */
+
+static void cmd648_sff_irq_clear(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned long base = pci_resource_start(pdev, 4);
+ int irq_mask = ap->port_no ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
+ u8 mrdmode;
+
+ ata_bmdma_irq_clear(ap);
+
+ /* Clear this port's interrupt bit (leaving the other port alone) */
+ mrdmode = inb(base + 1);
+ mrdmode &= ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1);
+ outb(mrdmode | irq_mask, base + 1);
+}
+
+/**
+ * cmd646r1_bmdma_stop - DMA stop callback
* @qc: Command in progress
*
* Stub for now while investigating the r1 quirk in the old driver.
@@ -277,124 +330,175 @@ static const struct ata_port_operations cmd64x_base_ops = {
static struct ata_port_operations cmd64x_port_ops = {
.inherits = &cmd64x_base_ops,
+ .sff_irq_check = cmd64x_sff_irq_check,
+ .sff_irq_clear = cmd64x_sff_irq_clear,
.cable_detect = ata_cable_40wire,
};
static struct ata_port_operations cmd646r1_port_ops = {
.inherits = &cmd64x_base_ops,
+ .sff_irq_check = cmd64x_sff_irq_check,
+ .sff_irq_clear = cmd64x_sff_irq_clear,
.bmdma_stop = cmd646r1_bmdma_stop,
.cable_detect = ata_cable_40wire,
};
+static struct ata_port_operations cmd646r3_port_ops = {
+ .inherits = &cmd64x_base_ops,
+ .sff_irq_check = cmd648_sff_irq_check,
+ .sff_irq_clear = cmd648_sff_irq_clear,
+ .cable_detect = ata_cable_40wire,
+};
+
static struct ata_port_operations cmd648_port_ops = {
.inherits = &cmd64x_base_ops,
- .bmdma_stop = cmd648_bmdma_stop,
+ .sff_irq_check = cmd648_sff_irq_check,
+ .sff_irq_clear = cmd648_sff_irq_clear,
.cable_detect = cmd648_cable_detect,
};
-static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+static void cmd64x_fixup(struct pci_dev *pdev)
{
- u32 class_rev;
+ u8 mrdmode;
- static const struct ata_port_info cmd_info[6] = {
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+ pci_read_config_byte(pdev, MRDMODE, &mrdmode);
+ mrdmode &= ~0x30; /* IRQ set up */
+ mrdmode |= 0x02; /* Memory read line enable */
+ pci_write_config_byte(pdev, MRDMODE, mrdmode);
+
+ /* PPC specific fixup copied from old driver */
+#ifdef CONFIG_PPC
+ pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
+#endif
+}
+
+static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static const struct ata_port_info cmd_info[7] = {
{ /* CMD 643 - no UDMA */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.port_ops = &cmd64x_port_ops
},
{ /* CMD 646 with broken UDMA */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.port_ops = &cmd64x_port_ops
},
- { /* CMD 646 with working UDMA */
+ { /* CMD 646U with broken UDMA */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .port_ops = &cmd646r3_port_ops
+ },
+ { /* CMD 646U2 with working UDMA */
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA2,
- .port_ops = &cmd64x_port_ops
+ .port_ops = &cmd646r3_port_ops
},
{ /* CMD 646 rev 1 */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.port_ops = &cmd646r1_port_ops
},
{ /* CMD 648 */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA4,
.port_ops = &cmd648_port_ops
},
{ /* CMD 649 */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &cmd648_port_ops
}
};
- const struct ata_port_info *ppi[] = { &cmd_info[id->driver_data], NULL };
- u8 mrdmode;
+ const struct ata_port_info *ppi[] = {
+ &cmd_info[id->driver_data],
+ &cmd_info[id->driver_data],
+ NULL
+ };
+ u8 reg;
int rc;
+ struct pci_dev *bridge = pdev->bus->self;
+ /* mobility split bridges don't report enabled ports correctly */
+ int port_ok = !(bridge && bridge->vendor ==
+ PCI_VENDOR_ID_MOBILITY_ELECTRONICS);
+ /* all (with exceptions below) apart from 643 have CNTRL_CH0 bit */
+ int cntrl_ch0_ok = (id->driver_data != 0);
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xFF;
-
if (id->driver_data == 0) /* 643 */
ata_pci_bmdma_clear_simplex(pdev);
- if (pdev->device == PCI_DEVICE_ID_CMD_646) {
- /* Does UDMA work ? */
- if (class_rev > 4)
- ppi[0] = &cmd_info[2];
- /* Early rev with other problems ? */
- else if (class_rev == 1)
+ if (pdev->device == PCI_DEVICE_ID_CMD_646)
+ switch (pdev->revision) {
+ /* UDMA works since rev 5 */
+ default:
ppi[0] = &cmd_info[3];
- }
+ ppi[1] = &cmd_info[3];
+ break;
+ /* Interrupts in MRDMODE since rev 3 */
+ case 3:
+ case 4:
+ ppi[0] = &cmd_info[2];
+ ppi[1] = &cmd_info[2];
+ break;
+ /* Rev 1 with other problems? */
+ case 1:
+ ppi[0] = &cmd_info[4];
+ ppi[1] = &cmd_info[4];
+ /* FALL THRU */
+ /* Early revs have no CNTRL_CH0 */
+ case 2:
+ case 0:
+ cntrl_ch0_ok = 0;
+ break;
+ }
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
- pci_read_config_byte(pdev, MRDMODE, &mrdmode);
- mrdmode &= ~ 0x30; /* IRQ set up */
- mrdmode |= 0x02; /* Memory read line enable */
- pci_write_config_byte(pdev, MRDMODE, mrdmode);
+ cmd64x_fixup(pdev);
- /* Force PIO 0 here.. */
+ /* check for enabled ports */
+ pci_read_config_byte(pdev, CNTRL, &reg);
+ if (!port_ok)
+ dev_notice(&pdev->dev, "Mobility Bridge detected, ignoring CNTRL port enable/disable\n");
+ if (port_ok && cntrl_ch0_ok && !(reg & CNTRL_CH0)) {
+ dev_notice(&pdev->dev, "Primary port is disabled\n");
+ ppi[0] = &ata_dummy_port_info;
- /* PPC specific fixup copied from old driver */
-#ifdef CONFIG_PPC
- pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
-#endif
+ }
+ if (port_ok && !(reg & CNTRL_CH1)) {
+ dev_notice(&pdev->dev, "Secondary port is disabled\n");
+ ppi[1] = &ata_dummy_port_info;
+ }
- return ata_pci_sff_init_one(pdev, ppi, &cmd64x_sht, NULL);
+ return ata_pci_bmdma_init_one(pdev, ppi, &cmd64x_sht, NULL, 0);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int cmd64x_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
- u8 mrdmode;
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
if (rc)
return rc;
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
- pci_read_config_byte(pdev, MRDMODE, &mrdmode);
- mrdmode &= ~ 0x30; /* IRQ set up */
- mrdmode |= 0x02; /* Memory read line enable */
- pci_write_config_byte(pdev, MRDMODE, mrdmode);
-#ifdef CONFIG_PPC
- pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
-#endif
+ cmd64x_fixup(pdev);
+
ata_host_resume(host);
return 0;
}
@@ -403,8 +507,8 @@ static int cmd64x_reinit_one(struct pci_dev *pdev)
static const struct pci_device_id cmd64x[] = {
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
- { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 4 },
- { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 5 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 5 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 6 },
{ },
};
@@ -414,27 +518,16 @@ static struct pci_driver cmd64x_pci_driver = {
.id_table = cmd64x,
.probe = cmd64x_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = cmd64x_reinit_one,
#endif
};
-static int __init cmd64x_init(void)
-{
- return pci_register_driver(&cmd64x_pci_driver);
-}
-
-static void __exit cmd64x_exit(void)
-{
- pci_unregister_driver(&cmd64x_pci_driver);
-}
+module_pci_driver(cmd64x_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for CMD64x series PATA controllers");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, cmd64x);
MODULE_VERSION(DRV_VERSION);
-
-module_init(cmd64x_init);
-module_exit(cmd64x_exit);
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 1186bcd2781..d65cb9d2fa8 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -29,12 +29,11 @@
* General Public License for more details.
*
* Documentation:
- * Not publically available.
+ * Not publicly available.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
@@ -90,48 +89,12 @@ static void cs5520_set_timings(struct ata_port *ap, struct ata_device *adev, int
}
/**
- * cs5520_enable_dma - turn on DMA bits
- *
- * Turn on the DMA bits for this disk. Needed because the BIOS probably
- * has not done the work for us. Belongs in the core SATA code.
- */
-
-static void cs5520_enable_dma(struct ata_port *ap, struct ata_device *adev)
-{
- /* Set the DMA enable/disable flag */
- u8 reg = ioread8(ap->ioaddr.bmdma_addr + 0x02);
- reg |= 1<<(adev->devno + 5);
- iowrite8(reg, ap->ioaddr.bmdma_addr + 0x02);
-}
-
-/**
- * cs5520_set_dmamode - program DMA timings
- * @ap: ATA port
- * @adev: ATA device
- *
- * Program the DMA mode timings for the controller according to the pio
- * clocking table. Note that this device sets the DMA timings to PIO
- * mode values. This may seem bizarre but the 5520 architecture talks
- * PIO mode to the disk and DMA mode to the controller so the underlying
- * transfers are PIO timed.
- */
-
-static void cs5520_set_dmamode(struct ata_port *ap, struct ata_device *adev)
-{
- static const int dma_xlate[3] = { XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 };
- cs5520_set_timings(ap, adev, dma_xlate[adev->dma_mode]);
- cs5520_enable_dma(ap, adev);
-}
-
-/**
* cs5520_set_piomode - program PIO timings
* @ap: ATA port
* @adev: ATA device
*
* Program the PIO mode timings for the controller according to the pio
- * clocking table. We know pio_mode will equal dma_mode because of the
- * CS5520 architecture. At least once we turned DMA on and wrote a
- * mode setter.
+ * clocking table.
*/
static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev)
@@ -146,19 +109,18 @@ static struct scsi_host_template cs5520_sht = {
static struct ata_port_operations cs5520_port_ops = {
.inherits = &ata_bmdma_port_ops,
- .qc_prep = ata_sff_dumb_qc_prep,
+ .qc_prep = ata_bmdma_dumb_qc_prep,
.cable_detect = ata_cable_40wire,
.set_piomode = cs5520_set_piomode,
- .set_dmamode = cs5520_set_dmamode,
};
-static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+static int cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
static const unsigned int cmd_port[] = { 0x1F0, 0x170 };
static const unsigned int ctl_port[] = { 0x3F6, 0x376 };
struct ata_port_info pi = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
+ .pio_mask = ATA_PIO4,
.port_ops = &cs5520_port_ops,
};
const struct ata_port_info *ppi[2];
@@ -186,8 +148,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
ppi[1] = &pi;
if ((pcicfg & 0x40) == 0) {
- dev_printk(KERN_WARNING, &pdev->dev,
- "DMA mode disabled. Enabling.\n");
+ dev_warn(&pdev->dev, "DMA mode disabled. Enabling.\n");
pci_write_config_byte(pdev, 0x60, pcicfg | 0x40);
}
@@ -203,11 +164,11 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
return -ENODEV;
}
- if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
printk(KERN_ERR DRV_NAME ": unable to configure DMA mask.\n");
return -ENODEV;
}
- if (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+ if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
printk(KERN_ERR DRV_NAME ": unable to configure consistent DMA mask.\n");
return -ENODEV;
}
@@ -258,7 +219,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
continue;
rc = devm_request_irq(&pdev->dev, irq[ap->port_no],
- ata_sff_interrupt, 0, DRV_NAME, host);
+ ata_bmdma_interrupt, 0, DRV_NAME, host);
if (rc)
return rc;
@@ -268,7 +229,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
return ata_host_register(host, &cs5520_sht);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/**
* cs5520_reinit_one - device resume
* @pdev: PCI device
@@ -279,7 +240,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
static int cs5520_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
u8 pcicfg;
int rc;
@@ -307,7 +268,7 @@ static int cs5520_reinit_one(struct pci_dev *pdev)
static int cs5520_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc = 0;
rc = ata_host_suspend(host, mesg);
@@ -317,7 +278,7 @@ static int cs5520_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
pci_save_state(pdev);
return 0;
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
/* For now keep DMA off. We can set it for all but A rev CS5510 once the
core ATA code can handle it */
@@ -334,28 +295,16 @@ static struct pci_driver cs5520_pci_driver = {
.id_table = pata_cs5520,
.probe = cs5520_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = cs5520_pci_device_suspend,
.resume = cs5520_reinit_one,
#endif
};
-static int __init cs5520_init(void)
-{
- return pci_register_driver(&cs5520_pci_driver);
-}
-
-static void __exit cs5520_exit(void)
-{
- pci_unregister_driver(&cs5520_pci_driver);
-}
+module_pci_driver(cs5520_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Cyrix CS5510/5520");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, pata_cs5520);
MODULE_VERSION(DRV_VERSION);
-
-module_init(cs5520_init);
-module_exit(cs5520_exit);
-
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index 744beebaaf4..48ae4b43447 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -1,7 +1,6 @@
/*
* pata-cs5530.c - CS5530 PATA for new ATA layer
* (C) 2005 Red Hat Inc
- * Alan Cox <alan@redhat.com>
*
* based upon cs5530.c by Mark Lord.
*
@@ -27,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
@@ -149,15 +147,15 @@ static unsigned int cs5530_qc_issue(struct ata_queued_cmd *qc)
struct ata_device *prev = ap->private_data;
/* See if the DMA settings could be wrong */
- if (adev->dma_mode != 0 && adev != prev && prev != NULL) {
+ if (ata_dma_enabled(adev) && adev != prev && prev != NULL) {
/* Maybe, but do the channels match MWDMA/UDMA ? */
- if ((adev->dma_mode >= XFER_UDMA_0 && prev->dma_mode < XFER_UDMA_0) ||
- (adev->dma_mode < XFER_UDMA_0 && prev->dma_mode >= XFER_UDMA_0))
+ if ((ata_using_udma(adev) && !ata_using_udma(prev)) ||
+ (ata_using_udma(prev) && !ata_using_udma(adev)))
/* Switch the mode bits */
cs5530_set_dmamode(ap, adev);
}
- return ata_sff_qc_issue(qc);
+ return ata_bmdma_qc_issue(qc);
}
static struct scsi_host_template cs5530_sht = {
@@ -168,7 +166,7 @@ static struct scsi_host_template cs5530_sht = {
static struct ata_port_operations cs5530_port_ops = {
.inherits = &ata_bmdma_port_ops,
- .qc_prep = ata_sff_dumb_qc_prep,
+ .qc_prep = ata_bmdma_dumb_qc_prep,
.qc_issue = cs5530_qc_issue,
.cable_detect = ata_cable_40wire,
@@ -299,15 +297,15 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
.port_ops = &cs5530_port_ops
};
/* The docking connector doesn't do UDMA, and it seems not MWDMA */
static const struct ata_port_info info_palmax_secondary = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
+ .pio_mask = ATA_PIO4,
.port_ops = &cs5530_port_ops
};
const struct ata_port_info *ppi[] = { &info, NULL };
@@ -325,13 +323,13 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
ppi[1] = &info_palmax_secondary;
/* Now kick off ATA set up */
- return ata_pci_sff_init_one(pdev, ppi, &cs5530_sht, NULL);
+ return ata_pci_bmdma_init_one(pdev, ppi, &cs5530_sht, NULL, 0);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int cs5530_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -345,7 +343,7 @@ static int cs5530_reinit_one(struct pci_dev *pdev)
ata_host_resume(host);
return 0;
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static const struct pci_device_id cs5530[] = {
{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
@@ -358,27 +356,16 @@ static struct pci_driver cs5530_pci_driver = {
.id_table = cs5530,
.probe = cs5530_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = cs5530_reinit_one,
#endif
};
-static int __init cs5530_init(void)
-{
- return pci_register_driver(&cs5530_pci_driver);
-}
-
-static void __exit cs5530_exit(void)
-{
- pci_unregister_driver(&cs5530_pci_driver);
-}
+module_pci_driver(cs5530_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the Cyrix/NS/AMD 5530");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, cs5530);
MODULE_VERSION(DRV_VERSION);
-
-module_init(cs5530_init);
-module_exit(cs5530_exit);
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index f1b6556f048..97584e8456d 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -1,10 +1,10 @@
/*
* pata-cs5535.c - CS5535 PATA for new ATA layer
* (C) 2005-2006 Red Hat Inc
- * Alan Cox <alan@redhat.com>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* based upon cs5535.c from AMD <Jens.Altmann@amd.com> as cleaned up and
- * made readable and Linux style by Wolfgang Zuleger <wolfgang.zuleger@gmx.de
+ * made readable and Linux style by Wolfgang Zuleger <wolfgang.zuleger@gmx.de>
* and Alexander Kiausch <alex.kiausch@t-online.de>
*
* This program is free software; you can redistribute it and/or modify
@@ -31,14 +31,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <asm/msr.h>
-#define DRV_NAME "cs5535"
+#define DRV_NAME "pata_cs5535"
#define DRV_VERSION "0.2.12"
/*
@@ -67,12 +66,9 @@
#define CS5535_CABLE_DETECT 0x48
-#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL)==0x00009172 )
-
/**
* cs5535_cable_detect - detect cable type
* @ap: Port to detect on
- * @deadline: deadline jiffies for the operation
*
* Perform cable detection for ATA66 capable cable. Return a libata
* cable type.
@@ -101,7 +97,7 @@ static int cs5535_cable_detect(struct ata_port *ap)
static void cs5535_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
static const u16 pio_timings[5] = {
- 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131
+ 0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131
};
static const u16 pio_cmd_timings[5] = {
0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131
@@ -182,28 +178,19 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA4,
.port_ops = &cs5535_port_ops
};
const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
- u32 timings, dummy;
-
- /* Check the BIOS set the initial timing clock. If not set the
- timings for PIO0 */
- rdmsr(ATAC_CH0D0_PIO, timings, dummy);
- if (CS5535_BAD_PIO(timings))
- wrmsr(ATAC_CH0D0_PIO, 0xF7F4F7F4UL, 0);
- rdmsr(ATAC_CH0D1_PIO, timings, dummy);
- if (CS5535_BAD_PIO(timings))
- wrmsr(ATAC_CH0D1_PIO, 0xF7F4F7F4UL, 0);
- return ata_pci_sff_init_one(dev, ppi, &cs5535_sht, NULL);
+ return ata_pci_bmdma_init_one(dev, ppi, &cs5535_sht, NULL, 0);
}
static const struct pci_device_id cs5535[] = {
- { PCI_VDEVICE(NS, 0x002D), },
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_CS5535_IDE), },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5535_IDE), },
{ },
};
@@ -213,27 +200,16 @@ static struct pci_driver cs5535_pci_driver = {
.id_table = cs5535,
.probe = cs5535_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init cs5535_init(void)
-{
- return pci_register_driver(&cs5535_pci_driver);
-}
-
-static void __exit cs5535_exit(void)
-{
- pci_unregister_driver(&cs5535_pci_driver);
-}
+module_pci_driver(cs5535_pci_driver);
MODULE_AUTHOR("Alan Cox, Jens Altmann, Wolfgan Zuleger, Alexander Kiausch");
-MODULE_DESCRIPTION("low-level driver for the NS/AMD 5530");
+MODULE_DESCRIPTION("low-level driver for the NS/AMD 5535");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, cs5535);
MODULE_VERSION(DRV_VERSION);
-
-module_init(cs5535_init);
-module_exit(cs5535_exit);
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c
index 73f8332cb67..6c15a554efb 100644
--- a/drivers/ata/pata_cs5536.c
+++ b/drivers/ata/pata_cs5536.c
@@ -1,6 +1,7 @@
/*
* pata_cs5536.c - CS5536 PATA for new ATA layer
* (C) 2007 Martin K. Petersen <mkp@mkp.net>
+ * (C) 2011 Bartlomiej Zolnierkiewicz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -32,35 +33,39 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/libata.h>
#include <scsi/scsi_host.h>
+#include <linux/dmi.h>
+
+#ifdef CONFIG_X86_32
#include <asm/msr.h>
+static int use_msr;
+module_param_named(msr, use_msr, int, 0644);
+MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
+#else
+#undef rdmsr /* avoid accidental MSR usage on, e.g. x86-64 */
+#undef wrmsr
+#define rdmsr(x, y, z) do { } while (0)
+#define wrmsr(x, y, z) do { } while (0)
+#define use_msr 0
+#endif
#define DRV_NAME "pata_cs5536"
-#define DRV_VERSION "0.0.7"
+#define DRV_VERSION "0.0.8"
enum {
- CFG = 0,
- DTC = 1,
- CAST = 2,
- ETC = 3,
-
- MSR_IDE_BASE = 0x51300000,
- MSR_IDE_CFG = (MSR_IDE_BASE + 0x10),
- MSR_IDE_DTC = (MSR_IDE_BASE + 0x12),
- MSR_IDE_CAST = (MSR_IDE_BASE + 0x13),
- MSR_IDE_ETC = (MSR_IDE_BASE + 0x14),
-
+ MSR_IDE_CFG = 0x51300010,
PCI_IDE_CFG = 0x40,
- PCI_IDE_DTC = 0x48,
- PCI_IDE_CAST = 0x4c,
- PCI_IDE_ETC = 0x50,
- IDE_CFG_CHANEN = 0x2,
- IDE_CFG_CABLE = 0x10000,
+ CFG = 0,
+ DTC = 2,
+ CAST = 3,
+ ETC = 4,
+
+ IDE_CFG_CHANEN = (1 << 1),
+ IDE_CFG_CABLE = (1 << 17) | (1 << 16),
IDE_D0_SHIFT = 24,
IDE_D1_SHIFT = 16,
@@ -72,48 +77,65 @@ enum {
IDE_CAST_CMD_MASK = 0xff,
IDE_CAST_CMD_SHIFT = 24,
- IDE_ETC_NODMA = 0x03,
+ IDE_ETC_UDMA_MASK = 0xc0,
};
-static int use_msr;
-
-static const u32 msr_reg[4] = {
- MSR_IDE_CFG, MSR_IDE_DTC, MSR_IDE_CAST, MSR_IDE_ETC,
-};
-
-static const u8 pci_reg[4] = {
- PCI_IDE_CFG, PCI_IDE_DTC, PCI_IDE_CAST, PCI_IDE_ETC,
+/* Some Bachmann OT200 devices have a non working UDMA support due a
+ * missing resistor.
+ */
+static const struct dmi_system_id udma_quirk_dmi_table[] = {
+ {
+ .ident = "Bachmann electronic OT200",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Bachmann electronic"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OT200"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "1")
+ },
+ },
+ { }
};
-static inline int cs5536_read(struct pci_dev *pdev, int reg, u32 *val)
+static int cs5536_read(struct pci_dev *pdev, int reg, u32 *val)
{
if (unlikely(use_msr)) {
- u32 dummy;
+ u32 dummy __maybe_unused;
- rdmsr(msr_reg[reg], *val, dummy);
+ rdmsr(MSR_IDE_CFG + reg, *val, dummy);
return 0;
}
- return pci_read_config_dword(pdev, pci_reg[reg], val);
+ return pci_read_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);
}
-static inline int cs5536_write(struct pci_dev *pdev, int reg, int val)
+static int cs5536_write(struct pci_dev *pdev, int reg, int val)
{
if (unlikely(use_msr)) {
- wrmsr(msr_reg[reg], val, 0);
+ wrmsr(MSR_IDE_CFG + reg, val, 0);
return 0;
}
- return pci_write_config_dword(pdev, pci_reg[reg], val);
+ return pci_write_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);
+}
+
+static void cs5536_program_dtc(struct ata_device *adev, u8 tim)
+{
+ struct pci_dev *pdev = to_pci_dev(adev->link->ap->host->dev);
+ int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT;
+ u32 dtc;
+
+ cs5536_read(pdev, DTC, &dtc);
+ dtc &= ~(IDE_DRV_MASK << dshift);
+ dtc |= tim << dshift;
+ cs5536_write(pdev, DTC, dtc);
}
/**
* cs5536_cable_detect - detect cable type
* @ap: Port to detect on
- * @deadline: deadline jiffies for the operation
*
- * Perform cable detection for ATA66 capable cable. Return a libata
- * cable type.
+ * Perform cable detection for ATA66 capable cable.
+ *
+ * Returns a cable type.
*/
static int cs5536_cable_detect(struct ata_port *ap)
@@ -123,7 +145,7 @@ static int cs5536_cable_detect(struct ata_port *ap)
cs5536_read(pdev, CFG, &cfg);
- if (cfg & (IDE_CFG_CABLE << ap->port_no))
+ if (cfg & IDE_CFG_CABLE)
return ATA_CBL_PATA80;
else
return ATA_CBL_PATA40;
@@ -153,19 +175,15 @@ static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev)
struct ata_device *pair = ata_dev_pair(adev);
int mode = adev->pio_mode - XFER_PIO_0;
int cmdmode = mode;
- int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT;
int cshift = adev->devno ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;
- u32 dtc, cast, etc;
+ u32 cast;
if (pair)
cmdmode = min(mode, pair->pio_mode - XFER_PIO_0);
- cs5536_read(pdev, DTC, &dtc);
- cs5536_read(pdev, CAST, &cast);
- cs5536_read(pdev, ETC, &etc);
+ cs5536_program_dtc(adev, drv_timings[mode]);
- dtc &= ~(IDE_DRV_MASK << dshift);
- dtc |= drv_timings[mode] << dshift;
+ cs5536_read(pdev, CAST, &cast);
cast &= ~(IDE_CAST_DRV_MASK << cshift);
cast |= addr_timings[mode] << cshift;
@@ -173,12 +191,7 @@ static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev)
cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT);
cast |= cmd_timings[cmdmode] << IDE_CAST_CMD_SHIFT;
- etc &= ~(IDE_DRV_MASK << dshift);
- etc |= IDE_ETC_NODMA << dshift;
-
- cs5536_write(pdev, DTC, dtc);
cs5536_write(pdev, CAST, cast);
- cs5536_write(pdev, ETC, etc);
}
/**
@@ -199,25 +212,21 @@ static void cs5536_set_dmamode(struct ata_port *ap, struct ata_device *adev)
};
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 dtc, etc;
+ u32 etc;
int mode = adev->dma_mode;
int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT;
- if (mode >= XFER_UDMA_0) {
- cs5536_read(pdev, ETC, &etc);
+ cs5536_read(pdev, ETC, &etc);
+ if (mode >= XFER_UDMA_0) {
etc &= ~(IDE_DRV_MASK << dshift);
etc |= udma_timings[mode - XFER_UDMA_0] << dshift;
-
- cs5536_write(pdev, ETC, etc);
} else { /* MWDMA */
- cs5536_read(pdev, DTC, &dtc);
-
- dtc &= ~(IDE_DRV_MASK << dshift);
- dtc |= mwdma_timings[mode - XFER_MW_DMA_0] << dshift;
-
- cs5536_write(pdev, DTC, dtc);
+ etc &= ~(IDE_ETC_UDMA_MASK << dshift);
+ cs5536_program_dtc(adev, mwdma_timings[mode - XFER_MW_DMA_0]);
}
+
+ cs5536_write(pdev, ETC, etc);
}
static struct scsi_host_template cs5536_sht = {
@@ -225,7 +234,7 @@ static struct scsi_host_template cs5536_sht = {
};
static struct ata_port_operations cs5536_port_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma32_port_ops,
.cable_detect = cs5536_cable_detect,
.set_piomode = cs5536_set_piomode,
.set_dmamode = cs5536_set_dmamode,
@@ -242,15 +251,29 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &cs5536_port_ops,
};
- const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
+ static const struct ata_port_info no_udma_info = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .port_ops = &cs5536_port_ops,
+ };
+
+
+ const struct ata_port_info *ppi[2];
u32 cfg;
+ if (dmi_check_system(udma_quirk_dmi_table))
+ ppi[0] = &no_udma_info;
+ else
+ ppi[0] = &info;
+
+ ppi[1] = &ata_dummy_port_info;
+
if (use_msr)
printk(KERN_ERR DRV_NAME ": Using MSR regs instead of PCI\n");
@@ -261,7 +284,7 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return -ENODEV;
}
- return ata_pci_sff_init_one(dev, ppi, &cs5536_sht, NULL);
+ return ata_pci_bmdma_init_one(dev, ppi, &cs5536_sht, NULL, 0);
}
static const struct pci_device_id cs5536[] = {
@@ -274,29 +297,16 @@ static struct pci_driver cs5536_pci_driver = {
.id_table = cs5536,
.probe = cs5536_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init cs5536_init(void)
-{
- return pci_register_driver(&cs5536_pci_driver);
-}
-
-static void __exit cs5536_exit(void)
-{
- pci_unregister_driver(&cs5536_pci_driver);
-}
+module_pci_driver(cs5536_pci_driver);
MODULE_AUTHOR("Martin K. Petersen");
MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, cs5536);
MODULE_VERSION(DRV_VERSION);
-module_param_named(msr, use_msr, int, 0644);
-MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
-
-module_init(cs5536_init);
-module_exit(cs5536_exit);
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index a9c3218e22f..793018460d8 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -1,7 +1,7 @@
/*
* pata_cypress.c - Cypress PATA for new ATA layer
* (C) 2006 Red Hat Inc
- * Alan Cox <alan@redhat.com>
+ * Alan Cox
*
* Based heavily on
* linux/drivers/ide/pci/cy82c693.c Version 0.40 Sep. 10, 2002
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
@@ -62,14 +61,16 @@ static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev)
return;
}
- time_16 = FIT(t.recover, 0, 15) | (FIT(t.active, 0, 15) << 4);
- time_8 = FIT(t.act8b, 0, 15) | (FIT(t.rec8b, 0, 15) << 4);
+ time_16 = clamp_val(t.recover - 1, 0, 15) |
+ (clamp_val(t.active - 1, 0, 15) << 4);
+ time_8 = clamp_val(t.act8b - 1, 0, 15) |
+ (clamp_val(t.rec8b - 1, 0, 15) << 4);
if (adev->devno == 0) {
pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
addr &= ~0x0F; /* Mask bits */
- addr |= FIT(t.setup, 0, 15);
+ addr |= clamp_val(t.setup - 1, 0, 15);
pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
pci_write_config_byte(pdev, CY82_IDE_MASTER_IOR, time_16);
@@ -79,7 +80,7 @@ static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev)
pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
addr &= ~0xF0; /* Mask bits */
- addr |= (FIT(t.setup, 0, 15) << 4);
+ addr |= (clamp_val(t.setup - 1, 0, 15) << 4);
pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOR, time_16);
@@ -124,8 +125,8 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i
{
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.port_ops = &cy82c693_port_ops
};
const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
@@ -136,7 +137,7 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i
if (PCI_FUNC(pdev->devfn) != 1)
return -ENODEV;
- return ata_pci_sff_init_one(pdev, ppi, &cy82c693_sht, NULL);
+ return ata_pci_bmdma_init_one(pdev, ppi, &cy82c693_sht, NULL, 0);
}
static const struct pci_device_id cy82c693[] = {
@@ -150,29 +151,16 @@ static struct pci_driver cy82c693_pci_driver = {
.id_table = cy82c693,
.probe = cy82c693_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init cy82c693_init(void)
-{
- return pci_register_driver(&cy82c693_pci_driver);
-}
-
-
-static void __exit cy82c693_exit(void)
-{
- pci_unregister_driver(&cy82c693_pci_driver);
-}
-
+module_pci_driver(cy82c693_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the CY82C693 PATA controller");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, cy82c693);
MODULE_VERSION(DRV_VERSION);
-
-module_init(cy82c693_init);
-module_exit(cy82c693_exit);
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index 9fba82976ba..4a57a6f032d 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -1,7 +1,8 @@
/*
* pata_efar.c - EFAR PIIX clone controller driver
*
- * (C) 2005 Red Hat <alan@redhat.com>
+ * (C) 2005 Red Hat
+ * (C) 2009-2010 Bartlomiej Zolnierkiewicz
*
* Some parts based on ata_piix.c by Jeff Garzik and others.
*
@@ -13,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -22,7 +22,7 @@
#include <linux/ata.h>
#define DRV_NAME "pata_efar"
-#define DRV_VERSION "0.4.4"
+#define DRV_VERSION "0.4.5"
/**
* efar_pre_reset - Enable bits
@@ -67,10 +67,12 @@ static int efar_cable_detect(struct ata_port *ap)
return ATA_CBL_PATA80;
}
+static DEFINE_SPINLOCK(efar_lock);
+
/**
* efar_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
- * @adev: um
+ * @adev: Device to program
*
* Set PIO mode for device, in host controller PCI config space.
*
@@ -82,8 +84,10 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
{
unsigned int pio = adev->pio_mode - XFER_PIO_0;
struct pci_dev *dev = to_pci_dev(ap->host->dev);
- unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
- u16 idetm_data;
+ unsigned int master_port = ap->port_no ? 0x42 : 0x40;
+ unsigned long flags;
+ u16 master_data;
+ u8 udma_enable;
int control = 0;
/*
@@ -98,39 +102,45 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
{ 2, 1 },
{ 2, 3 }, };
- if (pio > 2)
- control |= 1; /* TIME1 enable */
+ if (pio > 1)
+ control |= 1; /* TIME */
if (ata_pio_need_iordy(adev)) /* PIO 3/4 require IORDY */
- control |= 2; /* IE enable */
- /* Intel specifies that the PPE functionality is for disk only */
+ control |= 2; /* IE */
+ /* Intel specifies that the prefetch/posting is for disk only */
if (adev->class == ATA_DEV_ATA)
- control |= 4; /* PPE enable */
+ control |= 4; /* PPE */
- pci_read_config_word(dev, idetm_port, &idetm_data);
+ spin_lock_irqsave(&efar_lock, flags);
- /* Enable PPE, IE and TIME as appropriate */
+ pci_read_config_word(dev, master_port, &master_data);
+ /* Set PPE, IE, and TIME as appropriate */
if (adev->devno == 0) {
- idetm_data &= 0xCCF0;
- idetm_data |= control;
- idetm_data |= (timings[pio][0] << 12) |
+ master_data &= 0xCCF0;
+ master_data |= control;
+ master_data |= (timings[pio][0] << 12) |
(timings[pio][1] << 8);
} else {
int shift = 4 * ap->port_no;
u8 slave_data;
- idetm_data &= 0xCC0F;
- idetm_data |= (control << 4);
+ master_data &= 0xFF0F;
+ master_data |= (control << 4);
/* Slave timing in separate register */
pci_read_config_byte(dev, 0x44, &slave_data);
- slave_data &= 0x0F << shift;
+ slave_data &= ap->port_no ? 0x0F : 0xF0;
slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << shift;
pci_write_config_byte(dev, 0x44, slave_data);
}
- idetm_data |= 0x4000; /* Ensure SITRE is enabled */
- pci_write_config_word(dev, idetm_port, idetm_data);
+ master_data |= 0x4000; /* Ensure SITRE is set */
+ pci_write_config_word(dev, master_port, master_data);
+
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+ udma_enable &= ~(1 << (2 * ap->port_no + adev->devno));
+ pci_write_config_byte(dev, 0x48, udma_enable);
+ spin_unlock_irqrestore(&efar_lock, flags);
}
/**
@@ -151,6 +161,7 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
u16 master_data;
u8 speed = adev->dma_mode;
int devid = adev->devno + 2 * ap->port_no;
+ unsigned long flags;
u8 udma_enable;
static const /* ISP RTC */
@@ -160,6 +171,8 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
{ 2, 1 },
{ 2, 3 }, };
+ spin_lock_irqsave(&efar_lock, flags);
+
pci_read_config_word(dev, master_port, &master_data);
pci_read_config_byte(dev, 0x48, &udma_enable);
@@ -201,7 +214,7 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */
master_data |= control << 4;
pci_read_config_byte(dev, 0x44, &slave_data);
- slave_data &= (0x0F + 0xE1 * ap->port_no);
+ slave_data &= ap->port_no ? 0x0F : 0xF0;
/* Load the matching timing */
slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
pci_write_config_byte(dev, 0x44, slave_data);
@@ -217,6 +230,7 @@ static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
pci_write_config_word(dev, master_port, master_data);
}
pci_write_config_byte(dev, 0x48, udma_enable);
+ spin_unlock_irqrestore(&efar_lock, flags);
}
static struct scsi_host_template efar_sht = {
@@ -248,21 +262,19 @@ static struct ata_port_operations efar_ops = {
static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma1-2 */
- .udma_mask = 0x0f, /* UDMA 66 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA12_ONLY,
+ .udma_mask = ATA_UDMA4,
.port_ops = &efar_ops,
};
- const struct ata_port_info *ppi[] = { &info, NULL };
+ const struct ata_port_info *ppi[] = { &info, &info };
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev,
- "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
- return ata_pci_sff_init_one(pdev, ppi, &efar_sht, NULL);
+ return ata_pci_bmdma_init_one(pdev, ppi, &efar_sht, NULL,
+ ATA_HOST_PARALLEL_SCAN);
}
static const struct pci_device_id efar_pci_tbl[] = {
@@ -276,28 +288,16 @@ static struct pci_driver efar_pci_driver = {
.id_table = efar_pci_tbl,
.probe = efar_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init efar_init(void)
-{
- return pci_register_driver(&efar_pci_driver);
-}
-
-static void __exit efar_exit(void)
-{
- pci_unregister_driver(&efar_pci_driver);
-}
-
-module_init(efar_init);
-module_exit(efar_exit);
+module_pci_driver(efar_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("SCSI low-level driver for EFAR PIIX clones");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, efar_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
new file mode 100644
index 00000000000..4d37c5415fc
--- /dev/null
+++ b/drivers/ata/pata_ep93xx.c
@@ -0,0 +1,1037 @@
+/*
+ * EP93XX PATA controller driver.
+ *
+ * Copyright (c) 2012, Metasoft s.c.
+ * Rafal Prylowski <prylowski@metasoft.pl>
+ *
+ * Based on pata_scc.c, pata_icside.c and on earlier version of EP93XX
+ * PATA driver by Lennert Buytenhek and Alessandro Zummo.
+ * Read/Write timings, resource management and other improvements
+ * from driver by Joao Ramos and Bartlomiej Zolnierkiewicz.
+ * DMA engine support based on spi-ep93xx.c by Mika Westerberg.
+ *
+ * Original copyrights:
+ *
+ * Support for Cirrus Logic's EP93xx (EP9312, EP9315) CPUs
+ * PATA host controller driver.
+ *
+ * Copyright (c) 2009, Bartlomiej Zolnierkiewicz
+ *
+ * Heavily based on the ep93xx-ide.c driver:
+ *
+ * Copyright (c) 2009, Joao Ramos <joao.ramos@inov.pt>
+ * INESC Inovacao (INOV)
+ *
+ * EP93XX PATA controller driver.
+ * Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * An ATA driver for the Cirrus Logic EP93xx PATA controller.
+ *
+ * Based on an earlier version by Alessandro Zummo, which is:
+ * Copyright (C) 2006 Tower Technologies
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/ktime.h>
+
+#include <linux/platform_data/dma-ep93xx.h>
+#include <mach/platform.h>
+
+#define DRV_NAME "ep93xx-ide"
+#define DRV_VERSION "1.0"
+
+enum {
+ /* IDE Control Register */
+ IDECTRL = 0x00,
+ IDECTRL_CS0N = (1 << 0),
+ IDECTRL_CS1N = (1 << 1),
+ IDECTRL_DIORN = (1 << 5),
+ IDECTRL_DIOWN = (1 << 6),
+ IDECTRL_INTRQ = (1 << 9),
+ IDECTRL_IORDY = (1 << 10),
+ /*
+ * the device IDE register to be accessed is selected through
+ * IDECTRL register's specific bitfields 'DA', 'CS1N' and 'CS0N':
+ * b4 b3 b2 b1 b0
+ * A2 A1 A0 CS1N CS0N
+ * the values filled in this structure allows the value to be directly
+ * ORed to the IDECTRL register, hence giving directly the A[2:0] and
+ * CS1N/CS0N values for each IDE register.
+ * The values correspond to the transformation:
+ * ((real IDE address) << 2) | CS1N value << 1 | CS0N value
+ */
+ IDECTRL_ADDR_CMD = 0 + 2, /* CS1 */
+ IDECTRL_ADDR_DATA = (ATA_REG_DATA << 2) + 2,
+ IDECTRL_ADDR_ERROR = (ATA_REG_ERR << 2) + 2,
+ IDECTRL_ADDR_FEATURE = (ATA_REG_FEATURE << 2) + 2,
+ IDECTRL_ADDR_NSECT = (ATA_REG_NSECT << 2) + 2,
+ IDECTRL_ADDR_LBAL = (ATA_REG_LBAL << 2) + 2,
+ IDECTRL_ADDR_LBAM = (ATA_REG_LBAM << 2) + 2,
+ IDECTRL_ADDR_LBAH = (ATA_REG_LBAH << 2) + 2,
+ IDECTRL_ADDR_DEVICE = (ATA_REG_DEVICE << 2) + 2,
+ IDECTRL_ADDR_STATUS = (ATA_REG_STATUS << 2) + 2,
+ IDECTRL_ADDR_COMMAND = (ATA_REG_CMD << 2) + 2,
+ IDECTRL_ADDR_ALTSTATUS = (0x06 << 2) + 1, /* CS0 */
+ IDECTRL_ADDR_CTL = (0x06 << 2) + 1, /* CS0 */
+
+ /* IDE Configuration Register */
+ IDECFG = 0x04,
+ IDECFG_IDEEN = (1 << 0),
+ IDECFG_PIO = (1 << 1),
+ IDECFG_MDMA = (1 << 2),
+ IDECFG_UDMA = (1 << 3),
+ IDECFG_MODE_SHIFT = 4,
+ IDECFG_MODE_MASK = (0xf << 4),
+ IDECFG_WST_SHIFT = 8,
+ IDECFG_WST_MASK = (0x3 << 8),
+
+ /* MDMA Operation Register */
+ IDEMDMAOP = 0x08,
+
+ /* UDMA Operation Register */
+ IDEUDMAOP = 0x0c,
+ IDEUDMAOP_UEN = (1 << 0),
+ IDEUDMAOP_RWOP = (1 << 1),
+
+ /* PIO/MDMA/UDMA Data Registers */
+ IDEDATAOUT = 0x10,
+ IDEDATAIN = 0x14,
+ IDEMDMADATAOUT = 0x18,
+ IDEMDMADATAIN = 0x1c,
+ IDEUDMADATAOUT = 0x20,
+ IDEUDMADATAIN = 0x24,
+
+ /* UDMA Status Register */
+ IDEUDMASTS = 0x28,
+ IDEUDMASTS_DMAIDE = (1 << 16),
+ IDEUDMASTS_INTIDE = (1 << 17),
+ IDEUDMASTS_SBUSY = (1 << 18),
+ IDEUDMASTS_NDO = (1 << 24),
+ IDEUDMASTS_NDI = (1 << 25),
+ IDEUDMASTS_N4X = (1 << 26),
+
+ /* UDMA Debug Status Register */
+ IDEUDMADEBUG = 0x2c,
+};
+
+struct ep93xx_pata_data {
+ const struct platform_device *pdev;
+ void __iomem *ide_base;
+ struct ata_timing t;
+ bool iordy;
+
+ unsigned long udma_in_phys;
+ unsigned long udma_out_phys;
+
+ struct dma_chan *dma_rx_channel;
+ struct ep93xx_dma_data dma_rx_data;
+ struct dma_chan *dma_tx_channel;
+ struct ep93xx_dma_data dma_tx_data;
+};
+
+static void ep93xx_pata_clear_regs(void __iomem *base)
+{
+ writel(IDECTRL_CS0N | IDECTRL_CS1N | IDECTRL_DIORN |
+ IDECTRL_DIOWN, base + IDECTRL);
+
+ writel(0, base + IDECFG);
+ writel(0, base + IDEMDMAOP);
+ writel(0, base + IDEUDMAOP);
+ writel(0, base + IDEDATAOUT);
+ writel(0, base + IDEDATAIN);
+ writel(0, base + IDEMDMADATAOUT);
+ writel(0, base + IDEMDMADATAIN);
+ writel(0, base + IDEUDMADATAOUT);
+ writel(0, base + IDEUDMADATAIN);
+ writel(0, base + IDEUDMADEBUG);
+}
+
+static bool ep93xx_pata_check_iordy(void __iomem *base)
+{
+ return !!(readl(base + IDECTRL) & IDECTRL_IORDY);
+}
+
+/*
+ * According to EP93xx User's Guide, WST field of IDECFG specifies number
+ * of HCLK cycles to hold the data bus after a PIO write operation.
+ * It should be programmed to guarantee following delays:
+ *
+ * PIO Mode [ns]
+ * 0 30
+ * 1 20
+ * 2 15
+ * 3 10
+ * 4 5
+ *
+ * Maximum possible value for HCLK is 100MHz.
+ */
+static int ep93xx_pata_get_wst(int pio_mode)
+{
+ int val;
+
+ if (pio_mode == 0)
+ val = 3;
+ else if (pio_mode < 3)
+ val = 2;
+ else
+ val = 1;
+
+ return val << IDECFG_WST_SHIFT;
+}
+
+static void ep93xx_pata_enable_pio(void __iomem *base, int pio_mode)
+{
+ writel(IDECFG_IDEEN | IDECFG_PIO |
+ ep93xx_pata_get_wst(pio_mode) |
+ (pio_mode << IDECFG_MODE_SHIFT), base + IDECFG);
+}
+
+/*
+ * Based on delay loop found in mach-pxa/mp900.c.
+ *
+ * Single iteration should take 5 cpu cycles. This is 25ns assuming the
+ * fastest ep93xx cpu speed (200MHz) and is better optimized for PIO4 timings
+ * than eg. 20ns.
+ */
+static void ep93xx_pata_delay(unsigned long count)
+{
+ __asm__ volatile (
+ "0:\n"
+ "mov r0, r0\n"
+ "subs %0, %1, #1\n"
+ "bge 0b\n"
+ : "=r" (count)
+ : "0" (count)
+ );
+}
+
+static unsigned long ep93xx_pata_wait_for_iordy(void __iomem *base,
+ unsigned long t2)
+{
+ /*
+ * According to ATA specification, IORDY pin can be first sampled
+ * tA = 35ns after activation of DIOR-/DIOW-. Maximum IORDY pulse
+ * width is tB = 1250ns.
+ *
+ * We are already t2 delay loop iterations after activation of
+ * DIOR-/DIOW-, so we set timeout to (1250 + 35) / 25 - t2 additional
+ * delay loop iterations.
+ */
+ unsigned long start = (1250 + 35) / 25 - t2;
+ unsigned long counter = start;
+
+ while (!ep93xx_pata_check_iordy(base) && counter--)
+ ep93xx_pata_delay(1);
+ return start - counter;
+}
+
+/* common part at start of ep93xx_pata_read/write() */
+static void ep93xx_pata_rw_begin(void __iomem *base, unsigned long addr,
+ unsigned long t1)
+{
+ writel(IDECTRL_DIOWN | IDECTRL_DIORN | addr, base + IDECTRL);
+ ep93xx_pata_delay(t1);
+}
+
+/* common part at end of ep93xx_pata_read/write() */
+static void ep93xx_pata_rw_end(void __iomem *base, unsigned long addr,
+ bool iordy, unsigned long t0, unsigned long t2,
+ unsigned long t2i)
+{
+ ep93xx_pata_delay(t2);
+ /* lengthen t2 if needed */
+ if (iordy)
+ t2 += ep93xx_pata_wait_for_iordy(base, t2);
+ writel(IDECTRL_DIOWN | IDECTRL_DIORN | addr, base + IDECTRL);
+ if (t0 > t2 && t0 - t2 > t2i)
+ ep93xx_pata_delay(t0 - t2);
+ else
+ ep93xx_pata_delay(t2i);
+}
+
+static u16 ep93xx_pata_read(struct ep93xx_pata_data *drv_data,
+ unsigned long addr,
+ bool reg)
+{
+ void __iomem *base = drv_data->ide_base;
+ const struct ata_timing *t = &drv_data->t;
+ unsigned long t0 = reg ? t->cyc8b : t->cycle;
+ unsigned long t2 = reg ? t->act8b : t->active;
+ unsigned long t2i = reg ? t->rec8b : t->recover;
+
+ ep93xx_pata_rw_begin(base, addr, t->setup);
+ writel(IDECTRL_DIOWN | addr, base + IDECTRL);
+ /*
+ * The IDEDATAIN register is loaded from the DD pins at the positive
+ * edge of the DIORN signal. (EP93xx UG p27-14)
+ */
+ ep93xx_pata_rw_end(base, addr, drv_data->iordy, t0, t2, t2i);
+ return readl(base + IDEDATAIN);
+}
+
+/* IDE register read */
+static u16 ep93xx_pata_read_reg(struct ep93xx_pata_data *drv_data,
+ unsigned long addr)
+{
+ return ep93xx_pata_read(drv_data, addr, true);
+}
+
+/* PIO data read */
+static u16 ep93xx_pata_read_data(struct ep93xx_pata_data *drv_data,
+ unsigned long addr)
+{
+ return ep93xx_pata_read(drv_data, addr, false);
+}
+
+static void ep93xx_pata_write(struct ep93xx_pata_data *drv_data,
+ u16 value, unsigned long addr,
+ bool reg)
+{
+ void __iomem *base = drv_data->ide_base;
+ const struct ata_timing *t = &drv_data->t;
+ unsigned long t0 = reg ? t->cyc8b : t->cycle;
+ unsigned long t2 = reg ? t->act8b : t->active;
+ unsigned long t2i = reg ? t->rec8b : t->recover;
+
+ ep93xx_pata_rw_begin(base, addr, t->setup);
+ /*
+ * Value from IDEDATAOUT register is driven onto the DD pins when
+ * DIOWN is low. (EP93xx UG p27-13)
+ */
+ writel(value, base + IDEDATAOUT);
+ writel(IDECTRL_DIORN | addr, base + IDECTRL);
+ ep93xx_pata_rw_end(base, addr, drv_data->iordy, t0, t2, t2i);
+}
+
+/* IDE register write */
+static void ep93xx_pata_write_reg(struct ep93xx_pata_data *drv_data,
+ u16 value, unsigned long addr)
+{
+ ep93xx_pata_write(drv_data, value, addr, true);
+}
+
+/* PIO data write */
+static void ep93xx_pata_write_data(struct ep93xx_pata_data *drv_data,
+ u16 value, unsigned long addr)
+{
+ ep93xx_pata_write(drv_data, value, addr, false);
+}
+
+static void ep93xx_pata_set_piomode(struct ata_port *ap,
+ struct ata_device *adev)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ struct ata_device *pair = ata_dev_pair(adev);
+ /*
+ * Calculate timings for the delay loop, assuming ep93xx cpu speed
+ * is 200MHz (maximum possible for ep93xx). If actual cpu speed is
+ * slower, we will wait a bit longer in each delay.
+ * Additional division of cpu speed by 5, because single iteration
+ * of our delay loop takes 5 cpu cycles (25ns).
+ */
+ unsigned long T = 1000000 / (200 / 5);
+
+ ata_timing_compute(adev, adev->pio_mode, &drv_data->t, T, 0);
+ if (pair && pair->pio_mode) {
+ struct ata_timing t;
+ ata_timing_compute(pair, pair->pio_mode, &t, T, 0);
+ ata_timing_merge(&t, &drv_data->t, &drv_data->t,
+ ATA_TIMING_SETUP | ATA_TIMING_8BIT);
+ }
+ drv_data->iordy = ata_pio_need_iordy(adev);
+
+ ep93xx_pata_enable_pio(drv_data->ide_base,
+ adev->pio_mode - XFER_PIO_0);
+}
+
+/* Note: original code is ata_sff_check_status */
+static u8 ep93xx_pata_check_status(struct ata_port *ap)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ return ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_STATUS);
+}
+
+static u8 ep93xx_pata_check_altstatus(struct ata_port *ap)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ return ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_ALTSTATUS);
+}
+
+/* Note: original code is ata_sff_tf_load */
+static void ep93xx_pata_tf_load(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ ep93xx_pata_write_reg(drv_data, tf->ctl, IDECTRL_ADDR_CTL);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ ep93xx_pata_write_reg(drv_data, tf->hob_feature,
+ IDECTRL_ADDR_FEATURE);
+ ep93xx_pata_write_reg(drv_data, tf->hob_nsect,
+ IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, tf->hob_lbal,
+ IDECTRL_ADDR_LBAL);
+ ep93xx_pata_write_reg(drv_data, tf->hob_lbam,
+ IDECTRL_ADDR_LBAM);
+ ep93xx_pata_write_reg(drv_data, tf->hob_lbah,
+ IDECTRL_ADDR_LBAH);
+ }
+
+ if (is_addr) {
+ ep93xx_pata_write_reg(drv_data, tf->feature,
+ IDECTRL_ADDR_FEATURE);
+ ep93xx_pata_write_reg(drv_data, tf->nsect, IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, tf->lbal, IDECTRL_ADDR_LBAL);
+ ep93xx_pata_write_reg(drv_data, tf->lbam, IDECTRL_ADDR_LBAM);
+ ep93xx_pata_write_reg(drv_data, tf->lbah, IDECTRL_ADDR_LBAH);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE)
+ ep93xx_pata_write_reg(drv_data, tf->device,
+ IDECTRL_ADDR_DEVICE);
+
+ ata_wait_idle(ap);
+}
+
+/* Note: original code is ata_sff_tf_read */
+static void ep93xx_pata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ tf->command = ep93xx_pata_check_status(ap);
+ tf->feature = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_FEATURE);
+ tf->nsect = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_NSECT);
+ tf->lbal = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAL);
+ tf->lbam = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAM);
+ tf->lbah = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAH);
+ tf->device = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_DEVICE);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ ep93xx_pata_write_reg(drv_data, tf->ctl | ATA_HOB,
+ IDECTRL_ADDR_CTL);
+ tf->hob_feature = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_FEATURE);
+ tf->hob_nsect = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_NSECT);
+ tf->hob_lbal = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_LBAL);
+ tf->hob_lbam = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_LBAM);
+ tf->hob_lbah = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_LBAH);
+ ep93xx_pata_write_reg(drv_data, tf->ctl, IDECTRL_ADDR_CTL);
+ ap->last_ctl = tf->ctl;
+ }
+}
+
+/* Note: original code is ata_sff_exec_command */
+static void ep93xx_pata_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ ep93xx_pata_write_reg(drv_data, tf->command,
+ IDECTRL_ADDR_COMMAND);
+ ata_sff_pause(ap);
+}
+
+/* Note: original code is ata_sff_dev_select */
+static void ep93xx_pata_dev_select(struct ata_port *ap, unsigned int device)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ u8 tmp = ATA_DEVICE_OBS;
+
+ if (device != 0)
+ tmp |= ATA_DEV1;
+
+ ep93xx_pata_write_reg(drv_data, tmp, IDECTRL_ADDR_DEVICE);
+ ata_sff_pause(ap); /* needed; also flushes, for mmio */
+}
+
+/* Note: original code is ata_sff_set_devctl */
+static void ep93xx_pata_set_devctl(struct ata_port *ap, u8 ctl)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ ep93xx_pata_write_reg(drv_data, ctl, IDECTRL_ADDR_CTL);
+}
+
+/* Note: original code is ata_sff_data_xfer */
+static unsigned int ep93xx_pata_data_xfer(struct ata_device *adev,
+ unsigned char *buf,
+ unsigned int buflen, int rw)
+{
+ struct ata_port *ap = adev->link->ap;
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ u16 *data = (u16 *)buf;
+ unsigned int words = buflen >> 1;
+
+ /* Transfer multiple of 2 bytes */
+ while (words--)
+ if (rw == READ)
+ *data++ = cpu_to_le16(
+ ep93xx_pata_read_data(
+ drv_data, IDECTRL_ADDR_DATA));
+ else
+ ep93xx_pata_write_data(drv_data, le16_to_cpu(*data++),
+ IDECTRL_ADDR_DATA);
+
+ /* Transfer trailing 1 byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ unsigned char pad[2] = { };
+
+ buf += buflen - 1;
+
+ if (rw == READ) {
+ *pad = cpu_to_le16(
+ ep93xx_pata_read_data(
+ drv_data, IDECTRL_ADDR_DATA));
+ *buf = pad[0];
+ } else {
+ pad[0] = *buf;
+ ep93xx_pata_write_data(drv_data, le16_to_cpu(*pad),
+ IDECTRL_ADDR_DATA);
+ }
+ words++;
+ }
+
+ return words << 1;
+}
+
+/* Note: original code is ata_devchk */
+static bool ep93xx_pata_device_is_present(struct ata_port *ap,
+ unsigned int device)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ u8 nsect, lbal;
+
+ ap->ops->sff_dev_select(ap, device);
+
+ ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_LBAL);
+
+ ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_LBAL);
+
+ ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_LBAL);
+
+ nsect = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_NSECT);
+ lbal = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAL);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return true;
+
+ return false;
+}
+
+/* Note: original code is ata_sff_wait_after_reset */
+static int ep93xx_pata_wait_after_reset(struct ata_link *link,
+ unsigned int devmask,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ unsigned int dev0 = devmask & (1 << 0);
+ unsigned int dev1 = devmask & (1 << 1);
+ int rc, ret = 0;
+
+ ata_msleep(ap, ATA_WAIT_AFTER_RESET);
+
+ /* always check readiness of the master device */
+ rc = ata_sff_wait_ready(link, deadline);
+ /*
+ * -ENODEV means the odd clown forgot the D7 pulldown resistor
+ * and TF status is 0xff, bail out on it too.
+ */
+ if (rc)
+ return rc;
+
+ /*
+ * if device 1 was found in ata_devchk, wait for register
+ * access briefly, then wait for BSY to clear.
+ */
+ if (dev1) {
+ int i;
+
+ ap->ops->sff_dev_select(ap, 1);
+
+ /*
+ * Wait for register access. Some ATAPI devices fail
+ * to set nsect/lbal after reset, so don't waste too
+ * much time on it. We're gonna wait for !BSY anyway.
+ */
+ for (i = 0; i < 2; i++) {
+ u8 nsect, lbal;
+
+ nsect = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_NSECT);
+ lbal = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_LBAL);
+ if (nsect == 1 && lbal == 1)
+ break;
+ msleep(50); /* give drive a breather */
+ }
+
+ rc = ata_sff_wait_ready(link, deadline);
+ if (rc) {
+ if (rc != -ENODEV)
+ return rc;
+ ret = rc;
+ }
+ }
+ /* is all this really necessary? */
+ ap->ops->sff_dev_select(ap, 0);
+ if (dev1)
+ ap->ops->sff_dev_select(ap, 1);
+ if (dev0)
+ ap->ops->sff_dev_select(ap, 0);
+
+ return ret;
+}
+
+/* Note: original code is ata_bus_softreset */
+static int ep93xx_pata_bus_softreset(struct ata_port *ap, unsigned int devmask,
+ unsigned long deadline)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ ep93xx_pata_write_reg(drv_data, ap->ctl, IDECTRL_ADDR_CTL);
+ udelay(20); /* FIXME: flush */
+ ep93xx_pata_write_reg(drv_data, ap->ctl | ATA_SRST, IDECTRL_ADDR_CTL);
+ udelay(20); /* FIXME: flush */
+ ep93xx_pata_write_reg(drv_data, ap->ctl, IDECTRL_ADDR_CTL);
+ ap->last_ctl = ap->ctl;
+
+ return ep93xx_pata_wait_after_reset(&ap->link, devmask, deadline);
+}
+
+static void ep93xx_pata_release_dma(struct ep93xx_pata_data *drv_data)
+{
+ if (drv_data->dma_rx_channel) {
+ dma_release_channel(drv_data->dma_rx_channel);
+ drv_data->dma_rx_channel = NULL;
+ }
+ if (drv_data->dma_tx_channel) {
+ dma_release_channel(drv_data->dma_tx_channel);
+ drv_data->dma_tx_channel = NULL;
+ }
+}
+
+static bool ep93xx_pata_dma_filter(struct dma_chan *chan, void *filter_param)
+{
+ if (ep93xx_dma_chan_is_m2p(chan))
+ return false;
+
+ chan->private = filter_param;
+ return true;
+}
+
+static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
+{
+ const struct platform_device *pdev = drv_data->pdev;
+ dma_cap_mask_t mask;
+ struct dma_slave_config conf;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ /*
+ * Request two channels for IDE. Another possibility would be
+ * to request only one channel, and reprogram it's direction at
+ * start of new transfer.
+ */
+ drv_data->dma_rx_data.port = EP93XX_DMA_IDE;
+ drv_data->dma_rx_data.direction = DMA_FROM_DEVICE;
+ drv_data->dma_rx_data.name = "ep93xx-pata-rx";
+ drv_data->dma_rx_channel = dma_request_channel(mask,
+ ep93xx_pata_dma_filter, &drv_data->dma_rx_data);
+ if (!drv_data->dma_rx_channel)
+ return;
+
+ drv_data->dma_tx_data.port = EP93XX_DMA_IDE;
+ drv_data->dma_tx_data.direction = DMA_TO_DEVICE;
+ drv_data->dma_tx_data.name = "ep93xx-pata-tx";
+ drv_data->dma_tx_channel = dma_request_channel(mask,
+ ep93xx_pata_dma_filter, &drv_data->dma_tx_data);
+ if (!drv_data->dma_tx_channel) {
+ dma_release_channel(drv_data->dma_rx_channel);
+ return;
+ }
+
+ /* Configure receive channel direction and source address */
+ memset(&conf, 0, sizeof(conf));
+ conf.direction = DMA_FROM_DEVICE;
+ conf.src_addr = drv_data->udma_in_phys;
+ conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ if (dmaengine_slave_config(drv_data->dma_rx_channel, &conf)) {
+ dev_err(&pdev->dev, "failed to configure rx dma channel\n");
+ ep93xx_pata_release_dma(drv_data);
+ return;
+ }
+
+ /* Configure transmit channel direction and destination address */
+ memset(&conf, 0, sizeof(conf));
+ conf.direction = DMA_TO_DEVICE;
+ conf.dst_addr = drv_data->udma_out_phys;
+ conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ if (dmaengine_slave_config(drv_data->dma_tx_channel, &conf)) {
+ dev_err(&pdev->dev, "failed to configure tx dma channel\n");
+ ep93xx_pata_release_dma(drv_data);
+ }
+}
+
+static void ep93xx_pata_dma_start(struct ata_queued_cmd *qc)
+{
+ struct dma_async_tx_descriptor *txd;
+ struct ep93xx_pata_data *drv_data = qc->ap->host->private_data;
+ void __iomem *base = drv_data->ide_base;
+ struct ata_device *adev = qc->dev;
+ u32 v = qc->dma_dir == DMA_TO_DEVICE ? IDEUDMAOP_RWOP : 0;
+ struct dma_chan *channel = qc->dma_dir == DMA_TO_DEVICE
+ ? drv_data->dma_tx_channel : drv_data->dma_rx_channel;
+
+ txd = dmaengine_prep_slave_sg(channel, qc->sg, qc->n_elem, qc->dma_dir,
+ DMA_CTRL_ACK);
+ if (!txd) {
+ dev_err(qc->ap->dev, "failed to prepare slave for sg dma\n");
+ return;
+ }
+ txd->callback = NULL;
+ txd->callback_param = NULL;
+
+ if (dmaengine_submit(txd) < 0) {
+ dev_err(qc->ap->dev, "failed to submit dma transfer\n");
+ return;
+ }
+ dma_async_issue_pending(channel);
+
+ /*
+ * When enabling UDMA operation, IDEUDMAOP register needs to be
+ * programmed in three step sequence:
+ * 1) set or clear the RWOP bit,
+ * 2) perform dummy read of the register,
+ * 3) set the UEN bit.
+ */
+ writel(v, base + IDEUDMAOP);
+ readl(base + IDEUDMAOP);
+ writel(v | IDEUDMAOP_UEN, base + IDEUDMAOP);
+
+ writel(IDECFG_IDEEN | IDECFG_UDMA |
+ ((adev->xfer_mode - XFER_UDMA_0) << IDECFG_MODE_SHIFT),
+ base + IDECFG);
+}
+
+static void ep93xx_pata_dma_stop(struct ata_queued_cmd *qc)
+{
+ struct ep93xx_pata_data *drv_data = qc->ap->host->private_data;
+ void __iomem *base = drv_data->ide_base;
+
+ /* terminate all dma transfers, if not yet finished */
+ dmaengine_terminate_all(drv_data->dma_rx_channel);
+ dmaengine_terminate_all(drv_data->dma_tx_channel);
+
+ /*
+ * To properly stop IDE-DMA, IDEUDMAOP register must to be cleared
+ * and IDECTRL register must be set to default value.
+ */
+ writel(0, base + IDEUDMAOP);
+ writel(readl(base + IDECTRL) | IDECTRL_DIOWN | IDECTRL_DIORN |
+ IDECTRL_CS0N | IDECTRL_CS1N, base + IDECTRL);
+
+ ep93xx_pata_enable_pio(drv_data->ide_base,
+ qc->dev->pio_mode - XFER_PIO_0);
+
+ ata_sff_dma_pause(qc->ap);
+}
+
+static void ep93xx_pata_dma_setup(struct ata_queued_cmd *qc)
+{
+ qc->ap->ops->sff_exec_command(qc->ap, &qc->tf);
+}
+
+static u8 ep93xx_pata_dma_status(struct ata_port *ap)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ u32 val = readl(drv_data->ide_base + IDEUDMASTS);
+
+ /*
+ * UDMA Status Register bits:
+ *
+ * DMAIDE - DMA request signal from UDMA state machine,
+ * INTIDE - INT line generated by UDMA because of errors in the
+ * state machine,
+ * SBUSY - UDMA state machine busy, not in idle state,
+ * NDO - error for data-out not completed,
+ * NDI - error for data-in not completed,
+ * N4X - error for data transferred not multiplies of four
+ * 32-bit words.
+ * (EP93xx UG p27-17)
+ */
+ if (val & IDEUDMASTS_NDO || val & IDEUDMASTS_NDI ||
+ val & IDEUDMASTS_N4X || val & IDEUDMASTS_INTIDE)
+ return ATA_DMA_ERR;
+
+ /* read INTRQ (INT[3]) pin input state */
+ if (readl(drv_data->ide_base + IDECTRL) & IDECTRL_INTRQ)
+ return ATA_DMA_INTR;
+
+ if (val & IDEUDMASTS_SBUSY || val & IDEUDMASTS_DMAIDE)
+ return ATA_DMA_ACTIVE;
+
+ return 0;
+}
+
+/* Note: original code is ata_sff_softreset */
+static int ep93xx_pata_softreset(struct ata_link *al, unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = al->ap;
+ unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+ unsigned int devmask = 0;
+ int rc;
+ u8 err;
+
+ /* determine if device 0/1 are present */
+ if (ep93xx_pata_device_is_present(ap, 0))
+ devmask |= (1 << 0);
+ if (slave_possible && ep93xx_pata_device_is_present(ap, 1))
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ ap->ops->sff_dev_select(al->ap, 0);
+
+ /* issue bus reset */
+ rc = ep93xx_pata_bus_softreset(ap, devmask, deadline);
+ /* if link is ocuppied, -ENODEV too is an error */
+ if (rc && (rc != -ENODEV || sata_scr_valid(al))) {
+ ata_link_err(al, "SRST failed (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_sff_dev_classify(&al->device[0], devmask & (1 << 0),
+ &err);
+ if (slave_possible && err != 0x81)
+ classes[1] = ata_sff_dev_classify(&al->device[1],
+ devmask & (1 << 1), &err);
+
+ return 0;
+}
+
+/* Note: original code is ata_sff_drain_fifo */
+static void ep93xx_pata_drain_fifo(struct ata_queued_cmd *qc)
+{
+ int count;
+ struct ata_port *ap;
+ struct ep93xx_pata_data *drv_data;
+
+ /* We only need to flush incoming data when a command was running */
+ if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
+ return;
+
+ ap = qc->ap;
+ drv_data = ap->host->private_data;
+ /* Drain up to 64K of data before we give up this recovery method */
+ for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ)
+ && count < 65536; count += 2)
+ ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_DATA);
+
+ /* Can become DEBUG later */
+ if (count)
+ ata_port_dbg(ap, "drained %d bytes to clear DRQ.\n", count);
+
+}
+
+static int ep93xx_pata_port_start(struct ata_port *ap)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ /*
+ * Set timings to safe values at startup (= number of ns from ATA
+ * specification), we'll switch to properly calculated values later.
+ */
+ drv_data->t = *ata_timing_find_mode(XFER_PIO_0);
+ return 0;
+}
+
+static struct scsi_host_template ep93xx_pata_sht = {
+ ATA_BASE_SHT(DRV_NAME),
+ /* ep93xx dma implementation limit */
+ .sg_tablesize = 32,
+ /* ep93xx dma can't transfer 65536 bytes at once */
+ .dma_boundary = 0x7fff,
+};
+
+static struct ata_port_operations ep93xx_pata_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+
+ .qc_prep = ata_noop_qc_prep,
+
+ .softreset = ep93xx_pata_softreset,
+ .hardreset = ATA_OP_NULL,
+
+ .sff_dev_select = ep93xx_pata_dev_select,
+ .sff_set_devctl = ep93xx_pata_set_devctl,
+ .sff_check_status = ep93xx_pata_check_status,
+ .sff_check_altstatus = ep93xx_pata_check_altstatus,
+ .sff_tf_load = ep93xx_pata_tf_load,
+ .sff_tf_read = ep93xx_pata_tf_read,
+ .sff_exec_command = ep93xx_pata_exec_command,
+ .sff_data_xfer = ep93xx_pata_data_xfer,
+ .sff_drain_fifo = ep93xx_pata_drain_fifo,
+ .sff_irq_clear = ATA_OP_NULL,
+
+ .set_piomode = ep93xx_pata_set_piomode,
+
+ .bmdma_setup = ep93xx_pata_dma_setup,
+ .bmdma_start = ep93xx_pata_dma_start,
+ .bmdma_stop = ep93xx_pata_dma_stop,
+ .bmdma_status = ep93xx_pata_dma_status,
+
+ .cable_detect = ata_cable_unknown,
+ .port_start = ep93xx_pata_port_start,
+};
+
+static int ep93xx_pata_probe(struct platform_device *pdev)
+{
+ struct ep93xx_pata_data *drv_data;
+ struct ata_host *host;
+ struct ata_port *ap;
+ int irq;
+ struct resource *mem_res;
+ void __iomem *ide_base;
+ int err;
+
+ err = ep93xx_ide_acquire_gpio(pdev);
+ if (err)
+ return err;
+
+ /* INT[3] (IRQ_EP93XX_EXT3) line connected as pull down */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ err = -ENXIO;
+ goto err_rel_gpio;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ide_base = devm_ioremap_resource(&pdev->dev, mem_res);
+ if (IS_ERR(ide_base)) {
+ err = PTR_ERR(ide_base);
+ goto err_rel_gpio;
+ }
+
+ drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
+ if (!drv_data) {
+ err = -ENXIO;
+ goto err_rel_gpio;
+ }
+
+ platform_set_drvdata(pdev, drv_data);
+ drv_data->pdev = pdev;
+ drv_data->ide_base = ide_base;
+ drv_data->udma_in_phys = mem_res->start + IDEUDMADATAIN;
+ drv_data->udma_out_phys = mem_res->start + IDEUDMADATAOUT;
+ ep93xx_pata_dma_init(drv_data);
+
+ /* allocate host */
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host) {
+ err = -ENXIO;
+ goto err_rel_dma;
+ }
+
+ ep93xx_pata_clear_regs(ide_base);
+
+ host->private_data = drv_data;
+
+ ap = host->ports[0];
+ ap->dev = &pdev->dev;
+ ap->ops = &ep93xx_pata_port_ops;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
+ ap->pio_mask = ATA_PIO4;
+
+ /*
+ * Maximum UDMA modes:
+ * EP931x rev.E0 - UDMA2
+ * EP931x rev.E1 - UDMA3
+ * EP931x rev.E2 - UDMA4
+ *
+ * MWDMA support was removed from EP931x rev.E2,
+ * so this driver supports only UDMA modes.
+ */
+ if (drv_data->dma_rx_channel && drv_data->dma_tx_channel) {
+ int chip_rev = ep93xx_chip_revision();
+
+ if (chip_rev == EP93XX_CHIP_REV_E1)
+ ap->udma_mask = ATA_UDMA3;
+ else if (chip_rev == EP93XX_CHIP_REV_E2)
+ ap->udma_mask = ATA_UDMA4;
+ else
+ ap->udma_mask = ATA_UDMA2;
+ }
+
+ /* defaults, pio 0 */
+ ep93xx_pata_enable_pio(ide_base, 0);
+
+ dev_info(&pdev->dev, "version " DRV_VERSION "\n");
+
+ /* activate host */
+ err = ata_host_activate(host, irq, ata_bmdma_interrupt, 0,
+ &ep93xx_pata_sht);
+ if (err == 0)
+ return 0;
+
+err_rel_dma:
+ ep93xx_pata_release_dma(drv_data);
+err_rel_gpio:
+ ep93xx_ide_release_gpio(pdev);
+ return err;
+}
+
+static int ep93xx_pata_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct ep93xx_pata_data *drv_data = host->private_data;
+
+ ata_host_detach(host);
+ ep93xx_pata_release_dma(drv_data);
+ ep93xx_pata_clear_regs(drv_data->ide_base);
+ ep93xx_ide_release_gpio(pdev);
+ return 0;
+}
+
+static struct platform_driver ep93xx_pata_platform_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ep93xx_pata_probe,
+ .remove = ep93xx_pata_remove,
+};
+
+module_platform_driver(ep93xx_pata_platform_driver);
+
+MODULE_AUTHOR("Alessandro Zummo, Lennert Buytenhek, Joao Ramos, "
+ "Bartlomiej Zolnierkiewicz, Rafal Prylowski");
+MODULE_DESCRIPTION("low-level driver for cirrus ep93xx IDE controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:pata_ep93xx");
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index f2b83eabc7c..cbc3de793d1 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -11,49 +11,45 @@
*
*
* TODO
- * Maybe PLL mode
- * Look into engine reset on timeout errors. Should not be
- * required.
+ * Look into engine reset on timeout errors. Should not be required.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "pata_hpt366"
-#define DRV_VERSION "0.6.2"
+#define DRV_VERSION "0.6.11"
struct hpt_clock {
- u8 xfer_speed;
+ u8 xfer_mode;
u32 timing;
};
/* key for bus clock timings
* bit
- * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
- * DMA. cycles = value + 1
- * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
- * DMA. cycles = value + 1
- * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 4:7 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 8:11 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
* register access.
- * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * 12:15 cmd_low_time. Active time of DIOW_/DIOR_ during task file
* register access.
- * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
- * during task file register access.
- * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
- * xfer.
- * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * 16:18 udma_cycle_time. Clock cycles for UDMA xfer?
+ * 19:21 pre_high_time. Time to initialize 1st cycle for PIO and MW DMA xfer.
+ * 22:24 cmd_pre_high_time. Time to initialize 1st PIO cycle for task file
* register access.
- * 28 UDMA enable
- * 29 DMA enable
- * 30 PIO_MST enable. if set, the chip is in bus master mode during
- * PIO.
+ * 28 UDMA enable.
+ * 29 DMA enable.
+ * 30 PIO_MST enable. If set, the chip is in bus master mode during
+ * PIO xfer.
* 31 FIFO enable.
*/
@@ -114,18 +110,45 @@ static const struct hpt_clock hpt366_25[] = {
{ 0, 0x01208585 }
};
-static const char *bad_ata33[] = {
- "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
- "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
- "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+/**
+ * hpt36x_find_mode - find the hpt36x timing
+ * @ap: ATA port
+ * @speed: transfer mode
+ *
+ * Return the 32bit register programming information for this channel
+ * that matches the speed provided.
+ */
+
+static u32 hpt36x_find_mode(struct ata_port *ap, int speed)
+{
+ struct hpt_clock *clocks = ap->host->private_data;
+
+ while (clocks->xfer_mode) {
+ if (clocks->xfer_mode == speed)
+ return clocks->timing;
+ clocks++;
+ }
+ BUG();
+ return 0xffffffffU; /* silence compiler warning */
+}
+
+static const char * const bad_ata33[] = {
+ "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3",
+ "Maxtor 90845U3", "Maxtor 90650U2",
+ "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5",
+ "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+ "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6",
+ "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
"Maxtor 90510D4",
"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
- "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
- "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+ "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7",
+ "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+ "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5",
+ "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
NULL
};
-static const char *bad_ata66_4[] = {
+static const char * const bad_ata66_4[] = {
"IBM-DTLA-307075",
"IBM-DTLA-307060",
"IBM-DTLA-307045",
@@ -144,12 +167,13 @@ static const char *bad_ata66_4[] = {
NULL
};
-static const char *bad_ata66_3[] = {
+static const char * const bad_ata66_3[] = {
"WDC AC310200R",
NULL
};
-static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
+static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
+ const char * const list[])
{
unsigned char model_num[ATA_ID_PROD_LEN + 1];
int i = 0;
@@ -158,7 +182,7 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, cons
while (list[i] != NULL) {
if (!strcmp(list[i], model_num)) {
- printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
+ pr_warn("%s is not supported for %s\n",
modestr, list[i]);
return 1;
}
@@ -183,43 +207,54 @@ static unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask)
mask &= ~(0xF8 << ATA_SHIFT_UDMA);
if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4))
mask &= ~(0xF0 << ATA_SHIFT_UDMA);
- }
- return ata_bmdma_mode_filter(adev, mask);
-}
-
-/**
- * hpt36x_find_mode - reset the hpt36x bus
- * @ap: ATA port
- * @speed: transfer mode
- *
- * Return the 32bit register programming information for this channel
- * that matches the speed provided.
- */
+ } else if (adev->class == ATA_DEV_ATAPI)
+ mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
-static u32 hpt36x_find_mode(struct ata_port *ap, int speed)
-{
- struct hpt_clock *clocks = ap->host->private_data;
-
- while(clocks->xfer_speed) {
- if (clocks->xfer_speed == speed)
- return clocks->timing;
- clocks++;
- }
- BUG();
- return 0xffffffffU; /* silence compiler warning */
+ return mask;
}
static int hpt36x_cable_detect(struct ata_port *ap)
{
- u8 ata66;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 ata66;
+ /*
+ * Each channel of pata_hpt366 occupies separate PCI function
+ * as the primary channel and bit1 indicates the cable type.
+ */
pci_read_config_byte(pdev, 0x5A, &ata66);
- if (ata66 & (1 << ap->port_no))
+ if (ata66 & 2)
return ATA_CBL_PATA40;
return ATA_CBL_PATA80;
}
+static void hpt366_set_mode(struct ata_port *ap, struct ata_device *adev,
+ u8 mode)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr = 0x40 + 4 * adev->devno;
+ u32 mask, reg, t;
+
+ /* determine timing mask and find matching clock entry */
+ if (mode < XFER_MW_DMA_0)
+ mask = 0xc1f8ffff;
+ else if (mode < XFER_UDMA_0)
+ mask = 0x303800ff;
+ else
+ mask = 0x30070000;
+
+ t = hpt36x_find_mode(ap, mode);
+
+ /*
+ * Combine new mode bits with old config bits and disable
+ * on-chip PIO FIFO/buffer (and PIO MST mode as well) to avoid
+ * problems handling I/O errors later.
+ */
+ pci_read_config_dword(pdev, addr, &reg);
+ reg = ((reg & ~mask) | (t & mask)) & ~0xc0000000;
+ pci_write_config_dword(pdev, addr, reg);
+}
+
/**
* hpt366_set_piomode - PIO setup
* @ap: ATA interface
@@ -230,28 +265,7 @@ static int hpt36x_cable_detect(struct ata_port *ap)
static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 addr1, addr2;
- u32 reg;
- u32 mode;
- u8 fast;
-
- addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
- addr2 = 0x51 + 4 * ap->port_no;
-
- /* Fast interrupt prediction disable, hold off interrupt disable */
- pci_read_config_byte(pdev, addr2, &fast);
- if (fast & 0x80) {
- fast &= ~0x80;
- pci_write_config_byte(pdev, addr2, fast);
- }
-
- pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt36x_find_mode(ap, adev->pio_mode);
- mode &= ~0x8000000; /* No FIFO in PIO */
- mode &= ~0x30070000; /* Leave config bits alone */
- reg &= 0x30070000; /* Strip timing bits */
- pci_write_config_dword(pdev, addr1, reg | mode);
+ hpt366_set_mode(ap, adev, adev->pio_mode);
}
/**
@@ -265,28 +279,7 @@ static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void hpt366_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 addr1, addr2;
- u32 reg;
- u32 mode;
- u8 fast;
-
- addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
- addr2 = 0x51 + 4 * ap->port_no;
-
- /* Fast interrupt prediction disable, hold off interrupt disable */
- pci_read_config_byte(pdev, addr2, &fast);
- if (fast & 0x80) {
- fast &= ~0x80;
- pci_write_config_byte(pdev, addr2, fast);
- }
-
- pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt36x_find_mode(ap, adev->dma_mode);
- mode |= 0x8000000; /* FIFO in MWDMA or UDMA */
- mode &= ~0xC0000000; /* Leave config bits alone */
- reg &= 0xC0000000; /* Strip timing bits */
- pci_write_config_dword(pdev, addr1, reg | mode);
+ hpt366_set_mode(ap, adev, adev->dma_mode);
}
static struct scsi_host_template hpt36x_sht = {
@@ -316,6 +309,7 @@ static struct ata_port_operations hpt366_port_ops = {
static void hpt36x_init_chipset(struct pci_dev *dev)
{
u8 drive_fast;
+
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
@@ -351,15 +345,14 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
static const struct ata_port_info info_hpt366 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA4,
.port_ops = &hpt366_port_ops
};
const struct ata_port_info *ppi[] = { &info_hpt366, NULL };
void *hpriv = NULL;
- u32 class_rev;
u32 reg1;
int rc;
@@ -367,13 +360,10 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (rc)
return rc;
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xFF;
-
/* May be a later chip in disguise. Check */
/* Newer chips are not in the HPT36x driver. Ignore them */
- if (class_rev > 2)
- return -ENODEV;
+ if (dev->revision > 2)
+ return -ENODEV;
hpt36x_init_chipset(dev);
@@ -381,25 +371,25 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
/* PCI clocking determines the ATA timing values to use */
/* info_hpt366 is safe against re-entry so we can scribble on it */
- switch((reg1 & 0x700) >> 8) {
- case 5:
- hpriv = &hpt366_40;
- break;
- case 9:
- hpriv = &hpt366_25;
- break;
- default:
- hpriv = &hpt366_33;
- break;
+ switch ((reg1 & 0x700) >> 8) {
+ case 9:
+ hpriv = &hpt366_40;
+ break;
+ case 5:
+ hpriv = &hpt366_25;
+ break;
+ default:
+ hpriv = &hpt366_33;
+ break;
}
/* Now kick off ATA set up */
- return ata_pci_sff_init_one(dev, ppi, &hpt36x_sht, hpriv);
+ return ata_pci_bmdma_init_one(dev, ppi, &hpt36x_sht, hpriv, 0);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int hpt36x_reinit_one(struct pci_dev *dev)
{
- struct ata_host *host = dev_get_drvdata(&dev->dev);
+ struct ata_host *host = pci_get_drvdata(dev);
int rc;
rc = ata_pci_device_do_resume(dev);
@@ -417,31 +407,20 @@ static const struct pci_device_id hpt36x[] = {
};
static struct pci_driver hpt36x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt36x,
- .probe = hpt36x_init_one,
+ .probe = hpt36x_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = hpt36x_reinit_one,
#endif
};
-static int __init hpt36x_init(void)
-{
- return pci_register_driver(&hpt36x_pci_driver);
-}
-
-static void __exit hpt36x_exit(void)
-{
- pci_unregister_driver(&hpt36x_pci_driver);
-}
+module_pci_driver(hpt36x_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the Highpoint HPT366/368");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, hpt36x);
MODULE_VERSION(DRV_VERSION);
-
-module_init(hpt36x_init);
-module_exit(hpt36x_exit);
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index 42163998de9..3ba843f5cdc 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -8,23 +8,24 @@
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
* Portions Copyright (C) 2003 Red Hat Inc
- * Portions Copyright (C) 2005-2007 MontaVista Software, Inc.
+ * Portions Copyright (C) 2005-2010 MontaVista Software, Inc.
*
* TODO
* Look into engine reset on timeout errors. Should not be required.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "pata_hpt37x"
-#define DRV_VERSION "0.6.11"
+#define DRV_VERSION "0.6.23"
struct hpt_clock {
u8 xfer_speed;
@@ -39,25 +40,24 @@ struct hpt_chip {
/* key for bus clock timings
* bit
- * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
- * DMA. cycles = value + 1
- * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
- * DMA. cycles = value + 1
- * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 4:8 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 9:12 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
* register access.
- * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file
* register access.
- * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
- * during task file register access.
- * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
- * xfer.
- * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * 18:20 udma_cycle_time. Clock cycles for UDMA xfer.
+ * 21 CLK frequency for UDMA: 0=ATA clock, 1=dual ATA clock.
+ * 22:24 pre_high_time. Time to initialize 1st cycle for PIO and MW DMA xfer.
+ * 25:27 cmd_pre_high_time. Time to initialize 1st PIO cycle for task file
* register access.
- * 28 UDMA enable
- * 29 DMA enable
- * 30 PIO_MST enable. if set, the chip is in bus master mode during
- * PIO.
- * 31 FIFO enable.
+ * 28 UDMA enable.
+ * 29 DMA enable.
+ * 30 PIO_MST enable. If set, the chip is in bus master mode during
+ * PIO xfer.
+ * 31 FIFO enable. Only for PIO.
*/
static struct hpt_clock hpt37x_timings_33[] = {
@@ -211,7 +211,7 @@ static u32 hpt37x_find_mode(struct ata_port *ap, int speed)
{
struct hpt_clock *clocks = ap->host->private_data;
- while(clocks->xfer_speed) {
+ while (clocks->xfer_speed) {
if (clocks->xfer_speed == speed)
return clocks->timing;
clocks++;
@@ -220,7 +220,8 @@ static u32 hpt37x_find_mode(struct ata_port *ap, int speed)
return 0xffffffffU; /* silence compiler warning */
}
-static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
+static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
+ const char * const list[])
{
unsigned char model_num[ATA_ID_PROD_LEN + 1];
int i = 0;
@@ -229,7 +230,7 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, cons
while (list[i] != NULL) {
if (!strcmp(list[i], model_num)) {
- printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
+ pr_warn("%s is not supported for %s\n",
modestr, list[i]);
return 1;
}
@@ -238,18 +239,23 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, cons
return 0;
}
-static const char *bad_ata33[] = {
- "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
- "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
- "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+static const char * const bad_ata33[] = {
+ "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3",
+ "Maxtor 90845U3", "Maxtor 90650U2",
+ "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5",
+ "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+ "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6",
+ "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
"Maxtor 90510D4",
"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
- "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
- "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+ "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7",
+ "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+ "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5",
+ "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
NULL
};
-static const char *bad_ata100_5[] = {
+static const char * const bad_ata100_5[] = {
"IBM-DTLA-307075",
"IBM-DTLA-307060",
"IBM-DTLA-307045",
@@ -283,7 +289,7 @@ static unsigned long hpt370_filter(struct ata_device *adev, unsigned long mask)
if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
mask &= ~(0xE0 << ATA_SHIFT_UDMA);
}
- return ata_bmdma_mode_filter(adev, mask);
+ return mask;
}
/**
@@ -299,76 +305,100 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask)
if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
mask &= ~(0xE0 << ATA_SHIFT_UDMA);
}
- return ata_bmdma_mode_filter(adev, mask);
+ return mask;
}
/**
- * hpt37x_pre_reset - reset the hpt37x bus
- * @link: ATA link to reset
- * @deadline: deadline jiffies for the operation
+ * hpt372_filter - mode selection filter
+ * @adev: ATA device
+ * @mask: mode mask
*
- * Perform the initial reset handling for the 370/372 and 374 func 0
+ * The Marvell bridge chips used on the HighPoint SATA cards do not seem
+ * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes...
*/
+static unsigned long hpt372_filter(struct ata_device *adev, unsigned long mask)
+{
+ if (ata_id_is_sata(adev->id))
+ mask &= ~((0xE << ATA_SHIFT_UDMA) | ATA_MASK_MWDMA);
-static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline)
+ return mask;
+}
+
+/**
+ * hpt37x_cable_detect - Detect the cable type
+ * @ap: ATA port to detect on
+ *
+ * Return the cable type attached to this port
+ */
+
+static int hpt37x_cable_detect(struct ata_port *ap)
{
- u8 scr2, ata66;
- struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- static const struct pci_bits hpt37x_enable_bits[] = {
- { 0x50, 1, 0x04, 0x04 },
- { 0x54, 1, 0x04, 0x04 }
- };
- if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
- return -ENOENT;
+ u8 scr2, ata66;
pci_read_config_byte(pdev, 0x5B, &scr2);
pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01);
+
+ udelay(10); /* debounce */
+
/* Cable register now active */
pci_read_config_byte(pdev, 0x5A, &ata66);
/* Restore state */
pci_write_config_byte(pdev, 0x5B, scr2);
if (ata66 & (2 >> ap->port_no))
- ap->cbl = ATA_CBL_PATA40;
+ return ATA_CBL_PATA40;
else
- ap->cbl = ATA_CBL_PATA80;
-
- /* Reset the state machine */
- pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
- udelay(100);
-
- return ata_sff_prereset(link, deadline);
+ return ATA_CBL_PATA80;
}
-static int hpt374_fn1_pre_reset(struct ata_link *link, unsigned long deadline)
+/**
+ * hpt374_fn1_cable_detect - Detect the cable type
+ * @ap: ATA port to detect on
+ *
+ * Return the cable type attached to this port
+ */
+
+static int hpt374_fn1_cable_detect(struct ata_port *ap)
{
- static const struct pci_bits hpt37x_enable_bits[] = {
- { 0x50, 1, 0x04, 0x04 },
- { 0x54, 1, 0x04, 0x04 }
- };
- u16 mcr3;
- u8 ata66;
- struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int mcrbase = 0x50 + 4 * ap->port_no;
-
- if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
- return -ENOENT;
+ u16 mcr3;
+ u8 ata66;
/* Do the extra channel work */
pci_read_config_word(pdev, mcrbase + 2, &mcr3);
- /* Set bit 15 of 0x52 to enable TCBLID as input
- */
+ /* Set bit 15 of 0x52 to enable TCBLID as input */
pci_write_config_word(pdev, mcrbase + 2, mcr3 | 0x8000);
pci_read_config_byte(pdev, 0x5A, &ata66);
/* Reset TCBLID/FCBLID to output */
pci_write_config_word(pdev, mcrbase + 2, mcr3);
if (ata66 & (2 >> ap->port_no))
- ap->cbl = ATA_CBL_PATA40;
+ return ATA_CBL_PATA40;
else
- ap->cbl = ATA_CBL_PATA80;
+ return ATA_CBL_PATA80;
+}
+
+/**
+ * hpt37x_pre_reset - reset the hpt37x bus
+ * @link: ATA link to reset
+ * @deadline: deadline jiffies for the operation
+ *
+ * Perform the initial reset handling for the HPT37x.
+ */
+
+static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const struct pci_bits hpt37x_enable_bits[] = {
+ { 0x50, 1, 0x04, 0x04 },
+ { 0x54, 1, 0x04, 0x04 }
+ };
+
+ if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
+ return -ENOENT;
/* Reset the state machine */
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
@@ -377,20 +407,12 @@ static int hpt374_fn1_pre_reset(struct ata_link *link, unsigned long deadline)
return ata_sff_prereset(link, deadline);
}
-/**
- * hpt370_set_piomode - PIO setup
- * @ap: ATA interface
- * @adev: device on the interface
- *
- * Perform PIO mode setup.
- */
-
-static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void hpt370_set_mode(struct ata_port *ap, struct ata_device *adev,
+ u8 mode)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 addr1, addr2;
- u32 reg;
- u32 mode;
+ u32 reg, timing, mask;
u8 fast;
addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
@@ -402,63 +424,44 @@ static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
fast |= 0x01;
pci_write_config_byte(pdev, addr2, fast);
+ /* Determine timing mask and find matching mode entry */
+ if (mode < XFER_MW_DMA_0)
+ mask = 0xcfc3ffff;
+ else if (mode < XFER_UDMA_0)
+ mask = 0x31c001ff;
+ else
+ mask = 0x303c0000;
+
+ timing = hpt37x_find_mode(ap, mode);
+
pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt37x_find_mode(ap, adev->pio_mode);
- mode &= ~0x8000000; /* No FIFO in PIO */
- mode &= ~0x30070000; /* Leave config bits alone */
- reg &= 0x30070000; /* Strip timing bits */
- pci_write_config_dword(pdev, addr1, reg | mode);
+ reg = (reg & ~mask) | (timing & mask);
+ pci_write_config_dword(pdev, addr1, reg);
}
-
/**
- * hpt370_set_dmamode - DMA timing setup
+ * hpt370_set_piomode - PIO setup
* @ap: ATA interface
- * @adev: Device being configured
+ * @adev: device on the interface
*
- * Set up the channel for MWDMA or UDMA modes. Much the same as with
- * PIO, load the mode number and then set MWDMA or UDMA flag.
+ * Perform PIO mode setup.
*/
-static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 addr1, addr2;
- u32 reg;
- u32 mode;
- u8 fast;
-
- addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
- addr2 = 0x51 + 4 * ap->port_no;
-
- /* Fast interrupt prediction disable, hold off interrupt disable */
- pci_read_config_byte(pdev, addr2, &fast);
- fast &= ~0x02;
- fast |= 0x01;
- pci_write_config_byte(pdev, addr2, fast);
-
- pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt37x_find_mode(ap, adev->dma_mode);
- mode |= 0x8000000; /* FIFO in MWDMA or UDMA */
- mode &= ~0xC0000000; /* Leave config bits alone */
- reg &= 0xC0000000; /* Strip timing bits */
- pci_write_config_dword(pdev, addr1, reg | mode);
+ hpt370_set_mode(ap, adev, adev->pio_mode);
}
/**
- * hpt370_bmdma_start - DMA engine begin
- * @qc: ATA command
+ * hpt370_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
*
- * The 370 and 370A want us to reset the DMA engine each time we
- * use it. The 372 and later are fine.
+ * Set up the channel for MWDMA or UDMA modes.
*/
-static void hpt370_bmdma_start(struct ata_queued_cmd *qc)
+static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
- struct ata_port *ap = qc->ap;
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
- udelay(10);
- ata_bmdma_start(qc);
+ hpt370_set_mode(ap, adev, adev->dma_mode);
}
/**
@@ -472,24 +475,25 @@ static void hpt370_bmdma_stop(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u8 dma_stat = ioread8(ap->ioaddr.bmdma_addr + 2);
- u8 dma_cmd;
void __iomem *bmdma = ap->ioaddr.bmdma_addr;
+ u8 dma_stat = ioread8(bmdma + ATA_DMA_STATUS);
+ u8 dma_cmd;
- if (dma_stat & 0x01) {
+ if (dma_stat & ATA_DMA_ACTIVE) {
udelay(20);
- dma_stat = ioread8(bmdma + 2);
+ dma_stat = ioread8(bmdma + ATA_DMA_STATUS);
}
- if (dma_stat & 0x01) {
+ if (dma_stat & ATA_DMA_ACTIVE) {
/* Clear the engine */
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(10);
/* Stop DMA */
- dma_cmd = ioread8(bmdma );
- iowrite8(dma_cmd & 0xFE, bmdma);
+ dma_cmd = ioread8(bmdma + ATA_DMA_CMD);
+ iowrite8(dma_cmd & ~ATA_DMA_START, bmdma + ATA_DMA_CMD);
/* Clear Error */
- dma_stat = ioread8(bmdma + 2);
- iowrite8(dma_stat | 0x06 , bmdma + 2);
+ dma_stat = ioread8(bmdma + ATA_DMA_STATUS);
+ iowrite8(dma_stat | ATA_DMA_INTR | ATA_DMA_ERR,
+ bmdma + ATA_DMA_STATUS);
/* Clear the engine */
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(10);
@@ -497,20 +501,12 @@ static void hpt370_bmdma_stop(struct ata_queued_cmd *qc)
ata_bmdma_stop(qc);
}
-/**
- * hpt372_set_piomode - PIO setup
- * @ap: ATA interface
- * @adev: device on the interface
- *
- * Perform PIO mode setup.
- */
-
-static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void hpt372_set_mode(struct ata_port *ap, struct ata_device *adev,
+ u8 mode)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 addr1, addr2;
- u32 reg;
- u32 mode;
+ u32 reg, timing, mask;
u8 fast;
addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
@@ -521,14 +517,32 @@ static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
fast &= ~0x07;
pci_write_config_byte(pdev, addr2, fast);
+ /* Determine timing mask and find matching mode entry */
+ if (mode < XFER_MW_DMA_0)
+ mask = 0xcfc3ffff;
+ else if (mode < XFER_UDMA_0)
+ mask = 0x31c001ff;
+ else
+ mask = 0x303c0000;
+
+ timing = hpt37x_find_mode(ap, mode);
+
pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt37x_find_mode(ap, adev->pio_mode);
+ reg = (reg & ~mask) | (timing & mask);
+ pci_write_config_dword(pdev, addr1, reg);
+}
+
+/**
+ * hpt372_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
- printk("Find mode for %d reports %X\n", adev->pio_mode, mode);
- mode &= ~0x80000000; /* No FIFO in PIO */
- mode &= ~0x30070000; /* Leave config bits alone */
- reg &= 0x30070000; /* Strip timing bits */
- pci_write_config_dword(pdev, addr1, reg | mode);
+static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ hpt372_set_mode(ap, adev, adev->pio_mode);
}
/**
@@ -536,33 +550,12 @@ static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
* @ap: ATA interface
* @adev: Device being configured
*
- * Set up the channel for MWDMA or UDMA modes. Much the same as with
- * PIO, load the mode number and then set MWDMA or UDMA flag.
+ * Set up the channel for MWDMA or UDMA modes.
*/
static void hpt372_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 addr1, addr2;
- u32 reg;
- u32 mode;
- u8 fast;
-
- addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
- addr2 = 0x51 + 4 * ap->port_no;
-
- /* Fast interrupt prediction disable, hold off interrupt disable */
- pci_read_config_byte(pdev, addr2, &fast);
- fast &= ~0x07;
- pci_write_config_byte(pdev, addr2, fast);
-
- pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt37x_find_mode(ap, adev->dma_mode);
- printk("Find mode for DMA %d reports %X\n", adev->dma_mode, mode);
- mode &= ~0xC0000000; /* Leave config bits alone */
- mode |= 0x80000000; /* FIFO in MWDMA or UDMA */
- reg &= 0xC0000000; /* Strip timing bits */
- pci_write_config_dword(pdev, addr1, reg | mode);
+ hpt372_set_mode(ap, adev, adev->dma_mode);
}
/**
@@ -598,10 +591,10 @@ static struct scsi_host_template hpt37x_sht = {
static struct ata_port_operations hpt370_port_ops = {
.inherits = &ata_bmdma_port_ops,
- .bmdma_start = hpt370_bmdma_start,
.bmdma_stop = hpt370_bmdma_stop,
.mode_filter = hpt370_filter,
+ .cable_detect = hpt37x_cable_detect,
.set_piomode = hpt370_set_piomode,
.set_dmamode = hpt370_set_dmamode,
.prereset = hpt37x_pre_reset,
@@ -617,32 +610,43 @@ static struct ata_port_operations hpt370a_port_ops = {
};
/*
- * Configuration for HPT372, HPT371, HPT302. Slightly different PIO
- * and DMA mode setting functionality.
+ * Configuration for HPT371 and HPT302. Slightly different PIO and DMA
+ * mode setting functionality.
*/
-static struct ata_port_operations hpt372_port_ops = {
+static struct ata_port_operations hpt302_port_ops = {
.inherits = &ata_bmdma_port_ops,
.bmdma_stop = hpt37x_bmdma_stop,
+ .cable_detect = hpt37x_cable_detect,
.set_piomode = hpt372_set_piomode,
.set_dmamode = hpt372_set_dmamode,
.prereset = hpt37x_pre_reset,
};
/*
- * Configuration for HPT374. Mode setting works like 372 and friends
+ * Configuration for HPT372. Mode setting works like 371 and 302
+ * but we have a mode filter.
+ */
+
+static struct ata_port_operations hpt372_port_ops = {
+ .inherits = &hpt302_port_ops,
+ .mode_filter = hpt372_filter,
+};
+
+/*
+ * Configuration for HPT374. Mode setting and filtering works like 372
* but we have a different cable detection procedure for function 1.
*/
static struct ata_port_operations hpt374_fn1_port_ops = {
.inherits = &hpt372_port_ops,
- .prereset = hpt374_fn1_pre_reset,
+ .cable_detect = hpt374_fn1_cable_detect,
};
/**
- * htp37x_clock_slot - Turn timing to PC clock entry
+ * hpt37x_clock_slot - Turn timing to PC clock entry
* @freq: Reported frequency timing
* @base: Base timing
*
@@ -676,12 +680,12 @@ static int hpt37x_calibrate_dpll(struct pci_dev *dev)
u32 reg5c;
int tries;
- for(tries = 0; tries < 0x5000; tries++) {
+ for (tries = 0; tries < 0x5000; tries++) {
udelay(50);
pci_read_config_byte(dev, 0x5b, &reg5b);
if (reg5b & 0x80) {
/* See if it stays set */
- for(tries = 0; tries < 0x1000; tries ++) {
+ for (tries = 0; tries < 0x1000; tries++) {
pci_read_config_byte(dev, 0x5b, &reg5b);
/* Failed ? */
if ((reg5b & 0x80) == 0)
@@ -689,7 +693,7 @@ static int hpt37x_calibrate_dpll(struct pci_dev *dev)
}
/* Turn off tuning, we have the DPLL set */
pci_read_config_dword(dev, 0x5c, &reg5c);
- pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100);
+ pci_write_config_dword(dev, 0x5c, reg5c & ~0x100);
return 1;
}
}
@@ -701,6 +705,7 @@ static u32 hpt374_read_freq(struct pci_dev *pdev)
{
u32 freq;
unsigned long io_base = pci_resource_start(pdev, 4);
+
if (PCI_FUNC(pdev->devfn) & 1) {
struct pci_dev *pdev_0;
@@ -753,55 +758,63 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
/* HPT370 - UDMA100 */
static const struct ata_port_info info_hpt370 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &hpt370_port_ops
};
/* HPT370A - UDMA100 */
static const struct ata_port_info info_hpt370a = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &hpt370a_port_ops
};
- /* HPT370 - UDMA100 */
+ /* HPT370 - UDMA66 */
static const struct ata_port_info info_hpt370_33 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA5,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
.port_ops = &hpt370_port_ops
};
- /* HPT370A - UDMA100 */
+ /* HPT370A - UDMA66 */
static const struct ata_port_info info_hpt370a_33 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA5,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
.port_ops = &hpt370a_port_ops
};
- /* HPT371, 372 and friends - UDMA133 */
+ /* HPT372 - UDMA133 */
static const struct ata_port_info info_hpt372 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &hpt372_port_ops
};
- /* HPT374 - UDMA100, function 1 uses different prereset method */
+ /* HPT371, 302 - UDMA133 */
+ static const struct ata_port_info info_hpt302 = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &hpt302_port_ops
+ };
+ /* HPT374 - UDMA100, function 1 uses different cable_detect method */
static const struct ata_port_info info_hpt374_fn0 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &hpt372_port_ops
};
static const struct ata_port_info info_hpt374_fn1 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &hpt374_fn1_port_ops
};
@@ -809,9 +822,8 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
static const int MHz[4] = { 33, 40, 50, 66 };
void *private_data = NULL;
const struct ata_port_info *ppi[] = { NULL, NULL };
-
+ u8 rev = dev->revision;
u8 irqmask;
- u32 class_rev;
u8 mcr1;
u32 freq;
int prefer_dpll = 1;
@@ -826,77 +838,75 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (rc)
return rc;
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xFF;
-
- if (dev->device == PCI_DEVICE_ID_TTI_HPT366) {
+ switch (dev->device) {
+ case PCI_DEVICE_ID_TTI_HPT366:
/* May be a later chip in disguise. Check */
/* Older chips are in the HPT366 driver. Ignore them */
- if (class_rev < 3)
+ if (rev < 3)
return -ENODEV;
/* N series chips have their own driver. Ignore */
- if (class_rev == 6)
+ if (rev == 6)
return -ENODEV;
- switch(class_rev) {
- case 3:
- ppi[0] = &info_hpt370;
- chip_table = &hpt370;
- prefer_dpll = 0;
- break;
- case 4:
- ppi[0] = &info_hpt370a;
- chip_table = &hpt370a;
- prefer_dpll = 0;
- break;
- case 5:
- ppi[0] = &info_hpt372;
- chip_table = &hpt372;
- break;
- default:
- printk(KERN_ERR "pata_hpt37x: Unknown HPT366 subtype please report (%d).\n", class_rev);
- return -ENODEV;
- }
- } else {
- switch(dev->device) {
- case PCI_DEVICE_ID_TTI_HPT372:
- /* 372N if rev >= 2*/
- if (class_rev >= 2)
- return -ENODEV;
- ppi[0] = &info_hpt372;
- chip_table = &hpt372a;
- break;
- case PCI_DEVICE_ID_TTI_HPT302:
- /* 302N if rev > 1 */
- if (class_rev > 1)
- return -ENODEV;
- ppi[0] = &info_hpt372;
- /* Check this */
- chip_table = &hpt302;
- break;
- case PCI_DEVICE_ID_TTI_HPT371:
- if (class_rev > 1)
- return -ENODEV;
- ppi[0] = &info_hpt372;
- chip_table = &hpt371;
- /* Single channel device, master is not present
- but the BIOS (or us for non x86) must mark it
- absent */
- pci_read_config_byte(dev, 0x50, &mcr1);
- mcr1 &= ~0x04;
- pci_write_config_byte(dev, 0x50, mcr1);
- break;
- case PCI_DEVICE_ID_TTI_HPT374:
- chip_table = &hpt374;
- if (!(PCI_FUNC(dev->devfn) & 1))
- *ppi = &info_hpt374_fn0;
- else
- *ppi = &info_hpt374_fn1;
- break;
- default:
- printk(KERN_ERR "pata_hpt37x: PCI table is bogus please report (%d).\n", dev->device);
- return -ENODEV;
+ switch (rev) {
+ case 3:
+ ppi[0] = &info_hpt370;
+ chip_table = &hpt370;
+ prefer_dpll = 0;
+ break;
+ case 4:
+ ppi[0] = &info_hpt370a;
+ chip_table = &hpt370a;
+ prefer_dpll = 0;
+ break;
+ case 5:
+ ppi[0] = &info_hpt372;
+ chip_table = &hpt372;
+ break;
+ default:
+ pr_err("Unknown HPT366 subtype, please report (%d)\n",
+ rev);
+ return -ENODEV;
}
+ break;
+ case PCI_DEVICE_ID_TTI_HPT372:
+ /* 372N if rev >= 2 */
+ if (rev >= 2)
+ return -ENODEV;
+ ppi[0] = &info_hpt372;
+ chip_table = &hpt372a;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT302:
+ /* 302N if rev > 1 */
+ if (rev > 1)
+ return -ENODEV;
+ ppi[0] = &info_hpt302;
+ /* Check this */
+ chip_table = &hpt302;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT371:
+ if (rev > 1)
+ return -ENODEV;
+ ppi[0] = &info_hpt302;
+ chip_table = &hpt371;
+ /*
+ * Single channel device, master is not present but the BIOS
+ * (or us for non x86) must mark it absent
+ */
+ pci_read_config_byte(dev, 0x50, &mcr1);
+ mcr1 &= ~0x04;
+ pci_write_config_byte(dev, 0x50, mcr1);
+ break;
+ case PCI_DEVICE_ID_TTI_HPT374:
+ chip_table = &hpt374;
+ if (!(PCI_FUNC(dev->devfn) & 1))
+ *ppi = &info_hpt374_fn0;
+ else
+ *ppi = &info_hpt374_fn1;
+ break;
+ default:
+ pr_err("PCI table is bogus, please report (%d)\n", dev->device);
+ return -ENODEV;
}
/* Ok so this is a chip we support */
@@ -925,9 +935,11 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (chip_table == &hpt372a)
outb(0x0e, iobase + 0x9c);
- /* Some devices do not let this value be accessed via PCI space
- according to the old driver. In addition we must use the value
- from FN 0 on the HPT374 */
+ /*
+ * Some devices do not let this value be accessed via PCI space
+ * according to the old driver. In addition we must use the value
+ * from FN 0 on the HPT374.
+ */
if (chip_table == &hpt374) {
freq = hpt374_read_freq(dev);
@@ -941,10 +953,10 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
u8 sr;
u32 total = 0;
- printk(KERN_WARNING "pata_hpt37x: BIOS has not set timing clocks.\n");
+ pr_warn("BIOS has not set timing clocks\n");
/* This is the process the HPT371 BIOS is reported to use */
- for(i = 0; i < 128; i++) {
+ for (i = 0; i < 128; i++) {
pci_read_config_byte(dev, 0x78, &sr);
total += sr & 0x1FF;
udelay(15);
@@ -979,20 +991,25 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
/* Select the DPLL clock. */
pci_write_config_byte(dev, 0x5b, 0x21);
- pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100);
+ pci_write_config_dword(dev, 0x5C,
+ (f_high << 16) | f_low | 0x100);
- for(adjust = 0; adjust < 8; adjust++) {
+ for (adjust = 0; adjust < 8; adjust++) {
if (hpt37x_calibrate_dpll(dev))
break;
- /* See if it'll settle at a fractionally different clock */
+ /*
+ * See if it'll settle at a fractionally
+ * different clock
+ */
if (adjust & 1)
f_low -= adjust >> 1;
else
f_high += adjust >> 1;
- pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100);
+ pci_write_config_dword(dev, 0x5C,
+ (f_high << 16) | f_low | 0x100);
}
if (adjust == 8) {
- printk(KERN_ERR "pata_hpt37x: DPLL did not stabilize!\n");
+ pr_err("DPLL did not stabilize!\n");
return -ENODEV;
}
if (dpll == 3)
@@ -1000,26 +1017,27 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
else
private_data = (void *)hpt37x_timings_50;
- printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using %dMHz DPLL.\n",
- MHz[clock_slot], MHz[dpll]);
+ pr_info("bus clock %dMHz, using %dMHz DPLL\n",
+ MHz[clock_slot], MHz[dpll]);
} else {
private_data = (void *)chip_table->clocks[clock_slot];
/*
* Perform a final fixup. Note that we will have used the
* DPLL on the HPT372 which means we don't have to worry
* about lack of UDMA133 support on lower clocks
- */
+ */
if (clock_slot < 2 && ppi[0] == &info_hpt370)
ppi[0] = &info_hpt370_33;
if (clock_slot < 2 && ppi[0] == &info_hpt370a)
ppi[0] = &info_hpt370a_33;
- printk(KERN_INFO "pata_hpt37x: %s using %dMHz bus clock.\n",
- chip_table->name, MHz[clock_slot]);
+
+ pr_info("%s using %dMHz bus clock\n",
+ chip_table->name, MHz[clock_slot]);
}
/* Now kick off ATA set up */
- return ata_pci_sff_init_one(dev, ppi, &hpt37x_sht, private_data);
+ return ata_pci_bmdma_init_one(dev, ppi, &hpt37x_sht, private_data, 0);
}
static const struct pci_device_id hpt37x[] = {
@@ -1033,27 +1051,16 @@ static const struct pci_device_id hpt37x[] = {
};
static struct pci_driver hpt37x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt37x,
- .probe = hpt37x_init_one,
+ .probe = hpt37x_init_one,
.remove = ata_pci_remove_one
};
-static int __init hpt37x_init(void)
-{
- return pci_register_driver(&hpt37x_pci_driver);
-}
-
-static void __exit hpt37x_exit(void)
-{
- pci_unregister_driver(&hpt37x_pci_driver);
-}
+module_pci_driver(hpt37x_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the Highpoint HPT37x/30x");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, hpt37x);
MODULE_VERSION(DRV_VERSION);
-
-module_init(hpt37x_init);
-module_exit(hpt37x_exit);
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index d5c9fd7b82b..b93c0f0729e 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -1,5 +1,5 @@
/*
- * Libata driver for the highpoint 372N and 302N UDMA66 ATA controllers.
+ * Libata driver for the HighPoint 371N, 372N, and 302N UDMA66 ATA controllers.
*
* This driver is heavily based upon:
*
@@ -8,24 +8,25 @@
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
* Portions Copyright (C) 2003 Red Hat Inc
- * Portions Copyright (C) 2005-2007 MontaVista Software, Inc.
+ * Portions Copyright (C) 2005-2010 MontaVista Software, Inc.
*
*
* TODO
* Work out best PLL policy
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "pata_hpt3x2n"
-#define DRV_VERSION "0.3.4"
+#define DRV_VERSION "0.3.15"
enum {
HPT_PCI_FAST = (1 << 31),
@@ -45,25 +46,24 @@ struct hpt_chip {
/* key for bus clock timings
* bit
- * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
- * DMA. cycles = value + 1
- * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
- * DMA. cycles = value + 1
- * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 4:8 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 9:12 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
* register access.
- * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file
* register access.
- * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
- * during task file register access.
- * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
- * xfer.
- * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * 18:20 udma_cycle_time. Clock cycles for UDMA xfer.
+ * 21 CLK frequency for UDMA: 0=ATA clock, 1=dual ATA clock.
+ * 22:24 pre_high_time. Time to initialize 1st cycle for PIO and MW DMA xfer.
+ * 25:27 cmd_pre_high_time. Time to initialize 1st PIO cycle for task file
* register access.
- * 28 UDMA enable
- * 29 DMA enable
- * 30 PIO_MST enable. if set, the chip is in bus master mode during
- * PIO.
- * 31 FIFO enable.
+ * 28 UDMA enable.
+ * 29 DMA enable.
+ * 30 PIO_MST enable. If set, the chip is in bus master mode during
+ * PIO xfer.
+ * 31 FIFO enable. Only for PIO.
*/
/* 66MHz DPLL clocks */
@@ -80,14 +80,13 @@ static struct hpt_clock hpt3x2n_clocks[] = {
{ XFER_MW_DMA_2, 0x2c829c62 },
{ XFER_MW_DMA_1, 0x2c829c66 },
- { XFER_MW_DMA_0, 0x2c829d2c },
+ { XFER_MW_DMA_0, 0x2c829d2e },
{ XFER_PIO_4, 0x0c829c62 },
{ XFER_PIO_3, 0x0c829c84 },
{ XFER_PIO_2, 0x0c829ca6 },
{ XFER_PIO_1, 0x0d029d26 },
{ XFER_PIO_0, 0x0d029d5e },
- { 0, 0x0d029d5e }
};
/**
@@ -105,7 +104,7 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
{
struct hpt_clock *clocks = hpt3x2n_clocks;
- while(clocks->xfer_speed) {
+ while (clocks->xfer_speed) {
if (clocks->xfer_speed == speed)
return clocks->timing;
clocks++;
@@ -115,6 +114,22 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
}
/**
+ * hpt372n_filter - mode selection filter
+ * @adev: ATA device
+ * @mask: mode mask
+ *
+ * The Marvell bridge chips used on the HighPoint SATA cards do not seem
+ * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes...
+ */
+static unsigned long hpt372n_filter(struct ata_device *adev, unsigned long mask)
+{
+ if (ata_id_is_sata(adev->id))
+ mask &= ~((0xE << ATA_SHIFT_UDMA) | ATA_MASK_MWDMA);
+
+ return mask;
+}
+
+/**
* hpt3x2n_cable_detect - Detect the cable type
* @ap: ATA port to detect on
*
@@ -128,12 +143,15 @@ static int hpt3x2n_cable_detect(struct ata_port *ap)
pci_read_config_byte(pdev, 0x5B, &scr2);
pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01);
+
+ udelay(10); /* debounce */
+
/* Cable register now active */
pci_read_config_byte(pdev, 0x5A, &ata66);
/* Restore state */
pci_write_config_byte(pdev, 0x5B, scr2);
- if (ata66 & (1 << ap->port_no))
+ if (ata66 & (2 >> ap->port_no))
return ATA_CBL_PATA40;
else
return ATA_CBL_PATA80;
@@ -152,6 +170,7 @@ static int hpt3x2n_pre_reset(struct ata_link *link, unsigned long deadline)
{
struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
/* Reset the state machine */
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(100);
@@ -159,20 +178,12 @@ static int hpt3x2n_pre_reset(struct ata_link *link, unsigned long deadline)
return ata_sff_prereset(link, deadline);
}
-/**
- * hpt3x2n_set_piomode - PIO setup
- * @ap: ATA interface
- * @adev: device on the interface
- *
- * Perform PIO mode setup.
- */
-
-static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void hpt3x2n_set_mode(struct ata_port *ap, struct ata_device *adev,
+ u8 mode)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 addr1, addr2;
- u32 reg;
- u32 mode;
+ u32 reg, timing, mask;
u8 fast;
addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
@@ -183,12 +194,32 @@ static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
fast &= ~0x07;
pci_write_config_byte(pdev, addr2, fast);
+ /* Determine timing mask and find matching mode entry */
+ if (mode < XFER_MW_DMA_0)
+ mask = 0xcfc3ffff;
+ else if (mode < XFER_UDMA_0)
+ mask = 0x31c001ff;
+ else
+ mask = 0x303c0000;
+
+ timing = hpt3x2n_find_mode(ap, mode);
+
pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt3x2n_find_mode(ap, adev->pio_mode);
- mode &= ~0x8000000; /* No FIFO in PIO */
- mode &= ~0x30070000; /* Leave config bits alone */
- reg &= 0x30070000; /* Strip timing bits */
- pci_write_config_dword(pdev, addr1, reg | mode);
+ reg = (reg & ~mask) | (timing & mask);
+ pci_write_config_dword(pdev, addr1, reg);
+}
+
+/**
+ * hpt3x2n_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
+
+static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ hpt3x2n_set_mode(ap, adev, adev->pio_mode);
}
/**
@@ -196,32 +227,12 @@ static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
* @ap: ATA interface
* @adev: Device being configured
*
- * Set up the channel for MWDMA or UDMA modes. Much the same as with
- * PIO, load the mode number and then set MWDMA or UDMA flag.
+ * Set up the channel for MWDMA or UDMA modes.
*/
static void hpt3x2n_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 addr1, addr2;
- u32 reg;
- u32 mode;
- u8 fast;
-
- addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
- addr2 = 0x51 + 4 * ap->port_no;
-
- /* Fast interrupt prediction disable, hold off interrupt disable */
- pci_read_config_byte(pdev, addr2, &fast);
- fast &= ~0x07;
- pci_write_config_byte(pdev, addr2, fast);
-
- pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt3x2n_find_mode(ap, adev->dma_mode);
- mode |= 0x8000000; /* FIFO in MWDMA or UDMA */
- mode &= ~0xC0000000; /* Leave config bits alone */
- reg &= 0xC0000000; /* Strip timing bits */
- pci_write_config_dword(pdev, addr1, reg | mode);
+ hpt3x2n_set_mode(ap, adev, adev->dma_mode);
}
/**
@@ -263,7 +274,7 @@ static void hpt3x2n_bmdma_stop(struct ata_queued_cmd *qc)
static void hpt3x2n_set_clock(struct ata_port *ap, int source)
{
- void __iomem *bmdma = ap->ioaddr.bmdma_addr;
+ void __iomem *bmdma = ap->ioaddr.bmdma_addr - ap->port_no * 8;
/* Tristate the bus */
iowrite8(0x80, bmdma+0x73);
@@ -273,9 +284,9 @@ static void hpt3x2n_set_clock(struct ata_port *ap, int source)
iowrite8(source, bmdma+0x7B);
iowrite8(0xC0, bmdma+0x79);
- /* Reset state machines */
- iowrite8(0x37, bmdma+0x70);
- iowrite8(0x37, bmdma+0x74);
+ /* Reset state machines, avoid enabling the disabled channels */
+ iowrite8(ioread8(bmdma+0x70) | 0x32, bmdma+0x70);
+ iowrite8(ioread8(bmdma+0x74) | 0x32, bmdma+0x74);
/* Complete reset */
iowrite8(0x00, bmdma+0x79);
@@ -285,21 +296,10 @@ static void hpt3x2n_set_clock(struct ata_port *ap, int source)
iowrite8(0x00, bmdma+0x77);
}
-/* Check if our partner interface is busy */
-
-static int hpt3x2n_pair_idle(struct ata_port *ap)
-{
- struct ata_host *host = ap->host;
- struct ata_port *pair = host->ports[ap->port_no ^ 1];
-
- if (pair->hsm_task_state == HSM_ST_IDLE)
- return 1;
- return 0;
-}
-
static int hpt3x2n_use_dpll(struct ata_port *ap, int writing)
{
long flags = (long)ap->host->private_data;
+
/* See if we should use the DPLL */
if (writing)
return USE_DPLL; /* Needed for write */
@@ -308,22 +308,37 @@ static int hpt3x2n_use_dpll(struct ata_port *ap, int writing)
return 0;
}
+static int hpt3x2n_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_port *alt = ap->host->ports[ap->port_no ^ 1];
+ int rc, flags = (long)ap->host->private_data;
+ int dpll = hpt3x2n_use_dpll(ap, qc->tf.flags & ATA_TFLAG_WRITE);
+
+ /* First apply the usual rules */
+ rc = ata_std_qc_defer(qc);
+ if (rc != 0)
+ return rc;
+
+ if ((flags & USE_DPLL) != dpll && alt->qc_active)
+ return ATA_DEFER_PORT;
+ return 0;
+}
+
static unsigned int hpt3x2n_qc_issue(struct ata_queued_cmd *qc)
{
- struct ata_taskfile *tf = &qc->tf;
struct ata_port *ap = qc->ap;
int flags = (long)ap->host->private_data;
+ int dpll = hpt3x2n_use_dpll(ap, qc->tf.flags & ATA_TFLAG_WRITE);
- if (hpt3x2n_pair_idle(ap)) {
- int dpll = hpt3x2n_use_dpll(ap, (tf->flags & ATA_TFLAG_WRITE));
- if ((flags & USE_DPLL) != dpll) {
- if (dpll == 1)
- hpt3x2n_set_clock(ap, 0x21);
- else
- hpt3x2n_set_clock(ap, 0x23);
- }
+ if ((flags & USE_DPLL) != dpll) {
+ flags &= ~USE_DPLL;
+ flags |= dpll;
+ ap->host->private_data = (void *)(long)flags;
+
+ hpt3x2n_set_clock(ap, dpll ? 0x21 : 0x23);
}
- return ata_sff_qc_issue(qc);
+ return ata_bmdma_qc_issue(qc);
}
static struct scsi_host_template hpt3x2n_sht = {
@@ -331,13 +346,15 @@ static struct scsi_host_template hpt3x2n_sht = {
};
/*
- * Configuration for HPT3x2n.
+ * Configuration for HPT302N/371N.
*/
-static struct ata_port_operations hpt3x2n_port_ops = {
+static struct ata_port_operations hpt3xxn_port_ops = {
.inherits = &ata_bmdma_port_ops,
.bmdma_stop = hpt3x2n_bmdma_stop,
+
+ .qc_defer = hpt3x2n_qc_defer,
.qc_issue = hpt3x2n_qc_issue,
.cable_detect = hpt3x2n_cable_detect,
@@ -346,6 +363,15 @@ static struct ata_port_operations hpt3x2n_port_ops = {
.prereset = hpt3x2n_pre_reset,
};
+/*
+ * Configuration for HPT372N. Same as 302N/371N but we have a mode filter.
+ */
+
+static struct ata_port_operations hpt372n_port_ops = {
+ .inherits = &hpt3xxn_port_ops,
+ .mode_filter = &hpt372n_filter,
+};
+
/**
* hpt3xn_calibrate_dpll - Calibrate the DPLL loop
* @dev: PCI device
@@ -360,12 +386,12 @@ static int hpt3xn_calibrate_dpll(struct pci_dev *dev)
u32 reg5c;
int tries;
- for(tries = 0; tries < 0x5000; tries++) {
+ for (tries = 0; tries < 0x5000; tries++) {
udelay(50);
pci_read_config_byte(dev, 0x5b, &reg5b);
if (reg5b & 0x80) {
/* See if it stays set */
- for(tries = 0; tries < 0x1000; tries ++) {
+ for (tries = 0; tries < 0x1000; tries++) {
pci_read_config_byte(dev, 0x5b, &reg5b);
/* Failed ? */
if ((reg5b & 0x80) == 0)
@@ -373,7 +399,7 @@ static int hpt3xn_calibrate_dpll(struct pci_dev *dev)
}
/* Turn off tuning, we have the DPLL set */
pci_read_config_dword(dev, 0x5c, &reg5c);
- pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100);
+ pci_write_config_dword(dev, 0x5c, reg5c & ~0x100);
return 1;
}
}
@@ -389,8 +415,19 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev)
fcnt = inl(iobase + 0x90); /* Not PCI readable for some chips */
if ((fcnt >> 12) != 0xABCDE) {
- printk(KERN_WARNING "hpt3xn: BIOS clock data not set.\n");
- return 33; /* Not BIOS set */
+ int i;
+ u16 sr;
+ u32 total = 0;
+
+ pr_warn("BIOS clock data not set\n");
+
+ /* This is the process the HPT371 BIOS is reported to use */
+ for (i = 0; i < 128; i++) {
+ pci_read_config_word(pdev, 0x78, &sr);
+ total += sr & 0x1FF;
+ udelay(15);
+ }
+ fcnt = total / 128;
}
fcnt &= 0x1FF;
@@ -432,63 +469,68 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev)
* HPT372N 9 (HPT372N) * UDMA133
*
* (1) UDMA133 support depends on the bus clock
- *
- * To pin down HPT371N
*/
static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- /* HPT372N and friends - UDMA133 */
- static const struct ata_port_info info = {
+ /* HPT372N - UDMA133 */
+ static const struct ata_port_info info_hpt372n = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
- .port_ops = &hpt3x2n_port_ops
+ .port_ops = &hpt372n_port_ops
};
- const struct ata_port_info *ppi[] = { &info, NULL };
-
+ /* HPT302N and HPT371N - UDMA133 */
+ static const struct ata_port_info info_hpt3xxn = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &hpt3xxn_port_ops
+ };
+ const struct ata_port_info *ppi[] = { &info_hpt3xxn, NULL };
+ u8 rev = dev->revision;
u8 irqmask;
- u32 class_rev;
-
unsigned int pci_mhz;
unsigned int f_low, f_high;
int adjust;
unsigned long iobase = pci_resource_start(dev, 4);
- void *hpriv = NULL;
+ void *hpriv = (void *)USE_DPLL;
int rc;
rc = pcim_enable_device(dev);
if (rc)
return rc;
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xFF;
-
- switch(dev->device) {
- case PCI_DEVICE_ID_TTI_HPT366:
- if (class_rev < 6)
- return -ENODEV;
- break;
- case PCI_DEVICE_ID_TTI_HPT371:
- if (class_rev < 2)
- return -ENODEV;
- /* 371N if rev > 1 */
- break;
- case PCI_DEVICE_ID_TTI_HPT372:
- /* 372N if rev >= 2*/
- if (class_rev < 2)
- return -ENODEV;
- break;
- case PCI_DEVICE_ID_TTI_HPT302:
- if (class_rev < 2)
- return -ENODEV;
- break;
- case PCI_DEVICE_ID_TTI_HPT372N:
- break;
- default:
- printk(KERN_ERR "pata_hpt3x2n: PCI table is bogus please report (%d).\n", dev->device);
+ switch (dev->device) {
+ case PCI_DEVICE_ID_TTI_HPT366:
+ /* 372N if rev >= 6 */
+ if (rev < 6)
return -ENODEV;
+ goto hpt372n;
+ case PCI_DEVICE_ID_TTI_HPT371:
+ /* 371N if rev >= 2 */
+ if (rev < 2)
+ return -ENODEV;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT372:
+ /* 372N if rev >= 2 */
+ if (rev < 2)
+ return -ENODEV;
+ goto hpt372n;
+ case PCI_DEVICE_ID_TTI_HPT302:
+ /* 302N if rev >= 2 */
+ if (rev < 2)
+ return -ENODEV;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT372N:
+hpt372n:
+ ppi[0] = &info_hpt372n;
+ break;
+ default:
+ pr_err("PCI table is bogus, please report (%d)\n", dev->device);
+ return -ENODEV;
}
/* Ok so this is a chip we support */
@@ -515,8 +557,10 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
pci_write_config_byte(dev, 0x50, mcr1);
}
- /* Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or
- 50 for UDMA100. Right now we always use 66 */
+ /*
+ * Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or
+ * 50 for UDMA100. Right now we always use 66
+ */
pci_mhz = hpt3x2n_pci_clock(dev);
@@ -528,33 +572,35 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
pci_write_config_byte(dev, 0x5B, 0x21);
/* Unlike the 37x we don't try jiggling the frequency */
- for(adjust = 0; adjust < 8; adjust++) {
+ for (adjust = 0; adjust < 8; adjust++) {
if (hpt3xn_calibrate_dpll(dev))
break;
pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
}
if (adjust == 8) {
- printk(KERN_ERR "pata_hpt3x2n: DPLL did not stabilize!\n");
+ pr_err("DPLL did not stabilize!\n");
return -ENODEV;
}
- printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using 66MHz DPLL.\n",
- pci_mhz);
- /* Set our private data up. We only need a few flags so we use
- it directly */
- if (pci_mhz > 60) {
- hpriv = (void *)PCI66;
- /*
- * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
- * the MISC. register to stretch the UltraDMA Tss timing.
- * NOTE: This register is only writeable via I/O space.
- */
- if (dev->device == PCI_DEVICE_ID_TTI_HPT371)
- outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c);
- }
+ pr_info("bus clock %dMHz, using 66MHz DPLL\n", pci_mhz);
+
+ /*
+ * Set our private data up. We only need a few flags
+ * so we use it directly.
+ */
+ if (pci_mhz > 60)
+ hpriv = (void *)(PCI66 | USE_DPLL);
+
+ /*
+ * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
+ * the MISC. register to stretch the UltraDMA Tss timing.
+ * NOTE: This register is only writeable via I/O space.
+ */
+ if (dev->device == PCI_DEVICE_ID_TTI_HPT371)
+ outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c);
/* Now kick off ATA set up */
- return ata_pci_sff_init_one(dev, ppi, &hpt3x2n_sht, hpriv);
+ return ata_pci_bmdma_init_one(dev, ppi, &hpt3x2n_sht, hpriv, 0);
}
static const struct pci_device_id hpt3x2n[] = {
@@ -568,27 +614,16 @@ static const struct pci_device_id hpt3x2n[] = {
};
static struct pci_driver hpt3x2n_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt3x2n,
- .probe = hpt3x2n_init_one,
+ .probe = hpt3x2n_init_one,
.remove = ata_pci_remove_one
};
-static int __init hpt3x2n_init(void)
-{
- return pci_register_driver(&hpt3x2n_pci_driver);
-}
-
-static void __exit hpt3x2n_exit(void)
-{
- pci_unregister_driver(&hpt3x2n_pci_driver);
-}
+module_pci_driver(hpt3x2n_pci_driver);
MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3x2n/30x");
+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3xxN");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, hpt3x2n);
MODULE_VERSION(DRV_VERSION);
-
-module_init(hpt3x2n_init);
-module_exit(hpt3x2n_exit);
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index f11a320337c..d019cdd5bc9 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -16,14 +16,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "pata_hpt3x3"
-#define DRV_VERSION "0.5.3"
+#define DRV_VERSION "0.6.1"
/**
* hpt3x3_set_piomode - PIO setup
@@ -80,14 +79,48 @@ static void hpt3x3_set_dmamode(struct ata_port *ap, struct ata_device *adev)
r2 &= ~(0x11 << dn); /* Clear MWDMA and UDMA bits */
if (adev->dma_mode >= XFER_UDMA_0)
- r2 |= (0x10 << dn); /* Ultra mode */
+ r2 |= (0x01 << dn); /* Ultra mode */
else
- r2 |= (0x01 << dn); /* MWDMA */
+ r2 |= (0x10 << dn); /* MWDMA */
pci_write_config_dword(pdev, 0x44, r1);
pci_write_config_dword(pdev, 0x48, r2);
}
-#endif /* CONFIG_PATA_HPT3X3_DMA */
+
+/**
+ * hpt3x3_freeze - DMA workaround
+ * @ap: port to freeze
+ *
+ * When freezing an HPT3x3 we must stop any pending DMA before
+ * writing to the control register or the chip will hang
+ */
+
+static void hpt3x3_freeze(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ iowrite8(ioread8(mmio + ATA_DMA_CMD) & ~ ATA_DMA_START,
+ mmio + ATA_DMA_CMD);
+ ata_sff_dma_pause(ap);
+ ata_sff_freeze(ap);
+}
+
+/**
+ * hpt3x3_bmdma_setup - DMA workaround
+ * @qc: Queued command
+ *
+ * When issuing BMDMA we must clean up the error/active bits in
+ * software on this device
+ */
+
+static void hpt3x3_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ u8 r = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ r |= ATA_DMA_INTR | ATA_DMA_ERR;
+ iowrite8(r, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ return ata_bmdma_setup(qc);
+}
/**
* hpt3x3_atapi_dma - ATAPI DMA check
@@ -101,18 +134,23 @@ static int hpt3x3_atapi_dma(struct ata_queued_cmd *qc)
return 1;
}
+#endif /* CONFIG_PATA_HPT3X3_DMA */
+
static struct scsi_host_template hpt3x3_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
static struct ata_port_operations hpt3x3_port_ops = {
.inherits = &ata_bmdma_port_ops,
- .check_atapi_dma= hpt3x3_atapi_dma,
.cable_detect = ata_cable_40wire,
.set_piomode = hpt3x3_set_piomode,
#if defined(CONFIG_PATA_HPT3X3_DMA)
.set_dmamode = hpt3x3_set_dmamode,
+ .bmdma_setup = hpt3x3_bmdma_setup,
+ .check_atapi_dma= hpt3x3_atapi_dma,
+ .freeze = hpt3x3_freeze,
#endif
+
};
/**
@@ -141,19 +179,18 @@ static void hpt3x3_init_chipset(struct pci_dev *dev)
* @id: Entry in match table
*
* Perform basic initialisation. We set the device up so we access all
- * ports via BAR4. This is neccessary to work around errata.
+ * ports via BAR4. This is necessary to work around errata.
*/
static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
- static int printed_version;
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
+ .pio_mask = ATA_PIO4,
#if defined(CONFIG_PATA_HPT3X3_DMA)
/* Further debug needed */
- .mwdma_mask = 0x07,
- .udma_mask = 0x07,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
#endif
.port_ops = &hpt3x3_port_ops
};
@@ -167,8 +204,7 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
hpt3x3_init_chipset(pdev);
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
if (!host)
@@ -209,15 +245,24 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
ata_port_pbar_desc(ap, 4, offset_cmd[i], "cmd");
}
pci_set_master(pdev);
- return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+ return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
IRQF_SHARED, &hpt3x3_sht);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int hpt3x3_reinit_one(struct pci_dev *dev)
{
+ struct ata_host *host = pci_get_drvdata(dev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(dev);
+ if (rc)
+ return rc;
+
hpt3x3_init_chipset(dev);
- return ata_pci_device_resume(dev);
+
+ ata_host_resume(host);
+ return 0;
}
#endif
@@ -232,29 +277,16 @@ static struct pci_driver hpt3x3_pci_driver = {
.id_table = hpt3x3,
.probe = hpt3x3_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = hpt3x3_reinit_one,
#endif
};
-static int __init hpt3x3_init(void)
-{
- return pci_register_driver(&hpt3x3_pci_driver);
-}
-
-
-static void __exit hpt3x3_exit(void)
-{
- pci_unregister_driver(&hpt3x3_pci_driver);
-}
-
+module_pci_driver(hpt3x3_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the Highpoint HPT343/363");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, hpt3x3);
MODULE_VERSION(DRV_VERSION);
-
-module_init(hpt3x3_init);
-module_exit(hpt3x3_exit);
diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c
index 17138436423..d7c732042a4 100644
--- a/drivers/ata/pata_icside.c
+++ b/drivers/ata/pata_icside.c
@@ -2,6 +2,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/blkdev.h>
+#include <linux/gfp.h>
#include <scsi/scsi_host.h>
#include <linux/ata.h>
#include <linux/libata.h>
@@ -45,8 +46,6 @@ static const struct portinfo pata_icside_portinfo_v6_2 = {
.stepping = 6,
};
-#define PATA_ICSIDE_MAX_SG 128
-
struct pata_icside_state {
void __iomem *irq_port;
void __iomem *ioc_base;
@@ -57,7 +56,6 @@ struct pata_icside_state {
u8 disabled;
unsigned int speed[ATA_MAX_DEVICES];
} port[2];
- struct scatterlist sg[PATA_ICSIDE_MAX_SG];
};
struct pata_icside_info {
@@ -212,8 +210,8 @@ static void pata_icside_set_dmamode(struct ata_port *ap, struct ata_device *adev
else
iomd_type = 'A', cycle = 562;
- ata_dev_printk(adev, KERN_INFO, "timings: act %dns rec %dns cyc %dns (%c)\n",
- t.active, t.recover, t.cycle, iomd_type);
+ ata_dev_info(adev, "timings: act %dns rec %dns cyc %dns (%c)\n",
+ t.active, t.recover, t.cycle, iomd_type);
state->port[ap->port_no].speed[adev->devno] = cycle;
}
@@ -222,9 +220,7 @@ static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pata_icside_state *state = ap->host->private_data;
- struct scatterlist *sg, *rsg = state->sg;
unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE;
- unsigned int si;
/*
* We are simplex; BUG if we try to fiddle with DMA
@@ -233,20 +229,12 @@ static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc)
BUG_ON(dma_channel_active(state->dma));
/*
- * Copy ATAs scattered sg list into a contiguous array of sg
- */
- for_each_sg(qc->sg, sg, qc->n_elem, si) {
- memcpy(rsg, sg, sizeof(*sg));
- rsg++;
- }
-
- /*
* Route the DMA signals to the correct interface
*/
writeb(state->port[ap->port_no].port_sel, state->ioc_base);
set_dma_speed(state->dma, state->port[ap->port_no].speed[qc->dev->devno]);
- set_dma_sg(state->dma, state->sg, rsg - state->sg);
+ set_dma_sg(state->dma, qc->sg, qc->n_elem);
set_dma_mode(state->dma, write ? DMA_MODE_WRITE : DMA_MODE_READ);
/* issue r/w command */
@@ -270,7 +258,7 @@ static void pata_icside_bmdma_stop(struct ata_queued_cmd *qc)
disable_dma(state->dma);
/* see ata_bmdma_stop */
- ata_sff_altstatus(ap);
+ ata_sff_dma_pause(ap);
}
static u8 pata_icside_bmdma_status(struct ata_port *ap)
@@ -297,7 +285,7 @@ static int icside_dma_init(struct pata_icside_info *info)
if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) {
state->dma = ec->dma;
- info->mwdma_mask = 0x07; /* MW0..2 */
+ info->mwdma_mask = ATA_MWDMA2;
}
return 0;
@@ -306,8 +294,8 @@ static int icside_dma_init(struct pata_icside_info *info)
static struct scsi_host_template pata_icside_sht = {
ATA_BASE_SHT(DRV_NAME),
- .sg_tablesize = PATA_ICSIDE_MAX_SG,
- .dma_boundary = ~0, /* no dma boundaries */
+ .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS,
+ .dma_boundary = IOMD_DMA_BOUNDARY,
};
static void pata_icside_postreset(struct ata_link *link, unsigned int *classes)
@@ -333,7 +321,7 @@ static void pata_icside_postreset(struct ata_link *link, unsigned int *classes)
}
static struct ata_port_operations pata_icside_port_ops = {
- .inherits = &ata_sff_port_ops,
+ .inherits = &ata_bmdma_port_ops,
/* no need to build any PRD tables for DMA */
.qc_prep = ata_noop_qc_prep,
.sff_data_xfer = ata_sff_data_xfer_noirq,
@@ -345,13 +333,13 @@ static struct ata_port_operations pata_icside_port_ops = {
.cable_detect = ata_cable_40wire,
.set_dmamode = pata_icside_set_dmamode,
.postreset = pata_icside_postreset,
- .post_internal_cmd = pata_icside_bmdma_stop,
+
+ .port_start = ATA_OP_NULL, /* don't need PRD table */
};
-static void __devinit
-pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,
- struct pata_icside_info *info,
- const struct portinfo *port)
+static void pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,
+ struct pata_icside_info *info,
+ const struct portinfo *port)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
void __iomem *cmd = base + port->dataoffset;
@@ -379,7 +367,7 @@ pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,
ata_port_desc(ap, "iocbase 0x%lx", info->raw_ioc_base);
}
-static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
+static int pata_icside_register_v5(struct pata_icside_info *info)
{
struct pata_icside_state *state = info->state;
void __iomem *base;
@@ -402,7 +390,7 @@ static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
return 0;
}
-static int __devinit pata_icside_register_v6(struct pata_icside_info *info)
+static int pata_icside_register_v6(struct pata_icside_info *info)
{
struct pata_icside_state *state = info->state;
struct expansion_card *ec = info->ec;
@@ -445,7 +433,7 @@ static int __devinit pata_icside_register_v6(struct pata_icside_info *info)
return icside_dma_init(info);
}
-static int __devinit pata_icside_add_ports(struct pata_icside_info *info)
+static int pata_icside_add_ports(struct pata_icside_info *info)
{
struct expansion_card *ec = info->ec;
struct ata_host *host;
@@ -473,7 +461,7 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info)
for (i = 0; i < info->nr_ports; i++) {
struct ata_port *ap = host->ports[i];
- ap->pio_mask = 0x1f;
+ ap->pio_mask = ATA_PIO4;
ap->mwdma_mask = info->mwdma_mask;
ap->flags |= ATA_FLAG_SLAVE_POSS;
ap->ops = &pata_icside_port_ops;
@@ -481,12 +469,12 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info)
pata_icside_setup_ioaddr(ap, info->base, info, info->port[i]);
}
- return ata_host_activate(host, ec->irq, ata_sff_interrupt, 0,
+ return ata_host_activate(host, ec->irq, ata_bmdma_interrupt, 0,
&pata_icside_sht);
}
-static int __devinit
-pata_icside_probe(struct expansion_card *ec, const struct ecard_id *id)
+static int pata_icside_probe(struct expansion_card *ec,
+ const struct ecard_id *id)
{
struct pata_icside_state *state;
struct pata_icside_info info;
@@ -586,7 +574,7 @@ static void pata_icside_shutdown(struct expansion_card *ec)
}
}
-static void __devexit pata_icside_remove(struct expansion_card *ec)
+static void pata_icside_remove(struct expansion_card *ec)
{
struct ata_host *host = ecard_get_drvdata(ec);
struct pata_icside_state *state = host->private_data;
@@ -613,7 +601,7 @@ static const struct ecard_id pata_icside_ids[] = {
static struct ecard_driver pata_icside_driver = {
.probe = pata_icside_probe,
- .remove = __devexit_p(pata_icside_remove),
+ .remove = pata_icside_remove,
.shutdown = pata_icside_shutdown,
.id_table = pata_icside_ids,
.drv = {
diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c
new file mode 100644
index 00000000000..af424573c2f
--- /dev/null
+++ b/drivers/ata/pata_imx.c
@@ -0,0 +1,258 @@
+/*
+ * Freescale iMX PATA driver
+ *
+ * Copyright (C) 2011 Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * Based on pata_platform - Copyright (C) 2006 - 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * TODO:
+ * - dmaengine support
+ * - check if timing stuff needed
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#define DRV_NAME "pata_imx"
+
+#define PATA_IMX_ATA_CONTROL 0x24
+#define PATA_IMX_ATA_CTRL_FIFO_RST_B (1<<7)
+#define PATA_IMX_ATA_CTRL_ATA_RST_B (1<<6)
+#define PATA_IMX_ATA_CTRL_IORDY_EN (1<<0)
+#define PATA_IMX_ATA_INT_EN 0x2C
+#define PATA_IMX_ATA_INTR_ATA_INTRQ2 (1<<3)
+#define PATA_IMX_DRIVE_DATA 0xA0
+#define PATA_IMX_DRIVE_CONTROL 0xD8
+
+struct pata_imx_priv {
+ struct clk *clk;
+ /* timings/interrupt/control regs */
+ void __iomem *host_regs;
+ u32 ata_ctl;
+};
+
+static int pata_imx_set_mode(struct ata_link *link, struct ata_device **unused)
+{
+ struct ata_device *dev;
+ struct ata_port *ap = link->ap;
+ struct pata_imx_priv *priv = ap->host->private_data;
+ u32 val;
+
+ ata_for_each_dev(dev, link, ENABLED) {
+ dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+
+ val = __raw_readl(priv->host_regs + PATA_IMX_ATA_CONTROL);
+ if (ata_pio_need_iordy(dev))
+ val |= PATA_IMX_ATA_CTRL_IORDY_EN;
+ else
+ val &= ~PATA_IMX_ATA_CTRL_IORDY_EN;
+ __raw_writel(val, priv->host_regs + PATA_IMX_ATA_CONTROL);
+
+ ata_dev_info(dev, "configured for PIO\n");
+ }
+ return 0;
+}
+
+static struct scsi_host_template pata_imx_sht = {
+ ATA_PIO_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations pata_imx_port_ops = {
+ .inherits = &ata_sff_port_ops,
+ .sff_data_xfer = ata_sff_data_xfer_noirq,
+ .cable_detect = ata_cable_unknown,
+ .set_mode = pata_imx_set_mode,
+};
+
+static void pata_imx_setup_port(struct ata_ioports *ioaddr)
+{
+ /* Fixup the port shift for platforms that need it */
+ ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << 2);
+ ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << 2);
+ ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << 2);
+ ioaddr->nsect_addr = ioaddr->cmd_addr + (ATA_REG_NSECT << 2);
+ ioaddr->lbal_addr = ioaddr->cmd_addr + (ATA_REG_LBAL << 2);
+ ioaddr->lbam_addr = ioaddr->cmd_addr + (ATA_REG_LBAM << 2);
+ ioaddr->lbah_addr = ioaddr->cmd_addr + (ATA_REG_LBAH << 2);
+ ioaddr->device_addr = ioaddr->cmd_addr + (ATA_REG_DEVICE << 2);
+ ioaddr->status_addr = ioaddr->cmd_addr + (ATA_REG_STATUS << 2);
+ ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << 2);
+}
+
+static int pata_imx_probe(struct platform_device *pdev)
+{
+ struct ata_host *host;
+ struct ata_port *ap;
+ struct pata_imx_priv *priv;
+ int irq = 0;
+ struct resource *io_res;
+ int ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ priv = devm_kzalloc(&pdev->dev,
+ sizeof(struct pata_imx_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(&pdev->dev, "Failed to get clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ host->private_data = priv;
+ ap = host->ports[0];
+
+ ap->ops = &pata_imx_port_ops;
+ ap->pio_mask = ATA_PIO0;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
+
+ io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->host_regs = devm_ioremap_resource(&pdev->dev, io_res);
+ if (IS_ERR(priv->host_regs)) {
+ ret = PTR_ERR(priv->host_regs);
+ goto err;
+ }
+
+ ap->ioaddr.cmd_addr = priv->host_regs + PATA_IMX_DRIVE_DATA;
+ ap->ioaddr.ctl_addr = priv->host_regs + PATA_IMX_DRIVE_CONTROL;
+
+ ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
+
+ pata_imx_setup_port(&ap->ioaddr);
+
+ ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+ (unsigned long long)io_res->start + PATA_IMX_DRIVE_DATA,
+ (unsigned long long)io_res->start + PATA_IMX_DRIVE_CONTROL);
+
+ /* deassert resets */
+ __raw_writel(PATA_IMX_ATA_CTRL_FIFO_RST_B |
+ PATA_IMX_ATA_CTRL_ATA_RST_B,
+ priv->host_regs + PATA_IMX_ATA_CONTROL);
+ /* enable interrupts */
+ __raw_writel(PATA_IMX_ATA_INTR_ATA_INTRQ2,
+ priv->host_regs + PATA_IMX_ATA_INT_EN);
+
+ /* activate */
+ ret = ata_host_activate(host, irq, ata_sff_interrupt, 0,
+ &pata_imx_sht);
+
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ clk_disable_unprepare(priv->clk);
+
+ return ret;
+}
+
+static int pata_imx_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct pata_imx_priv *priv = host->private_data;
+
+ ata_host_detach(host);
+
+ __raw_writel(0, priv->host_regs + PATA_IMX_ATA_INT_EN);
+
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pata_imx_suspend(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct pata_imx_priv *priv = host->private_data;
+ int ret;
+
+ ret = ata_host_suspend(host, PMSG_SUSPEND);
+ if (!ret) {
+ __raw_writel(0, priv->host_regs + PATA_IMX_ATA_INT_EN);
+ priv->ata_ctl =
+ __raw_readl(priv->host_regs + PATA_IMX_ATA_CONTROL);
+ clk_disable_unprepare(priv->clk);
+ }
+
+ return ret;
+}
+
+static int pata_imx_resume(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct pata_imx_priv *priv = host->private_data;
+
+ int ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ __raw_writel(priv->ata_ctl, priv->host_regs + PATA_IMX_ATA_CONTROL);
+
+ __raw_writel(PATA_IMX_ATA_INTR_ATA_INTRQ2,
+ priv->host_regs + PATA_IMX_ATA_INT_EN);
+
+ ata_host_resume(host);
+
+ return 0;
+}
+
+static const struct dev_pm_ops pata_imx_pm_ops = {
+ .suspend = pata_imx_suspend,
+ .resume = pata_imx_resume,
+};
+#endif
+
+static const struct of_device_id imx_pata_dt_ids[] = {
+ {
+ .compatible = "fsl,imx27-pata",
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, imx_pata_dt_ids);
+
+static struct platform_driver pata_imx_driver = {
+ .probe = pata_imx_probe,
+ .remove = pata_imx_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = imx_pata_dt_ids,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM_SLEEP
+ .pm = &pata_imx_pm_ops,
+#endif
+ },
+};
+
+module_platform_driver(pata_imx_driver);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
+MODULE_DESCRIPTION("low-level driver for iMX PATA");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
index 6a111baab52..b33d1f99b3a 100644
--- a/drivers/ata/pata_isapnp.c
+++ b/drivers/ata/pata_isapnp.c
@@ -1,7 +1,7 @@
/*
* pata-isapnp.c - ISA PnP PATA controller driver.
- * Copyright 2005/2006 Red Hat Inc <alan@redhat.com>, all rights reserved.
+ * Copyright 2005/2006 Red Hat Inc, all rights reserved.
*
* Based in part on ide-pnp.c by Andrey Panin <pazke@donpac.ru>
*/
@@ -17,7 +17,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_isapnp"
-#define DRV_VERSION "0.2.2"
+#define DRV_VERSION "0.2.5"
static struct scsi_host_template isapnp_sht = {
ATA_PIO_SHT(DRV_NAME),
@@ -28,6 +28,13 @@ static struct ata_port_operations isapnp_port_ops = {
.cable_detect = ata_cable_40wire,
};
+static struct ata_port_operations isapnp_noalt_port_ops = {
+ .inherits = &ata_sff_port_ops,
+ .cable_detect = ata_cable_40wire,
+ /* No altstatus so we don't want to use the lost interrupt poll */
+ .lost_interrupt = ATA_OP_NULL,
+};
+
/**
* isapnp_init_one - attach an isapnp interface
* @idev: PnP device
@@ -65,17 +72,18 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
ap = host->ports[0];
- ap->ops = &isapnp_port_ops;
- ap->pio_mask = 1;
+ ap->ops = &isapnp_noalt_port_ops;
+ ap->pio_mask = ATA_PIO0;
ap->flags |= ATA_FLAG_SLAVE_POSS;
ap->ioaddr.cmd_addr = cmd_addr;
- if (pnp_port_valid(idev, 1) == 0) {
+ if (pnp_port_valid(idev, 1)) {
ctl_addr = devm_ioport_map(&idev->dev,
pnp_port_start(idev, 1), 1);
ap->ioaddr.altstatus_addr = ctl_addr;
ap->ioaddr.ctl_addr = ctl_addr;
+ ap->ops = &isapnp_port_ops;
}
ata_sff_std_ports(&ap->ioaddr);
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
index c113d7c079c..4f97d1e52f8 100644
--- a/drivers/ata/pata_it8213.c
+++ b/drivers/ata/pata_it8213.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -22,7 +21,7 @@
#define DRV_VERSION "0.0.3"
/**
- * it8213_pre_reset - check for 40/80 pin
+ * it8213_pre_reset - probe begin
* @link: link
* @deadline: deadline jiffies for the operation
*
@@ -76,8 +75,8 @@ static void it8213_set_piomode (struct ata_port *ap, struct ata_device *adev)
{
unsigned int pio = adev->pio_mode - XFER_PIO_0;
struct pci_dev *dev = to_pci_dev(ap->host->dev);
- unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
- u16 idetm_data;
+ unsigned int master_port = ap->port_no ? 0x42 : 0x40;
+ u16 master_data;
int control = 0;
/*
@@ -92,38 +91,37 @@ static void it8213_set_piomode (struct ata_port *ap, struct ata_device *adev)
{ 2, 1 },
{ 2, 3 }, };
- if (pio > 2)
- control |= 1; /* TIME1 enable */
+ if (pio > 1)
+ control |= 1; /* TIME */
if (ata_pio_need_iordy(adev)) /* PIO 3/4 require IORDY */
- control |= 2; /* IORDY enable */
+ control |= 2; /* IE */
/* Bit 2 is set for ATAPI on the IT8213 - reverse of ICH/PIIX */
if (adev->class != ATA_DEV_ATA)
- control |= 4;
-
- pci_read_config_word(dev, idetm_port, &idetm_data);
+ control |= 4; /* PPE */
- /* Enable PPE, IE and TIME as appropriate */
+ pci_read_config_word(dev, master_port, &master_data);
+ /* Set PPE, IE, and TIME as appropriate */
if (adev->devno == 0) {
- idetm_data &= 0xCCF0;
- idetm_data |= control;
- idetm_data |= (timings[pio][0] << 12) |
+ master_data &= 0xCCF0;
+ master_data |= control;
+ master_data |= (timings[pio][0] << 12) |
(timings[pio][1] << 8);
} else {
u8 slave_data;
- idetm_data &= 0xCC0F;
- idetm_data |= (control << 4);
+ master_data &= 0xFF0F;
+ master_data |= (control << 4);
/* Slave timing in separate register */
pci_read_config_byte(dev, 0x44, &slave_data);
slave_data &= 0xF0;
- slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << 4;
+ slave_data |= (timings[pio][0] << 2) | timings[pio][1];
pci_write_config_byte(dev, 0x44, slave_data);
}
- idetm_data |= 0x4000; /* Ensure SITRE is enabled */
- pci_write_config_word(dev, idetm_port, idetm_data);
+ master_data |= 0x4000; /* Ensure SITRE is set */
+ pci_write_config_word(dev, master_port, master_data);
}
/**
@@ -164,7 +162,7 @@ static void it8213_set_dmamode (struct ata_port *ap, struct ata_device *adev)
/* Clocks follow the PIIX style */
u_speed = min(2 - (udma & 1), udma);
- if (udma == 5)
+ if (udma > 4)
u_clock = 0x1000; /* 100Mhz */
else if (udma > 2)
u_clock = 1; /* 66Mhz */
@@ -173,10 +171,10 @@ static void it8213_set_dmamode (struct ata_port *ap, struct ata_device *adev)
udma_enable |= (1 << devid);
- /* Load the UDMA mode number */
+ /* Load the UDMA cycle time */
pci_read_config_word(dev, 0x4A, &udma_timing);
udma_timing &= ~(3 << (4 * devid));
- udma_timing |= (udma & 3) << (4 * devid);
+ udma_timing |= u_speed << (4 * devid);
pci_write_config_word(dev, 0x4A, udma_timing);
/* Load the clock selection */
@@ -211,7 +209,7 @@ static void it8213_set_dmamode (struct ata_port *ap, struct ata_device *adev)
master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */
master_data |= control << 4;
pci_read_config_byte(dev, 0x44, &slave_data);
- slave_data &= (0x0F + 0xE1 * ap->port_no);
+ slave_data &= 0xF0;
/* Load the matching timing */
slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
pci_write_config_byte(dev, 0x44, slave_data);
@@ -259,22 +257,19 @@ static struct ata_port_operations it8213_ops = {
static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = ATA_UDMA4, /* FIXME: want UDMA 100? */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA12_ONLY,
+ .udma_mask = ATA_UDMA6,
.port_ops = &it8213_ops,
};
/* Current IT8213 stuff is single port */
const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev,
- "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
- return ata_pci_sff_init_one(pdev, ppi, &it8213_sht, NULL);
+ return ata_pci_bmdma_init_one(pdev, ppi, &it8213_sht, NULL, 0);
}
static const struct pci_device_id it8213_pci_tbl[] = {
@@ -288,24 +283,13 @@ static struct pci_driver it8213_pci_driver = {
.id_table = it8213_pci_tbl,
.probe = it8213_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init it8213_init(void)
-{
- return pci_register_driver(&it8213_pci_driver);
-}
-
-static void __exit it8213_exit(void)
-{
- pci_unregister_driver(&it8213_pci_driver);
-}
-
-module_init(it8213_init);
-module_exit(it8213_exit);
+module_pci_driver(it8213_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("SCSI low-level driver for the ITE 8213");
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index e10816931b2..a5088ecb349 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -1,7 +1,7 @@
/*
* pata_it821x.c - IT821x PATA for new ATA layer
* (C) 2005 Red Hat Inc
- * Alan Cox <alan@redhat.com>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
* (C) 2007 Bartlomiej Zolnierkiewicz
*
* based upon
@@ -10,13 +10,13 @@
*
* linux/drivers/ide/pci/it821x.c Version 0.09 December 2004
*
- * Copyright (C) 2004 Red Hat <alan@redhat.com>
+ * Copyright (C) 2004 Red Hat
*
* May be copied or modified under the terms of the GNU General Public License
* Based in part on the ITE vendor provided SCSI driver.
*
- * Documentation available from
- * http://www.ite.com.tw/pc/IT8212F_V04.pdf
+ * Documentation available from IT8212F_V04.pdf
+ * http://www.ite.com.tw/EN/products_more.aspx?CategoryID=3&ID=5,91
* Some other documents are NDA.
*
* The ITE8212 isn't exactly a standard IDE controller. It has two
@@ -72,15 +72,15 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
+#include <linux/slab.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "pata_it821x"
-#define DRV_VERSION "0.3.8"
+#define DRV_VERSION "0.4.2"
struct it821x_dev
{
@@ -425,9 +425,11 @@ static unsigned int it821x_smart_qc_issue(struct ata_queued_cmd *qc)
case ATA_CMD_WRITE_MULTI:
case ATA_CMD_WRITE_MULTI_EXT:
case ATA_CMD_ID_ATA:
+ case ATA_CMD_INIT_DEV_PARAMS:
+ case 0xFC: /* Internal 'report rebuild state' */
/* Arguably should just no-op this one */
case ATA_CMD_SET_FEATURES:
- return ata_sff_qc_issue(qc);
+ return ata_bmdma_qc_issue(qc);
}
printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command);
return AC_ERR_DEV;
@@ -445,7 +447,7 @@ static unsigned int it821x_smart_qc_issue(struct ata_queued_cmd *qc)
static unsigned int it821x_passthru_qc_issue(struct ata_queued_cmd *qc)
{
it821x_passthru_dev_select(qc->ap, qc->dev->devno);
- return ata_sff_qc_issue(qc);
+ return ata_bmdma_qc_issue(qc);
}
/**
@@ -463,24 +465,22 @@ static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unus
{
struct ata_device *dev;
- ata_link_for_each_dev(dev, link) {
- if (ata_dev_enabled(dev)) {
- /* We don't really care */
- dev->pio_mode = XFER_PIO_0;
- dev->dma_mode = XFER_MW_DMA_0;
- /* We do need the right mode information for DMA or PIO
- and this comes from the current configuration flags */
- if (ata_id_has_dma(dev->id)) {
- ata_dev_printk(dev, KERN_INFO, "configured for DMA\n");
- dev->xfer_mode = XFER_MW_DMA_0;
- dev->xfer_shift = ATA_SHIFT_MWDMA;
- dev->flags &= ~ATA_DFLAG_PIO;
- } else {
- ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
- dev->xfer_mode = XFER_PIO_0;
- dev->xfer_shift = ATA_SHIFT_PIO;
- dev->flags |= ATA_DFLAG_PIO;
- }
+ ata_for_each_dev(dev, link, ENABLED) {
+ /* We don't really care */
+ dev->pio_mode = XFER_PIO_0;
+ dev->dma_mode = XFER_MW_DMA_0;
+ /* We do need the right mode information for DMA or PIO
+ and this comes from the current configuration flags */
+ if (ata_id_has_dma(dev->id)) {
+ ata_dev_info(dev, "configured for DMA\n");
+ dev->xfer_mode = XFER_MW_DMA_0;
+ dev->xfer_shift = ATA_SHIFT_MWDMA;
+ dev->flags &= ~ATA_DFLAG_PIO;
+ } else {
+ ata_dev_info(dev, "configured for PIO\n");
+ dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
}
}
return 0;
@@ -494,8 +494,6 @@ static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unus
* special. In our case we need to lock the sector count to avoid
* blowing the brains out of the firmware with large LBA48 requests
*
- * FIXME: When FUA appears we need to block FUA too. And SMART and
- * basically we need to filter commands for this chip.
*/
static void it821x_dev_config(struct ata_device *adev)
@@ -509,47 +507,63 @@ static void it821x_dev_config(struct ata_device *adev)
if (strstr(model_num, "Integrated Technology Express")) {
/* RAID mode */
- printk(KERN_INFO "IT821x %sRAID%d volume",
- adev->id[147]?"Bootable ":"",
- adev->id[129]);
+ ata_dev_info(adev, "%sRAID%d volume",
+ adev->id[147] ? "Bootable " : "",
+ adev->id[129]);
if (adev->id[129] != 1)
- printk("(%dK stripe)", adev->id[146]);
- printk(".\n");
+ pr_cont("(%dK stripe)", adev->id[146]);
+ pr_cont("\n");
}
/* This is a controller firmware triggered funny, don't
report the drive faulty! */
adev->horkage &= ~ATA_HORKAGE_DIAGNOSTIC;
+ /* No HPA in 'smart' mode */
+ adev->horkage |= ATA_HORKAGE_BROKEN_HPA;
}
/**
- * it821x_ident_hack - Hack identify data up
- * @ap: Port
+ * it821x_read_id - Hack identify data up
+ * @adev: device to read
+ * @tf: proposed taskfile
+ * @id: buffer for returned ident data
*
- * Walk the devices on this firmware driven port and slightly
+ * Query the devices on this firmware driven port and slightly
* mash the identify data to stop us and common tools trying to
* use features not firmware supported. The firmware itself does
* some masking (eg SMART) but not enough.
- *
- * This is a bit of an abuse of the cable method, but it is the
- * only method called at the right time. We could modify the libata
- * core specifically for ident hacking but while we have one offender
- * it seems better to keep the fallout localised.
*/
-static int it821x_ident_hack(struct ata_port *ap)
+static unsigned int it821x_read_id(struct ata_device *adev,
+ struct ata_taskfile *tf, u16 *id)
{
- struct ata_device *adev;
- ata_link_for_each_dev(adev, &ap->link) {
- if (ata_dev_enabled(adev)) {
- adev->id[84] &= ~(1 << 6); /* No FUA */
- adev->id[85] &= ~(1 << 10); /* No HPA */
- adev->id[76] = 0; /* No NCQ/AN etc */
- }
+ unsigned int err_mask;
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
+
+ err_mask = ata_do_dev_read_id(adev, tf, id);
+ if (err_mask)
+ return err_mask;
+ ata_id_c_string(id, model_num, ATA_ID_PROD, sizeof(model_num));
+
+ id[83] &= ~(1 << 12); /* Cache flush is firmware handled */
+ id[83] &= ~(1 << 13); /* Ditto for LBA48 flushes */
+ id[84] &= ~(1 << 6); /* No FUA */
+ id[85] &= ~(1 << 10); /* No HPA */
+ id[76] = 0; /* No NCQ/AN etc */
+
+ if (strstr(model_num, "Integrated Technology Express")) {
+ /* Set feature bits the firmware neglects */
+ id[49] |= 0x0300; /* LBA, DMA */
+ id[83] &= 0x7FFF;
+ id[83] |= 0x4400; /* Word 83 is valid and LBA48 */
+ id[86] |= 0x0400; /* LBA48 on */
+ id[ATA_ID_MAJOR_VER] |= 0x1F;
+ /* Clear the serial number because it's different each boot
+ which breaks validation on resume */
+ memset(&id[ATA_ID_SERNO], 0x20, ATA_ID_SERNO_LEN);
}
- return ata_cable_unknown(ap);
+ return err_mask;
}
-
/**
* it821x_check_atapi_dma - ATAPI DMA handler
* @qc: Command we are about to issue
@@ -577,6 +591,136 @@ static int it821x_check_atapi_dma(struct ata_queued_cmd *qc)
return 0;
}
+/**
+ * it821x_display_disk - display disk setup
+ * @n: Device number
+ * @buf: Buffer block from firmware
+ *
+ * Produce a nice informative display of the device setup as provided
+ * by the firmware.
+ */
+
+static void it821x_display_disk(int n, u8 *buf)
+{
+ unsigned char id[41];
+ int mode = 0;
+ char *mtype = "";
+ char mbuf[8];
+ char *cbl = "(40 wire cable)";
+
+ static const char *types[5] = {
+ "RAID0", "RAID1", "RAID 0+1", "JBOD", "DISK"
+ };
+
+ if (buf[52] > 4) /* No Disk */
+ return;
+
+ ata_id_c_string((u16 *)buf, id, 0, 41);
+
+ if (buf[51]) {
+ mode = ffs(buf[51]);
+ mtype = "UDMA";
+ } else if (buf[49]) {
+ mode = ffs(buf[49]);
+ mtype = "MWDMA";
+ }
+
+ if (buf[76])
+ cbl = "";
+
+ if (mode)
+ snprintf(mbuf, 8, "%5s%d", mtype, mode - 1);
+ else
+ strcpy(mbuf, "PIO");
+ if (buf[52] == 4)
+ printk(KERN_INFO "%d: %-6s %-8s %s %s\n",
+ n, mbuf, types[buf[52]], id, cbl);
+ else
+ printk(KERN_INFO "%d: %-6s %-8s Volume: %1d %s %s\n",
+ n, mbuf, types[buf[52]], buf[53], id, cbl);
+ if (buf[125] < 100)
+ printk(KERN_INFO "%d: Rebuilding: %d%%\n", n, buf[125]);
+}
+
+/**
+ * it821x_firmware_command - issue firmware command
+ * @ap: IT821x port to interrogate
+ * @cmd: command
+ * @len: length
+ *
+ * Issue firmware commands expecting data back from the controller. We
+ * use this to issue commands that do not go via the normal paths. Other
+ * commands such as 0xFC can be issued normally.
+ */
+
+static u8 *it821x_firmware_command(struct ata_port *ap, u8 cmd, int len)
+{
+ u8 status;
+ int n = 0;
+ u16 *buf = kmalloc(len, GFP_KERNEL);
+ if (buf == NULL) {
+ printk(KERN_ERR "it821x_firmware_command: Out of memory\n");
+ return NULL;
+ }
+ /* This isn't quite a normal ATA command as we are talking to the
+ firmware not the drives */
+ ap->ctl |= ATA_NIEN;
+ iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
+ ata_wait_idle(ap);
+ iowrite8(ATA_DEVICE_OBS, ap->ioaddr.device_addr);
+ iowrite8(cmd, ap->ioaddr.command_addr);
+ udelay(1);
+ /* This should be almost immediate but a little paranoia goes a long
+ way. */
+ while(n++ < 10) {
+ status = ioread8(ap->ioaddr.status_addr);
+ if (status & ATA_ERR) {
+ kfree(buf);
+ printk(KERN_ERR "it821x_firmware_command: rejected\n");
+ return NULL;
+ }
+ if (status & ATA_DRQ) {
+ ioread16_rep(ap->ioaddr.data_addr, buf, len/2);
+ return (u8 *)buf;
+ }
+ mdelay(1);
+ }
+ kfree(buf);
+ printk(KERN_ERR "it821x_firmware_command: timeout\n");
+ return NULL;
+}
+
+/**
+ * it821x_probe_firmware - firmware reporting/setup
+ * @ap: IT821x port being probed
+ *
+ * Probe the firmware of the controller by issuing firmware command
+ * 0xFA and analysing the returned data.
+ */
+
+static void it821x_probe_firmware(struct ata_port *ap)
+{
+ u8 *buf;
+ int i;
+
+ /* This is a bit ugly as we can't just issue a task file to a device
+ as this is controller magic */
+
+ buf = it821x_firmware_command(ap, 0xFA, 512);
+
+ if (buf != NULL) {
+ printk(KERN_INFO "pata_it821x: Firmware %02X/%02X/%02X%02X\n",
+ buf[505],
+ buf[506],
+ buf[507],
+ buf[508]);
+ for (i = 0; i < 4; i++)
+ it821x_display_disk(i, buf + 128 * i);
+ kfree(buf);
+ }
+}
+
+
/**
* it821x_port_start - port setup
@@ -594,7 +738,7 @@ static int it821x_port_start(struct ata_port *ap)
struct it821x_dev *itdev;
u8 conf;
- int ret = ata_sff_port_start(ap);
+ int ret = ata_bmdma_port_start(ap);
if (ret < 0)
return ret;
@@ -610,6 +754,8 @@ static int it821x_port_start(struct ata_port *ap)
/* Long I/O's although allowed in LBA48 space cause the
onboard firmware to enter the twighlight zone */
/* No ATAPI DMA in this mode either */
+ if (ap->port_no == 0)
+ it821x_probe_firmware(ap);
}
/* Pull the current clocks from 0x50 */
if (conf & (1 << (1 + ap->port_no)))
@@ -631,6 +777,25 @@ static int it821x_port_start(struct ata_port *ap)
return 0;
}
+/**
+ * it821x_rdc_cable - Cable detect for RDC1010
+ * @ap: port we are checking
+ *
+ * Return the RDC1010 cable type. Unlike the IT821x we know how to do
+ * this and can do host side cable detect
+ */
+
+static int it821x_rdc_cable(struct ata_port *ap)
+{
+ u16 r40;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_word(pdev, 0x40, &r40);
+ if (r40 & (1 << (2 + ap->port_no)))
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
+}
+
static struct scsi_host_template it821x_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
@@ -641,9 +806,10 @@ static struct ata_port_operations it821x_smart_port_ops = {
.check_atapi_dma= it821x_check_atapi_dma,
.qc_issue = it821x_smart_qc_issue,
- .cable_detect = it821x_ident_hack,
+ .cable_detect = ata_cable_80wire,
.set_mode = it821x_smart_set_mode,
.dev_config = it821x_dev_config,
+ .read_id = it821x_read_id,
.port_start = it821x_port_start,
};
@@ -664,8 +830,29 @@ static struct ata_port_operations it821x_passthru_port_ops = {
.port_start = it821x_port_start,
};
+static struct ata_port_operations it821x_rdc_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+
+ .check_atapi_dma= it821x_check_atapi_dma,
+ .sff_dev_select = it821x_passthru_dev_select,
+ .bmdma_start = it821x_passthru_bmdma_start,
+ .bmdma_stop = it821x_passthru_bmdma_stop,
+ .qc_issue = it821x_passthru_qc_issue,
+
+ .cable_detect = it821x_rdc_cable,
+ .set_piomode = it821x_passthru_set_piomode,
+ .set_dmamode = it821x_passthru_set_dmamode,
+
+ .port_start = it821x_port_start,
+};
+
static void it821x_disable_raid(struct pci_dev *pdev)
{
+ /* Neither the RDC nor the IT8211 */
+ if (pdev->vendor != PCI_VENDOR_ID_ITE ||
+ pdev->device != PCI_DEVICE_ID_ITE_8212)
+ return;
+
/* Reset local CPU, and set BIOS not ready */
pci_write_config_byte(pdev, 0x5E, 0x01);
@@ -688,17 +875,32 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
static const struct ata_port_info info_smart = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
.port_ops = &it821x_smart_port_ops
};
static const struct ata_port_info info_passthru = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &it821x_passthru_port_ops
};
+ static const struct ata_port_info info_rdc = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &it821x_rdc_port_ops
+ };
+ static const struct ata_port_info info_rdc_11 = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ /* No UDMA */
+ .port_ops = &it821x_rdc_port_ops
+ };
const struct ata_port_info *ppi[] = { NULL, NULL };
static char *mode[2] = { "pass through", "smart" };
@@ -708,27 +910,35 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (rc)
return rc;
- /* Force the card into bypass mode if so requested */
- if (it8212_noraid) {
- printk(KERN_INFO DRV_NAME ": forcing bypass mode.\n");
- it821x_disable_raid(pdev);
- }
- pci_read_config_byte(pdev, 0x50, &conf);
- conf &= 1;
-
- printk(KERN_INFO DRV_NAME ": controller in %s mode.\n", mode[conf]);
- if (conf == 0)
- ppi[0] = &info_passthru;
- else
- ppi[0] = &info_smart;
+ if (pdev->vendor == PCI_VENDOR_ID_RDC) {
+ /* Deal with Vortex86SX */
+ if (pdev->revision == 0x11)
+ ppi[0] = &info_rdc_11;
+ else
+ ppi[0] = &info_rdc;
+ } else {
+ /* Force the card into bypass mode if so requested */
+ if (it8212_noraid) {
+ printk(KERN_INFO DRV_NAME ": forcing bypass mode.\n");
+ it821x_disable_raid(pdev);
+ }
+ pci_read_config_byte(pdev, 0x50, &conf);
+ conf &= 1;
- return ata_pci_sff_init_one(pdev, ppi, &it821x_sht, NULL);
+ printk(KERN_INFO DRV_NAME": controller in %s mode.\n",
+ mode[conf]);
+ if (conf == 0)
+ ppi[0] = &info_passthru;
+ else
+ ppi[0] = &info_smart;
+ }
+ return ata_pci_bmdma_init_one(pdev, ppi, &it821x_sht, NULL, 0);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int it821x_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -745,6 +955,7 @@ static int it821x_reinit_one(struct pci_dev *pdev)
static const struct pci_device_id it821x[] = {
{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), },
{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), },
+ { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010), },
{ },
};
@@ -754,21 +965,13 @@ static struct pci_driver it821x_pci_driver = {
.id_table = it821x,
.probe = it821x_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = it821x_reinit_one,
#endif
};
-static int __init it821x_init(void)
-{
- return pci_register_driver(&it821x_pci_driver);
-}
-
-static void __exit it821x_exit(void)
-{
- pci_unregister_driver(&it821x_pci_driver);
-}
+module_pci_driver(it821x_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the IT8211/IT8212 IDE RAID controller");
@@ -776,9 +979,5 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, it821x);
MODULE_VERSION(DRV_VERSION);
-
module_param_named(noraid, it8212_noraid, int, S_IRUGO);
MODULE_PARM_DESC(noraid, "Force card into bypass mode");
-
-module_init(it821x_init);
-module_exit(it821x_exit);
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index 8a175f23b90..ddf470c2341 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -30,14 +30,12 @@ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
{
struct ata_device *dev;
- ata_link_for_each_dev(dev, link) {
- if (ata_dev_enabled(dev)) {
- ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
- dev->pio_mode = XFER_PIO_0;
- dev->xfer_mode = XFER_PIO_0;
- dev->xfer_shift = ATA_SHIFT_PIO;
- dev->flags |= ATA_DFLAG_PIO;
- }
+ ata_for_each_dev(dev, link, ENABLED) {
+ ata_dev_info(dev, "configured for PIO0\n");
+ dev->pio_mode = XFER_PIO_0;
+ dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
}
return 0;
}
@@ -50,7 +48,7 @@ static unsigned int ixp4xx_mmio_data_xfer(struct ata_device *dev,
u16 *buf16 = (u16 *) buf;
struct ata_port *ap = dev->link->ap;
void __iomem *mmio = ap->ioaddr.data_addr;
- struct ixp4xx_pata_data *data = ap->host->dev->platform_data;
+ struct ixp4xx_pata_data *data = dev_get_platdata(ap->host->dev);
/* set the expansion bus in 16bit mode and restore
* 8 bit mode after the transaction.
@@ -139,13 +137,14 @@ static void ixp4xx_setup_port(struct ata_port *ap,
ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", raw_cmd, raw_ctl);
}
-static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
+static int ixp4xx_pata_probe(struct platform_device *pdev)
{
unsigned int irq;
struct resource *cs0, *cs1;
struct ata_host *host;
struct ata_port *ap;
- struct ixp4xx_pata_data *data = pdev->dev.platform_data;
+ struct ixp4xx_pata_data *data = dev_get_platdata(&pdev->dev);
+ int ret;
cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -159,7 +158,9 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
return -ENOMEM;
/* acquire resources and fill host */
- pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
+ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);
data->cs1 = devm_ioremap(&pdev->dev, cs1->start, 0x1000);
@@ -169,7 +170,7 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq)
- set_irq_type(irq, IRQT_RISING);
+ irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
/* Setup expansion bus chip selects */
*data->cs0_cfg = data->cs0_bits;
@@ -178,49 +179,30 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
ap = host->ports[0];
ap->ops = &ixp4xx_port_ops;
- ap->pio_mask = 0x1f; /* PIO4 */
- ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI;
+ ap->pio_mask = ATA_PIO4;
+ ap->flags |= ATA_FLAG_NO_ATAPI;
ixp4xx_setup_port(ap, data, cs0->start, cs1->start);
- dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
/* activate host */
return ata_host_activate(host, irq, ata_sff_interrupt, 0, &ixp4xx_sht);
}
-static __devexit int ixp4xx_pata_remove(struct platform_device *dev)
-{
- struct ata_host *host = platform_get_drvdata(dev);
-
- ata_host_detach(host);
-
- return 0;
-}
-
static struct platform_driver ixp4xx_pata_platform_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
.probe = ixp4xx_pata_probe,
- .remove = __devexit_p(ixp4xx_pata_remove),
+ .remove = ata_platform_remove_one,
};
-static int __init ixp4xx_pata_init(void)
-{
- return platform_driver_register(&ixp4xx_pata_platform_driver);
-}
-
-static void __exit ixp4xx_pata_exit(void)
-{
- platform_driver_unregister(&ixp4xx_pata_platform_driver);
-}
+module_platform_driver(ixp4xx_pata_platform_driver);
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
MODULE_DESCRIPTION("low-level driver for ixp4xx Compact Flash PATA");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
-
-module_init(ixp4xx_pata_init);
-module_exit(ixp4xx_pata_exit);
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 73b7596816b..4d1a5d2c428 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -4,13 +4,12 @@
* driven by AHCI in the usual configuration although
* this driver can handle other setups if we need it.
*
- * (c) 2006 Red Hat <alan@redhat.com>
+ * (c) 2006 Red Hat
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -136,15 +135,15 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &jmicron_ops,
};
const struct ata_port_info *ppi[] = { &info, NULL };
- return ata_pci_sff_init_one(pdev, ppi, &jmicron_sht, NULL);
+ return ata_pci_bmdma_init_one(pdev, ppi, &jmicron_sht, NULL, 0);
}
static const struct pci_device_id jmicron_pci_tbl[] = {
@@ -158,24 +157,13 @@ static struct pci_driver jmicron_pci_driver = {
.id_table = jmicron_pci_tbl,
.probe = jmicron_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init jmicron_init(void)
-{
- return pci_register_driver(&jmicron_pci_driver);
-}
-
-static void __exit jmicron_exit(void)
-{
- pci_unregister_driver(&jmicron_pci_driver);
-}
-
-module_init(jmicron_init);
-module_exit(jmicron_exit);
+module_pci_driver(jmicron_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("SCSI low-level driver for Jmicron PATA ports");
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 7af4b29cc42..bce2a8ca467 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -1,6 +1,6 @@
/*
* pata-legacy.c - Legacy port PATA/SATA controller driver.
- * Copyright 2005/2006 Red Hat <alan@redhat.com>, all rights reserved.
+ * Copyright 2005/2006 Red Hat, all rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,6 +25,13 @@
* http://www.ryston.cz/petr/vlb/pdc20230b.html
* http://www.ryston.cz/petr/vlb/pdc20230c.html
* http://www.ryston.cz/petr/vlb/pdc20630.html
+ * QDI65x0:
+ * http://www.ryston.cz/petr/vlb/qd6500.html
+ * http://www.ryston.cz/petr/vlb/qd6580.html
+ *
+ * QDI65x0 probe code based on drivers/ide/legacy/qd65xx.c
+ * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
+ * Samuel Thibault <samuel.thibault@ens-lyon.org>
*
* Unsupported but docs exist:
* Appian/Adaptec AIC25VL01/Cirrus Logic PD7220
@@ -35,7 +42,10 @@
* the MPIIX where the tuning is PCI side but the IDE is "ISA side".
*
* Specific support is included for the ht6560a/ht6560b/opti82c611a/
- * opti82c465mv/promise 20230c/20630/winbond83759A
+ * opti82c465mv/promise 20230c/20630/qdi65x0/winbond83759A
+ *
+ * Support for the Winbond 83759A when operating in advanced mode.
+ * Multichip mode is not currently supported.
*
* Use the autospeed and pio_mask options with:
* Appian ADI/2 aka CLPD7220 or AIC25VL01.
@@ -48,6 +58,7 @@
*
*/
+#include <linux/async.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -68,15 +79,6 @@ static int all;
module_param(all, int, 0444);
MODULE_PARM_DESC(all, "Grab all legacy port devices, even if PCI(0=off, 1=on)");
-struct legacy_data {
- unsigned long timing;
- u8 clock[2];
- u8 last;
- int fast;
- struct platform_device *platform_dev;
-
-};
-
enum controller {
BIOS = 0,
SNOOP = 1,
@@ -93,6 +95,14 @@ enum controller {
UNKNOWN = -1
};
+struct legacy_data {
+ unsigned long timing;
+ u8 clock[2];
+ u8 last;
+ int fast;
+ enum controller type;
+ struct platform_device *platform_dev;
+};
struct legacy_probe {
unsigned char *name;
@@ -108,6 +118,7 @@ struct legacy_controller {
struct ata_port_operations *ops;
unsigned int pio_mask;
unsigned int flags;
+ unsigned int pflags;
int (*setup)(struct platform_device *, struct legacy_probe *probe,
struct legacy_data *data);
};
@@ -125,13 +136,25 @@ static int ht6560a; /* HT 6560A on primary 1, second 2, both 3 */
static int ht6560b; /* HT 6560A on primary 1, second 2, both 3 */
static int opti82c611a; /* Opti82c611A on primary 1, sec 2, both 3 */
static int opti82c46x; /* Opti 82c465MV present(pri/sec autodetect) */
-static int qdi; /* Set to probe QDI controllers */
-static int winbond; /* Set to probe Winbond controllers,
- give I/O port if non standard */
static int autospeed; /* Chip present which snoops speed changes */
-static int pio_mask = 0x1F; /* PIO range for autospeed devices */
+static int pio_mask = ATA_PIO4; /* PIO range for autospeed devices */
static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */
+/* Set to probe QDI controllers */
+#ifdef CONFIG_PATA_QDI_MODULE
+static int qdi = 1;
+#else
+static int qdi;
+#endif
+
+#ifdef CONFIG_PATA_WINBOND_VLB_MODULE
+static int winbond = 1; /* Set to probe Winbond controllers,
+ give I/O port if non standard */
+#else
+static int winbond; /* Set to probe Winbond controllers,
+ give I/O port if non standard */
+#endif
+
/**
* legacy_probe_add - Add interface to probe list
* @port: Controller port
@@ -194,15 +217,12 @@ static int legacy_set_mode(struct ata_link *link, struct ata_device **unused)
{
struct ata_device *dev;
- ata_link_for_each_dev(dev, link) {
- if (ata_dev_enabled(dev)) {
- ata_dev_printk(dev, KERN_INFO,
- "configured for PIO\n");
- dev->pio_mode = XFER_PIO_0;
- dev->xfer_mode = XFER_PIO_0;
- dev->xfer_shift = ATA_SHIFT_PIO;
- dev->flags |= ATA_DFLAG_PIO;
- }
+ ata_for_each_dev(dev, link, ENABLED) {
+ ata_dev_info(dev, "configured for PIO\n");
+ dev->pio_mode = XFER_PIO_0;
+ dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
}
return 0;
}
@@ -286,9 +306,12 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
static unsigned int pdc_data_xfer_vlb(struct ata_device *dev,
unsigned char *buf, unsigned int buflen, int rw)
{
- if (ata_id_has_dword_io(dev->id)) {
- struct ata_port *ap = dev->link->ap;
- int slop = buflen & 3;
+ int slop = buflen & 3;
+ struct ata_port *ap = dev->link->ap;
+
+ /* 32bit I/O capable *and* we need to write a whole number of dwords */
+ if (ata_id_has_dword_io(dev->id) && (slop == 0 || slop == 3)
+ && (ap->pflags & ATA_PFLAG_PIO32)) {
unsigned long flags;
local_irq_save(flags);
@@ -305,7 +328,7 @@ static unsigned int pdc_data_xfer_vlb(struct ata_device *dev,
iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) {
- u32 pad;
+ __le32 pad;
if (rw == READ) {
pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
memcpy(buf + buflen - slop, &pad, slop);
@@ -343,8 +366,8 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
/* Get the timing data in cycles. For now play safe at 50Mhz */
ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
- active = FIT(t.active, 2, 15);
- recover = FIT(t.recover, 4, 15);
+ active = clamp_val(t.active, 2, 15);
+ recover = clamp_val(t.recover, 4, 15);
inb(0x3E6);
inb(0x3E6);
@@ -377,9 +400,8 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
/* Get the timing data in cycles. For now play safe at 50Mhz */
ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
- active = FIT(t.active, 2, 15);
- recover = FIT(t.recover, 2, 16);
- recover &= 0x15;
+ active = clamp_val(t.active, 2, 15);
+ recover = clamp_val(t.recover, 2, 16) & 0x0F;
inb(0x3E6);
inb(0x3E6);
@@ -462,9 +484,9 @@ static void opti82c611a_set_piomode(struct ata_port *ap,
ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
}
- active = FIT(t.active, 2, 17) - 2;
- recover = FIT(t.recover, 1, 16) - 1;
- setup = FIT(t.setup, 1, 4) - 1;
+ active = clamp_val(t.active, 2, 17) - 2;
+ recover = clamp_val(t.recover, 1, 16) - 1;
+ setup = clamp_val(t.setup, 1, 4) - 1;
/* Select the right timing bank for write timing */
rc = ioread8(ap->ioaddr.lbal_addr);
@@ -520,7 +542,7 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev)
u8 sysclk;
/* Get the clock */
- sysclk = opti_syscfg(0xAC) & 0xC0; /* BIOS set */
+ sysclk = (opti_syscfg(0xAC) & 0xC0) >> 6; /* BIOS set */
/* Enter configuration mode */
ioread16(ap->ioaddr.error_addr);
@@ -541,9 +563,9 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
}
- active = FIT(t.active, 2, 17) - 2;
- recover = FIT(t.recover, 1, 16) - 1;
- setup = FIT(t.setup, 1, 4) - 1;
+ active = clamp_val(t.active, 2, 17) - 2;
+ recover = clamp_val(t.recover, 1, 16) - 1;
+ setup = clamp_val(t.setup, 1, 4) - 1;
/* Select the right timing bank for write timing */
rc = ioread8(ap->ioaddr.lbal_addr);
@@ -613,41 +635,20 @@ static struct ata_port_operations opti82c46x_port_ops = {
.qc_issue = opti82c46x_qc_issue,
};
-static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
-{
- struct ata_timing t;
- struct legacy_data *ld_qdi = ap->host->private_data;
- int active, recovery;
- u8 timing;
-
- /* Get the timing data in cycles */
- ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
-
- if (ld_qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
- } else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
- }
- timing = (recovery << 4) | active | 0x08;
-
- ld_qdi->clock[adev->devno] = timing;
-
- outb(timing, ld_qdi->timing);
-}
-
/**
- * qdi6580dp_set_piomode - PIO setup for dual channel
+ * qdi65x0_set_piomode - PIO setup for QDI65x0
* @ap: Port
* @adev: Device
- * @irq: interrupt line
+ *
+ * In single channel mode the 6580 has one clock per device and we can
+ * avoid the requirement to clock switch. We also have to load the timing
+ * into the right clock according to whether we are master or slave.
*
* In dual channel mode the 6580 has one clock per channel and we have
* to software clockswitch in qc_issue.
*/
-static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void qdi65x0_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
struct ata_timing t;
struct legacy_data *ld_qdi = ap->host->private_data;
@@ -658,55 +659,23 @@ static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
if (ld_qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
+ active = 8 - clamp_val(t.active, 1, 8);
+ recovery = 18 - clamp_val(t.recover, 3, 18);
} else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
+ active = 9 - clamp_val(t.active, 2, 9);
+ recovery = 15 - clamp_val(t.recover, 0, 15);
}
timing = (recovery << 4) | active | 0x08;
-
ld_qdi->clock[adev->devno] = timing;
- outb(timing, ld_qdi->timing + 2 * ap->port_no);
- /* Clear the FIFO */
- if (adev->class != ATA_DEV_ATA)
- outb(0x5F, ld_qdi->timing + 3);
-}
-
-/**
- * qdi6580_set_piomode - PIO setup for single channel
- * @ap: Port
- * @adev: Device
- *
- * In single channel mode the 6580 has one clock per device and we can
- * avoid the requirement to clock switch. We also have to load the timing
- * into the right clock according to whether we are master or slave.
- */
-
-static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
-{
- struct ata_timing t;
- struct legacy_data *ld_qdi = ap->host->private_data;
- int active, recovery;
- u8 timing;
-
- /* Get the timing data in cycles */
- ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+ if (ld_qdi->type == QDI6580)
+ outb(timing, ld_qdi->timing + 2 * adev->devno);
+ else
+ outb(timing, ld_qdi->timing + 2 * ap->port_no);
- if (ld_qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
- } else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
- }
- timing = (recovery << 4) | active | 0x08;
- ld_qdi->clock[adev->devno] = timing;
- outb(timing, ld_qdi->timing + 2 * adev->devno);
/* Clear the FIFO */
- if (adev->class != ATA_DEV_ATA)
- outb(0x5F, ld_qdi->timing + 3);
+ if (ld_qdi->type != QDI6500 && adev->class != ATA_DEV_ATA)
+ outb(0x5F, (ld_qdi->timing & 0xFFF0) + 3);
}
/**
@@ -739,21 +708,20 @@ static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf,
struct ata_port *ap = adev->link->ap;
int slop = buflen & 3;
- if (ata_id_has_dword_io(adev->id)) {
+ if (ata_id_has_dword_io(adev->id) && (slop == 0 || slop == 3)
+ && (ap->pflags & ATA_PFLAG_PIO32)) {
if (rw == WRITE)
iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
else
ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) {
- u32 pad;
+ __le32 pad;
if (rw == WRITE) {
memcpy(&pad, buf + buflen - slop, slop);
- pad = le32_to_cpu(pad);
- iowrite32(pad, ap->ioaddr.data_addr);
+ iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
} else {
- pad = ioread32(ap->ioaddr.data_addr);
- pad = cpu_to_le32(pad);
+ pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
memcpy(buf + buflen - slop, &pad, slop);
}
}
@@ -773,20 +741,21 @@ static int qdi_port(struct platform_device *dev,
static struct ata_port_operations qdi6500_port_ops = {
.inherits = &legacy_base_port_ops,
- .set_piomode = qdi6500_set_piomode,
+ .set_piomode = qdi65x0_set_piomode,
.qc_issue = qdi_qc_issue,
.sff_data_xfer = vlb32_data_xfer,
};
static struct ata_port_operations qdi6580_port_ops = {
.inherits = &legacy_base_port_ops,
- .set_piomode = qdi6580_set_piomode,
+ .set_piomode = qdi65x0_set_piomode,
.sff_data_xfer = vlb32_data_xfer,
};
static struct ata_port_operations qdi6580dp_port_ops = {
.inherits = &legacy_base_port_ops,
- .set_piomode = qdi6580dp_set_piomode,
+ .set_piomode = qdi65x0_set_piomode,
+ .qc_issue = qdi_qc_issue,
.sff_data_xfer = vlb32_data_xfer,
};
@@ -830,8 +799,8 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
else
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
- active = (FIT(t.active, 3, 17) - 1) & 0x0F;
- recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F;
+ active = (clamp_val(t.active, 3, 17) - 1) & 0x0F;
+ recovery = (clamp_val(t.recover, 1, 15) + 1) & 0x0F;
timing = (active << 4) | recovery;
winbond_writecfg(ld_winbond->timing, timing, reg);
@@ -842,7 +811,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
reg |= 0x08; /* FIFO off */
if (!ata_pio_need_iordy(adev))
reg |= 0x02; /* IORDY off */
- reg |= (FIT(t.setup, 0, 3) << 6);
+ reg |= (clamp_val(t.setup, 0, 3) << 6);
winbond_writecfg(ld_winbond->timing, timing + 1, reg);
}
@@ -862,28 +831,31 @@ static struct ata_port_operations winbond_port_ops = {
};
static struct legacy_controller controllers[] = {
- {"BIOS", &legacy_port_ops, 0x1F,
- ATA_FLAG_NO_IORDY, NULL },
- {"Snooping", &simple_port_ops, 0x1F,
- 0 , NULL },
- {"PDC20230", &pdc20230_port_ops, 0x7,
- ATA_FLAG_NO_IORDY, NULL },
- {"HT6560A", &ht6560a_port_ops, 0x07,
- ATA_FLAG_NO_IORDY, NULL },
- {"HT6560B", &ht6560b_port_ops, 0x1F,
- ATA_FLAG_NO_IORDY, NULL },
- {"OPTI82C611A", &opti82c611a_port_ops, 0x0F,
- 0 , NULL },
- {"OPTI82C46X", &opti82c46x_port_ops, 0x0F,
- 0 , NULL },
- {"QDI6500", &qdi6500_port_ops, 0x07,
- ATA_FLAG_NO_IORDY, qdi_port },
- {"QDI6580", &qdi6580_port_ops, 0x1F,
- 0 , qdi_port },
- {"QDI6580DP", &qdi6580dp_port_ops, 0x1F,
- 0 , qdi_port },
- {"W83759A", &winbond_port_ops, 0x1F,
- 0 , winbond_port }
+ {"BIOS", &legacy_port_ops, ATA_PIO4,
+ ATA_FLAG_NO_IORDY, 0, NULL },
+ {"Snooping", &simple_port_ops, ATA_PIO4,
+ 0, 0, NULL },
+ {"PDC20230", &pdc20230_port_ops, ATA_PIO2,
+ ATA_FLAG_NO_IORDY,
+ ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, NULL },
+ {"HT6560A", &ht6560a_port_ops, ATA_PIO2,
+ ATA_FLAG_NO_IORDY, 0, NULL },
+ {"HT6560B", &ht6560b_port_ops, ATA_PIO4,
+ ATA_FLAG_NO_IORDY, 0, NULL },
+ {"OPTI82C611A", &opti82c611a_port_ops, ATA_PIO3,
+ 0, 0, NULL },
+ {"OPTI82C46X", &opti82c46x_port_ops, ATA_PIO3,
+ 0, 0, NULL },
+ {"QDI6500", &qdi6500_port_ops, ATA_PIO2,
+ ATA_FLAG_NO_IORDY,
+ ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port },
+ {"QDI6580", &qdi6580_port_ops, ATA_PIO4,
+ 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port },
+ {"QDI6580DP", &qdi6580dp_port_ops, ATA_PIO4,
+ 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port },
+ {"W83759A", &winbond_port_ops, ATA_PIO4,
+ 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE,
+ winbond_port }
};
/**
@@ -944,7 +916,6 @@ static __init int probe_chip_type(struct legacy_probe *probe)
local_irq_restore(flags);
return BIOS;
}
- local_irq_restore(flags);
}
if (ht6560a & mask)
@@ -1002,6 +973,7 @@ static __init int legacy_init_one(struct legacy_probe *probe)
ctrl_addr = devm_ioport_map(&pdev->dev, io + 0x0206, 1);
if (!io_addr || !ctrl_addr)
goto fail;
+ ld->type = probe->type;
if (controller->setup)
if (controller->setup(pdev, probe, ld) < 0)
goto fail;
@@ -1013,6 +985,7 @@ static __init int legacy_init_one(struct legacy_probe *probe)
ap->ops = ops;
ap->pio_mask = pio_modes;
ap->flags |= ATA_FLAG_SLAVE_POSS | iordy;
+ ap->pflags |= controller->pflags;
ap->ioaddr.cmd_addr = io_addr;
ap->ioaddr.altstatus_addr = ctrl_addr;
ap->ioaddr.ctl_addr = ctrl_addr;
@@ -1025,18 +998,20 @@ static __init int legacy_init_one(struct legacy_probe *probe)
&legacy_sht);
if (ret)
goto fail;
+ async_synchronize_full();
ld->platform_dev = pdev;
/* Nothing found means we drop the port as its probably not there */
ret = -ENODEV;
- ata_link_for_each_dev(dev, &ap->link) {
+ ata_for_each_dev(dev, &ap->link, ALL) {
if (!ata_dev_absent(dev)) {
legacy_host[probe->slot] = host;
ld->platform_dev = pdev;
return 0;
}
}
+ ata_host_detach(host);
fail:
platform_device_unregister(pdev);
return ret;
@@ -1283,6 +1258,8 @@ MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for legacy ATA");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("pata_qdi");
+MODULE_ALIAS("pata_winbond");
module_param(probe_all, int, 0);
module_param(autospeed, int, 0);
@@ -1291,6 +1268,7 @@ module_param(ht6560b, int, 0);
module_param(opti82c611a, int, 0);
module_param(opti82c46x, int, 0);
module_param(qdi, int, 0);
+module_param(winbond, int, 0);
module_param(pio_mask, int, 0);
module_param(iordy_mask, int, 0);
diff --git a/drivers/ata/pata_macio.c b/drivers/ata/pata_macio.c
new file mode 100644
index 00000000000..a02f76fdcfc
--- /dev/null
+++ b/drivers/ata/pata_macio.c
@@ -0,0 +1,1421 @@
+/*
+ * Libata based driver for Apple "macio" family of PATA controllers
+ *
+ * Copyright 2008/2009 Benjamin Herrenschmidt, IBM Corp
+ * <benh@kernel.crashing.org>
+ *
+ * Some bits and pieces from drivers/ide/ppc/pmac.c
+ *
+ */
+
+#undef DEBUG
+#undef DEBUG_DMA
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/scatterlist.h>
+#include <linux/of.h>
+#include <linux/gfp.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+
+#include <asm/macio.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/mediabay.h>
+
+#ifdef DEBUG_DMA
+#define dev_dbgdma(dev, format, arg...) \
+ dev_printk(KERN_DEBUG , dev , format , ## arg)
+#else
+#define dev_dbgdma(dev, format, arg...) \
+ ({ if (0) dev_printk(KERN_DEBUG, dev, format, ##arg); 0; })
+#endif
+
+#define DRV_NAME "pata_macio"
+#define DRV_VERSION "0.9"
+
+/* Models of macio ATA controller */
+enum {
+ controller_ohare, /* OHare based */
+ controller_heathrow, /* Heathrow/Paddington */
+ controller_kl_ata3, /* KeyLargo ATA-3 */
+ controller_kl_ata4, /* KeyLargo ATA-4 */
+ controller_un_ata6, /* UniNorth2 ATA-6 */
+ controller_k2_ata6, /* K2 ATA-6 */
+ controller_sh_ata6, /* Shasta ATA-6 */
+};
+
+static const char* macio_ata_names[] = {
+ "OHare ATA", /* OHare based */
+ "Heathrow ATA", /* Heathrow/Paddington */
+ "KeyLargo ATA-3", /* KeyLargo ATA-3 (MDMA only) */
+ "KeyLargo ATA-4", /* KeyLargo ATA-4 (UDMA/66) */
+ "UniNorth ATA-6", /* UniNorth2 ATA-6 (UDMA/100) */
+ "K2 ATA-6", /* K2 ATA-6 (UDMA/100) */
+ "Shasta ATA-6", /* Shasta ATA-6 (UDMA/133) */
+};
+
+/*
+ * Extra registers, both 32-bit little-endian
+ */
+#define IDE_TIMING_CONFIG 0x200
+#define IDE_INTERRUPT 0x300
+
+/* Kauai (U2) ATA has different register setup */
+#define IDE_KAUAI_PIO_CONFIG 0x200
+#define IDE_KAUAI_ULTRA_CONFIG 0x210
+#define IDE_KAUAI_POLL_CONFIG 0x220
+
+/*
+ * Timing configuration register definitions
+ */
+
+/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
+#define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
+#define SYSCLK_TICKS_66(t) (((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
+#define IDE_SYSCLK_NS 30 /* 33Mhz cell */
+#define IDE_SYSCLK_66_NS 15 /* 66Mhz cell */
+
+/* 133Mhz cell, found in shasta.
+ * See comments about 100 Mhz Uninorth 2...
+ * Note that PIO_MASK and MDMA_MASK seem to overlap, that's just
+ * weird and I don't now why .. at this stage
+ */
+#define TR_133_PIOREG_PIO_MASK 0xff000fff
+#define TR_133_PIOREG_MDMA_MASK 0x00fff800
+#define TR_133_UDMAREG_UDMA_MASK 0x0003ffff
+#define TR_133_UDMAREG_UDMA_EN 0x00000001
+
+/* 100Mhz cell, found in Uninorth 2 and K2. It appears as a pci device
+ * (106b/0033) on uninorth or K2 internal PCI bus and it's clock is
+ * controlled like gem or fw. It appears to be an evolution of keylargo
+ * ATA4 with a timing register extended to 2x32bits registers (one
+ * for PIO & MWDMA and one for UDMA, and a similar DBDMA channel.
+ * It has it's own local feature control register as well.
+ *
+ * After scratching my mind over the timing values, at least for PIO
+ * and MDMA, I think I've figured the format of the timing register,
+ * though I use pre-calculated tables for UDMA as usual...
+ */
+#define TR_100_PIO_ADDRSETUP_MASK 0xff000000 /* Size of field unknown */
+#define TR_100_PIO_ADDRSETUP_SHIFT 24
+#define TR_100_MDMA_MASK 0x00fff000
+#define TR_100_MDMA_RECOVERY_MASK 0x00fc0000
+#define TR_100_MDMA_RECOVERY_SHIFT 18
+#define TR_100_MDMA_ACCESS_MASK 0x0003f000
+#define TR_100_MDMA_ACCESS_SHIFT 12
+#define TR_100_PIO_MASK 0xff000fff
+#define TR_100_PIO_RECOVERY_MASK 0x00000fc0
+#define TR_100_PIO_RECOVERY_SHIFT 6
+#define TR_100_PIO_ACCESS_MASK 0x0000003f
+#define TR_100_PIO_ACCESS_SHIFT 0
+
+#define TR_100_UDMAREG_UDMA_MASK 0x0000ffff
+#define TR_100_UDMAREG_UDMA_EN 0x00000001
+
+
+/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
+ * 40 connector cable and to 4 on 80 connector one.
+ * Clock unit is 15ns (66Mhz)
+ *
+ * 3 Values can be programmed:
+ * - Write data setup, which appears to match the cycle time. They
+ * also call it DIOW setup.
+ * - Ready to pause time (from spec)
+ * - Address setup. That one is weird. I don't see where exactly
+ * it fits in UDMA cycles, I got it's name from an obscure piece
+ * of commented out code in Darwin. They leave it to 0, we do as
+ * well, despite a comment that would lead to think it has a
+ * min value of 45ns.
+ * Apple also add 60ns to the write data setup (or cycle time ?) on
+ * reads.
+ */
+#define TR_66_UDMA_MASK 0xfff00000
+#define TR_66_UDMA_EN 0x00100000 /* Enable Ultra mode for DMA */
+#define TR_66_PIO_ADDRSETUP_MASK 0xe0000000 /* Address setup */
+#define TR_66_PIO_ADDRSETUP_SHIFT 29
+#define TR_66_UDMA_RDY2PAUS_MASK 0x1e000000 /* Ready 2 pause time */
+#define TR_66_UDMA_RDY2PAUS_SHIFT 25
+#define TR_66_UDMA_WRDATASETUP_MASK 0x01e00000 /* Write data setup time */
+#define TR_66_UDMA_WRDATASETUP_SHIFT 21
+#define TR_66_MDMA_MASK 0x000ffc00
+#define TR_66_MDMA_RECOVERY_MASK 0x000f8000
+#define TR_66_MDMA_RECOVERY_SHIFT 15
+#define TR_66_MDMA_ACCESS_MASK 0x00007c00
+#define TR_66_MDMA_ACCESS_SHIFT 10
+#define TR_66_PIO_MASK 0xe00003ff
+#define TR_66_PIO_RECOVERY_MASK 0x000003e0
+#define TR_66_PIO_RECOVERY_SHIFT 5
+#define TR_66_PIO_ACCESS_MASK 0x0000001f
+#define TR_66_PIO_ACCESS_SHIFT 0
+
+/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
+ * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
+ *
+ * The access time and recovery time can be programmed. Some older
+ * Darwin code base limit OHare to 150ns cycle time. I decided to do
+ * the same here fore safety against broken old hardware ;)
+ * The HalfTick bit, when set, adds half a clock (15ns) to the access
+ * time and removes one from recovery. It's not supported on KeyLargo
+ * implementation afaik. The E bit appears to be set for PIO mode 0 and
+ * is used to reach long timings used in this mode.
+ */
+#define TR_33_MDMA_MASK 0x003ff800
+#define TR_33_MDMA_RECOVERY_MASK 0x001f0000
+#define TR_33_MDMA_RECOVERY_SHIFT 16
+#define TR_33_MDMA_ACCESS_MASK 0x0000f800
+#define TR_33_MDMA_ACCESS_SHIFT 11
+#define TR_33_MDMA_HALFTICK 0x00200000
+#define TR_33_PIO_MASK 0x000007ff
+#define TR_33_PIO_E 0x00000400
+#define TR_33_PIO_RECOVERY_MASK 0x000003e0
+#define TR_33_PIO_RECOVERY_SHIFT 5
+#define TR_33_PIO_ACCESS_MASK 0x0000001f
+#define TR_33_PIO_ACCESS_SHIFT 0
+
+/*
+ * Interrupt register definitions. Only present on newer cells
+ * (Keylargo and later afaik) so we don't use it.
+ */
+#define IDE_INTR_DMA 0x80000000
+#define IDE_INTR_DEVICE 0x40000000
+
+/*
+ * FCR Register on Kauai. Not sure what bit 0x4 is ...
+ */
+#define KAUAI_FCR_UATA_MAGIC 0x00000004
+#define KAUAI_FCR_UATA_RESET_N 0x00000002
+#define KAUAI_FCR_UATA_ENABLE 0x00000001
+
+
+/* Allow up to 256 DBDMA commands per xfer */
+#define MAX_DCMDS 256
+
+/* Don't let a DMA segment go all the way to 64K */
+#define MAX_DBDMA_SEG 0xff00
+
+
+/*
+ * Wait 1s for disk to answer on IDE bus after a hard reset
+ * of the device (via GPIO/FCR).
+ *
+ * Some devices seem to "pollute" the bus even after dropping
+ * the BSY bit (typically some combo drives slave on the UDMA
+ * bus) after a hard reset. Since we hard reset all drives on
+ * KeyLargo ATA66, we have to keep that delay around. I may end
+ * up not hard resetting anymore on these and keep the delay only
+ * for older interfaces instead (we have to reset when coming
+ * from MacOS...) --BenH.
+ */
+#define IDE_WAKEUP_DELAY_MS 1000
+
+struct pata_macio_timing;
+
+struct pata_macio_priv {
+ int kind;
+ int aapl_bus_id;
+ int mediabay : 1;
+ struct device_node *node;
+ struct macio_dev *mdev;
+ struct pci_dev *pdev;
+ struct device *dev;
+ int irq;
+ u32 treg[2][2];
+ void __iomem *tfregs;
+ void __iomem *kauai_fcr;
+ struct dbdma_cmd * dma_table_cpu;
+ dma_addr_t dma_table_dma;
+ struct ata_host *host;
+ const struct pata_macio_timing *timings;
+};
+
+/* Previous variants of this driver used to calculate timings
+ * for various variants of the chip and use tables for others.
+ *
+ * Not only was this confusing, but in addition, it isn't clear
+ * whether our calculation code was correct. It didn't entirely
+ * match the darwin code and whatever documentation I could find
+ * on these cells
+ *
+ * I decided to entirely rely on a table instead for this version
+ * of the driver. Also, because I don't really care about derated
+ * modes and really old HW other than making it work, I'm not going
+ * to calculate / snoop timing values for something else than the
+ * standard modes.
+ */
+struct pata_macio_timing {
+ int mode;
+ u32 reg1; /* Bits to set in first timing reg */
+ u32 reg2; /* Bits to set in second timing reg */
+};
+
+static const struct pata_macio_timing pata_macio_ohare_timings[] = {
+ { XFER_PIO_0, 0x00000526, 0, },
+ { XFER_PIO_1, 0x00000085, 0, },
+ { XFER_PIO_2, 0x00000025, 0, },
+ { XFER_PIO_3, 0x00000025, 0, },
+ { XFER_PIO_4, 0x00000025, 0, },
+ { XFER_MW_DMA_0, 0x00074000, 0, },
+ { XFER_MW_DMA_1, 0x00221000, 0, },
+ { XFER_MW_DMA_2, 0x00211000, 0, },
+ { -1, 0, 0 }
+};
+
+static const struct pata_macio_timing pata_macio_heathrow_timings[] = {
+ { XFER_PIO_0, 0x00000526, 0, },
+ { XFER_PIO_1, 0x00000085, 0, },
+ { XFER_PIO_2, 0x00000025, 0, },
+ { XFER_PIO_3, 0x00000025, 0, },
+ { XFER_PIO_4, 0x00000025, 0, },
+ { XFER_MW_DMA_0, 0x00074000, 0, },
+ { XFER_MW_DMA_1, 0x00221000, 0, },
+ { XFER_MW_DMA_2, 0x00211000, 0, },
+ { -1, 0, 0 }
+};
+
+static const struct pata_macio_timing pata_macio_kl33_timings[] = {
+ { XFER_PIO_0, 0x00000526, 0, },
+ { XFER_PIO_1, 0x00000085, 0, },
+ { XFER_PIO_2, 0x00000025, 0, },
+ { XFER_PIO_3, 0x00000025, 0, },
+ { XFER_PIO_4, 0x00000025, 0, },
+ { XFER_MW_DMA_0, 0x00084000, 0, },
+ { XFER_MW_DMA_1, 0x00021800, 0, },
+ { XFER_MW_DMA_2, 0x00011800, 0, },
+ { -1, 0, 0 }
+};
+
+static const struct pata_macio_timing pata_macio_kl66_timings[] = {
+ { XFER_PIO_0, 0x0000038c, 0, },
+ { XFER_PIO_1, 0x0000020a, 0, },
+ { XFER_PIO_2, 0x00000127, 0, },
+ { XFER_PIO_3, 0x000000c6, 0, },
+ { XFER_PIO_4, 0x00000065, 0, },
+ { XFER_MW_DMA_0, 0x00084000, 0, },
+ { XFER_MW_DMA_1, 0x00029800, 0, },
+ { XFER_MW_DMA_2, 0x00019400, 0, },
+ { XFER_UDMA_0, 0x19100000, 0, },
+ { XFER_UDMA_1, 0x14d00000, 0, },
+ { XFER_UDMA_2, 0x10900000, 0, },
+ { XFER_UDMA_3, 0x0c700000, 0, },
+ { XFER_UDMA_4, 0x0c500000, 0, },
+ { -1, 0, 0 }
+};
+
+static const struct pata_macio_timing pata_macio_kauai_timings[] = {
+ { XFER_PIO_0, 0x08000a92, 0, },
+ { XFER_PIO_1, 0x0800060f, 0, },
+ { XFER_PIO_2, 0x0800038b, 0, },
+ { XFER_PIO_3, 0x05000249, 0, },
+ { XFER_PIO_4, 0x04000148, 0, },
+ { XFER_MW_DMA_0, 0x00618000, 0, },
+ { XFER_MW_DMA_1, 0x00209000, 0, },
+ { XFER_MW_DMA_2, 0x00148000, 0, },
+ { XFER_UDMA_0, 0, 0x000070c1, },
+ { XFER_UDMA_1, 0, 0x00005d81, },
+ { XFER_UDMA_2, 0, 0x00004a61, },
+ { XFER_UDMA_3, 0, 0x00003a51, },
+ { XFER_UDMA_4, 0, 0x00002a31, },
+ { XFER_UDMA_5, 0, 0x00002921, },
+ { -1, 0, 0 }
+};
+
+static const struct pata_macio_timing pata_macio_shasta_timings[] = {
+ { XFER_PIO_0, 0x0a000c97, 0, },
+ { XFER_PIO_1, 0x07000712, 0, },
+ { XFER_PIO_2, 0x040003cd, 0, },
+ { XFER_PIO_3, 0x0500028b, 0, },
+ { XFER_PIO_4, 0x0400010a, 0, },
+ { XFER_MW_DMA_0, 0x00820800, 0, },
+ { XFER_MW_DMA_1, 0x0028b000, 0, },
+ { XFER_MW_DMA_2, 0x001ca000, 0, },
+ { XFER_UDMA_0, 0, 0x00035901, },
+ { XFER_UDMA_1, 0, 0x000348b1, },
+ { XFER_UDMA_2, 0, 0x00033881, },
+ { XFER_UDMA_3, 0, 0x00033861, },
+ { XFER_UDMA_4, 0, 0x00033841, },
+ { XFER_UDMA_5, 0, 0x00033031, },
+ { XFER_UDMA_6, 0, 0x00033021, },
+ { -1, 0, 0 }
+};
+
+static const struct pata_macio_timing *pata_macio_find_timing(
+ struct pata_macio_priv *priv,
+ int mode)
+{
+ int i;
+
+ for (i = 0; priv->timings[i].mode > 0; i++) {
+ if (priv->timings[i].mode == mode)
+ return &priv->timings[i];
+ }
+ return NULL;
+}
+
+
+static void pata_macio_apply_timings(struct ata_port *ap, unsigned int device)
+{
+ struct pata_macio_priv *priv = ap->private_data;
+ void __iomem *rbase = ap->ioaddr.cmd_addr;
+
+ if (priv->kind == controller_sh_ata6 ||
+ priv->kind == controller_un_ata6 ||
+ priv->kind == controller_k2_ata6) {
+ writel(priv->treg[device][0], rbase + IDE_KAUAI_PIO_CONFIG);
+ writel(priv->treg[device][1], rbase + IDE_KAUAI_ULTRA_CONFIG);
+ } else
+ writel(priv->treg[device][0], rbase + IDE_TIMING_CONFIG);
+}
+
+static void pata_macio_dev_select(struct ata_port *ap, unsigned int device)
+{
+ ata_sff_dev_select(ap, device);
+
+ /* Apply timings */
+ pata_macio_apply_timings(ap, device);
+}
+
+static void pata_macio_set_timings(struct ata_port *ap,
+ struct ata_device *adev)
+{
+ struct pata_macio_priv *priv = ap->private_data;
+ const struct pata_macio_timing *t;
+
+ dev_dbg(priv->dev, "Set timings: DEV=%d,PIO=0x%x (%s),DMA=0x%x (%s)\n",
+ adev->devno,
+ adev->pio_mode,
+ ata_mode_string(ata_xfer_mode2mask(adev->pio_mode)),
+ adev->dma_mode,
+ ata_mode_string(ata_xfer_mode2mask(adev->dma_mode)));
+
+ /* First clear timings */
+ priv->treg[adev->devno][0] = priv->treg[adev->devno][1] = 0;
+
+ /* Now get the PIO timings */
+ t = pata_macio_find_timing(priv, adev->pio_mode);
+ if (t == NULL) {
+ dev_warn(priv->dev, "Invalid PIO timing requested: 0x%x\n",
+ adev->pio_mode);
+ t = pata_macio_find_timing(priv, XFER_PIO_0);
+ }
+ BUG_ON(t == NULL);
+
+ /* PIO timings only ever use the first treg */
+ priv->treg[adev->devno][0] |= t->reg1;
+
+ /* Now get DMA timings */
+ t = pata_macio_find_timing(priv, adev->dma_mode);
+ if (t == NULL || (t->reg1 == 0 && t->reg2 == 0)) {
+ dev_dbg(priv->dev, "DMA timing not set yet, using MW_DMA_0\n");
+ t = pata_macio_find_timing(priv, XFER_MW_DMA_0);
+ }
+ BUG_ON(t == NULL);
+
+ /* DMA timings can use both tregs */
+ priv->treg[adev->devno][0] |= t->reg1;
+ priv->treg[adev->devno][1] |= t->reg2;
+
+ dev_dbg(priv->dev, " -> %08x %08x\n",
+ priv->treg[adev->devno][0],
+ priv->treg[adev->devno][1]);
+
+ /* Apply to hardware */
+ pata_macio_apply_timings(ap, adev->devno);
+}
+
+/*
+ * Blast some well known "safe" values to the timing registers at init or
+ * wakeup from sleep time, before we do real calculation
+ */
+static void pata_macio_default_timings(struct pata_macio_priv *priv)
+{
+ unsigned int value, value2 = 0;
+
+ switch(priv->kind) {
+ case controller_sh_ata6:
+ value = 0x0a820c97;
+ value2 = 0x00033031;
+ break;
+ case controller_un_ata6:
+ case controller_k2_ata6:
+ value = 0x08618a92;
+ value2 = 0x00002921;
+ break;
+ case controller_kl_ata4:
+ value = 0x0008438c;
+ break;
+ case controller_kl_ata3:
+ value = 0x00084526;
+ break;
+ case controller_heathrow:
+ case controller_ohare:
+ default:
+ value = 0x00074526;
+ break;
+ }
+ priv->treg[0][0] = priv->treg[1][0] = value;
+ priv->treg[0][1] = priv->treg[1][1] = value2;
+}
+
+static int pata_macio_cable_detect(struct ata_port *ap)
+{
+ struct pata_macio_priv *priv = ap->private_data;
+
+ /* Get cable type from device-tree */
+ if (priv->kind == controller_kl_ata4 ||
+ priv->kind == controller_un_ata6 ||
+ priv->kind == controller_k2_ata6 ||
+ priv->kind == controller_sh_ata6) {
+ const char* cable = of_get_property(priv->node, "cable-type",
+ NULL);
+ struct device_node *root = of_find_node_by_path("/");
+ const char *model = of_get_property(root, "model", NULL);
+
+ if (cable && !strncmp(cable, "80-", 3)) {
+ /* Some drives fail to detect 80c cable in PowerBook
+ * These machine use proprietary short IDE cable
+ * anyway
+ */
+ if (!strncmp(model, "PowerBook", 9))
+ return ATA_CBL_PATA40_SHORT;
+ else
+ return ATA_CBL_PATA80;
+ }
+ }
+
+ /* G5's seem to have incorrect cable type in device-tree.
+ * Let's assume they always have a 80 conductor cable, this seem to
+ * be always the case unless the user mucked around
+ */
+ if (of_device_is_compatible(priv->node, "K2-UATA") ||
+ of_device_is_compatible(priv->node, "shasta-ata"))
+ return ATA_CBL_PATA80;
+
+ /* Anything else is 40 connectors */
+ return ATA_CBL_PATA40;
+}
+
+static void pata_macio_qc_prep(struct ata_queued_cmd *qc)
+{
+ unsigned int write = (qc->tf.flags & ATA_TFLAG_WRITE);
+ struct ata_port *ap = qc->ap;
+ struct pata_macio_priv *priv = ap->private_data;
+ struct scatterlist *sg;
+ struct dbdma_cmd *table;
+ unsigned int si, pi;
+
+ dev_dbgdma(priv->dev, "%s: qc %p flags %lx, write %d dev %d\n",
+ __func__, qc, qc->flags, write, qc->dev->devno);
+
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
+
+ table = (struct dbdma_cmd *) priv->dma_table_cpu;
+
+ pi = 0;
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ u32 addr, sg_len, len;
+
+ /* determine if physical DMA addr spans 64K boundary.
+ * Note h/w doesn't support 64-bit, so we unconditionally
+ * truncate dma_addr_t to u32.
+ */
+ addr = (u32) sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ while (sg_len) {
+ /* table overflow should never happen */
+ BUG_ON (pi++ >= MAX_DCMDS);
+
+ len = (sg_len < MAX_DBDMA_SEG) ? sg_len : MAX_DBDMA_SEG;
+ st_le16(&table->command, write ? OUTPUT_MORE: INPUT_MORE);
+ st_le16(&table->req_count, len);
+ st_le32(&table->phy_addr, addr);
+ table->cmd_dep = 0;
+ table->xfer_status = 0;
+ table->res_count = 0;
+ addr += len;
+ sg_len -= len;
+ ++table;
+ }
+ }
+
+ /* Should never happen according to Tejun */
+ BUG_ON(!pi);
+
+ /* Convert the last command to an input/output */
+ table--;
+ st_le16(&table->command, write ? OUTPUT_LAST: INPUT_LAST);
+ table++;
+
+ /* Add the stop command to the end of the list */
+ memset(table, 0, sizeof(struct dbdma_cmd));
+ st_le16(&table->command, DBDMA_STOP);
+
+ dev_dbgdma(priv->dev, "%s: %d DMA list entries\n", __func__, pi);
+}
+
+
+static void pata_macio_freeze(struct ata_port *ap)
+{
+ struct dbdma_regs __iomem *dma_regs = ap->ioaddr.bmdma_addr;
+
+ if (dma_regs) {
+ unsigned int timeout = 1000000;
+
+ /* Make sure DMA controller is stopped */
+ writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma_regs->control);
+ while (--timeout && (readl(&dma_regs->status) & RUN))
+ udelay(1);
+ }
+
+ ata_sff_freeze(ap);
+}
+
+
+static void pata_macio_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pata_macio_priv *priv = ap->private_data;
+ struct dbdma_regs __iomem *dma_regs = ap->ioaddr.bmdma_addr;
+ int dev = qc->dev->devno;
+
+ dev_dbgdma(priv->dev, "%s: qc %p\n", __func__, qc);
+
+ /* Make sure DMA commands updates are visible */
+ writel(priv->dma_table_dma, &dma_regs->cmdptr);
+
+ /* On KeyLargo 66Mhz cell, we need to add 60ns to wrDataSetup on
+ * UDMA reads
+ */
+ if (priv->kind == controller_kl_ata4 &&
+ (priv->treg[dev][0] & TR_66_UDMA_EN)) {
+ void __iomem *rbase = ap->ioaddr.cmd_addr;
+ u32 reg = priv->treg[dev][0];
+
+ if (!(qc->tf.flags & ATA_TFLAG_WRITE))
+ reg += 0x00800000;
+ writel(reg, rbase + IDE_TIMING_CONFIG);
+ }
+
+ /* issue r/w command */
+ ap->ops->sff_exec_command(ap, &qc->tf);
+}
+
+static void pata_macio_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pata_macio_priv *priv = ap->private_data;
+ struct dbdma_regs __iomem *dma_regs = ap->ioaddr.bmdma_addr;
+
+ dev_dbgdma(priv->dev, "%s: qc %p\n", __func__, qc);
+
+ writel((RUN << 16) | RUN, &dma_regs->control);
+ /* Make sure it gets to the controller right now */
+ (void)readl(&dma_regs->control);
+}
+
+static void pata_macio_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pata_macio_priv *priv = ap->private_data;
+ struct dbdma_regs __iomem *dma_regs = ap->ioaddr.bmdma_addr;
+ unsigned int timeout = 1000000;
+
+ dev_dbgdma(priv->dev, "%s: qc %p\n", __func__, qc);
+
+ /* Stop the DMA engine and wait for it to full halt */
+ writel (((RUN|WAKE|DEAD) << 16), &dma_regs->control);
+ while (--timeout && (readl(&dma_regs->status) & RUN))
+ udelay(1);
+}
+
+static u8 pata_macio_bmdma_status(struct ata_port *ap)
+{
+ struct pata_macio_priv *priv = ap->private_data;
+ struct dbdma_regs __iomem *dma_regs = ap->ioaddr.bmdma_addr;
+ u32 dstat, rstat = ATA_DMA_INTR;
+ unsigned long timeout = 0;
+
+ dstat = readl(&dma_regs->status);
+
+ dev_dbgdma(priv->dev, "%s: dstat=%x\n", __func__, dstat);
+
+ /* We have two things to deal with here:
+ *
+ * - The dbdma won't stop if the command was started
+ * but completed with an error without transferring all
+ * datas. This happens when bad blocks are met during
+ * a multi-block transfer.
+ *
+ * - The dbdma fifo hasn't yet finished flushing to
+ * to system memory when the disk interrupt occurs.
+ *
+ */
+
+ /* First check for errors */
+ if ((dstat & (RUN|DEAD)) != RUN)
+ rstat |= ATA_DMA_ERR;
+
+ /* If ACTIVE is cleared, the STOP command has been hit and
+ * the transfer is complete. If not, we have to flush the
+ * channel.
+ */
+ if ((dstat & ACTIVE) == 0)
+ return rstat;
+
+ dev_dbgdma(priv->dev, "%s: DMA still active, flushing...\n", __func__);
+
+ /* If dbdma didn't execute the STOP command yet, the
+ * active bit is still set. We consider that we aren't
+ * sharing interrupts (which is hopefully the case with
+ * those controllers) and so we just try to flush the
+ * channel for pending data in the fifo
+ */
+ udelay(1);
+ writel((FLUSH << 16) | FLUSH, &dma_regs->control);
+ for (;;) {
+ udelay(1);
+ dstat = readl(&dma_regs->status);
+ if ((dstat & FLUSH) == 0)
+ break;
+ if (++timeout > 1000) {
+ dev_warn(priv->dev, "timeout flushing DMA\n");
+ rstat |= ATA_DMA_ERR;
+ break;
+ }
+ }
+ return rstat;
+}
+
+/* port_start is when we allocate the DMA command list */
+static int pata_macio_port_start(struct ata_port *ap)
+{
+ struct pata_macio_priv *priv = ap->private_data;
+
+ if (ap->ioaddr.bmdma_addr == NULL)
+ return 0;
+
+ /* Allocate space for the DBDMA commands.
+ *
+ * The +2 is +1 for the stop command and +1 to allow for
+ * aligning the start address to a multiple of 16 bytes.
+ */
+ priv->dma_table_cpu =
+ dmam_alloc_coherent(priv->dev,
+ (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+ &priv->dma_table_dma, GFP_KERNEL);
+ if (priv->dma_table_cpu == NULL) {
+ dev_err(priv->dev, "Unable to allocate DMA command list\n");
+ ap->ioaddr.bmdma_addr = NULL;
+ ap->mwdma_mask = 0;
+ ap->udma_mask = 0;
+ }
+ return 0;
+}
+
+static void pata_macio_irq_clear(struct ata_port *ap)
+{
+ struct pata_macio_priv *priv = ap->private_data;
+
+ /* Nothing to do here */
+
+ dev_dbgdma(priv->dev, "%s\n", __func__);
+}
+
+static void pata_macio_reset_hw(struct pata_macio_priv *priv, int resume)
+{
+ dev_dbg(priv->dev, "Enabling & resetting... \n");
+
+ if (priv->mediabay)
+ return;
+
+ if (priv->kind == controller_ohare && !resume) {
+ /* The code below is having trouble on some ohare machines
+ * (timing related ?). Until I can put my hand on one of these
+ * units, I keep the old way
+ */
+ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, priv->node, 0, 1);
+ } else {
+ int rc;
+
+ /* Reset and enable controller */
+ rc = ppc_md.feature_call(PMAC_FTR_IDE_RESET,
+ priv->node, priv->aapl_bus_id, 1);
+ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE,
+ priv->node, priv->aapl_bus_id, 1);
+ msleep(10);
+ /* Only bother waiting if there's a reset control */
+ if (rc == 0) {
+ ppc_md.feature_call(PMAC_FTR_IDE_RESET,
+ priv->node, priv->aapl_bus_id, 0);
+ msleep(IDE_WAKEUP_DELAY_MS);
+ }
+ }
+
+ /* If resuming a PCI device, restore the config space here */
+ if (priv->pdev && resume) {
+ int rc;
+
+ pci_restore_state(priv->pdev);
+ rc = pcim_enable_device(priv->pdev);
+ if (rc)
+ dev_err(&priv->pdev->dev,
+ "Failed to enable device after resume (%d)\n",
+ rc);
+ else
+ pci_set_master(priv->pdev);
+ }
+
+ /* On Kauai, initialize the FCR. We don't perform a reset, doesn't really
+ * seem necessary and speeds up the boot process
+ */
+ if (priv->kauai_fcr)
+ writel(KAUAI_FCR_UATA_MAGIC |
+ KAUAI_FCR_UATA_RESET_N |
+ KAUAI_FCR_UATA_ENABLE, priv->kauai_fcr);
+}
+
+/* Hook the standard slave config to fixup some HW related alignment
+ * restrictions
+ */
+static int pata_macio_slave_config(struct scsi_device *sdev)
+{
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct pata_macio_priv *priv = ap->private_data;
+ struct ata_device *dev;
+ u16 cmd;
+ int rc;
+
+ /* First call original */
+ rc = ata_scsi_slave_config(sdev);
+ if (rc)
+ return rc;
+
+ /* This is lifted from sata_nv */
+ dev = &ap->link.device[sdev->id];
+
+ /* OHare has issues with non cache aligned DMA on some chipsets */
+ if (priv->kind == controller_ohare) {
+ blk_queue_update_dma_alignment(sdev->request_queue, 31);
+ blk_queue_update_dma_pad(sdev->request_queue, 31);
+
+ /* Tell the world about it */
+ ata_dev_info(dev, "OHare alignment limits applied\n");
+ return 0;
+ }
+
+ /* We only have issues with ATAPI */
+ if (dev->class != ATA_DEV_ATAPI)
+ return 0;
+
+ /* Shasta and K2 seem to have "issues" with reads ... */
+ if (priv->kind == controller_sh_ata6 || priv->kind == controller_k2_ata6) {
+ /* Allright these are bad, apply restrictions */
+ blk_queue_update_dma_alignment(sdev->request_queue, 15);
+ blk_queue_update_dma_pad(sdev->request_queue, 15);
+
+ /* We enable MWI and hack cache line size directly here, this
+ * is specific to this chipset and not normal values, we happen
+ * to somewhat know what we are doing here (which is basically
+ * to do the same Apple does and pray they did not get it wrong :-)
+ */
+ BUG_ON(!priv->pdev);
+ pci_write_config_byte(priv->pdev, PCI_CACHE_LINE_SIZE, 0x08);
+ pci_read_config_word(priv->pdev, PCI_COMMAND, &cmd);
+ pci_write_config_word(priv->pdev, PCI_COMMAND,
+ cmd | PCI_COMMAND_INVALIDATE);
+
+ /* Tell the world about it */
+ ata_dev_info(dev, "K2/Shasta alignment limits applied\n");
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pata_macio_do_suspend(struct pata_macio_priv *priv, pm_message_t mesg)
+{
+ int rc;
+
+ /* First, core libata suspend to do most of the work */
+ rc = ata_host_suspend(priv->host, mesg);
+ if (rc)
+ return rc;
+
+ /* Restore to default timings */
+ pata_macio_default_timings(priv);
+
+ /* Mask interrupt. Not strictly necessary but old driver did
+ * it and I'd rather not change that here */
+ disable_irq(priv->irq);
+
+ /* The media bay will handle itself just fine */
+ if (priv->mediabay)
+ return 0;
+
+ /* Kauai has bus control FCRs directly here */
+ if (priv->kauai_fcr) {
+ u32 fcr = readl(priv->kauai_fcr);
+ fcr &= ~(KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE);
+ writel(fcr, priv->kauai_fcr);
+ }
+
+ /* For PCI, save state and disable DMA. No need to call
+ * pci_set_power_state(), the HW doesn't do D states that
+ * way, the platform code will take care of suspending the
+ * ASIC properly
+ */
+ if (priv->pdev) {
+ pci_save_state(priv->pdev);
+ pci_disable_device(priv->pdev);
+ }
+
+ /* Disable the bus on older machines and the cell on kauai */
+ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, priv->node,
+ priv->aapl_bus_id, 0);
+
+ return 0;
+}
+
+static int pata_macio_do_resume(struct pata_macio_priv *priv)
+{
+ /* Reset and re-enable the HW */
+ pata_macio_reset_hw(priv, 1);
+
+ /* Sanitize drive timings */
+ pata_macio_apply_timings(priv->host->ports[0], 0);
+
+ /* We want our IRQ back ! */
+ enable_irq(priv->irq);
+
+ /* Let the libata core take it from there */
+ ata_host_resume(priv->host);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static struct scsi_host_template pata_macio_sht = {
+ ATA_BASE_SHT(DRV_NAME),
+ .sg_tablesize = MAX_DCMDS,
+ /* We may not need that strict one */
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = pata_macio_slave_config,
+};
+
+static struct ata_port_operations pata_macio_ops = {
+ .inherits = &ata_bmdma_port_ops,
+
+ .freeze = pata_macio_freeze,
+ .set_piomode = pata_macio_set_timings,
+ .set_dmamode = pata_macio_set_timings,
+ .cable_detect = pata_macio_cable_detect,
+ .sff_dev_select = pata_macio_dev_select,
+ .qc_prep = pata_macio_qc_prep,
+ .bmdma_setup = pata_macio_bmdma_setup,
+ .bmdma_start = pata_macio_bmdma_start,
+ .bmdma_stop = pata_macio_bmdma_stop,
+ .bmdma_status = pata_macio_bmdma_status,
+ .port_start = pata_macio_port_start,
+ .sff_irq_clear = pata_macio_irq_clear,
+};
+
+static void pata_macio_invariants(struct pata_macio_priv *priv)
+{
+ const int *bidp;
+
+ /* Identify the type of controller */
+ if (of_device_is_compatible(priv->node, "shasta-ata")) {
+ priv->kind = controller_sh_ata6;
+ priv->timings = pata_macio_shasta_timings;
+ } else if (of_device_is_compatible(priv->node, "kauai-ata")) {
+ priv->kind = controller_un_ata6;
+ priv->timings = pata_macio_kauai_timings;
+ } else if (of_device_is_compatible(priv->node, "K2-UATA")) {
+ priv->kind = controller_k2_ata6;
+ priv->timings = pata_macio_kauai_timings;
+ } else if (of_device_is_compatible(priv->node, "keylargo-ata")) {
+ if (strcmp(priv->node->name, "ata-4") == 0) {
+ priv->kind = controller_kl_ata4;
+ priv->timings = pata_macio_kl66_timings;
+ } else {
+ priv->kind = controller_kl_ata3;
+ priv->timings = pata_macio_kl33_timings;
+ }
+ } else if (of_device_is_compatible(priv->node, "heathrow-ata")) {
+ priv->kind = controller_heathrow;
+ priv->timings = pata_macio_heathrow_timings;
+ } else {
+ priv->kind = controller_ohare;
+ priv->timings = pata_macio_ohare_timings;
+ }
+
+ /* XXX FIXME --- setup priv->mediabay here */
+
+ /* Get Apple bus ID (for clock and ASIC control) */
+ bidp = of_get_property(priv->node, "AAPL,bus-id", NULL);
+ priv->aapl_bus_id = bidp ? *bidp : 0;
+
+ /* Fixup missing Apple bus ID in case of media-bay */
+ if (priv->mediabay && bidp == 0)
+ priv->aapl_bus_id = 1;
+}
+
+static void pata_macio_setup_ios(struct ata_ioports *ioaddr,
+ void __iomem * base, void __iomem * dma)
+{
+ /* cmd_addr is the base of regs for that port */
+ ioaddr->cmd_addr = base;
+
+ /* taskfile registers */
+ ioaddr->data_addr = base + (ATA_REG_DATA << 4);
+ ioaddr->error_addr = base + (ATA_REG_ERR << 4);
+ ioaddr->feature_addr = base + (ATA_REG_FEATURE << 4);
+ ioaddr->nsect_addr = base + (ATA_REG_NSECT << 4);
+ ioaddr->lbal_addr = base + (ATA_REG_LBAL << 4);
+ ioaddr->lbam_addr = base + (ATA_REG_LBAM << 4);
+ ioaddr->lbah_addr = base + (ATA_REG_LBAH << 4);
+ ioaddr->device_addr = base + (ATA_REG_DEVICE << 4);
+ ioaddr->status_addr = base + (ATA_REG_STATUS << 4);
+ ioaddr->command_addr = base + (ATA_REG_CMD << 4);
+ ioaddr->altstatus_addr = base + 0x160;
+ ioaddr->ctl_addr = base + 0x160;
+ ioaddr->bmdma_addr = dma;
+}
+
+static void pmac_macio_calc_timing_masks(struct pata_macio_priv *priv,
+ struct ata_port_info *pinfo)
+{
+ int i = 0;
+
+ pinfo->pio_mask = 0;
+ pinfo->mwdma_mask = 0;
+ pinfo->udma_mask = 0;
+
+ while (priv->timings[i].mode > 0) {
+ unsigned int mask = 1U << (priv->timings[i].mode & 0x0f);
+ switch(priv->timings[i].mode & 0xf0) {
+ case 0x00: /* PIO */
+ pinfo->pio_mask |= (mask >> 8);
+ break;
+ case 0x20: /* MWDMA */
+ pinfo->mwdma_mask |= mask;
+ break;
+ case 0x40: /* UDMA */
+ pinfo->udma_mask |= mask;
+ break;
+ }
+ i++;
+ }
+ dev_dbg(priv->dev, "Supported masks: PIO=%lx, MWDMA=%lx, UDMA=%lx\n",
+ pinfo->pio_mask, pinfo->mwdma_mask, pinfo->udma_mask);
+}
+
+static int pata_macio_common_init(struct pata_macio_priv *priv,
+ resource_size_t tfregs,
+ resource_size_t dmaregs,
+ resource_size_t fcregs,
+ unsigned long irq)
+{
+ struct ata_port_info pinfo;
+ const struct ata_port_info *ppi[] = { &pinfo, NULL };
+ void __iomem *dma_regs = NULL;
+
+ /* Fill up privates with various invariants collected from the
+ * device-tree
+ */
+ pata_macio_invariants(priv);
+
+ /* Make sure we have sane initial timings in the cache */
+ pata_macio_default_timings(priv);
+
+ /* Not sure what the real max is but we know it's less than 64K, let's
+ * use 64K minus 256
+ */
+ dma_set_max_seg_size(priv->dev, MAX_DBDMA_SEG);
+
+ /* Allocate libata host for 1 port */
+ memset(&pinfo, 0, sizeof(struct ata_port_info));
+ pmac_macio_calc_timing_masks(priv, &pinfo);
+ pinfo.flags = ATA_FLAG_SLAVE_POSS;
+ pinfo.port_ops = &pata_macio_ops;
+ pinfo.private_data = priv;
+
+ priv->host = ata_host_alloc_pinfo(priv->dev, ppi, 1);
+ if (priv->host == NULL) {
+ dev_err(priv->dev, "Failed to allocate ATA port structure\n");
+ return -ENOMEM;
+ }
+
+ /* Setup the private data in host too */
+ priv->host->private_data = priv;
+
+ /* Map base registers */
+ priv->tfregs = devm_ioremap(priv->dev, tfregs, 0x100);
+ if (priv->tfregs == NULL) {
+ dev_err(priv->dev, "Failed to map ATA ports\n");
+ return -ENOMEM;
+ }
+ priv->host->iomap = &priv->tfregs;
+
+ /* Map DMA regs */
+ if (dmaregs != 0) {
+ dma_regs = devm_ioremap(priv->dev, dmaregs,
+ sizeof(struct dbdma_regs));
+ if (dma_regs == NULL)
+ dev_warn(priv->dev, "Failed to map ATA DMA registers\n");
+ }
+
+ /* If chip has local feature control, map those regs too */
+ if (fcregs != 0) {
+ priv->kauai_fcr = devm_ioremap(priv->dev, fcregs, 4);
+ if (priv->kauai_fcr == NULL) {
+ dev_err(priv->dev, "Failed to map ATA FCR register\n");
+ return -ENOMEM;
+ }
+ }
+
+ /* Setup port data structure */
+ pata_macio_setup_ios(&priv->host->ports[0]->ioaddr,
+ priv->tfregs, dma_regs);
+ priv->host->ports[0]->private_data = priv;
+
+ /* hard-reset the controller */
+ pata_macio_reset_hw(priv, 0);
+ pata_macio_apply_timings(priv->host->ports[0], 0);
+
+ /* Enable bus master if necessary */
+ if (priv->pdev && dma_regs)
+ pci_set_master(priv->pdev);
+
+ dev_info(priv->dev, "Activating pata-macio chipset %s, Apple bus ID %d\n",
+ macio_ata_names[priv->kind], priv->aapl_bus_id);
+
+ /* Start it up */
+ priv->irq = irq;
+ return ata_host_activate(priv->host, irq, ata_bmdma_interrupt, 0,
+ &pata_macio_sht);
+}
+
+static int pata_macio_attach(struct macio_dev *mdev,
+ const struct of_device_id *match)
+{
+ struct pata_macio_priv *priv;
+ resource_size_t tfregs, dmaregs = 0;
+ unsigned long irq;
+ int rc;
+
+ /* Check for broken device-trees */
+ if (macio_resource_count(mdev) == 0) {
+ dev_err(&mdev->ofdev.dev,
+ "No addresses for controller\n");
+ return -ENXIO;
+ }
+
+ /* Enable managed resources */
+ macio_enable_devres(mdev);
+
+ /* Allocate and init private data structure */
+ priv = devm_kzalloc(&mdev->ofdev.dev,
+ sizeof(struct pata_macio_priv), GFP_KERNEL);
+ if (priv == NULL) {
+ dev_err(&mdev->ofdev.dev,
+ "Failed to allocate private memory\n");
+ return -ENOMEM;
+ }
+ priv->node = of_node_get(mdev->ofdev.dev.of_node);
+ priv->mdev = mdev;
+ priv->dev = &mdev->ofdev.dev;
+
+ /* Request memory resource for taskfile registers */
+ if (macio_request_resource(mdev, 0, "pata-macio")) {
+ dev_err(&mdev->ofdev.dev,
+ "Cannot obtain taskfile resource\n");
+ return -EBUSY;
+ }
+ tfregs = macio_resource_start(mdev, 0);
+
+ /* Request resources for DMA registers if any */
+ if (macio_resource_count(mdev) >= 2) {
+ if (macio_request_resource(mdev, 1, "pata-macio-dma"))
+ dev_err(&mdev->ofdev.dev,
+ "Cannot obtain DMA resource\n");
+ else
+ dmaregs = macio_resource_start(mdev, 1);
+ }
+
+ /*
+ * Fixup missing IRQ for some old implementations with broken
+ * device-trees.
+ *
+ * This is a bit bogus, it should be fixed in the device-tree itself,
+ * via the existing macio fixups, based on the type of interrupt
+ * controller in the machine. However, I have no test HW for this case,
+ * and this trick works well enough on those old machines...
+ */
+ if (macio_irq_count(mdev) == 0) {
+ dev_warn(&mdev->ofdev.dev,
+ "No interrupts for controller, using 13\n");
+ irq = irq_create_mapping(NULL, 13);
+ } else
+ irq = macio_irq(mdev, 0);
+
+ /* Prevvent media bay callbacks until fully registered */
+ lock_media_bay(priv->mdev->media_bay);
+
+ /* Get register addresses and call common initialization */
+ rc = pata_macio_common_init(priv,
+ tfregs, /* Taskfile regs */
+ dmaregs, /* DBDMA regs */
+ 0, /* Feature control */
+ irq);
+ unlock_media_bay(priv->mdev->media_bay);
+
+ return rc;
+}
+
+static int pata_macio_detach(struct macio_dev *mdev)
+{
+ struct ata_host *host = macio_get_drvdata(mdev);
+ struct pata_macio_priv *priv = host->private_data;
+
+ lock_media_bay(priv->mdev->media_bay);
+
+ /* Make sure the mediabay callback doesn't try to access
+ * dead stuff
+ */
+ priv->host->private_data = NULL;
+
+ ata_host_detach(host);
+
+ unlock_media_bay(priv->mdev->media_bay);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pata_macio_suspend(struct macio_dev *mdev, pm_message_t mesg)
+{
+ struct ata_host *host = macio_get_drvdata(mdev);
+
+ return pata_macio_do_suspend(host->private_data, mesg);
+}
+
+static int pata_macio_resume(struct macio_dev *mdev)
+{
+ struct ata_host *host = macio_get_drvdata(mdev);
+
+ return pata_macio_do_resume(host->private_data);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PMAC_MEDIABAY
+static void pata_macio_mb_event(struct macio_dev* mdev, int mb_state)
+{
+ struct ata_host *host = macio_get_drvdata(mdev);
+ struct ata_port *ap;
+ struct ata_eh_info *ehi;
+ struct ata_device *dev;
+ unsigned long flags;
+
+ if (!host || !host->private_data)
+ return;
+ ap = host->ports[0];
+ spin_lock_irqsave(ap->lock, flags);
+ ehi = &ap->link.eh_info;
+ if (mb_state == MB_CD) {
+ ata_ehi_push_desc(ehi, "mediabay plug");
+ ata_ehi_hotplugged(ehi);
+ ata_port_freeze(ap);
+ } else {
+ ata_ehi_push_desc(ehi, "mediabay unplug");
+ ata_for_each_dev(dev, &ap->link, ALL)
+ dev->flags |= ATA_DFLAG_DETACH;
+ ata_port_abort(ap);
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+
+}
+#endif /* CONFIG_PMAC_MEDIABAY */
+
+
+static int pata_macio_pci_attach(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct pata_macio_priv *priv;
+ struct device_node *np;
+ resource_size_t rbase;
+
+ /* We cannot use a MacIO controller without its OF device node */
+ np = pci_device_to_OF_node(pdev);
+ if (np == NULL) {
+ dev_err(&pdev->dev,
+ "Cannot find OF device node for controller\n");
+ return -ENODEV;
+ }
+
+ /* Check that it can be enabled */
+ if (pcim_enable_device(pdev)) {
+ dev_err(&pdev->dev,
+ "Cannot enable controller PCI device\n");
+ return -ENXIO;
+ }
+
+ /* Allocate and init private data structure */
+ priv = devm_kzalloc(&pdev->dev,
+ sizeof(struct pata_macio_priv), GFP_KERNEL);
+ if (priv == NULL) {
+ dev_err(&pdev->dev,
+ "Failed to allocate private memory\n");
+ return -ENOMEM;
+ }
+ priv->node = of_node_get(np);
+ priv->pdev = pdev;
+ priv->dev = &pdev->dev;
+
+ /* Get MMIO regions */
+ if (pci_request_regions(pdev, "pata-macio")) {
+ dev_err(&pdev->dev,
+ "Cannot obtain PCI resources\n");
+ return -EBUSY;
+ }
+
+ /* Get register addresses and call common initialization */
+ rbase = pci_resource_start(pdev, 0);
+ if (pata_macio_common_init(priv,
+ rbase + 0x2000, /* Taskfile regs */
+ rbase + 0x1000, /* DBDMA regs */
+ rbase, /* Feature control */
+ pdev->irq))
+ return -ENXIO;
+
+ return 0;
+}
+
+static void pata_macio_pci_detach(struct pci_dev *pdev)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+
+ ata_host_detach(host);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pata_macio_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+
+ return pata_macio_do_suspend(host->private_data, mesg);
+}
+
+static int pata_macio_pci_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+
+ return pata_macio_do_resume(host->private_data);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static struct of_device_id pata_macio_match[] =
+{
+ {
+ .name = "IDE",
+ },
+ {
+ .name = "ATA",
+ },
+ {
+ .type = "ide",
+ },
+ {
+ .type = "ata",
+ },
+ {},
+};
+
+static struct macio_driver pata_macio_driver =
+{
+ .driver = {
+ .name = "pata-macio",
+ .owner = THIS_MODULE,
+ .of_match_table = pata_macio_match,
+ },
+ .probe = pata_macio_attach,
+ .remove = pata_macio_detach,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = pata_macio_suspend,
+ .resume = pata_macio_resume,
+#endif
+#ifdef CONFIG_PMAC_MEDIABAY
+ .mediabay_event = pata_macio_mb_event,
+#endif
+};
+
+static const struct pci_device_id pata_macio_pci_match[] = {
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA), 0 },
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100), 0 },
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100), 0 },
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_SH_ATA), 0 },
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA), 0 },
+ {},
+};
+
+static struct pci_driver pata_macio_pci_driver = {
+ .name = "pata-pci-macio",
+ .id_table = pata_macio_pci_match,
+ .probe = pata_macio_pci_attach,
+ .remove = pata_macio_pci_detach,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = pata_macio_pci_suspend,
+ .resume = pata_macio_pci_resume,
+#endif
+ .driver = {
+ .owner = THIS_MODULE,
+ },
+};
+MODULE_DEVICE_TABLE(pci, pata_macio_pci_match);
+
+
+static int __init pata_macio_init(void)
+{
+ int rc;
+
+ if (!machine_is(powermac))
+ return -ENODEV;
+
+ rc = pci_register_driver(&pata_macio_pci_driver);
+ if (rc)
+ return rc;
+ rc = macio_register_driver(&pata_macio_driver);
+ if (rc) {
+ pci_unregister_driver(&pata_macio_pci_driver);
+ return rc;
+ }
+ return 0;
+}
+
+static void __exit pata_macio_exit(void)
+{
+ macio_unregister_driver(&pata_macio_driver);
+ pci_unregister_driver(&pata_macio_pci_driver);
+}
+
+module_init(pata_macio_init);
+module_exit(pata_macio_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt");
+MODULE_DESCRIPTION("Apple MacIO PATA driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index 24a011b2502..ae9feb1ba8f 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -5,13 +5,12 @@
* isn't making full use of the device functionality but it is
* easy to get working.
*
- * (c) 2006 Red Hat <alan@redhat.com>
+ * (c) 2006 Red Hat
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -20,29 +19,30 @@
#include <linux/ata.h>
#define DRV_NAME "pata_marvell"
-#define DRV_VERSION "0.1.4"
+#define DRV_VERSION "0.1.6"
/**
- * marvell_pre_reset - check for 40/80 pin
- * @link: link
- * @deadline: deadline jiffies for the operation
+ * marvell_pata_active - check if PATA is active
+ * @pdev: PCI device
*
- * Perform the PATA port setup we need.
+ * Returns 1 if the PATA port may be active. We know how to check this
+ * for the 6145 but not the other devices
*/
-static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
+static int marvell_pata_active(struct pci_dev *pdev)
{
- struct ata_port *ap = link->ap;
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int i;
u32 devices;
void __iomem *barp;
- int i;
- /* Check if our port is enabled */
+ /* We don't yet know how to do this for other devices */
+ if (pdev->device != 0x6145)
+ return 1;
barp = pci_iomap(pdev, 5, 0x10);
if (barp == NULL)
return -ENOMEM;
+
printk("BAR5:");
for(i = 0; i <= 0x0F; i++)
printk("%02X:%02X ", i, ioread8(barp + i));
@@ -51,9 +51,27 @@ static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
devices = ioread32(barp + 0x0C);
pci_iounmap(pdev, barp);
- if ((pdev->device == 0x6145) && (ap->port_no == 0) &&
- (!(devices & 0x10))) /* PATA enable ? */
- return -ENOENT;
+ if (devices & 0x10)
+ return 1;
+ return 0;
+}
+
+/**
+ * marvell_pre_reset - probe begin
+ * @link: link
+ * @deadline: deadline jiffies for the operation
+ *
+ * Perform the PATA port setup we need.
+ */
+
+static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (pdev->device == 0x6145 && ap->port_no == 0 &&
+ !marvell_pata_active(pdev)) /* PATA enable ? */
+ return -ENOENT;
return ata_sff_prereset(link, deadline);
}
@@ -107,8 +125,8 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &marvell_ops,
@@ -117,8 +135,8 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i
/* Slave possible as its magically mapped not real */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &marvell_ops,
@@ -128,7 +146,13 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i
if (pdev->device == 0x6101)
ppi[1] = &ata_dummy_port_info;
- return ata_pci_sff_init_one(pdev, ppi, &marvell_sht, NULL);
+#if defined(CONFIG_SATA_AHCI) || defined(CONFIG_SATA_AHCI_MODULE)
+ if (!marvell_pata_active(pdev)) {
+ printk(KERN_INFO DRV_NAME ": PATA port not active, deferring to AHCI driver.\n");
+ return -ENODEV;
+ }
+#endif
+ return ata_pci_bmdma_init_one(pdev, ppi, &marvell_sht, NULL, 0);
}
static const struct pci_device_id marvell_pci_tbl[] = {
@@ -136,6 +160,9 @@ static const struct pci_device_id marvell_pci_tbl[] = {
{ PCI_DEVICE(0x11AB, 0x6121), },
{ PCI_DEVICE(0x11AB, 0x6123), },
{ PCI_DEVICE(0x11AB, 0x6145), },
+ { PCI_DEVICE(0x1B4B, 0x91A0), },
+ { PCI_DEVICE(0x1B4B, 0x91A4), },
+
{ } /* terminate list */
};
@@ -144,28 +171,16 @@ static struct pci_driver marvell_pci_driver = {
.id_table = marvell_pci_tbl,
.probe = marvell_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init marvell_init(void)
-{
- return pci_register_driver(&marvell_pci_driver);
-}
-
-static void __exit marvell_exit(void)
-{
- pci_unregister_driver(&marvell_pci_driver);
-}
-
-module_init(marvell_init);
-module_exit(marvell_exit);
+module_pci_driver(marvell_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("SCSI low-level driver for Marvell ATA in legacy mode");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, marvell_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index bc79df6e7cb..ccd1c83a05c 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -6,6 +6,9 @@
* Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
* Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
*
+ * UDMA support based on patches by Freescale (Bernard Kuhn, John Rigby),
+ * Domen Puncer and Tim Yamin.
+ *
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
@@ -13,46 +16,165 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
+#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/libata.h>
+#include <linux/of_platform.h>
+#include <linux/types.h>
-#include <asm/types.h>
+#include <asm/cacheflush.h>
#include <asm/prom.h>
-#include <asm/of_platform.h>
#include <asm/mpc52xx.h>
+#include <linux/fsl/bestcomm/bestcomm.h>
+#include <linux/fsl/bestcomm/bestcomm_priv.h>
+#include <linux/fsl/bestcomm/ata.h>
#define DRV_NAME "mpc52xx_ata"
-#define DRV_VERSION "0.1.2"
-
/* Private structures used by the driver */
struct mpc52xx_ata_timings {
u32 pio1;
u32 pio2;
+ u32 mdma1;
+ u32 mdma2;
+ u32 udma1;
+ u32 udma2;
+ u32 udma3;
+ u32 udma4;
+ u32 udma5;
+ int using_udma;
};
struct mpc52xx_ata_priv {
unsigned int ipb_period;
- struct mpc52xx_ata __iomem * ata_regs;
+ struct mpc52xx_ata __iomem *ata_regs;
+ phys_addr_t ata_regs_pa;
int ata_irq;
struct mpc52xx_ata_timings timings[2];
int csel;
+
+ /* DMA */
+ struct bcom_task *dmatsk;
+ const struct udmaspec *udmaspec;
+ const struct mdmaspec *mdmaspec;
+ int mpc52xx_ata_dma_last_write;
+ int waiting_for_dma;
};
/* ATAPI-4 PIO specs (in ns) */
-static const int ataspec_t0[5] = {600, 383, 240, 180, 120};
-static const int ataspec_t1[5] = { 70, 50, 30, 30, 25};
-static const int ataspec_t2_8[5] = {290, 290, 290, 80, 70};
-static const int ataspec_t2_16[5] = {165, 125, 100, 80, 70};
-static const int ataspec_t2i[5] = { 0, 0, 0, 70, 25};
-static const int ataspec_t4[5] = { 30, 20, 15, 10, 10};
-static const int ataspec_ta[5] = { 35, 35, 35, 35, 35};
+static const u16 ataspec_t0[5] = {600, 383, 240, 180, 120};
+static const u16 ataspec_t1[5] = { 70, 50, 30, 30, 25};
+static const u16 ataspec_t2_8[5] = {290, 290, 290, 80, 70};
+static const u16 ataspec_t2_16[5] = {165, 125, 100, 80, 70};
+static const u16 ataspec_t2i[5] = { 0, 0, 0, 70, 25};
+static const u16 ataspec_t4[5] = { 30, 20, 15, 10, 10};
+static const u16 ataspec_ta[5] = { 35, 35, 35, 35, 35};
#define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c)))
+/* ======================================================================== */
+
+/* ATAPI-4 MDMA specs (in clocks) */
+struct mdmaspec {
+ u8 t0M;
+ u8 td;
+ u8 th;
+ u8 tj;
+ u8 tkw;
+ u8 tm;
+ u8 tn;
+};
+
+static const struct mdmaspec mdmaspec66[3] = {
+ { .t0M = 32, .td = 15, .th = 2, .tj = 2, .tkw = 15, .tm = 4, .tn = 1 },
+ { .t0M = 10, .td = 6, .th = 1, .tj = 1, .tkw = 4, .tm = 2, .tn = 1 },
+ { .t0M = 8, .td = 5, .th = 1, .tj = 1, .tkw = 2, .tm = 2, .tn = 1 },
+};
+
+static const struct mdmaspec mdmaspec132[3] = {
+ { .t0M = 64, .td = 29, .th = 3, .tj = 3, .tkw = 29, .tm = 7, .tn = 2 },
+ { .t0M = 20, .td = 11, .th = 2, .tj = 1, .tkw = 7, .tm = 4, .tn = 1 },
+ { .t0M = 16, .td = 10, .th = 2, .tj = 1, .tkw = 4, .tm = 4, .tn = 1 },
+};
+
+/* ATAPI-4 UDMA specs (in clocks) */
+struct udmaspec {
+ u8 tcyc;
+ u8 t2cyc;
+ u8 tds;
+ u8 tdh;
+ u8 tdvs;
+ u8 tdvh;
+ u8 tfs;
+ u8 tli;
+ u8 tmli;
+ u8 taz;
+ u8 tzah;
+ u8 tenv;
+ u8 tsr;
+ u8 trfs;
+ u8 trp;
+ u8 tack;
+ u8 tss;
+};
+
+static const struct udmaspec udmaspec66[6] = {
+ { .tcyc = 8, .t2cyc = 16, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1,
+ .tfs = 16, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 3, .trfs = 5, .trp = 11, .tack = 2, .tss = 4,
+ },
+ { .tcyc = 5, .t2cyc = 11, .tds = 1, .tdh = 1, .tdvs = 4, .tdvh = 1,
+ .tfs = 14, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 2, .trfs = 5, .trp = 9, .tack = 2, .tss = 4,
+ },
+ { .tcyc = 4, .t2cyc = 8, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1,
+ .tfs = 12, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4,
+ },
+ { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 2, .tdvh = 1,
+ .tfs = 9, .tli = 7, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4,
+ },
+ { .tcyc = 2, .t2cyc = 4, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1,
+ .tfs = 8, .tli = 8, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4,
+ },
+ { .tcyc = 2, .t2cyc = 2, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1,
+ .tfs = 6, .tli = 5, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 2, .trfs = 4, .trp = 6, .tack = 2, .tss = 4,
+ },
+};
+
+static const struct udmaspec udmaspec132[6] = {
+ { .tcyc = 15, .t2cyc = 31, .tds = 2, .tdh = 1, .tdvs = 10, .tdvh = 1,
+ .tfs = 30, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
+ .tsr = 7, .trfs = 10, .trp = 22, .tack = 3, .tss = 7,
+ },
+ { .tcyc = 10, .t2cyc = 21, .tds = 2, .tdh = 1, .tdvs = 7, .tdvh = 1,
+ .tfs = 27, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
+ .tsr = 4, .trfs = 10, .trp = 17, .tack = 3, .tss = 7,
+ },
+ { .tcyc = 6, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1,
+ .tfs = 23, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
+ .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7,
+ },
+ { .tcyc = 7, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1,
+ .tfs = 15, .tli = 13, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
+ .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7,
+ },
+ { .tcyc = 2, .t2cyc = 5, .tds = 0, .tdh = 0, .tdvs = 1, .tdvh = 1,
+ .tfs = 16, .tli = 14, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2,
+ .tsr = 2, .trfs = 7, .trp = 13, .tack = 2, .tss = 6,
+ },
+ { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1,
+ .tfs = 12, .tli = 10, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3,
+ .tsr = 3, .trfs = 7, .trp = 12, .tack = 3, .tss = 7,
+ },
+};
+
+/* ======================================================================== */
/* Bit definitions inside the registers */
#define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */
@@ -66,6 +188,7 @@ static const int ataspec_ta[5] = { 35, 35, 35, 35, 35};
#define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */
#define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */
+#define MPC52xx_ATA_FIFOSTAT_ERROR 0x40 /* FIFO Error */
#define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */
#define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */
@@ -75,6 +198,8 @@ static const int ataspec_ta[5] = { 35, 35, 35, 35, 35};
#define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */
#define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */
+#define MAX_DMA_BUFFERS 128
+#define MAX_DMA_BUFFER_SIZE 0x20000u
/* Structure of the hardware registers */
struct mpc52xx_ata {
@@ -140,15 +265,14 @@ struct mpc52xx_ata {
/* MPC52xx low level hw control */
-
static int
mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio)
{
struct mpc52xx_ata_timings *timing = &priv->timings[dev];
unsigned int ipb_period = priv->ipb_period;
- unsigned int t0, t1, t2_8, t2_16, t2i, t4, ta;
+ u32 t0, t1, t2_8, t2_16, t2i, t4, ta;
- if ((pio<0) || (pio>4))
+ if ((pio < 0) || (pio > 4))
return -EINVAL;
t0 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t0[pio]);
@@ -165,6 +289,43 @@ mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio)
return 0;
}
+static int
+mpc52xx_ata_compute_mdma_timings(struct mpc52xx_ata_priv *priv, int dev,
+ int speed)
+{
+ struct mpc52xx_ata_timings *t = &priv->timings[dev];
+ const struct mdmaspec *s = &priv->mdmaspec[speed];
+
+ if (speed < 0 || speed > 2)
+ return -EINVAL;
+
+ t->mdma1 = ((u32)s->t0M << 24) | ((u32)s->td << 16) | ((u32)s->tkw << 8) | s->tm;
+ t->mdma2 = ((u32)s->th << 24) | ((u32)s->tj << 16) | ((u32)s->tn << 8);
+ t->using_udma = 0;
+
+ return 0;
+}
+
+static int
+mpc52xx_ata_compute_udma_timings(struct mpc52xx_ata_priv *priv, int dev,
+ int speed)
+{
+ struct mpc52xx_ata_timings *t = &priv->timings[dev];
+ const struct udmaspec *s = &priv->udmaspec[speed];
+
+ if (speed < 0 || speed > 2)
+ return -EINVAL;
+
+ t->udma1 = ((u32)s->t2cyc << 24) | ((u32)s->tcyc << 16) | ((u32)s->tds << 8) | s->tdh;
+ t->udma2 = ((u32)s->tdvs << 24) | ((u32)s->tdvh << 16) | ((u32)s->tfs << 8) | s->tli;
+ t->udma3 = ((u32)s->tmli << 24) | ((u32)s->taz << 16) | ((u32)s->tenv << 8) | s->tsr;
+ t->udma4 = ((u32)s->tss << 24) | ((u32)s->trfs << 16) | ((u32)s->trp << 8) | s->tack;
+ t->udma5 = (u32)s->tzah << 24;
+ t->using_udma = 1;
+
+ return 0;
+}
+
static void
mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device)
{
@@ -173,14 +334,13 @@ mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device)
out_be32(&regs->pio1, timing->pio1);
out_be32(&regs->pio2, timing->pio2);
- out_be32(&regs->mdma1, 0);
- out_be32(&regs->mdma2, 0);
- out_be32(&regs->udma1, 0);
- out_be32(&regs->udma2, 0);
- out_be32(&regs->udma3, 0);
- out_be32(&regs->udma4, 0);
- out_be32(&regs->udma5, 0);
-
+ out_be32(&regs->mdma1, timing->mdma1);
+ out_be32(&regs->mdma2, timing->mdma2);
+ out_be32(&regs->udma1, timing->udma1);
+ out_be32(&regs->udma2, timing->udma2);
+ out_be32(&regs->udma3, timing->udma3);
+ out_be32(&regs->udma4, timing->udma4);
+ out_be32(&regs->udma5, timing->udma5);
priv->csel = device;
}
@@ -208,7 +368,7 @@ mpc52xx_ata_hw_init(struct mpc52xx_ata_priv *priv)
/* Set the time slot to 1us */
tslot = CALC_CLKCYC(priv->ipb_period, 1000000);
- out_be32(&regs->share_cnt, tslot << 16 );
+ out_be32(&regs->share_cnt, tslot << 16);
/* Init timings to PIO0 */
memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings));
@@ -237,13 +397,37 @@ mpc52xx_ata_set_piomode(struct ata_port *ap, struct ata_device *adev)
rv = mpc52xx_ata_compute_pio_timings(priv, adev->devno, pio);
if (rv) {
- printk(KERN_ERR DRV_NAME
- ": Trying to select invalid PIO mode %d\n", pio);
+ dev_err(ap->dev, "error: invalid PIO mode: %d\n", pio);
+ return;
+ }
+
+ mpc52xx_ata_apply_timings(priv, adev->devno);
+}
+
+static void
+mpc52xx_ata_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+ int rv;
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ int dma = adev->dma_mode - XFER_UDMA_0;
+ rv = mpc52xx_ata_compute_udma_timings(priv, adev->devno, dma);
+ } else {
+ int dma = adev->dma_mode - XFER_MW_DMA_0;
+ rv = mpc52xx_ata_compute_mdma_timings(priv, adev->devno, dma);
+ }
+
+ if (rv) {
+ dev_alert(ap->dev,
+ "Trying to select invalid DMA mode %d\n",
+ adev->dma_mode);
return;
}
mpc52xx_ata_apply_timings(priv, adev->devno);
}
+
static void
mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device)
{
@@ -252,7 +436,173 @@ mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device)
if (device != priv->csel)
mpc52xx_ata_apply_timings(priv, device);
- ata_sff_dev_select(ap,device);
+ ata_sff_dev_select(ap, device);
+}
+
+static int
+mpc52xx_ata_build_dmatable(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+ struct bcom_ata_bd *bd;
+ unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE), si;
+ struct scatterlist *sg;
+ int count = 0;
+
+ if (read)
+ bcom_ata_rx_prepare(priv->dmatsk);
+ else
+ bcom_ata_tx_prepare(priv->dmatsk);
+
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ dma_addr_t cur_addr = sg_dma_address(sg);
+ u32 cur_len = sg_dma_len(sg);
+
+ while (cur_len) {
+ unsigned int tc = min(cur_len, MAX_DMA_BUFFER_SIZE);
+ bd = (struct bcom_ata_bd *)
+ bcom_prepare_next_buffer(priv->dmatsk);
+
+ if (read) {
+ bd->status = tc;
+ bd->src_pa = (__force u32) priv->ata_regs_pa +
+ offsetof(struct mpc52xx_ata, fifo_data);
+ bd->dst_pa = (__force u32) cur_addr;
+ } else {
+ bd->status = tc;
+ bd->src_pa = (__force u32) cur_addr;
+ bd->dst_pa = (__force u32) priv->ata_regs_pa +
+ offsetof(struct mpc52xx_ata, fifo_data);
+ }
+
+ bcom_submit_next_buffer(priv->dmatsk, NULL);
+
+ cur_addr += tc;
+ cur_len -= tc;
+ count++;
+
+ if (count > MAX_DMA_BUFFERS) {
+ dev_alert(ap->dev, "dma table"
+ "too small\n");
+ goto use_pio_instead;
+ }
+ }
+ }
+ return 1;
+
+ use_pio_instead:
+ bcom_ata_reset_bd(priv->dmatsk);
+ return 0;
+}
+
+static void
+mpc52xx_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+ struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+
+ unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE);
+ u8 dma_mode;
+
+ if (!mpc52xx_ata_build_dmatable(qc))
+ dev_alert(ap->dev, "%s: %i, return 1?\n",
+ __func__, __LINE__);
+
+ /* Check FIFO is OK... */
+ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR)
+ dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
+ __func__, in_8(&priv->ata_regs->fifo_status));
+
+ if (read) {
+ dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_READ |
+ MPC52xx_ATA_DMAMODE_FE;
+
+ /* Setup FIFO if direction changed */
+ if (priv->mpc52xx_ata_dma_last_write != 0) {
+ priv->mpc52xx_ata_dma_last_write = 0;
+
+ /* Configure FIFO with granularity to 7 */
+ out_8(&regs->fifo_control, 7);
+ out_be16(&regs->fifo_alarm, 128);
+
+ /* Set FIFO Reset bit (FR) */
+ out_8(&regs->dma_mode, MPC52xx_ATA_DMAMODE_FR);
+ }
+ } else {
+ dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_WRITE;
+
+ /* Setup FIFO if direction changed */
+ if (priv->mpc52xx_ata_dma_last_write != 1) {
+ priv->mpc52xx_ata_dma_last_write = 1;
+
+ /* Configure FIFO with granularity to 4 */
+ out_8(&regs->fifo_control, 4);
+ out_be16(&regs->fifo_alarm, 128);
+ }
+ }
+
+ if (priv->timings[qc->dev->devno].using_udma)
+ dma_mode |= MPC52xx_ATA_DMAMODE_UDMA;
+
+ out_8(&regs->dma_mode, dma_mode);
+ priv->waiting_for_dma = ATA_DMA_ACTIVE;
+
+ ata_wait_idle(ap);
+ ap->ops->sff_exec_command(ap, &qc->tf);
+}
+
+static void
+mpc52xx_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+ bcom_set_task_auto_start(priv->dmatsk->tasknum, priv->dmatsk->tasknum);
+ bcom_enable(priv->dmatsk);
+}
+
+static void
+mpc52xx_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+ bcom_disable(priv->dmatsk);
+ bcom_ata_reset_bd(priv->dmatsk);
+ priv->waiting_for_dma = 0;
+
+ /* Check FIFO is OK... */
+ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR)
+ dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
+ __func__, in_8(&priv->ata_regs->fifo_status));
+}
+
+static u8
+mpc52xx_bmdma_status(struct ata_port *ap)
+{
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+ /* Check FIFO is OK... */
+ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) {
+ dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
+ __func__, in_8(&priv->ata_regs->fifo_status));
+ return priv->waiting_for_dma | ATA_DMA_ERR;
+ }
+
+ return priv->waiting_for_dma;
+}
+
+static irqreturn_t
+mpc52xx_ata_task_irq(int irq, void *vpriv)
+{
+ struct mpc52xx_ata_priv *priv = vpriv;
+ while (bcom_buffer_done(priv->dmatsk))
+ bcom_retrieve_buffer(priv->dmatsk, NULL, NULL);
+
+ priv->waiting_for_dma |= ATA_DMA_INTR;
+
+ return IRQ_HANDLED;
}
static struct scsi_host_template mpc52xx_ata_sht = {
@@ -260,16 +610,21 @@ static struct scsi_host_template mpc52xx_ata_sht = {
};
static struct ata_port_operations mpc52xx_ata_port_ops = {
- .inherits = &ata_sff_port_ops,
+ .inherits = &ata_bmdma_port_ops,
.sff_dev_select = mpc52xx_ata_dev_select,
- .cable_detect = ata_cable_40wire,
.set_piomode = mpc52xx_ata_set_piomode,
- .post_internal_cmd = ATA_OP_NULL,
+ .set_dmamode = mpc52xx_ata_set_dmamode,
+ .bmdma_setup = mpc52xx_bmdma_setup,
+ .bmdma_start = mpc52xx_bmdma_start,
+ .bmdma_stop = mpc52xx_bmdma_stop,
+ .bmdma_status = mpc52xx_bmdma_status,
+ .qc_prep = ata_noop_qc_prep,
};
-static int __devinit
-mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
- unsigned long raw_ata_regs)
+static int mpc52xx_ata_init_one(struct device *dev,
+ struct mpc52xx_ata_priv *priv,
+ unsigned long raw_ata_regs,
+ int mwdma_mask, int udma_mask)
{
struct ata_host *host;
struct ata_port *ap;
@@ -281,9 +636,9 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
ap = host->ports[0];
ap->flags |= ATA_FLAG_SLAVE_POSS;
- ap->pio_mask = 0x1f; /* Up to PIO4 */
- ap->mwdma_mask = 0x00; /* No MWDMA */
- ap->udma_mask = 0x00; /* No UDMA */
+ ap->pio_mask = ATA_PIO4;
+ ap->mwdma_mask = mwdma_mask;
+ ap->udma_mask = udma_mask;
ap->ops = &mpc52xx_ata_port_ops;
host->private_data = priv;
@@ -305,149 +660,184 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs);
/* activate host */
- return ata_host_activate(host, priv->ata_irq, ata_sff_interrupt, 0,
+ return ata_host_activate(host, priv->ata_irq, ata_bmdma_interrupt, 0,
&mpc52xx_ata_sht);
}
-static struct mpc52xx_ata_priv *
-mpc52xx_ata_remove_one(struct device *dev)
-{
- struct ata_host *host = dev_get_drvdata(dev);
- struct mpc52xx_ata_priv *priv = host->private_data;
-
- ata_host_detach(host);
-
- return priv;
-}
-
-
/* ======================================================================== */
/* OF Platform driver */
/* ======================================================================== */
-static int __devinit
-mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
+static int mpc52xx_ata_probe(struct platform_device *op)
{
unsigned int ipb_freq;
struct resource res_mem;
- int ata_irq;
+ int ata_irq = 0;
struct mpc52xx_ata __iomem *ata_regs;
- struct mpc52xx_ata_priv *priv;
- int rv;
+ struct mpc52xx_ata_priv *priv = NULL;
+ int rv, task_irq;
+ int mwdma_mask = 0, udma_mask = 0;
+ const __be32 *prop;
+ int proplen;
+ struct bcom_task *dmatsk;
/* Get ipb frequency */
- ipb_freq = mpc52xx_find_ipb_freq(op->node);
+ ipb_freq = mpc5xxx_get_bus_frequency(op->dev.of_node);
if (!ipb_freq) {
- printk(KERN_ERR DRV_NAME ": "
- "Unable to find IPB Bus frequency\n" );
+ dev_err(&op->dev, "could not determine IPB bus frequency\n");
return -ENODEV;
}
- /* Get IRQ and register */
- rv = of_address_to_resource(op->node, 0, &res_mem);
+ /* Get device base address from device tree, request the region
+ * and ioremap it. */
+ rv = of_address_to_resource(op->dev.of_node, 0, &res_mem);
if (rv) {
- printk(KERN_ERR DRV_NAME ": "
- "Error while parsing device node resource\n" );
+ dev_err(&op->dev, "could not determine device base address\n");
return rv;
}
- ata_irq = irq_of_parse_and_map(op->node, 0);
- if (ata_irq == NO_IRQ) {
- printk(KERN_ERR DRV_NAME ": "
- "Error while mapping the irq\n");
- return -EINVAL;
- }
-
- /* Request mem region */
if (!devm_request_mem_region(&op->dev, res_mem.start,
- sizeof(struct mpc52xx_ata), DRV_NAME)) {
- printk(KERN_ERR DRV_NAME ": "
- "Error while requesting mem region\n");
- rv = -EBUSY;
- goto err;
+ sizeof(*ata_regs), DRV_NAME)) {
+ dev_err(&op->dev, "error requesting register region\n");
+ return -EBUSY;
}
- /* Remap registers */
- ata_regs = devm_ioremap(&op->dev, res_mem.start,
- sizeof(struct mpc52xx_ata));
+ ata_regs = devm_ioremap(&op->dev, res_mem.start, sizeof(*ata_regs));
if (!ata_regs) {
- printk(KERN_ERR DRV_NAME ": "
- "Error while mapping register set\n");
- rv = -ENOMEM;
- goto err;
+ dev_err(&op->dev, "error mapping device registers\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * By default, all DMA modes are disabled for the MPC5200. Some
+ * boards don't have the required signals routed to make DMA work.
+ * Also, the MPC5200B has a silicon bug that causes data corruption
+ * with UDMA if it is used at the same time as the LocalPlus bus.
+ *
+ * Instead of trying to guess what modes are usable, check the
+ * ATA device tree node to find out what DMA modes work on the board.
+ * UDMA/MWDMA modes can also be forced by adding "libata.force=<mode>"
+ * to the kernel boot parameters.
+ *
+ * The MPC5200 ATA controller supports MWDMA modes 0, 1 and 2 and
+ * UDMA modes 0, 1 and 2.
+ */
+ prop = of_get_property(op->dev.of_node, "mwdma-mode", &proplen);
+ if ((prop) && (proplen >= 4))
+ mwdma_mask = ATA_MWDMA2 & ((1 << (*prop + 1)) - 1);
+ prop = of_get_property(op->dev.of_node, "udma-mode", &proplen);
+ if ((prop) && (proplen >= 4))
+ udma_mask = ATA_UDMA2 & ((1 << (*prop + 1)) - 1);
+
+ ata_irq = irq_of_parse_and_map(op->dev.of_node, 0);
+ if (ata_irq == NO_IRQ) {
+ dev_err(&op->dev, "error mapping irq\n");
+ return -EINVAL;
}
/* Prepare our private structure */
- priv = devm_kzalloc(&op->dev, sizeof(struct mpc52xx_ata_priv),
- GFP_ATOMIC);
+ priv = devm_kzalloc(&op->dev, sizeof(*priv), GFP_ATOMIC);
if (!priv) {
- printk(KERN_ERR DRV_NAME ": "
- "Error while allocating private structure\n");
+ dev_err(&op->dev, "error allocating private structure\n");
rv = -ENOMEM;
- goto err;
+ goto err1;
}
priv->ipb_period = 1000000000 / (ipb_freq / 1000);
priv->ata_regs = ata_regs;
+ priv->ata_regs_pa = res_mem.start;
priv->ata_irq = ata_irq;
priv->csel = -1;
+ priv->mpc52xx_ata_dma_last_write = -1;
+
+ if (ipb_freq/1000000 == 66) {
+ priv->mdmaspec = mdmaspec66;
+ priv->udmaspec = udmaspec66;
+ } else {
+ priv->mdmaspec = mdmaspec132;
+ priv->udmaspec = udmaspec132;
+ }
+
+ /* Allocate a BestComm task for DMA */
+ dmatsk = bcom_ata_init(MAX_DMA_BUFFERS, MAX_DMA_BUFFER_SIZE);
+ if (!dmatsk) {
+ dev_err(&op->dev, "bestcomm initialization failed\n");
+ rv = -ENOMEM;
+ goto err1;
+ }
+
+ task_irq = bcom_get_task_irq(dmatsk);
+ rv = devm_request_irq(&op->dev, task_irq, &mpc52xx_ata_task_irq, 0,
+ "ATA task", priv);
+ if (rv) {
+ dev_err(&op->dev, "error requesting DMA IRQ\n");
+ goto err2;
+ }
+ priv->dmatsk = dmatsk;
/* Init the hw */
rv = mpc52xx_ata_hw_init(priv);
if (rv) {
- printk(KERN_ERR DRV_NAME ": Error during HW init\n");
- goto err;
+ dev_err(&op->dev, "error initializing hardware\n");
+ goto err2;
}
/* Register ourselves to libata */
- rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start);
+ rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start,
+ mwdma_mask, udma_mask);
if (rv) {
- printk(KERN_ERR DRV_NAME ": "
- "Error while registering to ATA layer\n");
- return rv;
+ dev_err(&op->dev, "error registering with ATA layer\n");
+ goto err2;
}
- /* Done */
return 0;
- /* Error path */
-err:
+ err2:
+ irq_dispose_mapping(task_irq);
+ bcom_ata_release(dmatsk);
+ err1:
irq_dispose_mapping(ata_irq);
return rv;
}
static int
-mpc52xx_ata_remove(struct of_device *op)
+mpc52xx_ata_remove(struct platform_device *op)
{
- struct mpc52xx_ata_priv *priv;
+ struct ata_host *host = platform_get_drvdata(op);
+ struct mpc52xx_ata_priv *priv = host->private_data;
+ int task_irq;
+
+ /* Deregister the ATA interface */
+ ata_platform_remove_one(op);
- priv = mpc52xx_ata_remove_one(&op->dev);
+ /* Clean up DMA */
+ task_irq = bcom_get_task_irq(priv->dmatsk);
+ irq_dispose_mapping(task_irq);
+ bcom_ata_release(priv->dmatsk);
irq_dispose_mapping(priv->ata_irq);
return 0;
}
-
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
static int
-mpc52xx_ata_suspend(struct of_device *op, pm_message_t state)
+mpc52xx_ata_suspend(struct platform_device *op, pm_message_t state)
{
- struct ata_host *host = dev_get_drvdata(&op->dev);
+ struct ata_host *host = platform_get_drvdata(op);
return ata_host_suspend(host, state);
}
static int
-mpc52xx_ata_resume(struct of_device *op)
+mpc52xx_ata_resume(struct platform_device *op)
{
- struct ata_host *host = dev_get_drvdata(&op->dev);
+ struct ata_host *host = platform_get_drvdata(op);
struct mpc52xx_ata_priv *priv = host->private_data;
int rv;
rv = mpc52xx_ata_hw_init(priv);
if (rv) {
- printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+ dev_err(host->dev, "error initializing hardware\n");
return rv;
}
@@ -455,10 +845,8 @@ mpc52xx_ata_resume(struct of_device *op)
return 0;
}
-
#endif
-
static struct of_device_id mpc52xx_ata_of_match[] = {
{ .compatible = "fsl,mpc5200-ata", },
{ .compatible = "mpc5200-ata", },
@@ -466,46 +854,24 @@ static struct of_device_id mpc52xx_ata_of_match[] = {
};
-static struct of_platform_driver mpc52xx_ata_of_platform_driver = {
- .owner = THIS_MODULE,
- .name = DRV_NAME,
- .match_table = mpc52xx_ata_of_match,
+static struct platform_driver mpc52xx_ata_of_platform_driver = {
.probe = mpc52xx_ata_probe,
.remove = mpc52xx_ata_remove,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = mpc52xx_ata_suspend,
.resume = mpc52xx_ata_resume,
#endif
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .of_match_table = mpc52xx_ata_of_match,
},
};
-
-/* ======================================================================== */
-/* Module */
-/* ======================================================================== */
-
-static int __init
-mpc52xx_ata_init(void)
-{
- printk(KERN_INFO "ata: MPC52xx IDE/ATA libata driver\n");
- return of_register_platform_driver(&mpc52xx_ata_of_platform_driver);
-}
-
-static void __exit
-mpc52xx_ata_exit(void)
-{
- of_unregister_platform_driver(&mpc52xx_ata_of_platform_driver);
-}
-
-module_init(mpc52xx_ata_init);
-module_exit(mpc52xx_ata_exit);
+module_platform_driver(mpc52xx_ata_of_platform_driver);
MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match);
-MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 7d7e3fdab71..202b4d60139 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -1,7 +1,7 @@
/*
* pata_mpiix.c - Intel MPIIX PATA for new ATA layer
* (C) 2005-2006 Red Hat Inc
- * Alan Cox <alan@redhat.com>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* The MPIIX is different enough to the PIIX4 and friends that we give it
* a separate driver. The old ide/pci code handles this by just not tuning
@@ -15,7 +15,7 @@
* with PCI IDE and also that we do not disable the device when our driver is
* unloaded (as it has many other functions).
*
- * The driver conciously keeps this logic internally to avoid pushing quirky
+ * The driver consciously keeps this logic internally to avoid pushing quirky
* PATA history into the clean libata layer.
*
* Thinkpad specific note: If you boot an MPIIX using a thinkpad with a PCMCIA
@@ -28,14 +28,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "pata_mpiix"
-#define DRV_VERSION "0.7.6"
+#define DRV_VERSION "0.7.7"
enum {
IDETIM = 0x6C, /* IDE control register */
@@ -146,20 +145,19 @@ static struct ata_port_operations mpiix_port_ops = {
.cable_detect = ata_cable_40wire,
.set_piomode = mpiix_set_piomode,
.prereset = mpiix_pre_reset,
+ .sff_data_xfer = ata_sff_data_xfer32,
};
static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
/* Single threaded by the PCI probe logic */
- static int printed_version;
struct ata_host *host;
struct ata_port *ap;
void __iomem *cmd_addr, *ctl_addr;
u16 idetim;
int cmd, ctl, irq;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&dev->dev, DRV_VERSION);
host = ata_host_alloc(&dev->dev, 1);
if (!host)
@@ -199,7 +197,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
the MPIIX your box goes castors up */
ap->ops = &mpiix_port_ops;
- ap->pio_mask = 0x1F;
+ ap->pio_mask = ATA_PIO4;
ap->flags |= ATA_FLAG_SLAVE_POSS;
ap->ioaddr.cmd_addr = cmd_addr;
@@ -225,27 +223,16 @@ static struct pci_driver mpiix_pci_driver = {
.id_table = mpiix,
.probe = mpiix_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init mpiix_init(void)
-{
- return pci_register_driver(&mpiix_pci_driver);
-}
-
-static void __exit mpiix_exit(void)
-{
- pci_unregister_driver(&mpiix_pci_driver);
-}
+module_pci_driver(mpiix_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Intel MPIIX");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, mpiix);
MODULE_VERSION(DRV_VERSION);
-
-module_init(mpiix_init);
-module_exit(mpiix_exit);
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index d9719c8b9db..0ea18331d46 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -1,13 +1,12 @@
/*
* pata_netcell.c - Netcell PATA driver
*
- * (c) 2006 Red Hat <alan@redhat.com>
+ * (c) 2006 Red Hat
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -20,13 +19,24 @@
/* No PIO or DMA methods needed for this device */
+static unsigned int netcell_read_id(struct ata_device *adev,
+ struct ata_taskfile *tf, u16 *id)
+{
+ unsigned int err_mask = ata_do_dev_read_id(adev, tf, id);
+ /* Firmware forgets to mark words 85-87 valid */
+ if (err_mask == 0)
+ id[ATA_ID_CSF_DEFAULT] |= 0x4000;
+ return err_mask;
+}
+
static struct scsi_host_template netcell_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
static struct ata_port_operations netcell_ops = {
.inherits = &ata_bmdma_port_ops,
- .cable_detect = ata_cable_80wire,
+ .cable_detect = ata_cable_80wire,
+ .read_id = netcell_read_id,
};
@@ -46,22 +56,19 @@ static struct ata_port_operations netcell_ops = {
static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
/* Actually we don't really care about these as the
firmware deals with it */
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5, /* UDMA 133 */
.port_ops = &netcell_ops,
};
const struct ata_port_info *port_info[] = { &info, NULL };
int rc;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev,
- "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
rc = pcim_enable_device(pdev);
if (rc)
@@ -71,7 +78,7 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e
ata_pci_bmdma_clear_simplex(pdev);
/* And let the library code do the work */
- return ata_pci_sff_init_one(pdev, port_info, &netcell_sht, NULL);
+ return ata_pci_bmdma_init_one(pdev, port_info, &netcell_sht, NULL, 0);
}
static const struct pci_device_id netcell_pci_tbl[] = {
@@ -85,28 +92,16 @@ static struct pci_driver netcell_pci_driver = {
.id_table = netcell_pci_tbl,
.probe = netcell_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init netcell_init(void)
-{
- return pci_register_driver(&netcell_pci_driver);
-}
-
-static void __exit netcell_exit(void)
-{
- pci_unregister_driver(&netcell_pci_driver);
-}
-
-module_init(netcell_init);
-module_exit(netcell_exit);
+module_pci_driver(netcell_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("SCSI low-level driver for Netcell PATA RAID");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, netcell_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c
index 565e67cd13f..efb272da856 100644
--- a/drivers/ata/pata_ninja32.c
+++ b/drivers/ata/pata_ninja32.c
@@ -1,7 +1,6 @@
/*
* pata_ninja32.c - Ninja32 PATA for new ATA layer
* (C) 2007 Red Hat Inc
- * Alan Cox <alan@redhat.com>
*
* Note: The controller like many controllers has shared timings for
* PIO and DMA. We thus flip to the DMA timings in dma_start and flip back
@@ -38,14 +37,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "pata_ninja32"
-#define DRV_VERSION "0.0.1"
+#define DRV_VERSION "0.1.5"
/**
@@ -87,8 +85,20 @@ static struct ata_port_operations ninja32_port_ops = {
.sff_dev_select = ninja32_dev_select,
.cable_detect = ata_cable_40wire,
.set_piomode = ninja32_set_piomode,
+ .sff_data_xfer = ata_sff_data_xfer32
};
+static void ninja32_program(void __iomem *base)
+{
+ iowrite8(0x05, base + 0x01); /* Enable interrupt lines */
+ iowrite8(0xBE, base + 0x02); /* Burst, ?? setup */
+ iowrite8(0x01, base + 0x03); /* Unknown */
+ iowrite8(0x20, base + 0x04); /* WAIT0 */
+ iowrite8(0x8f, base + 0x05); /* Unknown */
+ iowrite8(0xa4, base + 0x1c); /* Unknown */
+ iowrite8(0x83, base + 0x1d); /* BMDMA control: WAIT0 */
+}
+
static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
struct ata_host *host;
@@ -120,12 +130,13 @@ static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return rc;
pci_set_master(dev);
- /* Set up the register mappings */
+ /* Set up the register mappings. We use the I/O mapping as only the
+ older chips also have MMIO on BAR 1 */
base = host->iomap[0];
if (!base)
return -ENOMEM;
ap->ops = &ninja32_port_ops;
- ap->pio_mask = 0x1F;
+ ap->pio_mask = ATA_PIO4;
ap->flags |= ATA_FLAG_SLAVE_POSS;
ap->ioaddr.cmd_addr = base + 0x10;
@@ -133,22 +144,36 @@ static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id)
ap->ioaddr.altstatus_addr = base + 0x1E;
ap->ioaddr.bmdma_addr = base;
ata_sff_std_ports(&ap->ioaddr);
+ ap->pflags = ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE;
- iowrite8(0x05, base + 0x01); /* Enable interrupt lines */
- iowrite8(0xBE, base + 0x02); /* Burst, ?? setup */
- iowrite8(0x01, base + 0x03); /* Unknown */
- iowrite8(0x20, base + 0x04); /* WAIT0 */
- iowrite8(0x8f, base + 0x05); /* Unknown */
- iowrite8(0xa4, base + 0x1c); /* Unknown */
- iowrite8(0x83, base + 0x1d); /* BMDMA control: WAIT0 */
+ ninja32_program(base);
/* FIXME: Should we disable them at remove ? */
- return ata_host_activate(host, dev->irq, ata_sff_interrupt,
+ return ata_host_activate(host, dev->irq, ata_bmdma_interrupt,
IRQF_SHARED, &ninja32_sht);
}
+#ifdef CONFIG_PM_SLEEP
+static int ninja32_reinit_one(struct pci_dev *pdev)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+ ninja32_program(host->iomap[0]);
+ ata_host_resume(host);
+ return 0;
+}
+#endif
+
static const struct pci_device_id ninja32[] = {
+ { 0x10FC, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0x1145, 0x8008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0x1145, 0xf008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0x1145, 0xf02C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ },
};
@@ -156,24 +181,17 @@ static struct pci_driver ninja32_pci_driver = {
.name = DRV_NAME,
.id_table = ninja32,
.probe = ninja32_init_one,
- .remove = ata_pci_remove_one
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = ata_pci_device_suspend,
+ .resume = ninja32_reinit_one,
+#endif
};
-static int __init ninja32_init(void)
-{
- return pci_register_driver(&ninja32_pci_driver);
-}
-
-static void __exit ninja32_exit(void)
-{
- pci_unregister_driver(&ninja32_pci_driver);
-}
+module_pci_driver(ninja32_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Ninja32 ATA");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, ninja32);
MODULE_VERSION(DRV_VERSION);
-
-module_init(ninja32_init);
-module_exit(ninja32_exit);
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 76d2455bc45..200e1eb23a2 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -1,7 +1,6 @@
/*
* pata_ns87410.c - National Semiconductor 87410 PATA for new ATA layer
* (C) 2006 Red Hat Inc
- * Alan Cox <alan@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
@@ -87,13 +85,13 @@ static void ns87410_set_piomode(struct ata_port *ap, struct ata_device *adev)
idefr &= ~0x04;
if (ata_timing_compute(adev, adev->pio_mode, &at, 30303, 1) < 0) {
- dev_printk(KERN_ERR, &pdev->dev, "unknown mode %d.\n", adev->pio_mode);
+ dev_err(&pdev->dev, "unknown mode %d\n", adev->pio_mode);
return;
}
- at.active = FIT(at.active, 2, 16) - 2;
- at.setup = FIT(at.setup, 1, 4) - 1;
- at.recover = FIT(at.recover, 1, 12) - 1;
+ at.active = clamp_val(at.active, 2, 16) - 2;
+ at.setup = clamp_val(at.setup, 1, 4) - 1;
+ at.recover = clamp_val(at.recover, 1, 12) - 1;
idetcr = (at.setup << 6) | (recoverbits[at.recover] << 3) | activebits[at.active];
@@ -145,11 +143,11 @@ static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x0F,
+ .pio_mask = ATA_PIO3,
.port_ops = &ns87410_port_ops
};
const struct ata_port_info *ppi[] = { &info, NULL };
- return ata_pci_sff_init_one(dev, ppi, &ns87410_sht, NULL);
+ return ata_pci_sff_init_one(dev, ppi, &ns87410_sht, NULL, 0);
}
static const struct pci_device_id ns87410[] = {
@@ -163,27 +161,16 @@ static struct pci_driver ns87410_pci_driver = {
.id_table = ns87410,
.probe = ns87410_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init ns87410_init(void)
-{
- return pci_register_driver(&ns87410_pci_driver);
-}
-
-static void __exit ns87410_exit(void)
-{
- pci_unregister_driver(&ns87410_pci_driver);
-}
+module_pci_driver(ns87410_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Nat Semi 87410");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, ns87410);
MODULE_VERSION(DRV_VERSION);
-
-module_init(ns87410_init);
-module_exit(ns87410_exit);
diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c
index ae92b0049bd..84c6b225b56 100644
--- a/drivers/ata/pata_ns87415.c
+++ b/drivers/ata/pata_ns87415.c
@@ -1,7 +1,7 @@
/*
* pata_ns87415.c - NS87415 (non PARISC) PATA
*
- * (C) 2005 Red Hat <alan@redhat.com>
+ * (C) 2005 Red Hat <alan@lxorguk.ukuu.org.uk>
*
* This is a fairly generic MWDMA controller. It has some limitations
* as it requires timing reloads on PIO/DMA transitions but it is otherwise
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -66,8 +65,8 @@ static void ns87415_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo
ata_timing_compute(adev, adev->pio_mode, &t, T, 0);
- clocking = 17 - FIT(t.active, 2, 17);
- clocking |= (16 - FIT(t.recover, 1, 16)) << 4;
+ clocking = 17 - clamp_val(t.active, 2, 17);
+ clocking |= (16 - clamp_val(t.recover, 1, 16)) << 4;
/* Use the same timing for read and write bytes */
clocking |= (clocking << 8);
pci_write_config_word(dev, timing, clocking);
@@ -126,7 +125,7 @@ static void ns87415_bmdma_setup(struct ata_queued_cmd *qc)
/* load PRD table addr. */
mb(); /* make sure PRD table writes are visible to controller */
- iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+ iowrite32(ap->bmdma_prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
/* specify data direction, triple-check start bit is clear */
dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
@@ -325,6 +324,13 @@ static struct scsi_host_template ns87415_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
+static void ns87415_fixup(struct pci_dev *pdev)
+{
+ /* Select 512 byte sectors */
+ pci_write_config_byte(pdev, 0x55, 0xEE);
+ /* Select PIO0 8bit clocking */
+ pci_write_config_byte(pdev, 0x54, 0xB7);
+}
/**
* ns87415_init_one - Register 87415 ATA PCI device with kernel services
@@ -343,11 +349,10 @@ static struct scsi_host_template ns87415_sht = {
static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.port_ops = &ns87415_pata_ops,
};
const struct ata_port_info *ppi[] = { &info, NULL };
@@ -355,27 +360,23 @@ static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *e
#if defined(CONFIG_SUPERIO)
static const struct ata_port_info info87560 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.port_ops = &ns87560_pata_ops,
};
if (PCI_SLOT(pdev->devfn) == 0x0E)
ppi[0] = &info87560;
#endif
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev,
- "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- /* Select 512 byte sectors */
- pci_write_config_byte(pdev, 0x55, 0xEE);
- /* Select PIO0 8bit clocking */
- pci_write_config_byte(pdev, 0x54, 0xB7);
- return ata_pci_sff_init_one(pdev, ppi, &ns87415_sht, NULL);
+ ns87415_fixup(pdev);
+
+ return ata_pci_bmdma_init_one(pdev, ppi, &ns87415_sht, NULL, 0);
}
static const struct pci_device_id ns87415_pci_tbl[] = {
@@ -384,29 +385,35 @@ static const struct pci_device_id ns87415_pci_tbl[] = {
{ } /* terminate list */
};
+#ifdef CONFIG_PM_SLEEP
+static int ns87415_reinit_one(struct pci_dev *pdev)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ ns87415_fixup(pdev);
+
+ ata_host_resume(host);
+ return 0;
+}
+#endif
+
static struct pci_driver ns87415_pci_driver = {
.name = DRV_NAME,
.id_table = ns87415_pci_tbl,
.probe = ns87415_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
- .resume = ata_pci_device_resume,
+ .resume = ns87415_reinit_one,
#endif
};
-static int __init ns87415_init(void)
-{
- return pci_register_driver(&ns87415_pci_driver);
-}
-
-static void __exit ns87415_exit(void)
-{
- pci_unregister_driver(&ns87415_pci_driver);
-}
-
-module_init(ns87415_init);
-module_exit(ns87415_exit);
+module_pci_driver(ns87415_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("ATA low-level driver for NS87415 controllers");
diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c
new file mode 100644
index 00000000000..2a97d3a531e
--- /dev/null
+++ b/drivers/ata/pata_octeon_cf.c
@@ -0,0 +1,1080 @@
+/*
+ * Driver for the Octeon bootbus compact flash.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 - 2012 Cavium Inc.
+ * Copyright (C) 2008 Wind River Systems
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/libata.h>
+#include <linux/hrtimer.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <scsi/scsi_host.h>
+
+#include <asm/byteorder.h>
+#include <asm/octeon/octeon.h>
+
+/*
+ * The Octeon bootbus compact flash interface is connected in at least
+ * 3 different configurations on various evaluation boards:
+ *
+ * -- 8 bits no irq, no DMA
+ * -- 16 bits no irq, no DMA
+ * -- 16 bits True IDE mode with DMA, but no irq.
+ *
+ * In the last case the DMA engine can generate an interrupt when the
+ * transfer is complete. For the first two cases only PIO is supported.
+ *
+ */
+
+#define DRV_NAME "pata_octeon_cf"
+#define DRV_VERSION "2.2"
+
+/* Poll interval in nS. */
+#define OCTEON_CF_BUSY_POLL_INTERVAL 500000
+
+#define DMA_CFG 0
+#define DMA_TIM 0x20
+#define DMA_INT 0x38
+#define DMA_INT_EN 0x50
+
+struct octeon_cf_port {
+ struct hrtimer delayed_finish;
+ struct ata_port *ap;
+ int dma_finished;
+ void *c0;
+ unsigned int cs0;
+ unsigned int cs1;
+ bool is_true_ide;
+ u64 dma_base;
+};
+
+static struct scsi_host_template octeon_cf_sht = {
+ ATA_PIO_SHT(DRV_NAME),
+};
+
+static int enable_dma;
+module_param(enable_dma, int, 0444);
+MODULE_PARM_DESC(enable_dma,
+ "Enable use of DMA on interfaces that support it (0=no dma [default], 1=use dma)");
+
+/**
+ * Convert nanosecond based time to setting used in the
+ * boot bus timing register, based on timing multiple
+ */
+static unsigned int ns_to_tim_reg(unsigned int tim_mult, unsigned int nsecs)
+{
+ unsigned int val;
+
+ /*
+ * Compute # of eclock periods to get desired duration in
+ * nanoseconds.
+ */
+ val = DIV_ROUND_UP(nsecs * (octeon_get_io_clock_rate() / 1000000),
+ 1000 * tim_mult);
+
+ return val;
+}
+
+static void octeon_cf_set_boot_reg_cfg(int cs, unsigned int multiplier)
+{
+ union cvmx_mio_boot_reg_cfgx reg_cfg;
+ unsigned int tim_mult;
+
+ switch (multiplier) {
+ case 8:
+ tim_mult = 3;
+ break;
+ case 4:
+ tim_mult = 0;
+ break;
+ case 2:
+ tim_mult = 2;
+ break;
+ default:
+ tim_mult = 1;
+ break;
+ }
+
+ reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs));
+ reg_cfg.s.dmack = 0; /* Don't assert DMACK on access */
+ reg_cfg.s.tim_mult = tim_mult; /* Timing mutiplier */
+ reg_cfg.s.rd_dly = 0; /* Sample on falling edge of BOOT_OE */
+ reg_cfg.s.sam = 0; /* Don't combine write and output enable */
+ reg_cfg.s.we_ext = 0; /* No write enable extension */
+ reg_cfg.s.oe_ext = 0; /* No read enable extension */
+ reg_cfg.s.en = 1; /* Enable this region */
+ reg_cfg.s.orbit = 0; /* Don't combine with previous region */
+ reg_cfg.s.ale = 0; /* Don't do address multiplexing */
+ cvmx_write_csr(CVMX_MIO_BOOT_REG_CFGX(cs), reg_cfg.u64);
+}
+
+/**
+ * Called after libata determines the needed PIO mode. This
+ * function programs the Octeon bootbus regions to support the
+ * timing requirements of the PIO mode.
+ *
+ * @ap: ATA port information
+ * @dev: ATA device
+ */
+static void octeon_cf_set_piomode(struct ata_port *ap, struct ata_device *dev)
+{
+ struct octeon_cf_port *cf_port = ap->private_data;
+ union cvmx_mio_boot_reg_timx reg_tim;
+ int T;
+ struct ata_timing timing;
+
+ unsigned int div;
+ int use_iordy;
+ int trh;
+ int pause;
+ /* These names are timing parameters from the ATA spec */
+ int t1;
+ int t2;
+ int t2i;
+
+ /*
+ * A divisor value of four will overflow the timing fields at
+ * clock rates greater than 800MHz
+ */
+ if (octeon_get_io_clock_rate() <= 800000000)
+ div = 4;
+ else
+ div = 8;
+ T = (int)((1000000000000LL * div) / octeon_get_io_clock_rate());
+
+ if (ata_timing_compute(dev, dev->pio_mode, &timing, T, T))
+ BUG();
+
+ t1 = timing.setup;
+ if (t1)
+ t1--;
+ t2 = timing.active;
+ if (t2)
+ t2--;
+ t2i = timing.act8b;
+ if (t2i)
+ t2i--;
+
+ trh = ns_to_tim_reg(div, 20);
+ if (trh)
+ trh--;
+
+ pause = (int)timing.cycle - (int)timing.active -
+ (int)timing.setup - trh;
+ if (pause < 0)
+ pause = 0;
+ if (pause)
+ pause--;
+
+ octeon_cf_set_boot_reg_cfg(cf_port->cs0, div);
+ if (cf_port->is_true_ide)
+ /* True IDE mode, program both chip selects. */
+ octeon_cf_set_boot_reg_cfg(cf_port->cs1, div);
+
+
+ use_iordy = ata_pio_need_iordy(dev);
+
+ reg_tim.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_TIMX(cf_port->cs0));
+ /* Disable page mode */
+ reg_tim.s.pagem = 0;
+ /* Enable dynamic timing */
+ reg_tim.s.waitm = use_iordy;
+ /* Pages are disabled */
+ reg_tim.s.pages = 0;
+ /* We don't use multiplexed address mode */
+ reg_tim.s.ale = 0;
+ /* Not used */
+ reg_tim.s.page = 0;
+ /* Time after IORDY to coninue to assert the data */
+ reg_tim.s.wait = 0;
+ /* Time to wait to complete the cycle. */
+ reg_tim.s.pause = pause;
+ /* How long to hold after a write to de-assert CE. */
+ reg_tim.s.wr_hld = trh;
+ /* How long to wait after a read to de-assert CE. */
+ reg_tim.s.rd_hld = trh;
+ /* How long write enable is asserted */
+ reg_tim.s.we = t2;
+ /* How long read enable is asserted */
+ reg_tim.s.oe = t2;
+ /* Time after CE that read/write starts */
+ reg_tim.s.ce = ns_to_tim_reg(div, 5);
+ /* Time before CE that address is valid */
+ reg_tim.s.adr = 0;
+
+ /* Program the bootbus region timing for the data port chip select. */
+ cvmx_write_csr(CVMX_MIO_BOOT_REG_TIMX(cf_port->cs0), reg_tim.u64);
+ if (cf_port->is_true_ide)
+ /* True IDE mode, program both chip selects. */
+ cvmx_write_csr(CVMX_MIO_BOOT_REG_TIMX(cf_port->cs1),
+ reg_tim.u64);
+}
+
+static void octeon_cf_set_dmamode(struct ata_port *ap, struct ata_device *dev)
+{
+ struct octeon_cf_port *cf_port = ap->private_data;
+ union cvmx_mio_boot_pin_defs pin_defs;
+ union cvmx_mio_boot_dma_timx dma_tim;
+ unsigned int oe_a;
+ unsigned int oe_n;
+ unsigned int dma_ackh;
+ unsigned int dma_arq;
+ unsigned int pause;
+ unsigned int T0, Tkr, Td;
+ unsigned int tim_mult;
+ int c;
+
+ const struct ata_timing *timing;
+
+ timing = ata_timing_find_mode(dev->dma_mode);
+ T0 = timing->cycle;
+ Td = timing->active;
+ Tkr = timing->recover;
+ dma_ackh = timing->dmack_hold;
+
+ dma_tim.u64 = 0;
+ /* dma_tim.s.tim_mult = 0 --> 4x */
+ tim_mult = 4;
+
+ /* not spec'ed, value in eclocks, not affected by tim_mult */
+ dma_arq = 8;
+ pause = 25 - dma_arq * 1000 /
+ (octeon_get_io_clock_rate() / 1000000); /* Tz */
+
+ oe_a = Td;
+ /* Tkr from cf spec, lengthened to meet T0 */
+ oe_n = max(T0 - oe_a, Tkr);
+
+ pin_defs.u64 = cvmx_read_csr(CVMX_MIO_BOOT_PIN_DEFS);
+
+ /* DMA channel number. */
+ c = (cf_port->dma_base & 8) >> 3;
+
+ /* Invert the polarity if the default is 0*/
+ dma_tim.s.dmack_pi = (pin_defs.u64 & (1ull << (11 + c))) ? 0 : 1;
+
+ dma_tim.s.oe_n = ns_to_tim_reg(tim_mult, oe_n);
+ dma_tim.s.oe_a = ns_to_tim_reg(tim_mult, oe_a);
+
+ /*
+ * This is tI, C.F. spec. says 0, but Sony CF card requires
+ * more, we use 20 nS.
+ */
+ dma_tim.s.dmack_s = ns_to_tim_reg(tim_mult, 20);
+ dma_tim.s.dmack_h = ns_to_tim_reg(tim_mult, dma_ackh);
+
+ dma_tim.s.dmarq = dma_arq;
+ dma_tim.s.pause = ns_to_tim_reg(tim_mult, pause);
+
+ dma_tim.s.rd_dly = 0; /* Sample right on edge */
+
+ /* writes only */
+ dma_tim.s.we_n = ns_to_tim_reg(tim_mult, oe_n);
+ dma_tim.s.we_a = ns_to_tim_reg(tim_mult, oe_a);
+
+ pr_debug("ns to ticks (mult %d) of %d is: %d\n", tim_mult, 60,
+ ns_to_tim_reg(tim_mult, 60));
+ pr_debug("oe_n: %d, oe_a: %d, dmack_s: %d, dmack_h: %d, dmarq: %d, pause: %d\n",
+ dma_tim.s.oe_n, dma_tim.s.oe_a, dma_tim.s.dmack_s,
+ dma_tim.s.dmack_h, dma_tim.s.dmarq, dma_tim.s.pause);
+
+ cvmx_write_csr(cf_port->dma_base + DMA_TIM, dma_tim.u64);
+}
+
+/**
+ * Handle an 8 bit I/O request.
+ *
+ * @dev: Device to access
+ * @buffer: Data buffer
+ * @buflen: Length of the buffer.
+ * @rw: True to write.
+ */
+static unsigned int octeon_cf_data_xfer8(struct ata_device *dev,
+ unsigned char *buffer,
+ unsigned int buflen,
+ int rw)
+{
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned long words;
+ int count;
+
+ words = buflen;
+ if (rw) {
+ count = 16;
+ while (words--) {
+ iowrite8(*buffer, data_addr);
+ buffer++;
+ /*
+ * Every 16 writes do a read so the bootbus
+ * FIFO doesn't fill up.
+ */
+ if (--count == 0) {
+ ioread8(ap->ioaddr.altstatus_addr);
+ count = 16;
+ }
+ }
+ } else {
+ ioread8_rep(data_addr, buffer, words);
+ }
+ return buflen;
+}
+
+/**
+ * Handle a 16 bit I/O request.
+ *
+ * @dev: Device to access
+ * @buffer: Data buffer
+ * @buflen: Length of the buffer.
+ * @rw: True to write.
+ */
+static unsigned int octeon_cf_data_xfer16(struct ata_device *dev,
+ unsigned char *buffer,
+ unsigned int buflen,
+ int rw)
+{
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned long words;
+ int count;
+
+ words = buflen / 2;
+ if (rw) {
+ count = 16;
+ while (words--) {
+ iowrite16(*(uint16_t *)buffer, data_addr);
+ buffer += sizeof(uint16_t);
+ /*
+ * Every 16 writes do a read so the bootbus
+ * FIFO doesn't fill up.
+ */
+ if (--count == 0) {
+ ioread8(ap->ioaddr.altstatus_addr);
+ count = 16;
+ }
+ }
+ } else {
+ while (words--) {
+ *(uint16_t *)buffer = ioread16(data_addr);
+ buffer += sizeof(uint16_t);
+ }
+ }
+ /* Transfer trailing 1 byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ __le16 align_buf[1] = { 0 };
+
+ if (rw == READ) {
+ align_buf[0] = cpu_to_le16(ioread16(data_addr));
+ memcpy(buffer, align_buf, 1);
+ } else {
+ memcpy(align_buf, buffer, 1);
+ iowrite16(le16_to_cpu(align_buf[0]), data_addr);
+ }
+ words++;
+ }
+ return buflen;
+}
+
+/**
+ * Read the taskfile for 16bit non-True IDE only.
+ */
+static void octeon_cf_tf_read16(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ u16 blob;
+ /* The base of the registers is at ioaddr.data_addr. */
+ void __iomem *base = ap->ioaddr.data_addr;
+
+ blob = __raw_readw(base + 0xc);
+ tf->feature = blob >> 8;
+
+ blob = __raw_readw(base + 2);
+ tf->nsect = blob & 0xff;
+ tf->lbal = blob >> 8;
+
+ blob = __raw_readw(base + 4);
+ tf->lbam = blob & 0xff;
+ tf->lbah = blob >> 8;
+
+ blob = __raw_readw(base + 6);
+ tf->device = blob & 0xff;
+ tf->command = blob >> 8;
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ if (likely(ap->ioaddr.ctl_addr)) {
+ iowrite8(tf->ctl | ATA_HOB, ap->ioaddr.ctl_addr);
+
+ blob = __raw_readw(base + 0xc);
+ tf->hob_feature = blob >> 8;
+
+ blob = __raw_readw(base + 2);
+ tf->hob_nsect = blob & 0xff;
+ tf->hob_lbal = blob >> 8;
+
+ blob = __raw_readw(base + 4);
+ tf->hob_lbam = blob & 0xff;
+ tf->hob_lbah = blob >> 8;
+
+ iowrite8(tf->ctl, ap->ioaddr.ctl_addr);
+ ap->last_ctl = tf->ctl;
+ } else {
+ WARN_ON(1);
+ }
+ }
+}
+
+static u8 octeon_cf_check_status16(struct ata_port *ap)
+{
+ u16 blob;
+ void __iomem *base = ap->ioaddr.data_addr;
+
+ blob = __raw_readw(base + 6);
+ return blob >> 8;
+}
+
+static int octeon_cf_softreset16(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ void __iomem *base = ap->ioaddr.data_addr;
+ int rc;
+ u8 err;
+
+ DPRINTK("about to softreset\n");
+ __raw_writew(ap->ctl, base + 0xe);
+ udelay(20);
+ __raw_writew(ap->ctl | ATA_SRST, base + 0xe);
+ udelay(20);
+ __raw_writew(ap->ctl, base + 0xe);
+
+ rc = ata_sff_wait_after_reset(link, 1, deadline);
+ if (rc) {
+ ata_link_err(link, "SRST failed (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_sff_dev_classify(&link->device[0], 1, &err);
+ DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
+ return 0;
+}
+
+/**
+ * Load the taskfile for 16bit non-True IDE only. The device_addr is
+ * not loaded, we do this as part of octeon_cf_exec_command16.
+ */
+static void octeon_cf_tf_load16(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+ /* The base of the registers is at ioaddr.data_addr. */
+ void __iomem *base = ap->ioaddr.data_addr;
+
+ if (tf->ctl != ap->last_ctl) {
+ iowrite8(tf->ctl, ap->ioaddr.ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ __raw_writew(tf->hob_feature << 8, base + 0xc);
+ __raw_writew(tf->hob_nsect | tf->hob_lbal << 8, base + 2);
+ __raw_writew(tf->hob_lbam | tf->hob_lbah << 8, base + 4);
+ VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+ tf->hob_feature,
+ tf->hob_nsect,
+ tf->hob_lbal,
+ tf->hob_lbam,
+ tf->hob_lbah);
+ }
+ if (is_addr) {
+ __raw_writew(tf->feature << 8, base + 0xc);
+ __raw_writew(tf->nsect | tf->lbal << 8, base + 2);
+ __raw_writew(tf->lbam | tf->lbah << 8, base + 4);
+ VPRINTK("feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+ tf->feature,
+ tf->nsect,
+ tf->lbal,
+ tf->lbam,
+ tf->lbah);
+ }
+ ata_wait_idle(ap);
+}
+
+
+static void octeon_cf_dev_select(struct ata_port *ap, unsigned int device)
+{
+/* There is only one device, do nothing. */
+ return;
+}
+
+/*
+ * Issue ATA command to host controller. The device_addr is also sent
+ * as it must be written in a combined write with the command.
+ */
+static void octeon_cf_exec_command16(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ /* The base of the registers is at ioaddr.data_addr. */
+ void __iomem *base = ap->ioaddr.data_addr;
+ u16 blob;
+
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ VPRINTK("device 0x%X\n", tf->device);
+ blob = tf->device;
+ } else {
+ blob = 0;
+ }
+
+ DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+ blob |= (tf->command << 8);
+ __raw_writew(blob, base + 6);
+
+
+ ata_wait_idle(ap);
+}
+
+static void octeon_cf_ata_port_noaction(struct ata_port *ap)
+{
+}
+
+static void octeon_cf_dma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct octeon_cf_port *cf_port;
+
+ cf_port = ap->private_data;
+ DPRINTK("ENTER\n");
+ /* issue r/w command */
+ qc->cursg = qc->sg;
+ cf_port->dma_finished = 0;
+ ap->ops->sff_exec_command(ap, &qc->tf);
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * Start a DMA transfer that was already setup
+ *
+ * @qc: Information about the DMA
+ */
+static void octeon_cf_dma_start(struct ata_queued_cmd *qc)
+{
+ struct octeon_cf_port *cf_port = qc->ap->private_data;
+ union cvmx_mio_boot_dma_cfgx mio_boot_dma_cfg;
+ union cvmx_mio_boot_dma_intx mio_boot_dma_int;
+ struct scatterlist *sg;
+
+ VPRINTK("%d scatterlists\n", qc->n_elem);
+
+ /* Get the scatter list entry we need to DMA into */
+ sg = qc->cursg;
+ BUG_ON(!sg);
+
+ /*
+ * Clear the DMA complete status.
+ */
+ mio_boot_dma_int.u64 = 0;
+ mio_boot_dma_int.s.done = 1;
+ cvmx_write_csr(cf_port->dma_base + DMA_INT, mio_boot_dma_int.u64);
+
+ /* Enable the interrupt. */
+ cvmx_write_csr(cf_port->dma_base + DMA_INT_EN, mio_boot_dma_int.u64);
+
+ /* Set the direction of the DMA */
+ mio_boot_dma_cfg.u64 = 0;
+#ifdef __LITTLE_ENDIAN
+ mio_boot_dma_cfg.s.endian = 1;
+#endif
+ mio_boot_dma_cfg.s.en = 1;
+ mio_boot_dma_cfg.s.rw = ((qc->tf.flags & ATA_TFLAG_WRITE) != 0);
+
+ /*
+ * Don't stop the DMA if the device deasserts DMARQ. Many
+ * compact flashes deassert DMARQ for a short time between
+ * sectors. Instead of stopping and restarting the DMA, we'll
+ * let the hardware do it. If the DMA is really stopped early
+ * due to an error condition, a later timeout will force us to
+ * stop.
+ */
+ mio_boot_dma_cfg.s.clr = 0;
+
+ /* Size is specified in 16bit words and minus one notation */
+ mio_boot_dma_cfg.s.size = sg_dma_len(sg) / 2 - 1;
+
+ /* We need to swap the high and low bytes of every 16 bits */
+ mio_boot_dma_cfg.s.swap8 = 1;
+
+ mio_boot_dma_cfg.s.adr = sg_dma_address(sg);
+
+ VPRINTK("%s %d bytes address=%p\n",
+ (mio_boot_dma_cfg.s.rw) ? "write" : "read", sg->length,
+ (void *)(unsigned long)mio_boot_dma_cfg.s.adr);
+
+ cvmx_write_csr(cf_port->dma_base + DMA_CFG, mio_boot_dma_cfg.u64);
+}
+
+/**
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ */
+static unsigned int octeon_cf_dma_finished(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
+{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ struct octeon_cf_port *cf_port = ap->private_data;
+ union cvmx_mio_boot_dma_cfgx dma_cfg;
+ union cvmx_mio_boot_dma_intx dma_int;
+ u8 status;
+
+ VPRINTK("ata%u: protocol %d task_state %d\n",
+ ap->print_id, qc->tf.protocol, ap->hsm_task_state);
+
+
+ if (ap->hsm_task_state != HSM_ST_LAST)
+ return 0;
+
+ dma_cfg.u64 = cvmx_read_csr(cf_port->dma_base + DMA_CFG);
+ if (dma_cfg.s.size != 0xfffff) {
+ /* Error, the transfer was not complete. */
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ ap->hsm_task_state = HSM_ST_ERR;
+ }
+
+ /* Stop and clear the dma engine. */
+ dma_cfg.u64 = 0;
+ dma_cfg.s.size = -1;
+ cvmx_write_csr(cf_port->dma_base + DMA_CFG, dma_cfg.u64);
+
+ /* Disable the interrupt. */
+ dma_int.u64 = 0;
+ cvmx_write_csr(cf_port->dma_base + DMA_INT_EN, dma_int.u64);
+
+ /* Clear the DMA complete status */
+ dma_int.s.done = 1;
+ cvmx_write_csr(cf_port->dma_base + DMA_INT, dma_int.u64);
+
+ status = ap->ops->sff_check_status(ap);
+
+ ata_sff_hsm_move(ap, qc, status, 0);
+
+ if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA))
+ ata_ehi_push_desc(ehi, "DMA stat 0x%x", status);
+
+ return 1;
+}
+
+/*
+ * Check if any queued commands have more DMAs, if so start the next
+ * transfer, else do end of transfer handling.
+ */
+static irqreturn_t octeon_cf_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ struct octeon_cf_port *cf_port;
+ int i;
+ unsigned int handled = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ DPRINTK("ENTER\n");
+ for (i = 0; i < host->n_ports; i++) {
+ u8 status;
+ struct ata_port *ap;
+ struct ata_queued_cmd *qc;
+ union cvmx_mio_boot_dma_intx dma_int;
+ union cvmx_mio_boot_dma_cfgx dma_cfg;
+
+ ap = host->ports[i];
+ cf_port = ap->private_data;
+
+ dma_int.u64 = cvmx_read_csr(cf_port->dma_base + DMA_INT);
+ dma_cfg.u64 = cvmx_read_csr(cf_port->dma_base + DMA_CFG);
+
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+
+ if (!qc || (qc->tf.flags & ATA_TFLAG_POLLING))
+ continue;
+
+ if (dma_int.s.done && !dma_cfg.s.en) {
+ if (!sg_is_last(qc->cursg)) {
+ qc->cursg = sg_next(qc->cursg);
+ handled = 1;
+ octeon_cf_dma_start(qc);
+ continue;
+ } else {
+ cf_port->dma_finished = 1;
+ }
+ }
+ if (!cf_port->dma_finished)
+ continue;
+ status = ioread8(ap->ioaddr.altstatus_addr);
+ if (status & (ATA_BUSY | ATA_DRQ)) {
+ /*
+ * We are busy, try to handle it later. This
+ * is the DMA finished interrupt, and it could
+ * take a little while for the card to be
+ * ready for more commands.
+ */
+ /* Clear DMA irq. */
+ dma_int.u64 = 0;
+ dma_int.s.done = 1;
+ cvmx_write_csr(cf_port->dma_base + DMA_INT,
+ dma_int.u64);
+ hrtimer_start_range_ns(&cf_port->delayed_finish,
+ ns_to_ktime(OCTEON_CF_BUSY_POLL_INTERVAL),
+ OCTEON_CF_BUSY_POLL_INTERVAL / 5,
+ HRTIMER_MODE_REL);
+ handled = 1;
+ } else {
+ handled |= octeon_cf_dma_finished(ap, qc);
+ }
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+ DPRINTK("EXIT\n");
+ return IRQ_RETVAL(handled);
+}
+
+static enum hrtimer_restart octeon_cf_delayed_finish(struct hrtimer *hrt)
+{
+ struct octeon_cf_port *cf_port = container_of(hrt,
+ struct octeon_cf_port,
+ delayed_finish);
+ struct ata_port *ap = cf_port->ap;
+ struct ata_host *host = ap->host;
+ struct ata_queued_cmd *qc;
+ unsigned long flags;
+ u8 status;
+ enum hrtimer_restart rv = HRTIMER_NORESTART;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ /*
+ * If the port is not waiting for completion, it must have
+ * handled it previously. The hsm_task_state is
+ * protected by host->lock.
+ */
+ if (ap->hsm_task_state != HSM_ST_LAST || !cf_port->dma_finished)
+ goto out;
+
+ status = ioread8(ap->ioaddr.altstatus_addr);
+ if (status & (ATA_BUSY | ATA_DRQ)) {
+ /* Still busy, try again. */
+ hrtimer_forward_now(hrt,
+ ns_to_ktime(OCTEON_CF_BUSY_POLL_INTERVAL));
+ rv = HRTIMER_RESTART;
+ goto out;
+ }
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
+ octeon_cf_dma_finished(ap, qc);
+out:
+ spin_unlock_irqrestore(&host->lock, flags);
+ return rv;
+}
+
+static void octeon_cf_dev_config(struct ata_device *dev)
+{
+ /*
+ * A maximum of 2^20 - 1 16 bit transfers are possible with
+ * the bootbus DMA. So we need to throttle max_sectors to
+ * (2^12 - 1 == 4095) to assure that this can never happen.
+ */
+ dev->max_sectors = min(dev->max_sectors, 4095U);
+}
+
+/*
+ * We don't do ATAPI DMA so return 0.
+ */
+static int octeon_cf_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ return 0;
+}
+
+static unsigned int octeon_cf_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
+
+ ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */
+ octeon_cf_dma_setup(qc); /* set up dma */
+ octeon_cf_dma_start(qc); /* initiate dma */
+ ap->hsm_task_state = HSM_ST_LAST;
+ break;
+
+ case ATAPI_PROT_DMA:
+ dev_err(ap->dev, "Error, ATAPI not supported\n");
+ BUG();
+
+ default:
+ return ata_sff_qc_issue(qc);
+ }
+
+ return 0;
+}
+
+static struct ata_port_operations octeon_cf_ops = {
+ .inherits = &ata_sff_port_ops,
+ .check_atapi_dma = octeon_cf_check_atapi_dma,
+ .qc_prep = ata_noop_qc_prep,
+ .qc_issue = octeon_cf_qc_issue,
+ .sff_dev_select = octeon_cf_dev_select,
+ .sff_irq_on = octeon_cf_ata_port_noaction,
+ .sff_irq_clear = octeon_cf_ata_port_noaction,
+ .cable_detect = ata_cable_40wire,
+ .set_piomode = octeon_cf_set_piomode,
+ .set_dmamode = octeon_cf_set_dmamode,
+ .dev_config = octeon_cf_dev_config,
+};
+
+static int octeon_cf_probe(struct platform_device *pdev)
+{
+ struct resource *res_cs0, *res_cs1;
+
+ bool is_16bit;
+ const __be32 *cs_num;
+ struct property *reg_prop;
+ int n_addr, n_size, reg_len;
+ struct device_node *node;
+ const void *prop;
+ void __iomem *cs0;
+ void __iomem *cs1 = NULL;
+ struct ata_host *host;
+ struct ata_port *ap;
+ int irq = 0;
+ irq_handler_t irq_handler = NULL;
+ void __iomem *base;
+ struct octeon_cf_port *cf_port;
+ int rv = -ENOMEM;
+
+
+ node = pdev->dev.of_node;
+ if (node == NULL)
+ return -EINVAL;
+
+ cf_port = devm_kzalloc(&pdev->dev, sizeof(*cf_port), GFP_KERNEL);
+ if (!cf_port)
+ return -ENOMEM;
+
+ cf_port->is_true_ide = (of_find_property(node, "cavium,true-ide", NULL) != NULL);
+
+ prop = of_get_property(node, "cavium,bus-width", NULL);
+ if (prop)
+ is_16bit = (be32_to_cpup(prop) == 16);
+ else
+ is_16bit = false;
+
+ n_addr = of_n_addr_cells(node);
+ n_size = of_n_size_cells(node);
+
+ reg_prop = of_find_property(node, "reg", &reg_len);
+ if (!reg_prop || reg_len < sizeof(__be32))
+ return -EINVAL;
+
+ cs_num = reg_prop->value;
+ cf_port->cs0 = be32_to_cpup(cs_num);
+
+ if (cf_port->is_true_ide) {
+ struct device_node *dma_node;
+ dma_node = of_parse_phandle(node,
+ "cavium,dma-engine-handle", 0);
+ if (dma_node) {
+ struct platform_device *dma_dev;
+ dma_dev = of_find_device_by_node(dma_node);
+ if (dma_dev) {
+ struct resource *res_dma;
+ int i;
+ res_dma = platform_get_resource(dma_dev, IORESOURCE_MEM, 0);
+ if (!res_dma) {
+ of_node_put(dma_node);
+ return -EINVAL;
+ }
+ cf_port->dma_base = (u64)devm_ioremap_nocache(&pdev->dev, res_dma->start,
+ resource_size(res_dma));
+ if (!cf_port->dma_base) {
+ of_node_put(dma_node);
+ return -EINVAL;
+ }
+
+ irq_handler = octeon_cf_interrupt;
+ i = platform_get_irq(dma_dev, 0);
+ if (i > 0)
+ irq = i;
+ }
+ of_node_put(dma_node);
+ }
+ res_cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res_cs1)
+ return -EINVAL;
+
+ cs1 = devm_ioremap_nocache(&pdev->dev, res_cs1->start,
+ resource_size(res_cs1));
+ if (!cs1)
+ return rv;
+
+ if (reg_len < (n_addr + n_size + 1) * sizeof(__be32))
+ return -EINVAL;
+
+ cs_num += n_addr + n_size;
+ cf_port->cs1 = be32_to_cpup(cs_num);
+ }
+
+ res_cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_cs0)
+ return -EINVAL;
+
+ cs0 = devm_ioremap_nocache(&pdev->dev, res_cs0->start,
+ resource_size(res_cs0));
+ if (!cs0)
+ return rv;
+
+ /* allocate host */
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ return rv;
+
+ ap = host->ports[0];
+ ap->private_data = cf_port;
+ pdev->dev.platform_data = cf_port;
+ cf_port->ap = ap;
+ ap->ops = &octeon_cf_ops;
+ ap->pio_mask = ATA_PIO6;
+ ap->flags |= ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING;
+
+ if (!is_16bit) {
+ base = cs0 + 0x800;
+ ap->ioaddr.cmd_addr = base;
+ ata_sff_std_ports(&ap->ioaddr);
+
+ ap->ioaddr.altstatus_addr = base + 0xe;
+ ap->ioaddr.ctl_addr = base + 0xe;
+ octeon_cf_ops.sff_data_xfer = octeon_cf_data_xfer8;
+ } else if (cf_port->is_true_ide) {
+ base = cs0;
+ ap->ioaddr.cmd_addr = base + (ATA_REG_CMD << 1) + 1;
+ ap->ioaddr.data_addr = base + (ATA_REG_DATA << 1);
+ ap->ioaddr.error_addr = base + (ATA_REG_ERR << 1) + 1;
+ ap->ioaddr.feature_addr = base + (ATA_REG_FEATURE << 1) + 1;
+ ap->ioaddr.nsect_addr = base + (ATA_REG_NSECT << 1) + 1;
+ ap->ioaddr.lbal_addr = base + (ATA_REG_LBAL << 1) + 1;
+ ap->ioaddr.lbam_addr = base + (ATA_REG_LBAM << 1) + 1;
+ ap->ioaddr.lbah_addr = base + (ATA_REG_LBAH << 1) + 1;
+ ap->ioaddr.device_addr = base + (ATA_REG_DEVICE << 1) + 1;
+ ap->ioaddr.status_addr = base + (ATA_REG_STATUS << 1) + 1;
+ ap->ioaddr.command_addr = base + (ATA_REG_CMD << 1) + 1;
+ ap->ioaddr.altstatus_addr = cs1 + (6 << 1) + 1;
+ ap->ioaddr.ctl_addr = cs1 + (6 << 1) + 1;
+ octeon_cf_ops.sff_data_xfer = octeon_cf_data_xfer16;
+
+ ap->mwdma_mask = enable_dma ? ATA_MWDMA4 : 0;
+
+ /* True IDE mode needs a timer to poll for not-busy. */
+ hrtimer_init(&cf_port->delayed_finish, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ cf_port->delayed_finish.function = octeon_cf_delayed_finish;
+ } else {
+ /* 16 bit but not True IDE */
+ base = cs0 + 0x800;
+ octeon_cf_ops.sff_data_xfer = octeon_cf_data_xfer16;
+ octeon_cf_ops.softreset = octeon_cf_softreset16;
+ octeon_cf_ops.sff_check_status = octeon_cf_check_status16;
+ octeon_cf_ops.sff_tf_read = octeon_cf_tf_read16;
+ octeon_cf_ops.sff_tf_load = octeon_cf_tf_load16;
+ octeon_cf_ops.sff_exec_command = octeon_cf_exec_command16;
+
+ ap->ioaddr.data_addr = base + ATA_REG_DATA;
+ ap->ioaddr.nsect_addr = base + ATA_REG_NSECT;
+ ap->ioaddr.lbal_addr = base + ATA_REG_LBAL;
+ ap->ioaddr.ctl_addr = base + 0xe;
+ ap->ioaddr.altstatus_addr = base + 0xe;
+ }
+ cf_port->c0 = ap->ioaddr.ctl_addr;
+
+ rv = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (rv)
+ return rv;
+
+ ata_port_desc(ap, "cmd %p ctl %p", base, ap->ioaddr.ctl_addr);
+
+ dev_info(&pdev->dev, "version " DRV_VERSION" %d bit%s.\n",
+ is_16bit ? 16 : 8,
+ cf_port->is_true_ide ? ", True IDE" : "");
+
+ return ata_host_activate(host, irq, irq_handler,
+ IRQF_SHARED, &octeon_cf_sht);
+}
+
+static void octeon_cf_shutdown(struct device *dev)
+{
+ union cvmx_mio_boot_dma_cfgx dma_cfg;
+ union cvmx_mio_boot_dma_intx dma_int;
+
+ struct octeon_cf_port *cf_port = dev_get_platdata(dev);
+
+ if (cf_port->dma_base) {
+ /* Stop and clear the dma engine. */
+ dma_cfg.u64 = 0;
+ dma_cfg.s.size = -1;
+ cvmx_write_csr(cf_port->dma_base + DMA_CFG, dma_cfg.u64);
+
+ /* Disable the interrupt. */
+ dma_int.u64 = 0;
+ cvmx_write_csr(cf_port->dma_base + DMA_INT_EN, dma_int.u64);
+
+ /* Clear the DMA complete status */
+ dma_int.s.done = 1;
+ cvmx_write_csr(cf_port->dma_base + DMA_INT, dma_int.u64);
+
+ __raw_writeb(0, cf_port->c0);
+ udelay(20);
+ __raw_writeb(ATA_SRST, cf_port->c0);
+ udelay(20);
+ __raw_writeb(0, cf_port->c0);
+ mdelay(100);
+ }
+}
+
+static struct of_device_id octeon_cf_match[] = {
+ {
+ .compatible = "cavium,ebt3000-compact-flash",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, octeon_i2c_match);
+
+static struct platform_driver octeon_cf_driver = {
+ .probe = octeon_cf_probe,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = octeon_cf_match,
+ .shutdown = octeon_cf_shutdown
+ },
+};
+
+static int __init octeon_cf_init(void)
+{
+ return platform_driver_register(&octeon_cf_driver);
+}
+
+
+MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
+MODULE_DESCRIPTION("low-level driver for Cavium OCTEON Compact Flash PATA");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);
+
+module_init(octeon_cf_init);
diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c
index 408da30594c..a7e95a54c78 100644
--- a/drivers/ata/pata_of_platform.c
+++ b/drivers/ata/pata_of_platform.c
@@ -11,17 +11,18 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include <linux/ata_platform.h>
+#include <linux/libata.h>
-static int __devinit pata_of_platform_probe(struct of_device *ofdev,
- const struct of_device_id *match)
+static int pata_of_platform_probe(struct platform_device *ofdev)
{
int ret;
- struct device_node *dn = ofdev->node;
+ struct device_node *dn = ofdev->dev.of_node;
struct resource io_res;
struct resource ctl_res;
- struct resource irq_res;
+ struct resource *irq_res;
unsigned int reg_shift = 0;
int pio_mode = 0;
int pio_mask;
@@ -50,19 +51,17 @@ static int __devinit pata_of_platform_probe(struct of_device *ofdev,
}
}
- ret = of_irq_to_resource(dn, 0, &irq_res);
- if (ret == NO_IRQ)
- irq_res.start = irq_res.end = -1;
- else
- irq_res.flags = 0;
+ irq_res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0);
+ if (irq_res)
+ irq_res->flags = 0;
prop = of_get_property(dn, "reg-shift", NULL);
if (prop)
- reg_shift = *prop;
+ reg_shift = be32_to_cpup(prop);
prop = of_get_property(dn, "pio-mode", NULL);
if (prop) {
- pio_mode = *prop;
+ pio_mode = be32_to_cpup(prop);
if (pio_mode > 6) {
dev_err(&ofdev->dev, "invalid pio-mode\n");
return -EINVAL;
@@ -74,15 +73,10 @@ static int __devinit pata_of_platform_probe(struct of_device *ofdev,
pio_mask = 1 << pio_mode;
pio_mask |= (1 << pio_mode) - 1;
- return __pata_platform_probe(&ofdev->dev, &io_res, &ctl_res, &irq_res,
+ return __pata_platform_probe(&ofdev->dev, &io_res, &ctl_res, irq_res,
reg_shift, pio_mask);
}
-static int __devexit pata_of_platform_remove(struct of_device *ofdev)
-{
- return __pata_platform_remove(&ofdev->dev);
-}
-
static struct of_device_id pata_of_platform_match[] = {
{ .compatible = "ata-generic", },
{ .compatible = "electra-ide", },
@@ -90,24 +84,17 @@ static struct of_device_id pata_of_platform_match[] = {
};
MODULE_DEVICE_TABLE(of, pata_of_platform_match);
-static struct of_platform_driver pata_of_platform_driver = {
- .name = "pata_of_platform",
- .match_table = pata_of_platform_match,
+static struct platform_driver pata_of_platform_driver = {
+ .driver = {
+ .name = "pata_of_platform",
+ .owner = THIS_MODULE,
+ .of_match_table = pata_of_platform_match,
+ },
.probe = pata_of_platform_probe,
- .remove = __devexit_p(pata_of_platform_remove),
+ .remove = ata_platform_remove_one,
};
-static int __init pata_of_platform_init(void)
-{
- return of_register_platform_driver(&pata_of_platform_driver);
-}
-module_init(pata_of_platform_init);
-
-static void __exit pata_of_platform_exit(void)
-{
- of_unregister_platform_driver(&pata_of_platform_driver);
-}
-module_exit(pata_of_platform_exit);
+module_platform_driver(pata_of_platform_driver);
MODULE_DESCRIPTION("OF-platform PATA driver");
MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index e678af383d1..b9bf78b7d48 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -1,7 +1,7 @@
/*
* pata_oldpiix.c - Intel PATA/SATA controllers
*
- * (C) 2005 Red Hat <alan@redhat.com>
+ * (C) 2005 Red Hat
*
* Some parts based on ata_piix.c by Jeff Garzik and others.
*
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -116,7 +115,6 @@ static void oldpiix_set_piomode (struct ata_port *ap, struct ata_device *adev)
* oldpiix_set_dmamode - Initialize host controller PATA DMA timings
* @ap: Port whose timings we are configuring
* @adev: Device to program
- * @isich: True if the device is an ICH and has IOCFG registers
*
* Set MWDMA mode for device, in host controller PCI config space.
*
@@ -198,10 +196,10 @@ static unsigned int oldpiix_qc_issue(struct ata_queued_cmd *qc)
if (adev != ap->private_data) {
oldpiix_set_piomode(ap, adev);
- if (adev->dma_mode)
+ if (ata_dma_enabled(adev))
oldpiix_set_dmamode(ap, adev);
}
- return ata_sff_qc_issue(qc);
+ return ata_bmdma_qc_issue(qc);
}
@@ -236,20 +234,17 @@ static struct ata_port_operations oldpiix_pata_ops = {
static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma1-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA12_ONLY,
.port_ops = &oldpiix_pata_ops,
};
const struct ata_port_info *ppi[] = { &info, NULL };
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev,
- "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
- return ata_pci_sff_init_one(pdev, ppi, &oldpiix_sht, NULL);
+ return ata_pci_bmdma_init_one(pdev, ppi, &oldpiix_sht, NULL, 0);
}
static const struct pci_device_id oldpiix_pci_tbl[] = {
@@ -263,28 +258,16 @@ static struct pci_driver oldpiix_pci_driver = {
.id_table = oldpiix_pci_tbl,
.probe = oldpiix_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init oldpiix_init(void)
-{
- return pci_register_driver(&oldpiix_pci_driver);
-}
-
-static void __exit oldpiix_exit(void)
-{
- pci_unregister_driver(&oldpiix_pci_driver);
-}
-
-module_init(oldpiix_init);
-module_exit(oldpiix_exit);
+module_pci_driver(oldpiix_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("SCSI low-level driver for early PIIX series controllers");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, oldpiix_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index fb2cf661b0e..3a944a02926 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -1,7 +1,6 @@
/*
* pata_opti.c - ATI PATA for new ATA layer
* (C) 2005 Red Hat Inc
- * Alan Cox <alan@redhat.com>
*
* Based on
* linux/drivers/ide/pci/opti621.c Version 0.7 Sept 10, 2002
@@ -27,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
@@ -164,16 +162,14 @@ static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
+ .pio_mask = ATA_PIO4,
.port_ops = &opti_port_ops
};
const struct ata_port_info *ppi[] = { &info, NULL };
- static int printed_version;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&dev->dev, DRV_VERSION);
- return ata_pci_sff_init_one(dev, ppi, &opti_sht, NULL);
+ return ata_pci_sff_init_one(dev, ppi, &opti_sht, NULL, 0);
}
static const struct pci_device_id opti[] = {
@@ -188,28 +184,16 @@ static struct pci_driver opti_pci_driver = {
.id_table = opti,
.probe = opti_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init opti_init(void)
-{
- return pci_register_driver(&opti_pci_driver);
-}
-
-static void __exit opti_exit(void)
-{
- pci_unregister_driver(&opti_pci_driver);
-}
-
+module_pci_driver(opti_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Opti 621/621X");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, opti);
MODULE_VERSION(DRV_VERSION);
-
-module_init(opti_init);
-module_exit(opti_exit);
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index 4cd74445631..bdec7efa464 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -1,7 +1,6 @@
/*
* pata_optidma.c - Opti DMA PATA for new ATA layer
* (C) 2006 Red Hat Inc
- * Alan Cox <alan@redhat.com>
*
* The Opti DMA controllers are related to the older PIO PCI controllers
* and indeed the VLB ones. The main differences are that the timing
@@ -26,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
@@ -400,23 +398,21 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
static const struct ata_port_info info_82c700 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.port_ops = &optidma_port_ops
};
static const struct ata_port_info info_82c700_udma = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
.port_ops = &optiplus_port_ops
};
const struct ata_port_info *ppi[] = { &info_82c700, NULL };
- static int printed_version;
int rc;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&dev->dev, DRV_VERSION);
rc = pcim_enable_device(dev);
if (rc)
@@ -430,7 +426,7 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (optiplus_with_udma(dev))
ppi[0] = &info_82c700_udma;
- return ata_pci_sff_init_one(dev, ppi, &optidma_sht, NULL);
+ return ata_pci_bmdma_init_one(dev, ppi, &optidma_sht, NULL, 0);
}
static const struct pci_device_id optidma[] = {
@@ -444,27 +440,16 @@ static struct pci_driver optidma_pci_driver = {
.id_table = optidma,
.probe = optidma_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init optidma_init(void)
-{
- return pci_register_driver(&optidma_pci_driver);
-}
-
-static void __exit optidma_exit(void)
-{
- pci_unregister_driver(&optidma_pci_driver);
-}
+module_pci_driver(optidma_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Opti Firestar/Firestar Plus");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, optidma);
MODULE_VERSION(DRV_VERSION);
-
-module_init(optidma_init);
-module_exit(optidma_exit);
diff --git a/drivers/ata/pata_palmld.c b/drivers/ata/pata_palmld.c
new file mode 100644
index 00000000000..df2bb7504fc
--- /dev/null
+++ b/drivers/ata/pata_palmld.c
@@ -0,0 +1,138 @@
+/*
+ * drivers/ata/pata_palmld.c
+ *
+ * Driver for IDE channel in Palm LifeDrive
+ *
+ * Based on research of:
+ * Alex Osborne <ato@meshy.org>
+ *
+ * Rewrite for mainline:
+ * Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Rewritten version based on pata_ixp4xx_cf.c:
+ * ixp4xx PATA/Compact Flash driver
+ * Copyright (C) 2006-07 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/libata.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <scsi/scsi_host.h>
+#include <mach/palmld.h>
+
+#define DRV_NAME "pata_palmld"
+
+static struct gpio palmld_hdd_gpios[] = {
+ { GPIO_NR_PALMLD_IDE_PWEN, GPIOF_INIT_HIGH, "HDD Power" },
+ { GPIO_NR_PALMLD_IDE_RESET, GPIOF_INIT_LOW, "HDD Reset" },
+};
+
+static struct scsi_host_template palmld_sht = {
+ ATA_PIO_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations palmld_port_ops = {
+ .inherits = &ata_sff_port_ops,
+ .sff_data_xfer = ata_sff_data_xfer_noirq,
+ .cable_detect = ata_cable_40wire,
+};
+
+static int palmld_pata_probe(struct platform_device *pdev)
+{
+ struct ata_host *host;
+ struct ata_port *ap;
+ void __iomem *mem;
+ int ret;
+
+ /* allocate host */
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ /* remap drive's physical memory address */
+ mem = devm_ioremap(&pdev->dev, PALMLD_IDE_PHYS, 0x1000);
+ if (!mem) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ /* request and activate power GPIO, IRQ GPIO */
+ ret = gpio_request_array(palmld_hdd_gpios,
+ ARRAY_SIZE(palmld_hdd_gpios));
+ if (ret)
+ goto err1;
+
+ /* reset the drive */
+ gpio_set_value(GPIO_NR_PALMLD_IDE_RESET, 0);
+ msleep(30);
+ gpio_set_value(GPIO_NR_PALMLD_IDE_RESET, 1);
+ msleep(30);
+
+ /* setup the ata port */
+ ap = host->ports[0];
+ ap->ops = &palmld_port_ops;
+ ap->pio_mask = ATA_PIO4;
+ ap->flags |= ATA_FLAG_PIO_POLLING;
+
+ /* memory mapping voodoo */
+ ap->ioaddr.cmd_addr = mem + 0x10;
+ ap->ioaddr.altstatus_addr = mem + 0xe;
+ ap->ioaddr.ctl_addr = mem + 0xe;
+
+ /* start the port */
+ ata_sff_std_ports(&ap->ioaddr);
+
+ /* activate host */
+ ret = ata_host_activate(host, 0, NULL, IRQF_TRIGGER_RISING,
+ &palmld_sht);
+ if (ret)
+ goto err2;
+
+ return ret;
+
+err2:
+ gpio_free_array(palmld_hdd_gpios, ARRAY_SIZE(palmld_hdd_gpios));
+err1:
+ return ret;
+}
+
+static int palmld_pata_remove(struct platform_device *dev)
+{
+ ata_platform_remove_one(dev);
+
+ /* power down the HDD */
+ gpio_set_value(GPIO_NR_PALMLD_IDE_PWEN, 0);
+
+ gpio_free_array(palmld_hdd_gpios, ARRAY_SIZE(palmld_hdd_gpios));
+
+ return 0;
+}
+
+static struct platform_driver palmld_pata_platform_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = palmld_pata_probe,
+ .remove = palmld_pata_remove,
+};
+
+module_platform_driver(palmld_pata_platform_driver);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("PalmLD PATA driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 3d39f9dfec5..bcc4b968c04 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -1,6 +1,6 @@
/*
* pata_pcmcia.c - PCMCIA PATA controller driver.
- * Copyright 2005-2006 Red Hat Inc <alan@redhat.com>, all rights reserved.
+ * Copyright 2005-2006 Red Hat Inc, all rights reserved.
* PCMCIA ident update Copyright 2006 Marcin Juszkiewicz
* <openembedded@hrw.one.pl>
*
@@ -26,15 +26,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
+#include <linux/slab.h>
#include <scsi/scsi_host.h>
#include <linux/ata.h>
#include <linux/libata.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include <pcmcia/cisreg.h>
@@ -42,17 +40,7 @@
#define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.3.3"
-
-/*
- * Private data structure to glue stuff together
- */
-
-struct ata_pcmcia_info {
- struct pcmcia_device *pdev;
- int ndev;
- dev_node_t node;
-};
+#define DRV_VERSION "0.3.5"
/**
* pcmcia_set_mode - PCMCIA specific mode setup
@@ -79,7 +67,7 @@ static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_d
the same vendor - check serial */
if (memcmp(master->id + ATA_ID_SERNO, slave->id + ATA_ID_SERNO,
ATA_ID_SERNO_LEN) == 0 && master->id[ATA_ID_SERNO] >> 8) {
- ata_dev_printk(slave, KERN_WARNING, "is a ghost device, ignoring.\n");
+ ata_dev_warn(slave, "is a ghost device, ignoring\n");
ata_dev_disable(slave);
}
}
@@ -126,6 +114,36 @@ static unsigned int ata_data_xfer_8bit(struct ata_device *dev,
return buflen;
}
+/**
+ * pcmcia_8bit_drain_fifo - Stock FIFO drain logic for SFF controllers
+ * @qc: command
+ *
+ * Drain the FIFO and device of any stuck data following a command
+ * failing to complete. In some cases this is necessary before a
+ * reset will recover the device.
+ *
+ */
+
+static void pcmcia_8bit_drain_fifo(struct ata_queued_cmd *qc)
+{
+ int count;
+ struct ata_port *ap;
+
+ /* We only need to flush incoming data when a command was running */
+ if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
+ return;
+
+ ap = qc->ap;
+
+ /* Drain up to 64K of data before we give up this recovery method */
+ for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ)
+ && count++ < 65536;)
+ ioread8(ap->ioaddr.data_addr);
+
+ if (count)
+ ata_port_warn(ap, "drained %d bytes to clear DRQ\n", count);
+
+}
static struct scsi_host_template pcmcia_sht = {
ATA_PIO_SHT(DRV_NAME),
@@ -143,10 +161,32 @@ static struct ata_port_operations pcmcia_8bit_port_ops = {
.sff_data_xfer = ata_data_xfer_8bit,
.cable_detect = ata_cable_40wire,
.set_mode = pcmcia_set_mode_8bit,
+ .sff_drain_fifo = pcmcia_8bit_drain_fifo,
};
-#define CS_CHECK(fn, ret) \
-do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data)
+{
+ int *is_kme = priv_data;
+
+ if ((pdev->resource[0]->flags & IO_DATA_PATH_WIDTH)
+ != IO_DATA_PATH_WIDTH_8) {
+ pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+ }
+ pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
+ pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
+
+ if (pdev->resource[1]->end) {
+ pdev->resource[0]->end = 8;
+ pdev->resource[1]->end = (*is_kme) ? 2 : 1;
+ } else {
+ if (pdev->resource[0]->end < 16)
+ return -ENODEV;
+ }
+
+ return pcmcia_request_io(pdev);
+}
/**
* pcmcia_init_one - attach a PCMCIA interface
@@ -160,52 +200,15 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
{
struct ata_host *host;
struct ata_port *ap;
- struct ata_pcmcia_info *info;
- tuple_t tuple;
- struct {
- unsigned short buf[128];
- cisparse_t parse;
- config_info_t conf;
- cistpl_cftable_entry_t dflt;
- } *stk = NULL;
- cistpl_cftable_entry_t *cfg;
- int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM, p;
+ int is_kme = 0, ret = -ENOMEM, p;
unsigned long io_base, ctl_base;
void __iomem *io_addr, *ctl_addr;
int n_ports = 1;
-
struct ata_port_operations *ops = &pcmcia_port_ops;
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (info == NULL)
- return -ENOMEM;
-
- /* Glue stuff together. FIXME: We may be able to get rid of info with care */
- info->pdev = pdev;
- pdev->priv = info;
-
/* Set up attributes in order to probe card and get resources */
- pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- pdev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
- pdev->io.IOAddrLines = 3;
- pdev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
- pdev->irq.IRQInfo1 = IRQ_LEVEL_ID;
- pdev->conf.Attributes = CONF_ENABLE_IRQ;
- pdev->conf.IntType = INT_MEMORY_AND_IO;
-
- /* Allocate resoure probing structures */
-
- stk = kzalloc(sizeof(*stk), GFP_KERNEL);
- if (!stk)
- goto out1;
-
- cfg = &stk->parse.cftable_entry;
-
- /* Tuples we are walking */
- tuple.TupleData = (cisdata_t *)&stk->buf;
- tuple.TupleOffset = 0;
- tuple.TupleDataMax = 255;
- tuple.Attributes = 0;
+ pdev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO |
+ CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
/* See if we have a manufacturer identifier. Use it to set is_kme for
vendor quirks */
@@ -213,78 +216,23 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
((pdev->card_id == PRODID_KME_KXLC005_A) ||
(pdev->card_id == PRODID_KME_KXLC005_B)));
- /* Not sure if this is right... look up the current Vcc */
- CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(pdev, &stk->conf));
-/* link->conf.Vcc = stk->conf.Vcc; */
-
- pass = io_base = ctl_base = 0;
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
- tuple.Attributes = 0;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
-
- /* Now munch the resources looking for a suitable set */
- while (1) {
- if (pcmcia_get_tuple_data(pdev, &tuple) != 0)
- goto next_entry;
- if (pcmcia_parse_tuple(pdev, &tuple, &stk->parse) != 0)
- goto next_entry;
- /* Check for matching Vcc, unless we're desperate */
- if (!pass) {
- if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
- if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
- goto next_entry;
- } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
- if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000)
- goto next_entry;
- }
- }
-
- if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
- pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
- else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
- pdev->conf.Vpp = stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
- if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) {
- cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io;
- pdev->conf.ConfigIndex = cfg->index;
- pdev->io.BasePort1 = io->win[0].base;
- pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- if (!(io->flags & CISTPL_IO_16BIT))
- pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- if (io->nwin == 2) {
- pdev->io.NumPorts1 = 8;
- pdev->io.BasePort2 = io->win[1].base;
- pdev->io.NumPorts2 = (is_kme) ? 2 : 1;
- if (pcmcia_request_io(pdev, &pdev->io) != 0)
- goto next_entry;
- io_base = pdev->io.BasePort1;
- ctl_base = pdev->io.BasePort2;
- } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
- pdev->io.NumPorts1 = io->win[0].len;
- pdev->io.NumPorts2 = 0;
- if (pcmcia_request_io(pdev, &pdev->io) != 0)
- goto next_entry;
- io_base = pdev->io.BasePort1;
- ctl_base = pdev->io.BasePort1 + 0x0e;
- } else
- goto next_entry;
- /* If we've got this far, we're done */
- break;
- }
-next_entry:
- if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
- memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
- if (pass) {
- CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(pdev, &tuple));
- } else if (pcmcia_get_next_tuple(pdev, &tuple) != 0) {
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
- memset(&stk->dflt, 0, sizeof(stk->dflt));
- pass++;
- }
+ if (pcmcia_loop_config(pdev, pcmcia_check_one_config, &is_kme)) {
+ pdev->config_flags &= ~CONF_AUTO_CHECK_VCC;
+ if (pcmcia_loop_config(pdev, pcmcia_check_one_config, &is_kme))
+ goto failed; /* No suitable config found */
}
+ io_base = pdev->resource[0]->start;
+ if (pdev->resource[1]->end)
+ ctl_base = pdev->resource[1]->start;
+ else
+ ctl_base = pdev->resource[0]->start + 0x0e;
- CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq));
- CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf));
+ if (!pdev->irq)
+ goto failed;
+
+ ret = pcmcia_enable_device(pdev);
+ if (ret)
+ goto failed;
/* iomap */
ret = -ENOMEM;
@@ -300,7 +248,7 @@ next_entry:
/* FIXME: Could be more ports at base + 0x10 but we only deal with
one right now */
- if (pdev->io.NumPorts1 >= 0x20)
+ if (resource_size(pdev->resource[0]) >= 0x20)
n_ports = 2;
if (pdev->manf_id == 0x0097 && pdev->card_id == 0x1620)
@@ -318,7 +266,7 @@ next_entry:
ap = host->ports[p];
ap->ops = ops;
- ap->pio_mask = 1; /* ISA so PIO 0 cycles */
+ ap->pio_mask = ATA_PIO0; /* ISA so PIO 0 cycles */
ap->flags |= ATA_FLAG_SLAVE_POSS;
ap->ioaddr.cmd_addr = io_addr + 0x10 * p;
ap->ioaddr.altstatus_addr = ctl_addr + 0x10 * p;
@@ -329,23 +277,16 @@ next_entry:
}
/* activate */
- ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_sff_interrupt,
+ ret = ata_host_activate(host, pdev->irq, ata_sff_interrupt,
IRQF_SHARED, &pcmcia_sht);
if (ret)
goto failed;
- info->ndev = 1;
- kfree(stk);
+ pdev->priv = host;
return 0;
-cs_failed:
- cs_error(pdev, last_fn, last_ret);
failed:
- kfree(stk);
- info->ndev = 0;
pcmcia_disable_device(pdev);
-out1:
- kfree(info);
return ret;
}
@@ -359,23 +300,15 @@ out1:
static void pcmcia_remove_one(struct pcmcia_device *pdev)
{
- struct ata_pcmcia_info *info = pdev->priv;
- struct device *dev = &pdev->dev;
-
- if (info != NULL) {
- /* If we have attached the device to the ATA layer, detach it */
- if (info->ndev) {
- struct ata_host *host = dev_get_drvdata(dev);
- ata_host_detach(host);
- }
- info->ndev = 0;
- pdev->priv = NULL;
- }
+ struct ata_host *host = pdev->priv;
+
+ if (host)
+ ata_host_detach(host);
+
pcmcia_disable_device(pdev);
- kfree(info);
}
-static struct pcmcia_device_id pcmcia_devices[] = {
+static const struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_FUNC_ID(4),
PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000), /* Corsair */
PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */
@@ -384,6 +317,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904),
PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */
+ PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000), /* Kingston */
PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620), /* TI emulated */
PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */
PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
@@ -397,6 +331,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("CNF ", "CD-ROM", 0x46d7db81, 0x66536591),
PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
@@ -404,16 +339,19 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591),
PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
- PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
+ PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+ PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x55d5bffb),
+ PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10),
PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b),
+ PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee),
PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
@@ -424,14 +362,18 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF45", 0x709b1bf1, 0xf68b6f32),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x7558f133),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47),
PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6),
+ PCMCIA_DEVICE_PROD_ID2("Flash Card", 0x5a362506),
PCMCIA_DEVICE_NULL,
};
@@ -439,28 +381,14 @@ MODULE_DEVICE_TABLE(pcmcia, pcmcia_devices);
static struct pcmcia_driver pcmcia_driver = {
.owner = THIS_MODULE,
- .drv = {
- .name = DRV_NAME,
- },
+ .name = DRV_NAME,
.id_table = pcmcia_devices,
.probe = pcmcia_init_one,
.remove = pcmcia_remove_one,
};
-
-static int __init pcmcia_init(void)
-{
- return pcmcia_register_driver(&pcmcia_driver);
-}
-
-static void __exit pcmcia_exit(void)
-{
- pcmcia_unregister_driver(&pcmcia_driver);
-}
+module_pcmcia_driver(pcmcia_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for PCMCIA ATA");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
-
-module_init(pcmcia_init);
-module_exit(pcmcia_exit);
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 0e1c2c1134d..4d06a5cda98 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -63,6 +62,9 @@ enum {
};
static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+#ifdef CONFIG_PM_SLEEP
+static int pdc2027x_reinit_one(struct pci_dev *pdev);
+#endif
static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline);
static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev);
static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
@@ -126,6 +128,10 @@ static struct pci_driver pdc2027x_pci_driver = {
.id_table = pdc2027x_pci_tbl,
.probe = pdc2027x_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = ata_pci_device_suspend,
+ .resume = pdc2027x_reinit_one,
+#endif
};
static struct scsi_host_template pdc2027x_sht = {
@@ -150,20 +156,18 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
static struct ata_port_info pdc2027x_port_info[] = {
/* PDC_UDMA_100 */
{
- .flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
- ATA_FLAG_MMIO,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = ATA_UDMA5, /* udma0-5 */
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
.port_ops = &pdc2027x_pata100_ops,
},
/* PDC_UDMA_133 */
{
- .flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
- ATA_FLAG_MMIO,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = ATA_UDMA6, /* udma0-6 */
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
.port_ops = &pdc2027x_pata133_ops,
},
};
@@ -265,7 +269,7 @@ static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long
struct ata_device *pair = ata_dev_pair(adev);
if (adev->class != ATA_DEV_ATA || adev->devno == 0 || pair == NULL)
- return ata_bmdma_mode_filter(adev, mask);
+ return mask;
/* Check for slave of a Maxtor at UDMA6 */
ata_id_c_string(pair->id, model_num, ATA_ID_PROD,
@@ -274,14 +278,13 @@ static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long
if (strstr(model_num, "Maxtor") == NULL && pair->dma_mode == XFER_UDMA_6)
mask &= ~ (1 << (6 + ATA_SHIFT_UDMA));
- return ata_bmdma_mode_filter(adev, mask);
+ return mask;
}
/**
* pdc2027x_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port to configure
* @adev: um
- * @pio: PIO mode, 0 - 4
*
* Set PIO mode for device.
*
@@ -326,7 +329,6 @@ static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev)
* pdc2027x_set_dmamode - Initialize host controller PATA UDMA timings
* @ap: Port to configure
* @adev: um
- * @udma: udma mode, XFER_UDMA_0 to XFER_UDMA_6
*
* Set UDMA mode for device.
*
@@ -406,23 +408,20 @@ static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed
if (rc < 0)
return rc;
- ata_link_for_each_dev(dev, link) {
- if (ata_dev_enabled(dev)) {
+ ata_for_each_dev(dev, link, ENABLED) {
+ pdc2027x_set_piomode(ap, dev);
- pdc2027x_set_piomode(ap, dev);
+ /*
+ * Enable prefetch if the device support PIO only.
+ */
+ if (dev->xfer_shift == ATA_SHIFT_PIO) {
+ u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1));
+ ctcr1 |= (1 << 25);
+ iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
- /*
- * Enable prefetch if the device support PIO only.
- */
- if (dev->xfer_shift == ATA_SHIFT_PIO) {
- u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1));
- ctcr1 |= (1 << 25);
- iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
-
- PDPRINTK("Turn on prefetch\n");
- } else {
- pdc2027x_set_dmamode(ap, dev);
- }
+ PDPRINTK("Turn on prefetch\n");
+ } else {
+ pdc2027x_set_dmamode(ap, dev);
}
}
return 0;
@@ -662,7 +661,7 @@ static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx)
*/
pll_clock = pdc_detect_pll_input_clock(host);
- dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
+ dev_info(host->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
/* Adjust PLL control register */
pdc_adjust_pll(host, pll_clock, board_idx);
@@ -702,9 +701,9 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
* @pdev: instance of pci_dev found
* @ent: matching entry in the id_tbl[]
*/
-static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int pdc2027x_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- static int printed_version;
static const unsigned long cmd_offset[] = { 0x17c0, 0x15c0 };
static const unsigned long bmdma_offset[] = { 0x1000, 0x1008 };
unsigned int board_idx = (unsigned int) ent->driver_data;
@@ -714,8 +713,7 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
void __iomem *mmio_base;
int i, rc;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
/* alloc host */
host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
@@ -759,25 +757,33 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
return -EIO;
pci_set_master(pdev);
- return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+ return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
IRQF_SHARED, &pdc2027x_sht);
}
-/**
- * pdc2027x_init - Called after this module is loaded into the kernel.
- */
-static int __init pdc2027x_init(void)
+#ifdef CONFIG_PM_SLEEP
+static int pdc2027x_reinit_one(struct pci_dev *pdev)
{
- return pci_register_driver(&pdc2027x_pci_driver);
-}
+ struct ata_host *host = pci_get_drvdata(pdev);
+ unsigned int board_idx;
+ int rc;
-/**
- * pdc2027x_exit - Called before this module unloaded from the kernel
- */
-static void __exit pdc2027x_exit(void)
-{
- pci_unregister_driver(&pdc2027x_pci_driver);
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ if (pdev->device == PCI_DEVICE_ID_PROMISE_20268 ||
+ pdev->device == PCI_DEVICE_ID_PROMISE_20270)
+ board_idx = PDC_UDMA_100;
+ else
+ board_idx = PDC_UDMA_133;
+
+ if (pdc_hardware_init(host, board_idx))
+ return -EIO;
+
+ ata_host_resume(host);
+ return 0;
}
+#endif
-module_init(pdc2027x_init);
-module_exit(pdc2027x_exit);
+module_pci_driver(pdc2027x_pci_driver);
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index d2673060bc8..9001991d283 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -1,8 +1,8 @@
/*
* pata_pdc202xx_old.c - Promise PDC202xx PATA for new ATA layer
* (C) 2005 Red Hat Inc
- * Alan Cox <alan@redhat.com>
- * (C) 2007 Bartlomiej Zolnierkiewicz
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
+ * (C) 2007,2009,2010 Bartlomiej Zolnierkiewicz
*
* Based in part on linux/drivers/ide/pci/pdc202xx_old.c
*
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
@@ -35,6 +34,36 @@ static int pdc2026x_cable_detect(struct ata_port *ap)
return ATA_CBL_PATA80;
}
+static void pdc202xx_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+
+ iowrite8(tf->command, ap->ioaddr.command_addr);
+ ndelay(400);
+}
+
+static bool pdc202xx_irq_check(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned long master = pci_resource_start(pdev, 4);
+ u8 sc1d = inb(master + 0x1d);
+
+ if (ap->port_no) {
+ /*
+ * bit 7: error, bit 6: interrupting,
+ * bit 5: FIFO full, bit 4: FIFO empty
+ */
+ return sc1d & 0x40;
+ } else {
+ /*
+ * bit 3: error, bit 2: interrupting,
+ * bit 1: FIFO full, bit 0: FIFO empty
+ */
+ return sc1d & 0x04;
+ }
+}
+
/**
* pdc202xx_configure_piomode - set chip PIO timing
* @ap: ATA interface
@@ -158,7 +187,7 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
u32 len;
/* Check we keep host level locking here */
- if (adev->dma_mode >= XFER_UDMA_2)
+ if (adev->dma_mode > XFER_UDMA_2)
iowrite8(ioread8(clock) | sel66, clock);
else
iowrite8(ioread8(clock) & ~sel66, clock);
@@ -212,7 +241,7 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
iowrite8(ioread8(clock) & ~sel66, clock);
}
/* Flip back to 33Mhz for PIO */
- if (adev->dma_mode >= XFER_UDMA_2)
+ if (adev->dma_mode > XFER_UDMA_2)
iowrite8(ioread8(clock) & ~sel66, clock);
ata_bmdma_stop(qc);
pdc202xx_set_piomode(ap, adev);
@@ -240,7 +269,7 @@ static int pdc2026x_port_start(struct ata_port *ap)
u8 burst = ioread8(bmdma + 0x1f);
iowrite8(burst | 0x01, bmdma + 0x1f);
}
- return ata_sff_port_start(ap);
+ return ata_bmdma_port_start(ap);
}
/**
@@ -271,6 +300,9 @@ static struct ata_port_operations pdc2024x_port_ops = {
.cable_detect = ata_cable_40wire,
.set_piomode = pdc202xx_set_piomode,
.set_dmamode = pdc202xx_set_dmamode,
+
+ .sff_exec_command = pdc202xx_exec_command,
+ .sff_irq_check = pdc202xx_irq_check,
};
static struct ata_port_operations pdc2026x_port_ops = {
@@ -284,6 +316,9 @@ static struct ata_port_operations pdc2026x_port_ops = {
.dev_config = pdc2026x_dev_config,
.port_start = pdc2026x_port_start,
+
+ .sff_exec_command = pdc202xx_exec_command,
+ .sff_irq_check = pdc202xx_irq_check,
};
static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -291,22 +326,22 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id
static const struct ata_port_info info[3] = {
{
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA2,
.port_ops = &pdc2024x_port_ops
},
{
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA4,
.port_ops = &pdc2026x_port_ops
},
{
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &pdc2026x_port_ops
}
@@ -324,7 +359,7 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id
return -ENODEV;
}
}
- return ata_pci_sff_init_one(dev, ppi, &pdc202xx_sht, NULL);
+ return ata_pci_bmdma_init_one(dev, ppi, &pdc202xx_sht, NULL, 0);
}
static const struct pci_device_id pdc202xx[] = {
@@ -342,27 +377,16 @@ static struct pci_driver pdc202xx_pci_driver = {
.id_table = pdc202xx,
.probe = pdc202xx_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init pdc202xx_init(void)
-{
- return pci_register_driver(&pdc202xx_pci_driver);
-}
-
-static void __exit pdc202xx_exit(void)
-{
- pci_unregister_driver(&pdc202xx_pci_driver);
-}
+module_pci_driver(pdc202xx_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Promise 2024x and 20262-20267");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, pdc202xx);
MODULE_VERSION(DRV_VERSION);
-
-module_init(pdc202xx_init);
-module_exit(pdc202xx_exit);
diff --git a/drivers/ata/pata_piccolo.c b/drivers/ata/pata_piccolo.c
new file mode 100644
index 00000000000..35cb0e26323
--- /dev/null
+++ b/drivers/ata/pata_piccolo.c
@@ -0,0 +1,125 @@
+/*
+ * pata_piccolo.c - Toshiba Piccolo PATA/SATA controller driver.
+ *
+ * This is basically an update to ata_generic.c to add Toshiba Piccolo support
+ * then split out to keep ata_generic "clean".
+ *
+ * Copyright 2005 Red Hat Inc, all rights reserved.
+ *
+ * Elements from ide/pci/generic.c
+ * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
+ * Portions (C) Copyright 2002 Red Hat Inc <alan@redhat.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * The timing data tables/programming info are courtesy of the NetBSD driver
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_piccolo"
+#define DRV_VERSION "0.0.1"
+
+
+
+static void tosh_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u16 pio[6] = { /* For reg 0x50 low word & E088 */
+ 0x0566, 0x0433, 0x0311, 0x0201, 0x0200, 0x0100
+ };
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u16 conf;
+ pci_read_config_word(pdev, 0x50, &conf);
+ conf &= 0xE088;
+ conf |= pio[adev->pio_mode - XFER_PIO_0];
+ pci_write_config_word(pdev, 0x50, conf);
+}
+
+static void tosh_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 conf;
+ pci_read_config_dword(pdev, 0x5C, &conf);
+ conf &= 0x78FFE088; /* Keep the other bits */
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ int udma = adev->dma_mode - XFER_UDMA_0;
+ conf |= 0x80000000;
+ conf |= (udma + 2) << 28;
+ conf |= (2 - udma) * 0x111; /* spread into three nibbles */
+ } else {
+ static const u32 mwdma[4] = {
+ 0x0655, 0x0200, 0x0200, 0x0100
+ };
+ conf |= mwdma[adev->dma_mode - XFER_MW_DMA_0];
+ }
+ pci_write_config_dword(pdev, 0x5C, conf);
+}
+
+
+static struct scsi_host_template tosh_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations tosh_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+ .cable_detect = ata_cable_unknown,
+ .set_piomode = tosh_set_piomode,
+ .set_dmamode = tosh_set_dmamode
+};
+
+/**
+ * ata_tosh_init - attach generic IDE
+ * @dev: PCI device found
+ * @id: match entry
+ *
+ * Called each time a matching IDE interface is found. We check if the
+ * interface is one we wish to claim and if so we perform any chip
+ * specific hacks then let the ATA layer do the heavy lifting.
+ */
+
+static int ata_tosh_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static const struct ata_port_info info = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO5,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
+ .port_ops = &tosh_port_ops
+ };
+ const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
+ /* Just one port for the moment */
+ return ata_pci_bmdma_init_one(dev, ppi, &tosh_sht, NULL, 0);
+}
+
+static struct pci_device_id ata_tosh[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_3), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_5), },
+ { 0, },
+};
+
+static struct pci_driver ata_tosh_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = ata_tosh,
+ .probe = ata_tosh_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
+};
+
+module_pci_driver(ata_tosh_pci_driver);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("Low level driver for Toshiba Piccolo ATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ata_tosh);
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 6527c56c34a..a5579b55e33 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -5,7 +5,7 @@
*
* Based on pata_pcmcia:
*
- * Copyright 2005-2006 Red Hat Inc <alan@redhat.com>, all rights reserved.
+ * Copyright 2005-2006 Red Hat Inc, all rights reserved.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -13,7 +13,6 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <scsi/scsi_host.h>
#include <linux/ata.h>
@@ -34,14 +33,12 @@ static int pata_platform_set_mode(struct ata_link *link, struct ata_device **unu
{
struct ata_device *dev;
- ata_link_for_each_dev(dev, link) {
- if (ata_dev_enabled(dev)) {
- /* We don't really care */
- dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
- dev->xfer_shift = ATA_SHIFT_PIO;
- dev->flags |= ATA_DFLAG_PIO;
- ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
- }
+ ata_for_each_dev(dev, link, ENABLED) {
+ /* We don't really care */
+ dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+ ata_dev_info(dev, "configured for PIO\n");
}
return 0;
}
@@ -55,7 +52,6 @@ static struct ata_port_operations pata_platform_port_ops = {
.sff_data_xfer = ata_sff_data_xfer_noirq,
.cable_detect = ata_cable_unknown,
.set_mode = pata_platform_set_mode,
- .port_start = ATA_OP_NULL,
};
static void pata_platform_setup_port(struct ata_ioports *ioaddr,
@@ -101,12 +97,9 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
*
* If no IRQ resource is present, PIO polling mode is used instead.
*/
-int __devinit __pata_platform_probe(struct device *dev,
- struct resource *io_res,
- struct resource *ctl_res,
- struct resource *irq_res,
- unsigned int ioport_shift,
- int __pio_mask)
+int __pata_platform_probe(struct device *dev, struct resource *io_res,
+ struct resource *ctl_res, struct resource *irq_res,
+ unsigned int ioport_shift, int __pio_mask)
{
struct ata_host *host;
struct ata_port *ap;
@@ -153,14 +146,14 @@ int __devinit __pata_platform_probe(struct device *dev,
*/
if (mmio) {
ap->ioaddr.cmd_addr = devm_ioremap(dev, io_res->start,
- io_res->end - io_res->start + 1);
+ resource_size(io_res));
ap->ioaddr.ctl_addr = devm_ioremap(dev, ctl_res->start,
- ctl_res->end - ctl_res->start + 1);
+ resource_size(ctl_res));
} else {
ap->ioaddr.cmd_addr = devm_ioport_map(dev, io_res->start,
- io_res->end - io_res->start + 1);
+ resource_size(io_res));
ap->ioaddr.ctl_addr = devm_ioport_map(dev, ctl_res->start,
- ctl_res->end - ctl_res->start + 1);
+ resource_size(ctl_res));
}
if (!ap->ioaddr.cmd_addr || !ap->ioaddr.ctl_addr) {
dev_err(dev, "failed to map IO/CTL base\n");
@@ -181,29 +174,12 @@ int __devinit __pata_platform_probe(struct device *dev,
}
EXPORT_SYMBOL_GPL(__pata_platform_probe);
-/**
- * __pata_platform_remove - unplug a platform interface
- * @dev: device
- *
- * A platform bus ATA device has been unplugged. Perform the needed
- * cleanup. Also called on module unload for any active devices.
- */
-int __devexit __pata_platform_remove(struct device *dev)
-{
- struct ata_host *host = dev_get_drvdata(dev);
-
- ata_host_detach(host);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(__pata_platform_remove);
-
-static int __devinit pata_platform_probe(struct platform_device *pdev)
+static int pata_platform_probe(struct platform_device *pdev)
{
struct resource *io_res;
struct resource *ctl_res;
struct resource *irq_res;
- struct pata_platform_info *pp_info = pdev->dev.platform_data;
+ struct pata_platform_info *pp_info = dev_get_platdata(&pdev->dev);
/*
* Simple resource validation ..
@@ -245,31 +221,16 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
pio_mask);
}
-static int __devexit pata_platform_remove(struct platform_device *pdev)
-{
- return __pata_platform_remove(&pdev->dev);
-}
-
static struct platform_driver pata_platform_driver = {
.probe = pata_platform_probe,
- .remove = __devexit_p(pata_platform_remove),
+ .remove = ata_platform_remove_one,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
-static int __init pata_platform_init(void)
-{
- return platform_driver_register(&pata_platform_driver);
-}
-
-static void __exit pata_platform_exit(void)
-{
- platform_driver_unregister(&pata_platform_driver);
-}
-module_init(pata_platform_init);
-module_exit(pata_platform_exit);
+module_platform_driver(pata_platform_driver);
module_param(pio_mask, int, 0);
@@ -277,3 +238,4 @@ MODULE_AUTHOR("Paul Mundt");
MODULE_DESCRIPTION("low-level driver for platform device ATA");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/ata/pata_pxa.c b/drivers/ata/pata_pxa.c
new file mode 100644
index 00000000000..73259bfda1e
--- /dev/null
+++ b/drivers/ata/pata_pxa.c
@@ -0,0 +1,398 @@
+/*
+ * Generic PXA PATA driver
+ *
+ * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+
+#include <scsi/scsi_host.h>
+
+#include <mach/pxa2xx-regs.h>
+#include <linux/platform_data/ata-pxa.h>
+#include <mach/dma.h>
+
+#define DRV_NAME "pata_pxa"
+#define DRV_VERSION "0.1"
+
+struct pata_pxa_data {
+ uint32_t dma_channel;
+ struct pxa_dma_desc *dma_desc;
+ dma_addr_t dma_desc_addr;
+ uint32_t dma_desc_id;
+
+ /* DMA IO physical address */
+ uint32_t dma_io_addr;
+ /* PXA DREQ<0:2> pin selector */
+ uint32_t dma_dreq;
+ /* DMA DCSR register value */
+ uint32_t dma_dcsr;
+
+ struct completion dma_done;
+};
+
+/*
+ * Setup the DMA descriptors. The size is transfer capped at 4k per descriptor,
+ * if the transfer is longer, it is split into multiple chained descriptors.
+ */
+static void pxa_load_dmac(struct scatterlist *sg, struct ata_queued_cmd *qc)
+{
+ struct pata_pxa_data *pd = qc->ap->private_data;
+
+ uint32_t cpu_len, seg_len;
+ dma_addr_t cpu_addr;
+
+ cpu_addr = sg_dma_address(sg);
+ cpu_len = sg_dma_len(sg);
+
+ do {
+ seg_len = (cpu_len > 0x1000) ? 0x1000 : cpu_len;
+
+ pd->dma_desc[pd->dma_desc_id].ddadr = pd->dma_desc_addr +
+ ((pd->dma_desc_id + 1) * sizeof(struct pxa_dma_desc));
+
+ pd->dma_desc[pd->dma_desc_id].dcmd = DCMD_BURST32 |
+ DCMD_WIDTH2 | (DCMD_LENGTH & seg_len);
+
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ pd->dma_desc[pd->dma_desc_id].dsadr = cpu_addr;
+ pd->dma_desc[pd->dma_desc_id].dtadr = pd->dma_io_addr;
+ pd->dma_desc[pd->dma_desc_id].dcmd |= DCMD_INCSRCADDR |
+ DCMD_FLOWTRG;
+ } else {
+ pd->dma_desc[pd->dma_desc_id].dsadr = pd->dma_io_addr;
+ pd->dma_desc[pd->dma_desc_id].dtadr = cpu_addr;
+ pd->dma_desc[pd->dma_desc_id].dcmd |= DCMD_INCTRGADDR |
+ DCMD_FLOWSRC;
+ }
+
+ cpu_len -= seg_len;
+ cpu_addr += seg_len;
+ pd->dma_desc_id++;
+
+ } while (cpu_len);
+
+ /* Should not happen */
+ if (seg_len & 0x1f)
+ DALGN |= (1 << pd->dma_dreq);
+}
+
+/*
+ * Prepare taskfile for submission.
+ */
+static void pxa_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct pata_pxa_data *pd = qc->ap->private_data;
+ int si = 0;
+ struct scatterlist *sg;
+
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
+
+ pd->dma_desc_id = 0;
+
+ DCSR(pd->dma_channel) = 0;
+ DALGN &= ~(1 << pd->dma_dreq);
+
+ for_each_sg(qc->sg, sg, qc->n_elem, si)
+ pxa_load_dmac(sg, qc);
+
+ pd->dma_desc[pd->dma_desc_id - 1].ddadr = DDADR_STOP;
+
+ /* Fire IRQ only at the end of last block */
+ pd->dma_desc[pd->dma_desc_id - 1].dcmd |= DCMD_ENDIRQEN;
+
+ DDADR(pd->dma_channel) = pd->dma_desc_addr;
+ DRCMR(pd->dma_dreq) = DRCMR_MAPVLD | pd->dma_channel;
+
+}
+
+/*
+ * Configure the DMA controller, load the DMA descriptors, but don't start the
+ * DMA controller yet. Only issue the ATA command.
+ */
+static void pxa_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ qc->ap->ops->sff_exec_command(qc->ap, &qc->tf);
+}
+
+/*
+ * Execute the DMA transfer.
+ */
+static void pxa_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct pata_pxa_data *pd = qc->ap->private_data;
+ init_completion(&pd->dma_done);
+ DCSR(pd->dma_channel) = DCSR_RUN;
+}
+
+/*
+ * Wait until the DMA transfer completes, then stop the DMA controller.
+ */
+static void pxa_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct pata_pxa_data *pd = qc->ap->private_data;
+
+ if ((DCSR(pd->dma_channel) & DCSR_RUN) &&
+ wait_for_completion_timeout(&pd->dma_done, HZ))
+ dev_err(qc->ap->dev, "Timeout waiting for DMA completion!");
+
+ DCSR(pd->dma_channel) = 0;
+}
+
+/*
+ * Read DMA status. The bmdma_stop() will take care of properly finishing the
+ * DMA transfer so we always have DMA-complete interrupt here.
+ */
+static unsigned char pxa_bmdma_status(struct ata_port *ap)
+{
+ struct pata_pxa_data *pd = ap->private_data;
+ unsigned char ret = ATA_DMA_INTR;
+
+ if (pd->dma_dcsr & DCSR_BUSERR)
+ ret |= ATA_DMA_ERR;
+
+ return ret;
+}
+
+/*
+ * No IRQ register present so we do nothing.
+ */
+static void pxa_irq_clear(struct ata_port *ap)
+{
+}
+
+/*
+ * Check for ATAPI DMA. ATAPI DMA is unsupported by this driver. It's still
+ * unclear why ATAPI has DMA issues.
+ */
+static int pxa_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ return -EOPNOTSUPP;
+}
+
+static struct scsi_host_template pxa_ata_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations pxa_ata_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+ .cable_detect = ata_cable_40wire,
+
+ .bmdma_setup = pxa_bmdma_setup,
+ .bmdma_start = pxa_bmdma_start,
+ .bmdma_stop = pxa_bmdma_stop,
+ .bmdma_status = pxa_bmdma_status,
+
+ .check_atapi_dma = pxa_check_atapi_dma,
+
+ .sff_irq_clear = pxa_irq_clear,
+
+ .qc_prep = pxa_qc_prep,
+};
+
+/*
+ * DMA interrupt handler.
+ */
+static void pxa_ata_dma_irq(int dma, void *port)
+{
+ struct ata_port *ap = port;
+ struct pata_pxa_data *pd = ap->private_data;
+
+ pd->dma_dcsr = DCSR(dma);
+ DCSR(dma) = pd->dma_dcsr;
+
+ if (pd->dma_dcsr & DCSR_STOPSTATE)
+ complete(&pd->dma_done);
+}
+
+static int pxa_ata_probe(struct platform_device *pdev)
+{
+ struct ata_host *host;
+ struct ata_port *ap;
+ struct pata_pxa_data *data;
+ struct resource *cmd_res;
+ struct resource *ctl_res;
+ struct resource *dma_res;
+ struct resource *irq_res;
+ struct pata_pxa_pdata *pdata = dev_get_platdata(&pdev->dev);
+ int ret = 0;
+
+ /*
+ * Resource validation, three resources are needed:
+ * - CMD port base address
+ * - CTL port base address
+ * - DMA port base address
+ * - IRQ pin
+ */
+ if (pdev->num_resources != 4) {
+ dev_err(&pdev->dev, "invalid number of resources\n");
+ return -EINVAL;
+ }
+
+ /*
+ * CMD port base address
+ */
+ cmd_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(cmd_res == NULL))
+ return -EINVAL;
+
+ /*
+ * CTL port base address
+ */
+ ctl_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (unlikely(ctl_res == NULL))
+ return -EINVAL;
+
+ /*
+ * DMA port base address
+ */
+ dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (unlikely(dma_res == NULL))
+ return -EINVAL;
+
+ /*
+ * IRQ pin
+ */
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (unlikely(irq_res == NULL))
+ return -EINVAL;
+
+ /*
+ * Allocate the host
+ */
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ return -ENOMEM;
+
+ ap = host->ports[0];
+ ap->ops = &pxa_ata_port_ops;
+ ap->pio_mask = ATA_PIO4;
+ ap->mwdma_mask = ATA_MWDMA2;
+
+ ap->ioaddr.cmd_addr = devm_ioremap(&pdev->dev, cmd_res->start,
+ resource_size(cmd_res));
+ ap->ioaddr.ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
+ resource_size(ctl_res));
+ ap->ioaddr.bmdma_addr = devm_ioremap(&pdev->dev, dma_res->start,
+ resource_size(dma_res));
+
+ /*
+ * Adjust register offsets
+ */
+ ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
+ ap->ioaddr.data_addr = ap->ioaddr.cmd_addr +
+ (ATA_REG_DATA << pdata->reg_shift);
+ ap->ioaddr.error_addr = ap->ioaddr.cmd_addr +
+ (ATA_REG_ERR << pdata->reg_shift);
+ ap->ioaddr.feature_addr = ap->ioaddr.cmd_addr +
+ (ATA_REG_FEATURE << pdata->reg_shift);
+ ap->ioaddr.nsect_addr = ap->ioaddr.cmd_addr +
+ (ATA_REG_NSECT << pdata->reg_shift);
+ ap->ioaddr.lbal_addr = ap->ioaddr.cmd_addr +
+ (ATA_REG_LBAL << pdata->reg_shift);
+ ap->ioaddr.lbam_addr = ap->ioaddr.cmd_addr +
+ (ATA_REG_LBAM << pdata->reg_shift);
+ ap->ioaddr.lbah_addr = ap->ioaddr.cmd_addr +
+ (ATA_REG_LBAH << pdata->reg_shift);
+ ap->ioaddr.device_addr = ap->ioaddr.cmd_addr +
+ (ATA_REG_DEVICE << pdata->reg_shift);
+ ap->ioaddr.status_addr = ap->ioaddr.cmd_addr +
+ (ATA_REG_STATUS << pdata->reg_shift);
+ ap->ioaddr.command_addr = ap->ioaddr.cmd_addr +
+ (ATA_REG_CMD << pdata->reg_shift);
+
+ /*
+ * Allocate and load driver's internal data structure
+ */
+ data = devm_kzalloc(&pdev->dev, sizeof(struct pata_pxa_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ap->private_data = data;
+ data->dma_dreq = pdata->dma_dreq;
+ data->dma_io_addr = dma_res->start;
+
+ /*
+ * Allocate space for the DMA descriptors
+ */
+ data->dma_desc = dmam_alloc_coherent(&pdev->dev, PAGE_SIZE,
+ &data->dma_desc_addr, GFP_KERNEL);
+ if (!data->dma_desc)
+ return -EINVAL;
+
+ /*
+ * Request the DMA channel
+ */
+ data->dma_channel = pxa_request_dma(DRV_NAME, DMA_PRIO_LOW,
+ pxa_ata_dma_irq, ap);
+ if (data->dma_channel < 0)
+ return -EBUSY;
+
+ /*
+ * Stop and clear the DMA channel
+ */
+ DCSR(data->dma_channel) = 0;
+
+ /*
+ * Activate the ATA host
+ */
+ ret = ata_host_activate(host, irq_res->start, ata_sff_interrupt,
+ pdata->irq_flags, &pxa_ata_sht);
+ if (ret)
+ pxa_free_dma(data->dma_channel);
+
+ return ret;
+}
+
+static int pxa_ata_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct pata_pxa_data *data = host->ports[0]->private_data;
+
+ pxa_free_dma(data->dma_channel);
+
+ ata_host_detach(host);
+
+ return 0;
+}
+
+static struct platform_driver pxa_ata_driver = {
+ .probe = pxa_ata_probe,
+ .remove = pxa_ata_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(pxa_ata_driver);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("DMA-capable driver for PATA on PXA CPU");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
deleted file mode 100644
index bf45cf01775..00000000000
--- a/drivers/ata/pata_qdi.c
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * pata_qdi.c - QDI VLB ATA controllers
- * (C) 2006 Red Hat <alan@redhat.com>
- *
- * This driver mostly exists as a proof of concept for non PCI devices under
- * libata. While the QDI6580 was 'neat' in 1993 it is no longer terribly
- * useful.
- *
- * Tuning code written from the documentation at
- * http://www.ryston.cz/petr/vlb/qd6500.html
- * http://www.ryston.cz/petr/vlb/qd6580.html
- *
- * Probe code based on drivers/ide/legacy/qd65xx.c
- * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
- * Samuel Thibault <samuel.thibault@fnac.net>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <scsi/scsi_host.h>
-#include <linux/libata.h>
-#include <linux/platform_device.h>
-
-#define DRV_NAME "pata_qdi"
-#define DRV_VERSION "0.3.1"
-
-#define NR_HOST 4 /* Two 6580s */
-
-struct qdi_data {
- unsigned long timing;
- u8 clock[2];
- u8 last;
- int fast;
- struct platform_device *platform_dev;
-
-};
-
-static struct ata_host *qdi_host[NR_HOST];
-static struct qdi_data qdi_data[NR_HOST];
-static int nr_qdi_host;
-
-#ifdef MODULE
-static int probe_qdi = 1;
-#else
-static int probe_qdi;
-#endif
-
-static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
-{
- struct ata_timing t;
- struct qdi_data *qdi = ap->host->private_data;
- int active, recovery;
- u8 timing;
-
- /* Get the timing data in cycles */
- ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
-
- if (qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
- } else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
- }
- timing = (recovery << 4) | active | 0x08;
-
- qdi->clock[adev->devno] = timing;
-
- outb(timing, qdi->timing);
-}
-
-static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
-{
- struct ata_timing t;
- struct qdi_data *qdi = ap->host->private_data;
- int active, recovery;
- u8 timing;
-
- /* Get the timing data in cycles */
- ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
-
- if (qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
- } else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
- }
- timing = (recovery << 4) | active | 0x08;
-
- qdi->clock[adev->devno] = timing;
-
- outb(timing, qdi->timing);
-
- /* Clear the FIFO */
- if (adev->class != ATA_DEV_ATA)
- outb(0x5F, (qdi->timing & 0xFFF0) + 3);
-}
-
-/**
- * qdi_qc_issue - command issue
- * @qc: command pending
- *
- * Called when the libata layer is about to issue a command. We wrap
- * this interface so that we can load the correct ATA timings.
- */
-
-static unsigned int qdi_qc_issue(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct ata_device *adev = qc->dev;
- struct qdi_data *qdi = ap->host->private_data;
-
- if (qdi->clock[adev->devno] != qdi->last) {
- if (adev->pio_mode) {
- qdi->last = qdi->clock[adev->devno];
- outb(qdi->clock[adev->devno], qdi->timing);
- }
- }
- return ata_sff_qc_issue(qc);
-}
-
-static unsigned int qdi_data_xfer(struct ata_device *dev, unsigned char *buf,
- unsigned int buflen, int rw)
-{
- if (ata_id_has_dword_io(dev->id)) {
- struct ata_port *ap = dev->link->ap;
- int slop = buflen & 3;
-
- if (rw == READ)
- ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
- else
- iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
-
- if (unlikely(slop)) {
- u32 pad;
- if (rw == READ) {
- pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
- memcpy(buf + buflen - slop, &pad, slop);
- } else {
- memcpy(&pad, buf + buflen - slop, slop);
- iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
- }
- buflen += 4 - slop;
- }
- } else
- buflen = ata_sff_data_xfer(dev, buf, buflen, rw);
-
- return buflen;
-}
-
-static struct scsi_host_template qdi_sht = {
- ATA_PIO_SHT(DRV_NAME),
-};
-
-static struct ata_port_operations qdi6500_port_ops = {
- .inherits = &ata_sff_port_ops,
- .qc_issue = qdi_qc_issue,
- .sff_data_xfer = qdi_data_xfer,
- .cable_detect = ata_cable_40wire,
- .set_piomode = qdi6500_set_piomode,
-};
-
-static struct ata_port_operations qdi6580_port_ops = {
- .inherits = &qdi6500_port_ops,
- .set_piomode = qdi6580_set_piomode,
-};
-
-/**
- * qdi_init_one - attach a qdi interface
- * @type: Type to display
- * @io: I/O port start
- * @irq: interrupt line
- * @fast: True if on a > 33Mhz VLB
- *
- * Register an ISA bus IDE interface. Such interfaces are PIO and we
- * assume do not support IRQ sharing.
- */
-
-static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast)
-{
- unsigned long ctl = io + 0x206;
- struct platform_device *pdev;
- struct ata_host *host;
- struct ata_port *ap;
- void __iomem *io_addr, *ctl_addr;
- int ret;
-
- /*
- * Fill in a probe structure first of all
- */
-
- pdev = platform_device_register_simple(DRV_NAME, nr_qdi_host, NULL, 0);
- if (IS_ERR(pdev))
- return PTR_ERR(pdev);
-
- ret = -ENOMEM;
- io_addr = devm_ioport_map(&pdev->dev, io, 8);
- ctl_addr = devm_ioport_map(&pdev->dev, ctl, 1);
- if (!io_addr || !ctl_addr)
- goto fail;
-
- ret = -ENOMEM;
- host = ata_host_alloc(&pdev->dev, 1);
- if (!host)
- goto fail;
- ap = host->ports[0];
-
- if (type == 6580) {
- ap->ops = &qdi6580_port_ops;
- ap->pio_mask = 0x1F;
- ap->flags |= ATA_FLAG_SLAVE_POSS;
- } else {
- ap->ops = &qdi6500_port_ops;
- ap->pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */
- ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
- }
-
- ap->ioaddr.cmd_addr = io_addr;
- ap->ioaddr.altstatus_addr = ctl_addr;
- ap->ioaddr.ctl_addr = ctl_addr;
- ata_sff_std_ports(&ap->ioaddr);
-
- ata_port_desc(ap, "cmd %lx ctl %lx", io, ctl);
-
- /*
- * Hook in a private data structure per channel
- */
- ap->private_data = &qdi_data[nr_qdi_host];
-
- qdi_data[nr_qdi_host].timing = port;
- qdi_data[nr_qdi_host].fast = fast;
- qdi_data[nr_qdi_host].platform_dev = pdev;
-
- printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io);
-
- /* activate */
- ret = ata_host_activate(host, irq, ata_sff_interrupt, 0, &qdi_sht);
- if (ret)
- goto fail;
-
- qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev);
- return 0;
-
- fail:
- platform_device_unregister(pdev);
- return ret;
-}
-
-/**
- * qdi_init - attach qdi interfaces
- *
- * Attach qdi IDE interfaces by scanning the ports it may occupy.
- */
-
-static __init int qdi_init(void)
-{
- unsigned long flags;
- static const unsigned long qd_port[2] = { 0x30, 0xB0 };
- static const unsigned long ide_port[2] = { 0x170, 0x1F0 };
- static const int ide_irq[2] = { 14, 15 };
-
- int ct = 0;
- int i;
-
- if (probe_qdi == 0)
- return -ENODEV;
-
- /*
- * Check each possible QD65xx base address
- */
-
- for (i = 0; i < 2; i++) {
- unsigned long port = qd_port[i];
- u8 r, res;
-
-
- if (request_region(port, 2, "pata_qdi")) {
- /* Check for a card */
- local_irq_save(flags);
- r = inb_p(port);
- outb_p(0x19, port);
- res = inb_p(port);
- outb_p(r, port);
- local_irq_restore(flags);
-
- /* Fail */
- if (res == 0x19)
- {
- release_region(port, 2);
- continue;
- }
-
- /* Passes the presence test */
- r = inb_p(port + 1); /* Check port agrees with port set */
- if ((r & 2) >> 1 != i) {
- release_region(port, 2);
- continue;
- }
-
- /* Check card type */
- if ((r & 0xF0) == 0xC0) {
- /* QD6500: single channel */
- if (r & 8) {
- /* Disabled ? */
- release_region(port, 2);
- continue;
- }
- if (qdi_init_one(port, 6500, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04) == 0)
- ct++;
- }
- if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) {
- /* QD6580: dual channel */
- if (!request_region(port + 2 , 2, "pata_qdi"))
- {
- release_region(port, 2);
- continue;
- }
- res = inb(port + 3);
- if (res & 1) {
- /* Single channel mode */
- if (qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04) == 0)
- ct++;
- } else {
- /* Dual channel mode */
- if (qdi_init_one(port, 6580, 0x1F0, 14, r & 0x04) == 0)
- ct++;
- if (qdi_init_one(port + 2, 6580, 0x170, 15, r & 0x04) == 0)
- ct++;
- }
- }
- }
- }
- if (ct != 0)
- return 0;
- return -ENODEV;
-}
-
-static __exit void qdi_exit(void)
-{
- int i;
-
- for (i = 0; i < nr_qdi_host; i++) {
- ata_host_detach(qdi_host[i]);
- /* Free the control resource. The 6580 dual channel has the resources
- * claimed as a pair of 2 byte resources so we need no special cases...
- */
- release_region(qdi_data[i].timing, 2);
- platform_device_unregister(qdi_data[i].platform_dev);
- }
-}
-
-MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("low-level driver for qdi ATA");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
-module_init(qdi_init);
-module_exit(qdi_exit);
-
-module_param(probe_qdi, int, 0);
-
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index 1c0d9fa7ee5..a3f1123d17a 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -1,7 +1,7 @@
/*
* pata_radisys.c - Intel PATA/SATA controllers
*
- * (C) 2006 Red Hat <alan@redhat.com>
+ * (C) 2006 Red Hat <alan@lxorguk.ukuu.org.uk>
*
* Some parts based on ata_piix.c by Jeff Garzik and others.
*
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -81,7 +80,6 @@ static void radisys_set_piomode (struct ata_port *ap, struct ata_device *adev)
* radisys_set_dmamode - Initialize host controller PATA DMA timings
* @ap: Port whose timings we are configuring
* @adev: Device to program
- * @isich: True if the device is an ICH and has IOCFG registers
*
* Set MWDMA mode for device, in host controller PCI config space.
*
@@ -140,9 +138,9 @@ static void radisys_set_dmamode (struct ata_port *ap, struct ata_device *adev)
pci_read_config_byte(dev, 0x4A, &udma_mode);
if (adev->xfer_mode == XFER_UDMA_2)
- udma_mode &= ~ (1 << adev->devno);
+ udma_mode &= ~(2 << (adev->devno * 4));
else /* UDMA 4 */
- udma_mode |= (1 << adev->devno);
+ udma_mode |= (2 << (adev->devno * 4));
pci_write_config_byte(dev, 0x4A, udma_mode);
@@ -180,7 +178,7 @@ static unsigned int radisys_qc_issue(struct ata_queued_cmd *qc)
radisys_set_piomode(ap, adev);
}
}
- return ata_sff_qc_issue(qc);
+ return ata_bmdma_qc_issue(qc);
}
@@ -214,21 +212,18 @@ static struct ata_port_operations radisys_pata_ops = {
static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma1-2 */
- .udma_mask = 0x14, /* UDMA33/66 only */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA12_ONLY,
+ .udma_mask = ATA_UDMA24_ONLY,
.port_ops = &radisys_pata_ops,
};
const struct ata_port_info *ppi[] = { &info, NULL };
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev,
- "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
- return ata_pci_sff_init_one(pdev, ppi, &radisys_sht, NULL);
+ return ata_pci_bmdma_init_one(pdev, ppi, &radisys_sht, NULL, 0);
}
static const struct pci_device_id radisys_pci_tbl[] = {
@@ -242,28 +237,16 @@ static struct pci_driver radisys_pci_driver = {
.id_table = radisys_pci_tbl,
.probe = radisys_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init radisys_init(void)
-{
- return pci_register_driver(&radisys_pci_driver);
-}
-
-static void __exit radisys_exit(void)
-{
- pci_unregister_driver(&radisys_pci_driver);
-}
-
-module_init(radisys_init);
-module_exit(radisys_exit);
+module_pci_driver(radisys_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("SCSI low-level driver for Radisys R82600 controllers");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, radisys_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/ata/pata_rb500_cf.c b/drivers/ata/pata_rb532_cf.c
index 800ae4601f4..3c5eb8fa6bd 100644
--- a/drivers/ata/pata_rb500_cf.c
+++ b/drivers/ata/pata_rb532_cf.c
@@ -19,6 +19,7 @@
*
*/
+#include <linux/gfp.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -32,134 +33,82 @@
#include <asm/gpio.h>
-#define DRV_NAME "pata-rb500-cf"
+#define DRV_NAME "pata-rb532-cf"
#define DRV_VERSION "0.1.0"
#define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash"
#define RB500_CF_MAXPORTS 1
#define RB500_CF_IO_DELAY 400
-#define RB500_CF_REG_CMD 0x0800
+#define RB500_CF_REG_BASE 0x0800
+#define RB500_CF_REG_ERR 0x080D
#define RB500_CF_REG_CTRL 0x080E
-#define RB500_CF_REG_DATA 0x0C00
+/* 32bit buffered data register offset */
+#define RB500_CF_REG_DBUF32 0x0C00
-struct rb500_cf_info {
+struct rb532_cf_info {
void __iomem *iobase;
unsigned int gpio_line;
- int frozen;
unsigned int irq;
};
/* ------------------------------------------------------------------------ */
-static inline void rb500_pata_finish_io(struct ata_port *ap)
-{
- struct ata_host *ah = ap->host;
- struct rb500_cf_info *info = ah->private_data;
-
- ata_sff_altstatus(ap);
- ndelay(RB500_CF_IO_DELAY);
-
- set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH);
-}
-
-static void rb500_pata_exec_command(struct ata_port *ap,
- const struct ata_taskfile *tf)
-{
- writeb(tf->command, ap->ioaddr.command_addr);
- rb500_pata_finish_io(ap);
-}
-
-static void rb500_pata_data_xfer(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
-{
- struct ata_port *ap = adev->link->ap;
- void __iomem *ioaddr = ap->ioaddr.data_addr;
-
- if (write_data) {
- for (; buflen > 0; buflen--, buf++)
- writeb(*buf, ioaddr);
- } else {
- for (; buflen > 0; buflen--, buf++)
- *buf = readb(ioaddr);
- }
-
- rb500_pata_finish_io(adev->link->ap);
-}
-
-static void rb500_pata_freeze(struct ata_port *ap)
-{
- struct rb500_cf_info *info = ap->host->private_data;
-
- info->frozen = 1;
-}
-
-static void rb500_pata_thaw(struct ata_port *ap)
-{
- struct rb500_cf_info *info = ap->host->private_data;
-
- info->frozen = 0;
-}
-
-static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance)
+static irqreturn_t rb532_pata_irq_handler(int irq, void *dev_instance)
{
struct ata_host *ah = dev_instance;
- struct rb500_cf_info *info = ah->private_data;
+ struct rb532_cf_info *info = ah->private_data;
if (gpio_get_value(info->gpio_line)) {
- set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW);
- if (!info->frozen)
- ata_sff_interrupt(info->irq, dev_instance);
+ irq_set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW);
+ ata_sff_interrupt(info->irq, dev_instance);
} else {
- set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH);
+ irq_set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH);
}
return IRQ_HANDLED;
}
-static struct ata_port_operations rb500_pata_port_ops = {
+static struct ata_port_operations rb532_pata_port_ops = {
.inherits = &ata_sff_port_ops,
- .sff_exec_command = rb500_pata_exec_command,
- .sff_data_xfer = rb500_pata_data_xfer,
- .freeze = rb500_pata_freeze,
- .thaw = rb500_pata_thaw,
+ .sff_data_xfer = ata_sff_data_xfer32,
};
/* ------------------------------------------------------------------------ */
-static struct scsi_host_template rb500_pata_sht = {
+static struct scsi_host_template rb532_pata_sht = {
ATA_PIO_SHT(DRV_NAME),
};
/* ------------------------------------------------------------------------ */
-static void rb500_pata_setup_ports(struct ata_host *ah)
+static void rb532_pata_setup_ports(struct ata_host *ah)
{
- struct rb500_cf_info *info = ah->private_data;
+ struct rb532_cf_info *info = ah->private_data;
struct ata_port *ap;
ap = ah->ports[0];
- ap->ops = &rb500_pata_port_ops;
- ap->pio_mask = 0x1f; /* PIO4 */
- ap->flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO;
+ ap->ops = &rb532_pata_port_ops;
+ ap->pio_mask = ATA_PIO4;
- ap->ioaddr.cmd_addr = info->iobase + RB500_CF_REG_CMD;
+ ap->ioaddr.cmd_addr = info->iobase + RB500_CF_REG_BASE;
ap->ioaddr.ctl_addr = info->iobase + RB500_CF_REG_CTRL;
ap->ioaddr.altstatus_addr = info->iobase + RB500_CF_REG_CTRL;
ata_sff_std_ports(&ap->ioaddr);
- ap->ioaddr.data_addr = info->iobase + RB500_CF_REG_DATA;
+ ap->ioaddr.data_addr = info->iobase + RB500_CF_REG_DBUF32;
+ ap->ioaddr.error_addr = info->iobase + RB500_CF_REG_ERR;
}
-static __devinit int rb500_pata_driver_probe(struct platform_device *pdev)
+static int rb532_pata_driver_probe(struct platform_device *pdev)
{
- unsigned int irq;
+ int irq;
int gpio;
struct resource *res;
struct ata_host *ah;
- struct rb500_cf_info *info;
+ struct rb532_cf_info *info;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -202,7 +151,7 @@ static __devinit int rb500_pata_driver_probe(struct platform_device *pdev)
info->irq = irq;
info->iobase = devm_ioremap_nocache(&pdev->dev, res->start,
- res->end - res->start + 1);
+ resource_size(res));
if (!info->iobase)
return -ENOMEM;
@@ -213,10 +162,10 @@ static __devinit int rb500_pata_driver_probe(struct platform_device *pdev)
goto err_free_gpio;
}
- rb500_pata_setup_ports(ah);
+ rb532_pata_setup_ports(ah);
- ret = ata_host_activate(ah, irq, rb500_pata_irq_handler,
- IRQF_TRIGGER_LOW, &rb500_pata_sht);
+ ret = ata_host_activate(ah, irq, rb532_pata_irq_handler,
+ IRQF_TRIGGER_LOW, &rb532_pata_sht);
if (ret)
goto err_free_gpio;
@@ -228,10 +177,10 @@ err_free_gpio:
return ret;
}
-static __devexit int rb500_pata_driver_remove(struct platform_device *pdev)
+static int rb532_pata_driver_remove(struct platform_device *pdev)
{
struct ata_host *ah = platform_get_drvdata(pdev);
- struct rb500_cf_info *info = ah->private_data;
+ struct rb532_cf_info *info = ah->private_data;
ata_host_detach(ah);
gpio_free(info->gpio_line);
@@ -239,36 +188,22 @@ static __devexit int rb500_pata_driver_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver rb500_pata_platform_driver = {
- .probe = rb500_pata_driver_probe,
- .remove = __devexit_p(rb500_pata_driver_remove),
+static struct platform_driver rb532_pata_platform_driver = {
+ .probe = rb532_pata_driver_probe,
+ .remove = rb532_pata_driver_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
-/* ------------------------------------------------------------------------ */
-
#define DRV_INFO DRV_DESC " version " DRV_VERSION
-static int __init rb500_pata_module_init(void)
-{
- printk(KERN_INFO DRV_INFO "\n");
-
- return platform_driver_register(&rb500_pata_platform_driver);
-}
-
-static void __exit rb500_pata_module_exit(void)
-{
- platform_driver_unregister(&rb500_pata_platform_driver);
-}
+module_platform_driver(rb532_pata_platform_driver);
MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
MODULE_DESCRIPTION(DRV_DESC);
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
-
-module_init(rb500_pata_module_init);
-module_exit(rb500_pata_module_exit);
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/ata/pata_rdc.c b/drivers/ata/pata_rdc.c
new file mode 100644
index 00000000000..9ce5952216b
--- /dev/null
+++ b/drivers/ata/pata_rdc.c
@@ -0,0 +1,398 @@
+/*
+ * pata_rdc - Driver for later RDC PATA controllers
+ *
+ * This is actually a driver for hardware meeting
+ * INCITS 370-2004 (1510D): ATA Host Adapter Standards
+ *
+ * Based on ata_piix.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gfp.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/dmi.h>
+
+#define DRV_NAME "pata_rdc"
+#define DRV_VERSION "0.01"
+
+struct rdc_host_priv {
+ u32 saved_iocfg;
+};
+
+/**
+ * rdc_pata_cable_detect - Probe host controller cable detect info
+ * @ap: Port for which cable detect info is desired
+ *
+ * Read 80c cable indicator from ATA PCI device's PCI config
+ * register. This register is normally set by firmware (BIOS).
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static int rdc_pata_cable_detect(struct ata_port *ap)
+{
+ struct rdc_host_priv *hpriv = ap->host->private_data;
+ u8 mask;
+
+ /* check BIOS cable detect results */
+ mask = 0x30 << (2 * ap->port_no);
+ if ((hpriv->saved_iocfg & mask) == 0)
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
+}
+
+/**
+ * rdc_pata_prereset - prereset for PATA host controller
+ * @link: Target link
+ * @deadline: deadline jiffies for the operation
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static int rdc_pata_prereset(struct ata_link *link, unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ static const struct pci_bits rdc_enable_bits[] = {
+ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
+ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
+ };
+
+ if (!pci_test_config_bits(pdev, &rdc_enable_bits[ap->port_no]))
+ return -ENOENT;
+ return ata_sff_prereset(link, deadline);
+}
+
+static DEFINE_SPINLOCK(rdc_lock);
+
+/**
+ * rdc_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void rdc_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned long flags;
+ unsigned int is_slave = (adev->devno != 0);
+ unsigned int master_port= ap->port_no ? 0x42 : 0x40;
+ unsigned int slave_port = 0x44;
+ u16 master_data;
+ u8 slave_data;
+ u8 udma_enable;
+ int control = 0;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ if (pio >= 2)
+ control |= 1; /* TIME1 enable */
+ if (ata_pio_need_iordy(adev))
+ control |= 2; /* IE enable */
+
+ if (adev->class == ATA_DEV_ATA)
+ control |= 4; /* PPE enable */
+
+ spin_lock_irqsave(&rdc_lock, flags);
+
+ /* PIO configuration clears DTE unconditionally. It will be
+ * programmed in set_dmamode which is guaranteed to be called
+ * after set_piomode if any DMA mode is available.
+ */
+ pci_read_config_word(dev, master_port, &master_data);
+ if (is_slave) {
+ /* clear TIME1|IE1|PPE1|DTE1 */
+ master_data &= 0xff0f;
+ /* Enable SITRE (separate slave timing register) */
+ master_data |= 0x4000;
+ /* enable PPE1, IE1 and TIME1 as needed */
+ master_data |= (control << 4);
+ pci_read_config_byte(dev, slave_port, &slave_data);
+ slave_data &= (ap->port_no ? 0x0f : 0xf0);
+ /* Load the timing nibble for this slave */
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1])
+ << (ap->port_no ? 4 : 0);
+ } else {
+ /* clear ISP|RCT|TIME0|IE0|PPE0|DTE0 */
+ master_data &= 0xccf0;
+ /* Enable PPE, IE and TIME as appropriate */
+ master_data |= control;
+ /* load ISP and RCT */
+ master_data |=
+ (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ }
+ pci_write_config_word(dev, master_port, master_data);
+ if (is_slave)
+ pci_write_config_byte(dev, slave_port, slave_data);
+
+ /* Ensure the UDMA bit is off - it will be turned back on if
+ UDMA is selected */
+
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+ udma_enable &= ~(1 << (2 * ap->port_no + adev->devno));
+ pci_write_config_byte(dev, 0x48, udma_enable);
+
+ spin_unlock_irqrestore(&rdc_lock, flags);
+}
+
+/**
+ * rdc_set_dmamode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Drive in question
+ *
+ * Set UDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void rdc_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned long flags;
+ u8 master_port = ap->port_no ? 0x42 : 0x40;
+ u16 master_data;
+ u8 speed = adev->dma_mode;
+ int devid = adev->devno + 2 * ap->port_no;
+ u8 udma_enable = 0;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ spin_lock_irqsave(&rdc_lock, flags);
+
+ pci_read_config_word(dev, master_port, &master_data);
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+
+ if (speed >= XFER_UDMA_0) {
+ unsigned int udma = adev->dma_mode - XFER_UDMA_0;
+ u16 udma_timing;
+ u16 ideconf;
+ int u_clock, u_speed;
+
+ /*
+ * UDMA is handled by a combination of clock switching and
+ * selection of dividers
+ *
+ * Handy rule: Odd modes are UDMATIMx 01, even are 02
+ * except UDMA0 which is 00
+ */
+ u_speed = min(2 - (udma & 1), udma);
+ if (udma == 5)
+ u_clock = 0x1000; /* 100Mhz */
+ else if (udma > 2)
+ u_clock = 1; /* 66Mhz */
+ else
+ u_clock = 0; /* 33Mhz */
+
+ udma_enable |= (1 << devid);
+
+ /* Load the CT/RP selection */
+ pci_read_config_word(dev, 0x4A, &udma_timing);
+ udma_timing &= ~(3 << (4 * devid));
+ udma_timing |= u_speed << (4 * devid);
+ pci_write_config_word(dev, 0x4A, udma_timing);
+
+ /* Select a 33/66/100Mhz clock */
+ pci_read_config_word(dev, 0x54, &ideconf);
+ ideconf &= ~(0x1001 << devid);
+ ideconf |= u_clock << devid;
+ pci_write_config_word(dev, 0x54, ideconf);
+ } else {
+ /*
+ * MWDMA is driven by the PIO timings. We must also enable
+ * IORDY unconditionally along with TIME1. PPE has already
+ * been set when the PIO timing was set.
+ */
+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
+ unsigned int control;
+ u8 slave_data;
+ const unsigned int needed_pio[3] = {
+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
+ };
+ int pio = needed_pio[mwdma] - XFER_PIO_0;
+
+ control = 3; /* IORDY|TIME1 */
+
+ /* If the drive MWDMA is faster than it can do PIO then
+ we must force PIO into PIO0 */
+
+ if (adev->pio_mode < needed_pio[mwdma])
+ /* Enable DMA timing only */
+ control |= 8; /* PIO cycles in PIO0 */
+
+ if (adev->devno) { /* Slave */
+ master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */
+ master_data |= control << 4;
+ pci_read_config_byte(dev, 0x44, &slave_data);
+ slave_data &= (ap->port_no ? 0x0f : 0xf0);
+ /* Load the matching timing */
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
+ pci_write_config_byte(dev, 0x44, slave_data);
+ } else { /* Master */
+ master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY
+ and master timing bits */
+ master_data |= control;
+ master_data |=
+ (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ }
+
+ udma_enable &= ~(1 << devid);
+ pci_write_config_word(dev, master_port, master_data);
+ }
+ pci_write_config_byte(dev, 0x48, udma_enable);
+
+ spin_unlock_irqrestore(&rdc_lock, flags);
+}
+
+static struct ata_port_operations rdc_pata_ops = {
+ .inherits = &ata_bmdma32_port_ops,
+ .cable_detect = rdc_pata_cable_detect,
+ .set_piomode = rdc_set_piomode,
+ .set_dmamode = rdc_set_dmamode,
+ .prereset = rdc_pata_prereset,
+};
+
+static struct ata_port_info rdc_port_info = {
+
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA12_ONLY,
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &rdc_pata_ops,
+};
+
+static struct scsi_host_template rdc_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+};
+
+/**
+ * rdc_init_one - Register PIIX ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in rdc_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * and then hand over control to libata, for it to do the rest.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int rdc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct device *dev = &pdev->dev;
+ struct ata_port_info port_info[2];
+ const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] };
+ struct ata_host *host;
+ struct rdc_host_priv *hpriv;
+ int rc;
+
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
+
+ port_info[0] = rdc_port_info;
+ port_info[1] = rdc_port_info;
+
+ /* enable device and prepare host */
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
+
+ /* Save IOCFG, this will be used for cable detection, quirk
+ * detection and restoration on detach.
+ */
+ pci_read_config_dword(pdev, 0x54, &hpriv->saved_iocfg);
+
+ rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
+ if (rc)
+ return rc;
+ host->private_data = hpriv;
+
+ pci_intx(pdev, 1);
+
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+
+ pci_set_master(pdev);
+ return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, &rdc_sht);
+}
+
+static void rdc_remove_one(struct pci_dev *pdev)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+ struct rdc_host_priv *hpriv = host->private_data;
+
+ pci_write_config_dword(pdev, 0x54, hpriv->saved_iocfg);
+
+ ata_pci_remove_one(pdev);
+}
+
+static const struct pci_device_id rdc_pci_tbl[] = {
+ { PCI_DEVICE(0x17F3, 0x1011), },
+ { PCI_DEVICE(0x17F3, 0x1012), },
+ { } /* terminate list */
+};
+
+static struct pci_driver rdc_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = rdc_pci_tbl,
+ .probe = rdc_init_one,
+ .remove = rdc_remove_one,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
+};
+
+
+module_pci_driver(rdc_pci_driver);
+
+MODULE_AUTHOR("Alan Cox (based on ata_piix)");
+MODULE_DESCRIPTION("SCSI low-level driver for RDC PATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, rdc_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index 7dfd1f3f6f3..b3ec18c6bcc 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
@@ -38,15 +37,13 @@ static int rz1000_set_mode(struct ata_link *link, struct ata_device **unused)
{
struct ata_device *dev;
- ata_link_for_each_dev(dev, link) {
- if (ata_dev_enabled(dev)) {
- /* We don't really care */
- dev->pio_mode = XFER_PIO_0;
- dev->xfer_mode = XFER_PIO_0;
- dev->xfer_shift = ATA_SHIFT_PIO;
- dev->flags |= ATA_DFLAG_PIO;
- ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
- }
+ ata_for_each_dev(dev, link, ENABLED) {
+ /* We don't really care */
+ dev->pio_mode = XFER_PIO_0;
+ dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+ ata_dev_info(dev, "configured for PIO\n");
}
return 0;
}
@@ -87,33 +84,40 @@ static int rz1000_fifo_disable(struct pci_dev *pdev)
static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
+ .pio_mask = ATA_PIO4,
.port_ops = &rz1000_port_ops
};
const struct ata_port_info *ppi[] = { &info, NULL };
- if (!printed_version++)
- printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
if (rz1000_fifo_disable(pdev) == 0)
- return ata_pci_sff_init_one(pdev, ppi, &rz1000_sht, NULL);
+ return ata_pci_sff_init_one(pdev, ppi, &rz1000_sht, NULL, 0);
printk(KERN_ERR DRV_NAME ": failed to disable read-ahead on chipset..\n");
/* Not safe to use so skip */
return -ENODEV;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int rz1000_reinit_one(struct pci_dev *pdev)
{
- /* If this fails on resume (which is a "cant happen" case), we
+ struct ata_host *host = pci_get_drvdata(pdev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ /* If this fails on resume (which is a "can't happen" case), we
must stop as any progress risks data loss */
if (rz1000_fifo_disable(pdev))
panic("rz1000 fifo");
- return ata_pci_device_resume(pdev);
+
+ ata_host_resume(host);
+ return 0;
}
#endif
@@ -129,28 +133,16 @@ static struct pci_driver rz1000_pci_driver = {
.id_table = pata_rz1000,
.probe = rz1000_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = rz1000_reinit_one,
#endif
};
-static int __init rz1000_init(void)
-{
- return pci_register_driver(&rz1000_pci_driver);
-}
-
-static void __exit rz1000_exit(void)
-{
- pci_unregister_driver(&rz1000_pci_driver);
-}
+module_pci_driver(rz1000_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for RZ1000 PCI ATA");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, pata_rz1000);
MODULE_VERSION(DRV_VERSION);
-
-module_init(rz1000_init);
-module_exit(rz1000_exit);
-
diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c
new file mode 100644
index 00000000000..fb528831fb9
--- /dev/null
+++ b/drivers/ata/pata_samsung_cf.c
@@ -0,0 +1,684 @@
+/*
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * PATA driver for Samsung SoCs.
+ * Supports CF Interface in True IDE mode. Currently only PIO mode has been
+ * implemented; UDMA support has to be added.
+ *
+ * Based on:
+ * PATA driver for AT91SAM9260 Static Memory Controller
+ * PATA driver for Toshiba SCC controller
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/platform_data/ata-samsung_cf.h>
+
+#define DRV_NAME "pata_samsung_cf"
+#define DRV_VERSION "0.1"
+
+#define S3C_CFATA_REG(x) (x)
+#define S3C_CFATA_MUX S3C_CFATA_REG(0x0)
+#define S3C_ATA_CTRL S3C_CFATA_REG(0x0)
+#define S3C_ATA_CMD S3C_CFATA_REG(0x8)
+#define S3C_ATA_IRQ S3C_CFATA_REG(0x10)
+#define S3C_ATA_IRQ_MSK S3C_CFATA_REG(0x14)
+#define S3C_ATA_CFG S3C_CFATA_REG(0x18)
+
+#define S3C_ATA_PIO_TIME S3C_CFATA_REG(0x2c)
+#define S3C_ATA_PIO_DTR S3C_CFATA_REG(0x54)
+#define S3C_ATA_PIO_FED S3C_CFATA_REG(0x58)
+#define S3C_ATA_PIO_SCR S3C_CFATA_REG(0x5c)
+#define S3C_ATA_PIO_LLR S3C_CFATA_REG(0x60)
+#define S3C_ATA_PIO_LMR S3C_CFATA_REG(0x64)
+#define S3C_ATA_PIO_LHR S3C_CFATA_REG(0x68)
+#define S3C_ATA_PIO_DVR S3C_CFATA_REG(0x6c)
+#define S3C_ATA_PIO_CSD S3C_CFATA_REG(0x70)
+#define S3C_ATA_PIO_DAD S3C_CFATA_REG(0x74)
+#define S3C_ATA_PIO_RDATA S3C_CFATA_REG(0x7c)
+
+#define S3C_CFATA_MUX_TRUEIDE 0x01
+#define S3C_ATA_CFG_SWAP 0x40
+#define S3C_ATA_CFG_IORDYEN 0x02
+
+enum s3c_cpu_type {
+ TYPE_S3C64XX,
+ TYPE_S5PC100,
+ TYPE_S5PV210,
+};
+
+/*
+ * struct s3c_ide_info - S3C PATA instance.
+ * @clk: The clock resource for this controller.
+ * @ide_addr: The area mapped for the hardware registers.
+ * @sfr_addr: The area mapped for the special function registers.
+ * @irq: The IRQ number we are using.
+ * @cpu_type: The exact type of this controller.
+ * @fifo_status_reg: The ATA_FIFO_STATUS register offset.
+ */
+struct s3c_ide_info {
+ struct clk *clk;
+ void __iomem *ide_addr;
+ void __iomem *sfr_addr;
+ unsigned int irq;
+ enum s3c_cpu_type cpu_type;
+ unsigned int fifo_status_reg;
+};
+
+static void pata_s3c_set_endian(void __iomem *s3c_ide_regbase, u8 mode)
+{
+ u32 reg = readl(s3c_ide_regbase + S3C_ATA_CFG);
+ reg = mode ? (reg & ~S3C_ATA_CFG_SWAP) : (reg | S3C_ATA_CFG_SWAP);
+ writel(reg, s3c_ide_regbase + S3C_ATA_CFG);
+}
+
+static void pata_s3c_cfg_mode(void __iomem *s3c_ide_sfrbase)
+{
+ /* Select true-ide as the internal operating mode */
+ writel(readl(s3c_ide_sfrbase + S3C_CFATA_MUX) | S3C_CFATA_MUX_TRUEIDE,
+ s3c_ide_sfrbase + S3C_CFATA_MUX);
+}
+
+static unsigned long
+pata_s3c_setup_timing(struct s3c_ide_info *info, const struct ata_timing *ata)
+{
+ int t1 = ata->setup;
+ int t2 = ata->act8b;
+ int t2i = ata->rec8b;
+ ulong piotime;
+
+ piotime = ((t2i & 0xff) << 12) | ((t2 & 0xff) << 4) | (t1 & 0xf);
+
+ return piotime;
+}
+
+static void pata_s3c_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct s3c_ide_info *info = ap->host->private_data;
+ struct ata_timing timing;
+ int cycle_time;
+ ulong ata_cfg = readl(info->ide_addr + S3C_ATA_CFG);
+ ulong piotime;
+
+ /* Enables IORDY if mode requires it */
+ if (ata_pio_need_iordy(adev))
+ ata_cfg |= S3C_ATA_CFG_IORDYEN;
+ else
+ ata_cfg &= ~S3C_ATA_CFG_IORDYEN;
+
+ cycle_time = (int)(1000000000UL / clk_get_rate(info->clk));
+
+ ata_timing_compute(adev, adev->pio_mode, &timing,
+ cycle_time * 1000, 0);
+
+ piotime = pata_s3c_setup_timing(info, &timing);
+
+ writel(ata_cfg, info->ide_addr + S3C_ATA_CFG);
+ writel(piotime, info->ide_addr + S3C_ATA_PIO_TIME);
+}
+
+/*
+ * Waits until the IDE controller is able to perform next read/write
+ * operation to the disk. Needed for 64XX series boards only.
+ */
+static int wait_for_host_ready(struct s3c_ide_info *info)
+{
+ ulong timeout;
+ void __iomem *fifo_reg = info->ide_addr + info->fifo_status_reg;
+
+ /* wait for maximum of 20 msec */
+ timeout = jiffies + msecs_to_jiffies(20);
+ while (time_before(jiffies, timeout)) {
+ if ((readl(fifo_reg) >> 28) == 0)
+ return 0;
+ }
+ return -EBUSY;
+}
+
+/*
+ * Writes to one of the task file registers.
+ */
+static void ata_outb(struct ata_host *host, u8 addr, void __iomem *reg)
+{
+ struct s3c_ide_info *info = host->private_data;
+
+ wait_for_host_ready(info);
+ writeb(addr, reg);
+}
+
+/*
+ * Reads from one of the task file registers.
+ */
+static u8 ata_inb(struct ata_host *host, void __iomem *reg)
+{
+ struct s3c_ide_info *info = host->private_data;
+ u8 temp;
+
+ wait_for_host_ready(info);
+ (void) readb(reg);
+ wait_for_host_ready(info);
+ temp = readb(info->ide_addr + S3C_ATA_PIO_RDATA);
+ return temp;
+}
+
+/*
+ * pata_s3c_tf_load - send taskfile registers to host controller
+ */
+static void pata_s3c_tf_load(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ ata_outb(ap->host, tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ ata_outb(ap->host, tf->hob_feature, ioaddr->feature_addr);
+ ata_outb(ap->host, tf->hob_nsect, ioaddr->nsect_addr);
+ ata_outb(ap->host, tf->hob_lbal, ioaddr->lbal_addr);
+ ata_outb(ap->host, tf->hob_lbam, ioaddr->lbam_addr);
+ ata_outb(ap->host, tf->hob_lbah, ioaddr->lbah_addr);
+ }
+
+ if (is_addr) {
+ ata_outb(ap->host, tf->feature, ioaddr->feature_addr);
+ ata_outb(ap->host, tf->nsect, ioaddr->nsect_addr);
+ ata_outb(ap->host, tf->lbal, ioaddr->lbal_addr);
+ ata_outb(ap->host, tf->lbam, ioaddr->lbam_addr);
+ ata_outb(ap->host, tf->lbah, ioaddr->lbah_addr);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE)
+ ata_outb(ap->host, tf->device, ioaddr->device_addr);
+
+ ata_wait_idle(ap);
+}
+
+/*
+ * pata_s3c_tf_read - input device's ATA taskfile shadow registers
+ */
+static void pata_s3c_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->feature = ata_inb(ap->host, ioaddr->error_addr);
+ tf->nsect = ata_inb(ap->host, ioaddr->nsect_addr);
+ tf->lbal = ata_inb(ap->host, ioaddr->lbal_addr);
+ tf->lbam = ata_inb(ap->host, ioaddr->lbam_addr);
+ tf->lbah = ata_inb(ap->host, ioaddr->lbah_addr);
+ tf->device = ata_inb(ap->host, ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ ata_outb(ap->host, tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+ tf->hob_feature = ata_inb(ap->host, ioaddr->error_addr);
+ tf->hob_nsect = ata_inb(ap->host, ioaddr->nsect_addr);
+ tf->hob_lbal = ata_inb(ap->host, ioaddr->lbal_addr);
+ tf->hob_lbam = ata_inb(ap->host, ioaddr->lbam_addr);
+ tf->hob_lbah = ata_inb(ap->host, ioaddr->lbah_addr);
+ ata_outb(ap->host, tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ }
+}
+
+/*
+ * pata_s3c_exec_command - issue ATA command to host controller
+ */
+static void pata_s3c_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ ata_outb(ap->host, tf->command, ap->ioaddr.command_addr);
+ ata_sff_pause(ap);
+}
+
+/*
+ * pata_s3c_check_status - Read device status register
+ */
+static u8 pata_s3c_check_status(struct ata_port *ap)
+{
+ return ata_inb(ap->host, ap->ioaddr.status_addr);
+}
+
+/*
+ * pata_s3c_check_altstatus - Read alternate device status register
+ */
+static u8 pata_s3c_check_altstatus(struct ata_port *ap)
+{
+ return ata_inb(ap->host, ap->ioaddr.altstatus_addr);
+}
+
+/*
+ * pata_s3c_data_xfer - Transfer data by PIO
+ */
+static unsigned int pata_s3c_data_xfer(struct ata_device *dev,
+ unsigned char *buf, unsigned int buflen, int rw)
+{
+ struct ata_port *ap = dev->link->ap;
+ struct s3c_ide_info *info = ap->host->private_data;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned int words = buflen >> 1, i;
+ u16 *data_ptr = (u16 *)buf;
+
+ /* Requires wait same as in ata_inb/ata_outb */
+ if (rw == READ)
+ for (i = 0; i < words; i++, data_ptr++) {
+ wait_for_host_ready(info);
+ (void) readw(data_addr);
+ wait_for_host_ready(info);
+ *data_ptr = readw(info->ide_addr
+ + S3C_ATA_PIO_RDATA);
+ }
+ else
+ for (i = 0; i < words; i++, data_ptr++) {
+ wait_for_host_ready(info);
+ writew(*data_ptr, data_addr);
+ }
+
+ if (buflen & 0x01)
+ dev_err(ap->dev, "unexpected trailing data\n");
+
+ return words << 1;
+}
+
+/*
+ * pata_s3c_dev_select - Select device on ATA bus
+ */
+static void pata_s3c_dev_select(struct ata_port *ap, unsigned int device)
+{
+ u8 tmp = ATA_DEVICE_OBS;
+
+ if (device != 0)
+ tmp |= ATA_DEV1;
+
+ ata_outb(ap->host, tmp, ap->ioaddr.device_addr);
+ ata_sff_pause(ap);
+}
+
+/*
+ * pata_s3c_devchk - PATA device presence detection
+ */
+static unsigned int pata_s3c_devchk(struct ata_port *ap,
+ unsigned int device)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ u8 nsect, lbal;
+
+ pata_s3c_dev_select(ap, device);
+
+ ata_outb(ap->host, 0x55, ioaddr->nsect_addr);
+ ata_outb(ap->host, 0xaa, ioaddr->lbal_addr);
+
+ ata_outb(ap->host, 0xaa, ioaddr->nsect_addr);
+ ata_outb(ap->host, 0x55, ioaddr->lbal_addr);
+
+ ata_outb(ap->host, 0x55, ioaddr->nsect_addr);
+ ata_outb(ap->host, 0xaa, ioaddr->lbal_addr);
+
+ nsect = ata_inb(ap->host, ioaddr->nsect_addr);
+ lbal = ata_inb(ap->host, ioaddr->lbal_addr);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return 1; /* we found a device */
+
+ return 0; /* nothing found */
+}
+
+/*
+ * pata_s3c_wait_after_reset - wait for devices to become ready after reset
+ */
+static int pata_s3c_wait_after_reset(struct ata_link *link,
+ unsigned long deadline)
+{
+ int rc;
+
+ ata_msleep(link->ap, ATA_WAIT_AFTER_RESET);
+
+ /* always check readiness of the master device */
+ rc = ata_sff_wait_ready(link, deadline);
+ /* -ENODEV means the odd clown forgot the D7 pulldown resistor
+ * and TF status is 0xff, bail out on it too.
+ */
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+/*
+ * pata_s3c_bus_softreset - PATA device software reset
+ */
+static unsigned int pata_s3c_bus_softreset(struct ata_port *ap,
+ unsigned long deadline)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ /* software reset. causes dev0 to be selected */
+ ata_outb(ap->host, ap->ctl, ioaddr->ctl_addr);
+ udelay(20);
+ ata_outb(ap->host, ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+ udelay(20);
+ ata_outb(ap->host, ap->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = ap->ctl;
+
+ return pata_s3c_wait_after_reset(&ap->link, deadline);
+}
+
+/*
+ * pata_s3c_softreset - reset host port via ATA SRST
+ */
+static int pata_s3c_softreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ unsigned int devmask = 0;
+ int rc;
+ u8 err;
+
+ /* determine if device 0 is present */
+ if (pata_s3c_devchk(ap, 0))
+ devmask |= (1 << 0);
+
+ /* select device 0 again */
+ pata_s3c_dev_select(ap, 0);
+
+ /* issue bus reset */
+ rc = pata_s3c_bus_softreset(ap, deadline);
+ /* if link is occupied, -ENODEV too is an error */
+ if (rc && rc != -ENODEV) {
+ ata_link_err(link, "SRST failed (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_sff_dev_classify(&ap->link.device[0],
+ devmask & (1 << 0), &err);
+
+ return 0;
+}
+
+/*
+ * pata_s3c_set_devctl - Write device control register
+ */
+static void pata_s3c_set_devctl(struct ata_port *ap, u8 ctl)
+{
+ ata_outb(ap->host, ctl, ap->ioaddr.ctl_addr);
+}
+
+static struct scsi_host_template pata_s3c_sht = {
+ ATA_PIO_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations pata_s3c_port_ops = {
+ .inherits = &ata_sff_port_ops,
+ .sff_check_status = pata_s3c_check_status,
+ .sff_check_altstatus = pata_s3c_check_altstatus,
+ .sff_tf_load = pata_s3c_tf_load,
+ .sff_tf_read = pata_s3c_tf_read,
+ .sff_data_xfer = pata_s3c_data_xfer,
+ .sff_exec_command = pata_s3c_exec_command,
+ .sff_dev_select = pata_s3c_dev_select,
+ .sff_set_devctl = pata_s3c_set_devctl,
+ .softreset = pata_s3c_softreset,
+ .set_piomode = pata_s3c_set_piomode,
+};
+
+static struct ata_port_operations pata_s5p_port_ops = {
+ .inherits = &ata_sff_port_ops,
+ .set_piomode = pata_s3c_set_piomode,
+};
+
+static void pata_s3c_enable(void __iomem *s3c_ide_regbase, bool state)
+{
+ u32 temp = readl(s3c_ide_regbase + S3C_ATA_CTRL);
+ temp = state ? (temp | 1) : (temp & ~1);
+ writel(temp, s3c_ide_regbase + S3C_ATA_CTRL);
+}
+
+static irqreturn_t pata_s3c_irq(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ struct s3c_ide_info *info = host->private_data;
+ u32 reg;
+
+ reg = readl(info->ide_addr + S3C_ATA_IRQ);
+ writel(reg, info->ide_addr + S3C_ATA_IRQ);
+
+ return ata_sff_interrupt(irq, dev_instance);
+}
+
+static void pata_s3c_hwinit(struct s3c_ide_info *info,
+ struct s3c_ide_platdata *pdata)
+{
+ switch (info->cpu_type) {
+ case TYPE_S3C64XX:
+ /* Configure as big endian */
+ pata_s3c_cfg_mode(info->sfr_addr);
+ pata_s3c_set_endian(info->ide_addr, 1);
+ pata_s3c_enable(info->ide_addr, true);
+ msleep(100);
+
+ /* Remove IRQ Status */
+ writel(0x1f, info->ide_addr + S3C_ATA_IRQ);
+ writel(0x1b, info->ide_addr + S3C_ATA_IRQ_MSK);
+ break;
+
+ case TYPE_S5PC100:
+ pata_s3c_cfg_mode(info->sfr_addr);
+ /* FALLTHROUGH */
+
+ case TYPE_S5PV210:
+ /* Configure as little endian */
+ pata_s3c_set_endian(info->ide_addr, 0);
+ pata_s3c_enable(info->ide_addr, true);
+ msleep(100);
+
+ /* Remove IRQ Status */
+ writel(0x3f, info->ide_addr + S3C_ATA_IRQ);
+ writel(0x3f, info->ide_addr + S3C_ATA_IRQ_MSK);
+ break;
+
+ default:
+ BUG();
+ }
+}
+
+static int __init pata_s3c_probe(struct platform_device *pdev)
+{
+ struct s3c_ide_platdata *pdata = dev_get_platdata(&pdev->dev);
+ struct device *dev = &pdev->dev;
+ struct s3c_ide_info *info;
+ struct resource *res;
+ struct ata_port *ap;
+ struct ata_host *host;
+ enum s3c_cpu_type cpu_type;
+ int ret;
+
+ cpu_type = platform_get_device_id(pdev)->driver_data;
+
+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ dev_err(dev, "failed to allocate memory for device data\n");
+ return -ENOMEM;
+ }
+
+ info->irq = platform_get_irq(pdev, 0);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ info->ide_addr = devm_ioremap_resource(dev, res);
+ if (IS_ERR(info->ide_addr))
+ return PTR_ERR(info->ide_addr);
+
+ info->clk = devm_clk_get(&pdev->dev, "cfcon");
+ if (IS_ERR(info->clk)) {
+ dev_err(dev, "failed to get access to cf controller clock\n");
+ ret = PTR_ERR(info->clk);
+ info->clk = NULL;
+ return ret;
+ }
+
+ clk_enable(info->clk);
+
+ /* init ata host */
+ host = ata_host_alloc(dev, 1);
+ if (!host) {
+ dev_err(dev, "failed to allocate ide host\n");
+ ret = -ENOMEM;
+ goto stop_clk;
+ }
+
+ ap = host->ports[0];
+ ap->pio_mask = ATA_PIO4;
+
+ if (cpu_type == TYPE_S3C64XX) {
+ ap->ops = &pata_s3c_port_ops;
+ info->sfr_addr = info->ide_addr + 0x1800;
+ info->ide_addr += 0x1900;
+ info->fifo_status_reg = 0x94;
+ } else if (cpu_type == TYPE_S5PC100) {
+ ap->ops = &pata_s5p_port_ops;
+ info->sfr_addr = info->ide_addr + 0x1800;
+ info->ide_addr += 0x1900;
+ info->fifo_status_reg = 0x84;
+ } else {
+ ap->ops = &pata_s5p_port_ops;
+ info->fifo_status_reg = 0x84;
+ }
+
+ info->cpu_type = cpu_type;
+
+ if (info->irq <= 0) {
+ ap->flags |= ATA_FLAG_PIO_POLLING;
+ info->irq = 0;
+ ata_port_desc(ap, "no IRQ, using PIO polling\n");
+ }
+
+ ap->ioaddr.cmd_addr = info->ide_addr + S3C_ATA_CMD;
+ ap->ioaddr.data_addr = info->ide_addr + S3C_ATA_PIO_DTR;
+ ap->ioaddr.error_addr = info->ide_addr + S3C_ATA_PIO_FED;
+ ap->ioaddr.feature_addr = info->ide_addr + S3C_ATA_PIO_FED;
+ ap->ioaddr.nsect_addr = info->ide_addr + S3C_ATA_PIO_SCR;
+ ap->ioaddr.lbal_addr = info->ide_addr + S3C_ATA_PIO_LLR;
+ ap->ioaddr.lbam_addr = info->ide_addr + S3C_ATA_PIO_LMR;
+ ap->ioaddr.lbah_addr = info->ide_addr + S3C_ATA_PIO_LHR;
+ ap->ioaddr.device_addr = info->ide_addr + S3C_ATA_PIO_DVR;
+ ap->ioaddr.status_addr = info->ide_addr + S3C_ATA_PIO_CSD;
+ ap->ioaddr.command_addr = info->ide_addr + S3C_ATA_PIO_CSD;
+ ap->ioaddr.altstatus_addr = info->ide_addr + S3C_ATA_PIO_DAD;
+ ap->ioaddr.ctl_addr = info->ide_addr + S3C_ATA_PIO_DAD;
+
+ ata_port_desc(ap, "mmio cmd 0x%llx ",
+ (unsigned long long)res->start);
+
+ host->private_data = info;
+
+ if (pdata && pdata->setup_gpio)
+ pdata->setup_gpio();
+
+ /* Set endianness and enable the interface */
+ pata_s3c_hwinit(info, pdata);
+
+ platform_set_drvdata(pdev, host);
+
+ ret = ata_host_activate(host, info->irq,
+ info->irq ? pata_s3c_irq : NULL,
+ 0, &pata_s3c_sht);
+ if (ret)
+ goto stop_clk;
+
+ return 0;
+
+stop_clk:
+ clk_disable(info->clk);
+ return ret;
+}
+
+static int __exit pata_s3c_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct s3c_ide_info *info = host->private_data;
+
+ ata_host_detach(host);
+
+ clk_disable(info->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pata_s3c_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ata_host *host = platform_get_drvdata(pdev);
+
+ return ata_host_suspend(host, PMSG_SUSPEND);
+}
+
+static int pata_s3c_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct s3c_ide_platdata *pdata = dev_get_platdata(&pdev->dev);
+ struct s3c_ide_info *info = host->private_data;
+
+ pata_s3c_hwinit(info, pdata);
+ ata_host_resume(host);
+
+ return 0;
+}
+
+static const struct dev_pm_ops pata_s3c_pm_ops = {
+ .suspend = pata_s3c_suspend,
+ .resume = pata_s3c_resume,
+};
+#endif
+
+/* driver device registration */
+static struct platform_device_id pata_s3c_driver_ids[] = {
+ {
+ .name = "s3c64xx-pata",
+ .driver_data = TYPE_S3C64XX,
+ }, {
+ .name = "s5pc100-pata",
+ .driver_data = TYPE_S5PC100,
+ }, {
+ .name = "s5pv210-pata",
+ .driver_data = TYPE_S5PV210,
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(platform, pata_s3c_driver_ids);
+
+static struct platform_driver pata_s3c_driver = {
+ .remove = __exit_p(pata_s3c_remove),
+ .id_table = pata_s3c_driver_ids,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM_SLEEP
+ .pm = &pata_s3c_pm_ops,
+#endif
+ },
+};
+
+module_platform_driver_probe(pata_s3c_driver, pata_s3c_probe);
+
+MODULE_AUTHOR("Abhilash Kesavan, <a.kesavan@samsung.com>");
+MODULE_DESCRIPTION("low-level driver for Samsung PATA controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index cbab397e3db..c71de5d680d 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -1,8 +1,7 @@
/*
- * New ATA layer SC1200 driver Alan Cox <alan@redhat.com>
+ * New ATA layer SC1200 driver Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* TODO: Mode selection filtering
- * TODO: Can't enable second channel until ATA core has serialize
* TODO: Needs custom DMA cleanup code
*
* Based very heavily on
@@ -33,13 +32,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
-#define DRV_NAME "sc1200"
+#define DRV_NAME "pata_sc1200"
#define DRV_VERSION "0.2.6"
#define SC1200_REV_A 0x00
@@ -87,10 +85,14 @@ static int sc1200_clock(void)
static void sc1200_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
static const u32 pio_timings[4][5] = {
- {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, // format0 33Mhz
- {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}, // format1, 33Mhz
- {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021}, // format1, 48Mhz
- {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131} // format1, 66Mhz
+ /* format0, 33Mhz */
+ { 0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010 },
+ /* format1, 33Mhz */
+ { 0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010 },
+ /* format1, 48Mhz */
+ { 0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021 },
+ /* format1, 66Mhz */
+ { 0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131 }
};
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -167,15 +169,40 @@ static unsigned int sc1200_qc_issue(struct ata_queued_cmd *qc)
struct ata_device *prev = ap->private_data;
/* See if the DMA settings could be wrong */
- if (adev->dma_mode != 0 && adev != prev && prev != NULL) {
+ if (ata_dma_enabled(adev) && adev != prev && prev != NULL) {
/* Maybe, but do the channels match MWDMA/UDMA ? */
- if ((adev->dma_mode >= XFER_UDMA_0 && prev->dma_mode < XFER_UDMA_0) ||
- (adev->dma_mode < XFER_UDMA_0 && prev->dma_mode >= XFER_UDMA_0))
+ if ((ata_using_udma(adev) && !ata_using_udma(prev)) ||
+ (ata_using_udma(prev) && !ata_using_udma(adev)))
/* Switch the mode bits */
sc1200_set_dmamode(ap, adev);
}
- return ata_sff_qc_issue(qc);
+ return ata_bmdma_qc_issue(qc);
+}
+
+/**
+ * sc1200_qc_defer - implement serialization
+ * @qc: command
+ *
+ * Serialize command issue on this controller.
+ */
+
+static int sc1200_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_host *host = qc->ap->host;
+ struct ata_port *alt = host->ports[1 ^ qc->ap->port_no];
+ int rc;
+
+ /* First apply the usual rules */
+ rc = ata_std_qc_defer(qc);
+ if (rc != 0)
+ return rc;
+
+ /* Now apply serialization rules. Only allow a command if the
+ other channel state machine is idle */
+ if (alt && alt->qc_active)
+ return ATA_DEFER_PORT;
+ return 0;
}
static struct scsi_host_template sc1200_sht = {
@@ -185,8 +212,9 @@ static struct scsi_host_template sc1200_sht = {
static struct ata_port_operations sc1200_port_ops = {
.inherits = &ata_bmdma_port_ops,
- .qc_prep = ata_sff_dumb_qc_prep,
+ .qc_prep = ata_bmdma_dumb_qc_prep,
.qc_issue = sc1200_qc_issue,
+ .qc_defer = sc1200_qc_defer,
.cable_detect = ata_cable_40wire,
.set_piomode = sc1200_set_piomode,
.set_dmamode = sc1200_set_dmamode,
@@ -205,15 +233,14 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
.port_ops = &sc1200_port_ops
};
- /* Can't enable port 2 yet, see top comments */
- const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
+ const struct ata_port_info *ppi[] = { &info, NULL };
- return ata_pci_sff_init_one(dev, ppi, &sc1200_sht, NULL);
+ return ata_pci_bmdma_init_one(dev, ppi, &sc1200_sht, NULL, 0);
}
static const struct pci_device_id sc1200[] = {
@@ -227,27 +254,16 @@ static struct pci_driver sc1200_pci_driver = {
.id_table = sc1200,
.probe = sc1200_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init sc1200_init(void)
-{
- return pci_register_driver(&sc1200_pci_driver);
-}
-
-static void __exit sc1200_exit(void)
-{
- pci_unregister_driver(&sc1200_pci_driver);
-}
+module_pci_driver(sc1200_pci_driver);
MODULE_AUTHOR("Alan Cox, Mark Lord");
MODULE_DESCRIPTION("low-level driver for the NS/AMD SC1200");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, sc1200);
MODULE_VERSION(DRV_VERSION);
-
-module_init(sc1200_init);
-module_exit(sc1200_exit);
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index e965b251ca2..4e006d74bef 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -8,7 +8,7 @@
* Copyright 2003-2005 Jeff Garzik
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
* Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
+ * Copyright (C) 2003 Red Hat Inc
*
* and drivers/ata/ahci.c:
* Copyright 2004-2005 Red Hat, Inc.
@@ -35,7 +35,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -168,8 +167,7 @@ static const unsigned long JCACTSELtbl[2][7] = {
};
static const struct pci_device_id scc_pci_tbl[] = {
- {PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA), 0},
{ } /* terminate list */
};
@@ -210,7 +208,6 @@ static void scc_set_piomode (struct ata_port *ap, struct ata_device *adev)
* scc_set_dmamode - Initialize host controller PATA DMA timings
* @ap: Port whose timings we are configuring
* @adev: um
- * @udma: udma mode, 0 - 6
*
* Set UDMA mode for device.
*
@@ -266,7 +263,7 @@ unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask)
printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
mask &= ~(0xE0 << ATA_SHIFT_UDMA);
}
- return ata_bmdma_mode_filter(adev, mask);
+ return mask;
}
/**
@@ -417,6 +414,17 @@ static void scc_dev_select (struct ata_port *ap, unsigned int device)
}
/**
+ * scc_set_devctl - Write device control reg
+ * @ap: port where the device is
+ * @ctl: value to write
+ */
+
+static void scc_set_devctl(struct ata_port *ap, u8 ctl)
+{
+ out_be32(ap->ioaddr.ctl_addr, ctl);
+}
+
+/**
* scc_bmdma_setup - Set up PCI IDE BMDMA transaction
* @qc: Info associated with this ATA transaction.
*
@@ -431,7 +439,7 @@ static void scc_bmdma_setup (struct ata_queued_cmd *qc)
void __iomem *mmio = ap->ioaddr.bmdma_addr;
/* load PRD table addr */
- out_be32(mmio + SCC_DMA_TABLE_OFS, ap->prd_dma);
+ out_be32(mmio + SCC_DMA_TABLE_OFS, ap->bmdma_prd_dma);
/* specify data direction, triple-check start bit is clear */
dmactl = in_be32(mmio + SCC_DMA_CMD);
@@ -502,8 +510,8 @@ static unsigned int scc_devchk (struct ata_port *ap,
* Note: Original code is ata_sff_wait_after_reset
*/
-int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
- unsigned long deadline)
+static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
+ unsigned long deadline)
{
struct ata_port *ap = link->ap;
struct ata_ioports *ioaddr = &ap->ioaddr;
@@ -521,7 +529,7 @@ int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
*
* Old drivers/ide uses the 2mS rule and then waits for ready.
*/
- msleep(150);
+ ata_msleep(ap, 150);
/* always check readiness of the master device */
rc = ata_sff_wait_ready(link, deadline);
@@ -550,7 +558,7 @@ int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
lbal = in_be32(ioaddr->lbal_addr);
if ((nsect == 1) && (lbal == 1))
break;
- msleep(50); /* give drive a breather */
+ ata_msleep(ap, 50); /* give drive a breather */
}
rc = ata_sff_wait_ready(link, deadline);
@@ -628,8 +636,7 @@ static int scc_softreset(struct ata_link *link, unsigned int *classes,
DPRINTK("about to softreset, devmask=%x\n", devmask);
err_mask = scc_bus_softreset(ap, devmask, deadline);
if (err_mask) {
- ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
- err_mask);
+ ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", err_mask);
return -EIO;
}
@@ -696,7 +703,7 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc)
if (reg & INTSTS_BMSINT) {
unsigned int classes;
- unsigned long deadline = jiffies + ATA_TMOUT_BOOT;
+ unsigned long deadline = ata_deadline(jiffies, ATA_TMOUT_BOOT);
printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME);
out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT);
/* TBD: SW reset */
@@ -726,7 +733,7 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc)
in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
- ata_sff_altstatus(ap); /* dummy read */
+ ata_sff_dma_pause(ap); /* dummy read */
}
/**
@@ -747,7 +754,8 @@ static u8 scc_bmdma_status (struct ata_port *ap)
return host_stat;
/* errata A252,A308 workaround: Step4 */
- if ((ata_sff_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ))
+ if ((scc_check_altstatus(ap) & ATA_ERR)
+ && (int_status & INTSTS_INTRQ))
return (host_stat | ATA_DMA_INTR);
/* errata A308 workaround Step5 */
@@ -817,66 +825,6 @@ static unsigned int scc_data_xfer (struct ata_device *dev, unsigned char *buf,
}
/**
- * scc_irq_on - Enable interrupts on a port.
- * @ap: Port on which interrupts are enabled.
- *
- * Note: Original code is ata_sff_irq_on().
- */
-
-static u8 scc_irq_on (struct ata_port *ap)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- u8 tmp;
-
- ap->ctl &= ~ATA_NIEN;
- ap->last_ctl = ap->ctl;
-
- out_be32(ioaddr->ctl_addr, ap->ctl);
- tmp = ata_wait_idle(ap);
-
- ap->ops->sff_irq_clear(ap);
-
- return tmp;
-}
-
-/**
- * scc_freeze - Freeze BMDMA controller port
- * @ap: port to freeze
- *
- * Note: Original code is ata_sff_freeze().
- */
-
-static void scc_freeze (struct ata_port *ap)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
- ap->ctl |= ATA_NIEN;
- ap->last_ctl = ap->ctl;
-
- out_be32(ioaddr->ctl_addr, ap->ctl);
-
- /* Under certain circumstances, some controllers raise IRQ on
- * ATA_NIEN manipulation. Also, many controllers fail to mask
- * previously pending IRQ on ATA_NIEN assertion. Clear it.
- */
- ap->ops->sff_check_status(ap);
-
- ap->ops->sff_irq_clear(ap);
-}
-
-/**
- * scc_pata_prereset - prepare for reset
- * @ap: ATA port to be reset
- * @deadline: deadline jiffies for the operation
- */
-
-static int scc_pata_prereset(struct ata_link *link, unsigned long deadline)
-{
- link->ap->cbl = ATA_CBL_PATA80;
- return ata_sff_prereset(link, deadline);
-}
-
-/**
* scc_postreset - standard postreset callback
* @ap: the target ata_port
* @classes: classes of attached devices
@@ -903,8 +851,7 @@ static void scc_postreset(struct ata_link *link, unsigned int *classes)
}
/* set up device control */
- if (ap->ioaddr.ctl_addr)
- out_be32(ap->ioaddr.ctl_addr, ap->ctl);
+ out_be32(ap->ioaddr.ctl_addr, ap->ctl);
DPRINTK("EXIT\n");
}
@@ -913,7 +860,7 @@ static void scc_postreset(struct ata_link *link, unsigned int *classes)
* scc_irq_clear - Clear PCI IDE BMDMA interrupt.
* @ap: Port associated with this ATA transaction.
*
- * Note: Original code is ata_sff_irq_clear().
+ * Note: Original code is ata_bmdma_irq_clear().
*/
static void scc_irq_clear (struct ata_port *ap)
@@ -930,7 +877,7 @@ static void scc_irq_clear (struct ata_port *ap)
* scc_port_start - Set port up for dma.
* @ap: Port to initialize
*
- * Allocate space for PRD table using ata_port_start().
+ * Allocate space for PRD table using ata_bmdma_port_start().
* Set PRD table address for PTERADD. (PRD Transfer End Read)
*/
@@ -939,11 +886,11 @@ static int scc_port_start (struct ata_port *ap)
void __iomem *mmio = ap->ioaddr.bmdma_addr;
int rc;
- rc = ata_port_start(ap);
+ rc = ata_bmdma_port_start(ap);
if (rc)
return rc;
- out_be32(mmio + SCC_DMA_PTERADD, ap->prd_dma);
+ out_be32(mmio + SCC_DMA_PTERADD, ap->bmdma_prd_dma);
return 0;
}
@@ -978,6 +925,7 @@ static struct ata_port_operations scc_pata_ops = {
.sff_check_status = scc_check_status,
.sff_check_altstatus = scc_check_altstatus,
.sff_dev_select = scc_dev_select,
+ .sff_set_devctl = scc_set_devctl,
.bmdma_setup = scc_bmdma_setup,
.bmdma_start = scc_bmdma_start,
@@ -985,14 +933,11 @@ static struct ata_port_operations scc_pata_ops = {
.bmdma_status = scc_bmdma_status,
.sff_data_xfer = scc_data_xfer,
- .freeze = scc_freeze,
- .prereset = scc_pata_prereset,
+ .cable_detect = ata_cable_80wire,
.softreset = scc_softreset,
.postreset = scc_postreset,
- .post_internal_cmd = scc_bmdma_stop,
.sff_irq_clear = scc_irq_clear,
- .sff_irq_on = scc_irq_on,
.port_start = scc_port_start,
.port_stop = scc_port_stop,
@@ -1000,9 +945,9 @@ static struct ata_port_operations scc_pata_ops = {
static struct ata_port_info scc_port_info[] = {
{
- .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x00,
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ /* No MWDMA */
.udma_mask = ATA_UDMA6,
.port_ops = &scc_pata_ops,
},
@@ -1113,15 +1058,12 @@ static int scc_host_init(struct ata_host *host)
static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
unsigned int board_idx = (unsigned int) ent->driver_data;
const struct ata_port_info *ppi[] = { &scc_port_info[board_idx], NULL };
struct ata_host *host;
int rc;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev,
- "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1);
if (!host)
@@ -1145,7 +1087,7 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+ return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
IRQF_SHARED, &scc_sht);
}
@@ -1154,32 +1096,13 @@ static struct pci_driver scc_pci_driver = {
.id_table = scc_pci_tbl,
.probe = scc_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init scc_init (void)
-{
- int rc;
-
- DPRINTK("pci_register_driver\n");
- rc = pci_register_driver(&scc_pci_driver);
- if (rc)
- return rc;
-
- DPRINTK("done\n");
- return 0;
-}
-
-static void __exit scc_exit (void)
-{
- pci_unregister_driver(&scc_pci_driver);
-}
-
-module_init(scc_init);
-module_exit(scc_exit);
+module_pci_driver(scc_pci_driver);
MODULE_AUTHOR("Toshiba corp");
MODULE_DESCRIPTION("SCSI low-level driver for Toshiba SCC PATA controller");
diff --git a/drivers/ata/pata_sch.c b/drivers/ata/pata_sch.c
new file mode 100644
index 00000000000..b920c3407f8
--- /dev/null
+++ b/drivers/ata/pata_sch.c
@@ -0,0 +1,180 @@
+/*
+ * pata_sch.c - Intel SCH PATA controllers
+ *
+ * Copyright (c) 2008 Alek Du <alek.du@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * Supports:
+ * Intel SCH (AF82US15W, AF82US15L, AF82UL11L) chipsets -- see spec at:
+ * http://download.intel.com/design/chipsets/embedded/datashts/319537.pdf
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/dmi.h>
+
+#define DRV_NAME "pata_sch"
+#define DRV_VERSION "0.2"
+
+/* see SCH datasheet page 351 */
+enum {
+ D0TIM = 0x80, /* Device 0 Timing Register */
+ D1TIM = 0x84, /* Device 1 Timing Register */
+ PM = 0x07, /* PIO Mode Bit Mask */
+ MDM = (0x03 << 8), /* Multi-word DMA Mode Bit Mask */
+ UDM = (0x07 << 16), /* Ultra DMA Mode Bit Mask */
+ PPE = (1 << 30), /* Prefetch/Post Enable */
+ USD = (1 << 31), /* Use Synchronous DMA */
+};
+
+static int sch_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+static void sch_set_piomode(struct ata_port *ap, struct ata_device *adev);
+static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev);
+
+static const struct pci_device_id sch_pci_tbl[] = {
+ /* Intel SCH PATA Controller */
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SCH_IDE), 0 },
+ { } /* terminate list */
+};
+
+static struct pci_driver sch_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sch_pci_tbl,
+ .probe = sch_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
+};
+
+static struct scsi_host_template sch_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations sch_pata_ops = {
+ .inherits = &ata_bmdma_port_ops,
+ .cable_detect = ata_cable_unknown,
+ .set_piomode = sch_set_piomode,
+ .set_dmamode = sch_set_dmamode,
+};
+
+static struct ata_port_info sch_port_info = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &sch_pata_ops,
+};
+
+MODULE_AUTHOR("Alek Du <alek.du@intel.com>");
+MODULE_DESCRIPTION("SCSI low-level driver for Intel SCH PATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sch_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+/**
+ * sch_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: ATA device
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sch_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int port = adev->devno ? D1TIM : D0TIM;
+ unsigned int data;
+
+ pci_read_config_dword(dev, port, &data);
+ /* see SCH datasheet page 351 */
+ /* set PIO mode */
+ data &= ~(PM | PPE);
+ data |= pio;
+ /* enable PPE for block device */
+ if (adev->class == ATA_DEV_ATA)
+ data |= PPE;
+ pci_write_config_dword(dev, port, data);
+}
+
+/**
+ * sch_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: ATA device
+ *
+ * Set MW/UDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int dma_mode = adev->dma_mode;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int port = adev->devno ? D1TIM : D0TIM;
+ unsigned int data;
+
+ pci_read_config_dword(dev, port, &data);
+ /* see SCH datasheet page 351 */
+ if (dma_mode >= XFER_UDMA_0) {
+ /* enable Synchronous DMA mode */
+ data |= USD;
+ data &= ~UDM;
+ data |= (dma_mode - XFER_UDMA_0) << 16;
+ } else { /* must be MWDMA mode, since we masked SWDMA already */
+ data &= ~(USD | MDM);
+ data |= (dma_mode - XFER_MW_DMA_0) << 8;
+ }
+ pci_write_config_dword(dev, port, data);
+}
+
+/**
+ * sch_init_one - Register SCH ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in sch_pci_tbl matching with @pdev
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int sch_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ const struct ata_port_info *ppi[] = { &sch_port_info, NULL };
+
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
+
+ return ata_pci_bmdma_init_one(pdev, ppi, &sch_sht, NULL, 0);
+}
+
+module_pci_driver(sch_pci_driver);
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index ffd26d0dc50..fc5f31d4828 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -1,7 +1,7 @@
/*
* pata_serverworks.c - Serverworks PATA for new ATA layer
* (C) 2005 Red Hat Inc
- * Alan Cox <alan@redhat.com>
+ * (C) 2010 Bartlomiej Zolnierkiewicz
*
* based upon
*
@@ -34,7 +34,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
@@ -58,31 +57,15 @@ static const char *csb_bad_ata100[] = {
};
/**
- * dell_cable - Dell serverworks cable detection
+ * oem_cable - Dell/Sun serverworks cable detection
* @ap: ATA port to do cable detect
*
- * Dell hide the 40/80 pin select for their interfaces in the top two
- * bits of the subsystem ID.
+ * Dell PowerEdge and Sun Cobalt 'Alpine' hide the 40/80 pin select
+ * for their interfaces in the top two bits of the subsystem ID.
*/
-static int dell_cable(struct ata_port *ap) {
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-
- if (pdev->subsystem_device & (1 << (ap->port_no + 14)))
- return ATA_CBL_PATA80;
- return ATA_CBL_PATA40;
-}
-
-/**
- * sun_cable - Sun Cobalt 'Alpine' cable detection
- * @ap: ATA port to do cable select
- *
- * Cobalt CSB5 IDE hides the 40/80pin in the top two bits of the
- * subsystem ID the same as dell. We could use one function but we may
- * need to extend the Dell one in future
- */
-
-static int sun_cable(struct ata_port *ap) {
+static int oem_cable(struct ata_port *ap)
+{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (pdev->subsystem_device & (1 << (ap->port_no + 14)))
@@ -90,56 +73,27 @@ static int sun_cable(struct ata_port *ap) {
return ATA_CBL_PATA40;
}
-/**
- * osb4_cable - OSB4 cable detect
- * @ap: ATA port to check
- *
- * The OSB4 isn't UDMA66 capable so this is easy
- */
-
-static int osb4_cable(struct ata_port *ap) {
- return ATA_CBL_PATA40;
-}
-
-/**
- * csb_cable - CSB5/6 cable detect
- * @ap: ATA port to check
- *
- * Serverworks default arrangement is to use the drive side detection
- * only.
- */
-
-static int csb_cable(struct ata_port *ap) {
- return ATA_CBL_PATA_UNK;
-}
-
struct sv_cable_table {
int device;
int subvendor;
int (*cable_detect)(struct ata_port *ap);
};
-/*
- * Note that we don't copy the old serverworks code because the old
- * code contains obvious mistakes
- */
-
static struct sv_cable_table cable_detect[] = {
- { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_DELL, dell_cable },
- { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_VENDOR_ID_DELL, dell_cable },
- { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_SUN, sun_cable },
- { PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, osb4_cable },
- { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, csb_cable },
- { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, csb_cable },
- { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, csb_cable },
- { PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, csb_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_DELL, oem_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_VENDOR_ID_DELL, oem_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_SUN, oem_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, ata_cable_40wire },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, ata_cable_unknown },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, ata_cable_unknown },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, ata_cable_unknown },
+ { PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, ata_cable_unknown },
{ }
};
/**
* serverworks_cable_detect - cable detection
* @ap: ATA port
- * @deadline: deadline jiffies for the operation
*
* Perform cable detection according to the device and subvendor
* identifications
@@ -199,7 +153,7 @@ static unsigned long serverworks_osb4_filter(struct ata_device *adev, unsigned l
{
if (adev->class == ATA_DEV_ATA)
mask &= ~ATA_MASK_UDMA;
- return ata_bmdma_mode_filter(adev, mask);
+ return mask;
}
@@ -219,7 +173,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo
/* Disk, UDMA */
if (adev->class != ATA_DEV_ATA)
- return ata_bmdma_mode_filter(adev, mask);
+ return mask;
/* Actually do need to check */
ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
@@ -228,7 +182,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo
if (!strcmp(p, model_num))
mask &= ~(0xE0 << ATA_SHIFT_UDMA);
}
- return ata_bmdma_mode_filter(adev, mask);
+ return mask;
}
/**
@@ -255,7 +209,7 @@ static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev
if (serverworks_is_csb(pdev)) {
pci_read_config_word(pdev, 0x4A, &csb5_pio);
csb5_pio &= ~(0x0F << devbits);
- pci_write_config_byte(pdev, 0x4A, csb5_pio | (pio << devbits));
+ pci_write_config_word(pdev, 0x4A, csb5_pio | (pio << devbits));
}
}
@@ -329,7 +283,7 @@ static int serverworks_fixup_osb4(struct pci_dev *pdev)
pci_dev_put(isa_dev);
return 0;
}
- printk(KERN_WARNING "ata_serverworks: Unable to find bridge.\n");
+ printk(KERN_WARNING DRV_NAME ": Unable to find bridge.\n");
return -ENODEV;
}
@@ -394,32 +348,57 @@ static void serverworks_fixup_ht1000(struct pci_dev *pdev)
pci_write_config_byte(pdev, 0x5A, btr);
}
+static int serverworks_fixup(struct pci_dev *pdev)
+{
+ int rc = 0;
+
+ /* Force master latency timer to 64 PCI clocks */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
+
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
+ rc = serverworks_fixup_osb4(pdev);
+ break;
+ case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+ ata_pci_bmdma_clear_simplex(pdev);
+ /* fall through */
+ case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
+ case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
+ rc = serverworks_fixup_csb(pdev);
+ break;
+ case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE:
+ serverworks_fixup_ht1000(pdev);
+ break;
+ }
+
+ return rc;
+}
static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
static const struct ata_port_info info[4] = {
{ /* OSB4 */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
.port_ops = &serverworks_osb4_port_ops
}, { /* OSB4 no UDMA */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = 0x00,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ /* No UDMA */
.port_ops = &serverworks_osb4_port_ops
}, { /* CSB5 */
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA4,
.port_ops = &serverworks_csb_port_ops
}, { /* CSB5 - later revisions*/
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &serverworks_csb_port_ops
}
@@ -431,13 +410,12 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id
if (rc)
return rc;
- /* Force master latency timer to 64 PCI clocks */
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
+ rc = serverworks_fixup(pdev);
/* OSB4 : South Bridge and IDE */
if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
/* Select non UDMA capable OSB4 if we can't do fixups */
- if ( serverworks_fixup_osb4(pdev) < 0)
+ if (rc < 0)
ppi[0] = &info[1];
}
/* setup CSB5/CSB6 : South Bridge and IDE option RAID */
@@ -447,51 +425,28 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id
/* If the returned btr is the newer revision then
select the right info block */
- if (serverworks_fixup_csb(pdev) == 3)
+ if (rc == 3)
ppi[0] = &info[3];
/* Is this the 3rd channel CSB6 IDE ? */
if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)
ppi[1] = &ata_dummy_port_info;
}
- /* setup HT1000E */
- else if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE)
- serverworks_fixup_ht1000(pdev);
-
- if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
- ata_pci_bmdma_clear_simplex(pdev);
- return ata_pci_sff_init_one(pdev, ppi, &serverworks_sht, NULL);
+ return ata_pci_bmdma_init_one(pdev, ppi, &serverworks_sht, NULL, 0);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int serverworks_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
if (rc)
return rc;
- /* Force master latency timer to 64 PCI clocks */
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
-
- switch (pdev->device) {
- case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
- serverworks_fixup_osb4(pdev);
- break;
- case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
- ata_pci_bmdma_clear_simplex(pdev);
- /* fall through */
- case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
- case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
- serverworks_fixup_csb(pdev);
- break;
- case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE:
- serverworks_fixup_ht1000(pdev);
- break;
- }
+ (void)serverworks_fixup(pdev);
ata_host_resume(host);
return 0;
@@ -513,27 +468,16 @@ static struct pci_driver serverworks_pci_driver = {
.id_table = serverworks,
.probe = serverworks_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = serverworks_reinit_one,
#endif
};
-static int __init serverworks_init(void)
-{
- return pci_register_driver(&serverworks_pci_driver);
-}
-
-static void __exit serverworks_exit(void)
-{
- pci_unregister_driver(&serverworks_pci_driver);
-}
+module_pci_driver(serverworks_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Serverworks OSB4/CSB5/CSB6");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, serverworks);
MODULE_VERSION(DRV_VERSION);
-
-module_init(serverworks_init);
-module_exit(serverworks_exit);
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index 720b8645f58..f597edccede 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -1,7 +1,6 @@
/*
* pata_sil680.c - SIL680 PATA for new ATA layer
* (C) 2005 Red Hat Inc
- * Alan Cox <alan@redhat.com>
*
* based upon
*
@@ -12,7 +11,7 @@
*
* May be copied or modified under the terms of the GNU General Public License
*
- * Documentation publically available.
+ * Documentation publicly available.
*
* If you have strange problems with nVidia chipset systems please
* see the SI support documentation and update your system BIOS
@@ -26,25 +25,25 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "pata_sil680"
-#define DRV_VERSION "0.4.8"
+#define DRV_VERSION "0.4.9"
#define SIL680_MMIO_BAR 5
/**
* sil680_selreg - return register base
- * @hwif: interface
+ * @ap: ATA interface
* @r: config offset
*
- * Turn a config register offset into the right address in either
- * PCI space or MMIO space to access the control register in question
- * Thankfully this is a configuration operation so isnt performance
+ * Turn a config register offset into the right address in PCI space
+ * to access the control register in question.
+ *
+ * Thankfully this is a configuration operation so isn't performance
* criticial.
*/
@@ -57,12 +56,12 @@ static unsigned long sil680_selreg(struct ata_port *ap, int r)
/**
* sil680_seldev - return register base
- * @hwif: interface
+ * @ap: ATA interface
* @r: config offset
*
- * Turn a config register offset into the right address in either
- * PCI space or MMIO space to access the control register in question
- * including accounting for the unit shift.
+ * Turn a config register offset into the right address in PCI space
+ * to access the control register in question including accounting for
+ * the unit shift.
*/
static unsigned long sil680_seldev(struct ata_port *ap, struct ata_device *adev, int r)
@@ -82,7 +81,8 @@ static unsigned long sil680_seldev(struct ata_port *ap, struct ata_device *adev,
* space for us.
*/
-static int sil680_cable_detect(struct ata_port *ap) {
+static int sil680_cable_detect(struct ata_port *ap)
+{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned long addr = sil680_selreg(ap, 0);
u8 ata66;
@@ -94,7 +94,7 @@ static int sil680_cable_detect(struct ata_port *ap) {
}
/**
- * sil680_set_piomode - set initial PIO mode data
+ * sil680_set_piomode - set PIO mode data
* @ap: ATA interface
* @adev: ATA device
*
@@ -105,8 +105,12 @@ static int sil680_cable_detect(struct ata_port *ap) {
static void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
- static u16 speed_p[5] = { 0x328A, 0x2283, 0x1104, 0x10C3, 0x10C1 };
- static u16 speed_t[5] = { 0x328A, 0x2283, 0x1281, 0x10C3, 0x10C1 };
+ static const u16 speed_p[5] = {
+ 0x328A, 0x2283, 0x1104, 0x10C3, 0x10C1
+ };
+ static const u16 speed_t[5] = {
+ 0x328A, 0x2283, 0x1281, 0x10C3, 0x10C1
+ };
unsigned long tfaddr = sil680_selreg(ap, 0x02);
unsigned long addr = sil680_seldev(ap, adev, 0x04);
@@ -141,22 +145,23 @@ static void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev)
}
/**
- * sil680_set_dmamode - set initial DMA mode data
+ * sil680_set_dmamode - set DMA mode data
* @ap: ATA interface
* @adev: ATA device
*
- * Program the MWDMA/UDMA modes for the sil680 k
- * chipset. The MWDMA mode values are pulled from a lookup table
+ * Program the MWDMA/UDMA modes for the sil680 chipset.
+ *
+ * The MWDMA mode values are pulled from a lookup table
* while the chipset uses mode number for UDMA.
*/
static void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
- static u8 ultra_table[2][7] = {
+ static const u8 ultra_table[2][7] = {
{ 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01, 0xFF }, /* 100MHz */
{ 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }, /* 133Mhz */
};
- static u16 dma_table[3] = { 0x2208, 0x10C2, 0x10C1 };
+ static const u16 dma_table[3] = { 0x2208, 0x10C2, 0x10C1 };
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned long ma = sil680_seldev(ap, adev, 0x08);
@@ -176,7 +181,7 @@ static void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev)
mode &= ~(0x03 << port_shift);
/* Extract scsc */
- scsc = (scsc & 0x30) ? 1: 0;
+ scsc = (scsc & 0x30) ? 1 : 0;
if (adev->dma_mode >= XFER_UDMA_0) {
multi = 0x10C1;
@@ -191,15 +196,49 @@ static void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev)
pci_write_config_word(pdev, ua, ultra);
}
+/**
+ * sil680_sff_exec_command - issue ATA command to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Issues ATA command, with proper synchronization with interrupt
+ * handler / other threads. Use our MMIO space for PCI posting to avoid
+ * a hideously slow cycle all the way to the device.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+static void sil680_sff_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+ iowrite8(tf->command, ap->ioaddr.command_addr);
+ ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+}
+
+static bool sil680_sff_irq_check(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned long addr = sil680_selreg(ap, 1);
+ u8 val;
+
+ pci_read_config_byte(pdev, addr, &val);
+
+ return val & 0x08;
+}
+
static struct scsi_host_template sil680_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
+
static struct ata_port_operations sil680_port_ops = {
- .inherits = &ata_bmdma_port_ops,
- .cable_detect = sil680_cable_detect,
- .set_piomode = sil680_set_piomode,
- .set_dmamode = sil680_set_dmamode,
+ .inherits = &ata_bmdma32_port_ops,
+ .sff_exec_command = sil680_sff_exec_command,
+ .sff_irq_check = sil680_sff_irq_check,
+ .cable_detect = sil680_cable_detect,
+ .set_piomode = sil680_set_piomode,
+ .set_dmamode = sil680_set_dmamode,
};
/**
@@ -213,13 +252,11 @@ static struct ata_port_operations sil680_port_ops = {
static u8 sil680_init_chip(struct pci_dev *pdev, int *try_mmio)
{
- u32 class_rev = 0;
u8 tmpbyte = 0;
- pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
- /* FIXME: double check */
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255);
+ /* FIXME: double check */
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+ pdev->revision ? 1 : 255);
pci_write_config_byte(pdev, 0x80, 0x00);
pci_write_config_byte(pdev, 0x84, 0x00);
@@ -230,27 +267,27 @@ static u8 sil680_init_chip(struct pci_dev *pdev, int *try_mmio)
tmpbyte & 1, tmpbyte & 0x30);
*try_mmio = 0;
-#ifdef CONFIG_PPC_MERGE
+#ifdef CONFIG_PPC
if (machine_is(cell))
*try_mmio = (tmpbyte & 1) || pci_resource_start(pdev, 5);
#endif
- switch(tmpbyte & 0x30) {
- case 0x00:
- /* 133 clock attempt to force it on */
- pci_write_config_byte(pdev, 0x8A, tmpbyte|0x10);
- break;
- case 0x30:
- /* if clocking is disabled */
- /* 133 clock attempt to force it on */
- pci_write_config_byte(pdev, 0x8A, tmpbyte & ~0x20);
- break;
- case 0x10:
- /* 133 already */
- break;
- case 0x20:
- /* BIOS set PCI x2 clocking */
- break;
+ switch (tmpbyte & 0x30) {
+ case 0x00:
+ /* 133 clock attempt to force it on */
+ pci_write_config_byte(pdev, 0x8A, tmpbyte|0x10);
+ break;
+ case 0x30:
+ /* if clocking is disabled */
+ /* 133 clock attempt to force it on */
+ pci_write_config_byte(pdev, 0x8A, tmpbyte & ~0x20);
+ break;
+ case 0x10:
+ /* 133 already */
+ break;
+ case 0x20:
+ /* BIOS set PCI x2 clocking */
+ break;
}
pci_read_config_byte(pdev, 0x8A, &tmpbyte);
@@ -268,41 +305,45 @@ static u8 sil680_init_chip(struct pci_dev *pdev, int *try_mmio)
pci_write_config_dword(pdev, 0xB8, 0x43924392);
pci_write_config_dword(pdev, 0xBC, 0x40094009);
- switch(tmpbyte & 0x30) {
- case 0x00: printk(KERN_INFO "sil680: 100MHz clock.\n");break;
- case 0x10: printk(KERN_INFO "sil680: 133MHz clock.\n");break;
- case 0x20: printk(KERN_INFO "sil680: Using PCI clock.\n");break;
- /* This last case is _NOT_ ok */
- case 0x30: printk(KERN_ERR "sil680: Clock disabled ?\n");
+ switch (tmpbyte & 0x30) {
+ case 0x00:
+ printk(KERN_INFO "sil680: 100MHz clock.\n");
+ break;
+ case 0x10:
+ printk(KERN_INFO "sil680: 133MHz clock.\n");
+ break;
+ case 0x20:
+ printk(KERN_INFO "sil680: Using PCI clock.\n");
+ break;
+ /* This last case is _NOT_ ok */
+ case 0x30:
+ printk(KERN_ERR "sil680: Clock disabled ?\n");
}
return tmpbyte & 0x30;
}
-static int __devinit sil680_init_one(struct pci_dev *pdev,
- const struct pci_device_id *id)
+static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &sil680_port_ops
};
static const struct ata_port_info info_slow = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &sil680_port_ops
};
const struct ata_port_info *ppi[] = { &info, NULL };
- static int printed_version;
struct ata_host *host;
void __iomem *mmio_base;
int rc, try_mmio;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
rc = pcim_enable_device(pdev);
if (rc)
@@ -322,9 +363,6 @@ static int __devinit sil680_init_one(struct pci_dev *pdev,
/* Try to acquire MMIO resources and fallback to PIO if
* that fails
*/
- rc = pcim_enable_device(pdev);
- if (rc)
- return rc;
rc = pcim_iomap_regions(pdev, 1 << SIL680_MMIO_BAR, DRV_NAME);
if (rc)
goto use_ioports;
@@ -358,17 +396,17 @@ static int __devinit sil680_init_one(struct pci_dev *pdev,
ata_sff_std_ports(&host->ports[1]->ioaddr);
/* Register & activate */
- return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+ return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
IRQF_SHARED, &sil680_sht);
use_ioports:
- return ata_pci_sff_init_one(pdev, ppi, &sil680_sht, NULL);
+ return ata_pci_bmdma_init_one(pdev, ppi, &sil680_sht, NULL, 0);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int sil680_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int try_mmio, rc;
rc = ata_pci_device_do_resume(pdev);
@@ -391,27 +429,16 @@ static struct pci_driver sil680_pci_driver = {
.id_table = sil680,
.probe = sil680_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = sil680_reinit_one,
#endif
};
-static int __init sil680_init(void)
-{
- return pci_register_driver(&sil680_pci_driver);
-}
-
-static void __exit sil680_exit(void)
-{
- pci_unregister_driver(&sil680_pci_driver);
-}
+module_pci_driver(sil680_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for SI680 PATA");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, sil680);
MODULE_VERSION(DRV_VERSION);
-
-module_init(sil680_init);
-module_exit(sil680_exit);
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index e82c66e8d31..626f989d5c6 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -1,8 +1,8 @@
/*
* pata_sis.c - SiS ATA driver
*
- * (C) 2005 Red Hat <alan@redhat.com>
- * (C) 2007 Bartlomiej Zolnierkiewicz
+ * (C) 2005 Red Hat
+ * (C) 2007,2009 Bartlomiej Zolnierkiewicz
*
* Based upon linux/drivers/ide/pci/sis5513.c
* Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -55,7 +54,7 @@ static const struct sis_laptop sis_laptop[] = {
/* devid, subvendor, subdev */
{ 0x5513, 0x1043, 0x1107 }, /* ASUS A6K */
{ 0x5513, 0x1734, 0x105F }, /* FSC Amilo A1630 */
- { 0x5513, 0x1071, 0x8640 }, /* EasyNote K5305 */
+ { 0x5513, 0x1071, 0x8640 }, /* EasyNote K5305 */
/* end marker */
{ 0, }
};
@@ -76,7 +75,7 @@ static int sis_short_ata40(struct pci_dev *dev)
}
/**
- * sis_old_port_base - return PCI configuration base for dev
+ * sis_old_port_base - return PCI configuration base for dev
* @adev: device
*
* Returns the base of the PCI configuration registers for this port
@@ -85,11 +84,34 @@ static int sis_short_ata40(struct pci_dev *dev)
static int sis_old_port_base(struct ata_device *adev)
{
- return 0x40 + (4 * adev->link->ap->port_no) + (2 * adev->devno);
+ return 0x40 + (4 * adev->link->ap->port_no) + (2 * adev->devno);
}
/**
- * sis_133_cable_detect - check for 40/80 pin
+ * sis_port_base - return PCI configuration base for dev
+ * @adev: device
+ *
+ * Returns the base of the PCI configuration registers for this port
+ * number.
+ */
+
+static int sis_port_base(struct ata_device *adev)
+{
+ struct ata_port *ap = adev->link->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = 0x40;
+ u32 reg54;
+
+ /* If bit 30 is set then the registers are mapped at 0x70 not 0x40 */
+ pci_read_config_dword(pdev, 0x54, &reg54);
+ if (reg54 & 0x40000000)
+ port = 0x70;
+
+ return port + (8 * ap->port_no) + (4 * adev->devno);
+}
+
+/**
+ * sis_133_cable_detect - check for 40/80 pin
* @ap: Port
* @deadline: deadline jiffies for the operation
*
@@ -110,9 +132,8 @@ static int sis_133_cable_detect(struct ata_port *ap)
}
/**
- * sis_66_cable_detect - check for 40/80 pin
+ * sis_66_cable_detect - check for 40/80 pin
* @ap: Port
- * @deadline: deadline jiffies for the operation
*
* Perform cable detection on the UDMA66, UDMA100 and early UDMA133
* SiS IDE controllers.
@@ -133,7 +154,7 @@ static int sis_66_cable_detect(struct ata_port *ap)
/**
- * sis_pre_reset - probe begin
+ * sis_pre_reset - probe begin
* @link: ATA link
* @deadline: deadline jiffies for the operation
*
@@ -161,7 +182,7 @@ static int sis_pre_reset(struct ata_link *link, unsigned long deadline)
/**
- * sis_set_fifo - Set RWP fifo bits for this device
+ * sis_set_fifo - Set RWP fifo bits for this device
* @ap: Port
* @adev: Device
*
@@ -204,13 +225,13 @@ static void sis_set_fifo(struct ata_port *ap, struct ata_device *adev)
static void sis_old_set_piomode (struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
int port = sis_old_port_base(adev);
u8 t1, t2;
int speed = adev->pio_mode - XFER_PIO_0;
- const u8 active[] = { 0x00, 0x07, 0x04, 0x03, 0x01 };
- const u8 recovery[] = { 0x00, 0x06, 0x04, 0x03, 0x03 };
+ static const u8 active[] = { 0x00, 0x07, 0x04, 0x03, 0x01 };
+ static const u8 recovery[] = { 0x00, 0x06, 0x04, 0x03, 0x03 };
sis_set_fifo(ap, adev);
@@ -241,11 +262,11 @@ static void sis_old_set_piomode (struct ata_port *ap, struct ata_device *adev)
static void sis_100_set_piomode (struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
int port = sis_old_port_base(adev);
int speed = adev->pio_mode - XFER_PIO_0;
- const u8 actrec[] = { 0x00, 0x67, 0x44, 0x33, 0x31 };
+ static const u8 actrec[] = { 0x00, 0x67, 0x44, 0x33, 0x31 };
sis_set_fifo(ap, adev);
@@ -266,20 +287,19 @@ static void sis_100_set_piomode (struct ata_port *ap, struct ata_device *adev)
static void sis_133_set_piomode (struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- int port = 0x40;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port;
u32 t1;
- u32 reg54;
int speed = adev->pio_mode - XFER_PIO_0;
- const u32 timing133[] = {
+ static const u32 timing133[] = {
0x28269000, /* Recovery << 24 | Act << 16 | Ini << 12 */
0x0C266000,
0x04263000,
0x0C0A3000,
0x05093000
};
- const u32 timing100[] = {
+ static const u32 timing100[] = {
0x1E1C6000, /* Recovery << 24 | Act << 16 | Ini << 12 */
0x091C4000,
0x031C2000,
@@ -289,12 +309,7 @@ static void sis_133_set_piomode (struct ata_port *ap, struct ata_device *adev)
sis_set_fifo(ap, adev);
- /* If bit 14 is set then the registers are mapped at 0x70 not 0x40 */
- pci_read_config_dword(pdev, 0x54, &reg54);
- if (reg54 & 0x40000000)
- port = 0x70;
- port += 8 * ap->port_no + 4 * adev->devno;
-
+ port = sis_port_base(adev);
pci_read_config_dword(pdev, port, &t1);
t1 &= 0xC0C00FFF; /* Mask out timing */
@@ -320,19 +335,19 @@ static void sis_133_set_piomode (struct ata_port *ap, struct ata_device *adev)
static void sis_old_set_dmamode (struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
int speed = adev->dma_mode - XFER_MW_DMA_0;
int drive_pci = sis_old_port_base(adev);
u16 timing;
- const u16 mwdma_bits[] = { 0x008, 0x302, 0x301 };
- const u16 udma_bits[] = { 0xE000, 0xC000, 0xA000 };
+ static const u16 mwdma_bits[] = { 0x008, 0x302, 0x301 };
+ static const u16 udma_bits[] = { 0xE000, 0xC000, 0xA000 };
pci_read_config_word(pdev, drive_pci, &timing);
if (adev->dma_mode < XFER_UDMA_0) {
/* bits 3-0 hold recovery timing bits 8-10 active timing and
- the higher bits are dependant on the device */
+ the higher bits are dependent on the device */
timing &= ~0x870F;
timing |= mwdma_bits[speed];
} else {
@@ -359,20 +374,20 @@ static void sis_old_set_dmamode (struct ata_port *ap, struct ata_device *adev)
static void sis_66_set_dmamode (struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
int speed = adev->dma_mode - XFER_MW_DMA_0;
int drive_pci = sis_old_port_base(adev);
u16 timing;
/* MWDMA 0-2 and UDMA 0-5 */
- const u16 mwdma_bits[] = { 0x008, 0x302, 0x301 };
- const u16 udma_bits[] = { 0xF000, 0xD000, 0xB000, 0xA000, 0x9000, 0x8000 };
+ static const u16 mwdma_bits[] = { 0x008, 0x302, 0x301 };
+ static const u16 udma_bits[] = { 0xF000, 0xD000, 0xB000, 0xA000, 0x9000, 0x8000 };
pci_read_config_word(pdev, drive_pci, &timing);
if (adev->dma_mode < XFER_UDMA_0) {
/* bits 3-0 hold recovery timing bits 8-10 active timing and
- the higher bits are dependant on the device, bit 15 udma */
+ the higher bits are dependent on the device, bit 15 udma */
timing &= ~0x870F;
timing |= mwdma_bits[speed];
} else {
@@ -398,12 +413,12 @@ static void sis_66_set_dmamode (struct ata_port *ap, struct ata_device *adev)
static void sis_100_set_dmamode (struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
int speed = adev->dma_mode - XFER_MW_DMA_0;
int drive_pci = sis_old_port_base(adev);
u8 timing;
- const u8 udma_bits[] = { 0x8B, 0x87, 0x85, 0x83, 0x82, 0x81};
+ static const u8 udma_bits[] = { 0x8B, 0x87, 0x85, 0x83, 0x82, 0x81};
pci_read_config_byte(pdev, drive_pci + 1, &timing);
@@ -432,7 +447,7 @@ static void sis_100_set_dmamode (struct ata_port *ap, struct ata_device *adev)
static void sis_133_early_set_dmamode (struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
int speed = adev->dma_mode - XFER_MW_DMA_0;
int drive_pci = sis_old_port_base(adev);
u8 timing;
@@ -465,32 +480,34 @@ static void sis_133_early_set_dmamode (struct ata_port *ap, struct ata_device *a
static void sis_133_set_dmamode (struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- int speed = adev->dma_mode - XFER_MW_DMA_0;
- int port = 0x40;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port;
u32 t1;
- u32 reg54;
-
- /* bits 4- cycle time 8 - cvs time */
- static const u32 timing_u100[] = { 0x6B0, 0x470, 0x350, 0x140, 0x120, 0x110, 0x000 };
- static const u32 timing_u133[] = { 0x9F0, 0x6A0, 0x470, 0x250, 0x230, 0x220, 0x210 };
-
- /* If bit 14 is set then the registers are mapped at 0x70 not 0x40 */
- pci_read_config_dword(pdev, 0x54, &reg54);
- if (reg54 & 0x40000000)
- port = 0x70;
- port += (8 * ap->port_no) + (4 * adev->devno);
+ port = sis_port_base(adev);
pci_read_config_dword(pdev, port, &t1);
if (adev->dma_mode < XFER_UDMA_0) {
+ /* Recovery << 24 | Act << 16 | Ini << 12, like PIO modes */
+ static const u32 timing_u100[] = { 0x19154000, 0x06072000, 0x04062000 };
+ static const u32 timing_u133[] = { 0x221C6000, 0x0C0A3000, 0x05093000 };
+ int speed = adev->dma_mode - XFER_MW_DMA_0;
+
+ t1 &= 0xC0C00FFF;
+ /* disable UDMA */
t1 &= ~0x00000004;
- /* FIXME: need data sheet to add MWDMA here. Also lacking on
- ide/pci driver */
+ if (t1 & 0x08)
+ t1 |= timing_u133[speed];
+ else
+ t1 |= timing_u100[speed];
} else {
- speed = adev->dma_mode - XFER_UDMA_0;
- /* if & 8 no UDMA133 - need info for ... */
+ /* bits 4- cycle time 8 - cvs time */
+ static const u32 timing_u100[] = { 0x6B0, 0x470, 0x350, 0x140, 0x120, 0x110, 0x000 };
+ static const u32 timing_u133[] = { 0x9F0, 0x6A0, 0x470, 0x250, 0x230, 0x220, 0x210 };
+ int speed = adev->dma_mode - XFER_UDMA_0;
+
t1 &= ~0x00000FF0;
+ /* enable UDMA */
t1 |= 0x00000004;
if (t1 & 0x08)
t1 |= timing_u133[speed];
@@ -500,6 +517,27 @@ static void sis_133_set_dmamode (struct ata_port *ap, struct ata_device *adev)
pci_write_config_dword(pdev, port, t1);
}
+/**
+ * sis_133_mode_filter - mode selection filter
+ * @adev: ATA device
+ *
+ * Block UDMA6 on devices that do not support it.
+ */
+
+static unsigned long sis_133_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+ struct ata_port *ap = adev->link->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = sis_port_base(adev);
+ u32 t1;
+
+ pci_read_config_dword(pdev, port, &t1);
+ /* if ATA133 is disabled, mask it out */
+ if (!(t1 & 0x08))
+ mask &= ~(0xC0 << ATA_SHIFT_UDMA);
+ return mask;
+}
+
static struct scsi_host_template sis_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
@@ -521,6 +559,7 @@ static struct ata_port_operations sis_133_ops = {
.set_piomode = sis_133_set_piomode,
.set_dmamode = sis_133_set_dmamode,
.cable_detect = sis_133_cable_detect,
+ .mode_filter = sis_133_mode_filter,
};
static struct ata_port_operations sis_133_early_ops = {
@@ -553,51 +592,57 @@ static struct ata_port_operations sis_old_ops = {
static const struct ata_port_info sis_info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07,
- .udma_mask = 0,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ /* No UDMA */
.port_ops = &sis_old_ops,
};
static const struct ata_port_info sis_info33 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07,
- .udma_mask = ATA_UDMA2, /* UDMA 33 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
.port_ops = &sis_old_ops,
};
static const struct ata_port_info sis_info66 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = ATA_UDMA4, /* UDMA 66 */
+ .pio_mask = ATA_PIO4,
+ /* No MWDMA */
+ .udma_mask = ATA_UDMA4,
.port_ops = &sis_66_ops,
};
static const struct ata_port_info sis_info100 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
+ /* No MWDMA */
.udma_mask = ATA_UDMA5,
.port_ops = &sis_100_ops,
};
static const struct ata_port_info sis_info100_early = {
.flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ /* No MWDMA */
.udma_mask = ATA_UDMA5,
- .pio_mask = 0x1f, /* pio0-4 */
.port_ops = &sis_66_ops,
};
static const struct ata_port_info sis_info133 = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &sis_133_ops,
};
const struct ata_port_info sis_info133_for_sata = {
- .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
- .pio_mask = 0x1f, /* pio0-4 */
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ /* No MWDMA */
.udma_mask = ATA_UDMA6,
.port_ops = &sis_133_for_sata_ops,
};
static const struct ata_port_info sis_info133_early = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
+ .pio_mask = ATA_PIO4,
+ /* No MWDMA */
.udma_mask = ATA_UDMA6,
.port_ops = &sis_133_early_ops,
};
@@ -664,7 +709,7 @@ static void sis_fixup(struct pci_dev *pdev, struct sis_chipset *sis)
* @pdev: PCI device to register
* @ent: Entry in sis_pci_tbl matching with @pdev
*
- * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
* and then hand over control to libata, for it to do the rest.
*
* LOCKING:
@@ -676,7 +721,6 @@ static void sis_fixup(struct pci_dev *pdev, struct sis_chipset *sis)
static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
const struct ata_port_info *ppi[] = { NULL, NULL };
struct pci_dev *host = NULL;
struct sis_chipset *chipset = NULL;
@@ -730,9 +774,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
0x0, &sis_info100
};
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev,
- "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
rc = pcim_enable_device(pdev);
if (rc)
@@ -767,17 +809,20 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
switch(trueid) {
case 0x5518: /* SIS 962/963 */
+ dev_info(&pdev->dev,
+ "SiS 962/963 MuTIOL IDE UDMA133 controller\n");
chipset = &sis133;
if ((idemisc & 0x40000000) == 0) {
pci_write_config_dword(pdev, 0x54, idemisc | 0x40000000);
- printk(KERN_INFO "SIS5513: Switching to 5513 register mapping\n");
+ dev_info(&pdev->dev,
+ "Switching to 5513 register mapping\n");
}
break;
case 0x0180: /* SIS 965/965L */
- chipset = &sis133;
+ chipset = &sis133;
break;
case 0x1180: /* SIS 966/966L */
- chipset = &sis133;
+ chipset = &sis133;
break;
}
}
@@ -821,8 +866,25 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
sis_fixup(pdev, chipset);
- return ata_pci_sff_init_one(pdev, ppi, &sis_sht, chipset);
+ return ata_pci_bmdma_init_one(pdev, ppi, &sis_sht, chipset, 0);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sis_reinit_one(struct pci_dev *pdev)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ sis_fixup(pdev, host->private_data);
+
+ ata_host_resume(host);
+ return 0;
}
+#endif
static const struct pci_device_id sis_pci_tbl[] = {
{ PCI_VDEVICE(SI, 0x5513), }, /* SiS 5513 */
@@ -837,28 +899,16 @@ static struct pci_driver sis_pci_driver = {
.id_table = sis_pci_tbl,
.probe = sis_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
- .resume = ata_pci_device_resume,
+ .resume = sis_reinit_one,
#endif
};
-static int __init sis_init(void)
-{
- return pci_register_driver(&sis_pci_driver);
-}
-
-static void __exit sis_exit(void)
-{
- pci_unregister_driver(&sis_pci_driver);
-}
-
-module_init(sis_init);
-module_exit(sis_exit);
+module_pci_driver(sis_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("SCSI low-level driver for SiS ATA");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index 70d94fb28a5..4935f61f629 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -1,7 +1,7 @@
/*
* pata_sl82c105.c - SL82C105 PATA for new ATA layer
* (C) 2005 Red Hat Inc
- * Alan Cox <alan@redhat.com>
+ * (C) 2011 Bartlomiej Zolnierkiewicz
*
* Based in part on linux/drivers/ide/pci/sl82c105.c
* SL82C105/Winbond 553 IDE driver
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
@@ -216,7 +215,7 @@ static int sl82c105_qc_defer(struct ata_queued_cmd *qc)
struct ata_port *alt = host->ports[1 ^ qc->ap->port_no];
int rc;
- /* First apply the usual rules */
+ /* First apply the usual rules */
rc = ata_std_qc_defer(qc);
if (rc != 0)
return rc;
@@ -228,6 +227,16 @@ static int sl82c105_qc_defer(struct ata_queued_cmd *qc)
return 0;
}
+static bool sl82c105_sff_irq_check(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 val, mask = ap->port_no ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
+
+ pci_read_config_dword(pdev, 0x40, &val);
+
+ return val & mask;
+}
+
static struct scsi_host_template sl82c105_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
@@ -240,6 +249,7 @@ static struct ata_port_operations sl82c105_port_ops = {
.cable_detect = ata_cable_40wire,
.set_piomode = sl82c105_set_piomode,
.prereset = sl82c105_pre_reset,
+ .sff_irq_check = sl82c105_sff_irq_check,
};
/**
@@ -279,24 +289,31 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev)
return bridge->revision;
}
+static void sl82c105_fixup(struct pci_dev *pdev)
+{
+ u32 val;
+
+ pci_read_config_dword(pdev, 0x40, &val);
+ val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
+ pci_write_config_dword(pdev, 0x40, val);
+}
static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
static const struct ata_port_info info_dma = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.port_ops = &sl82c105_port_ops
};
static const struct ata_port_info info_early = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
+ .pio_mask = ATA_PIO4,
.port_ops = &sl82c105_port_ops
};
/* for now use only the first port */
const struct ata_port_info *ppi[] = { &info_early,
NULL };
- u32 val;
int rev;
int rc;
@@ -307,18 +324,35 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id
rev = sl82c105_bridge_revision(dev);
if (rev == -1)
- dev_printk(KERN_WARNING, &dev->dev, "pata_sl82c105: Unable to find bridge, disabling DMA.\n");
+ dev_warn(&dev->dev,
+ "pata_sl82c105: Unable to find bridge, disabling DMA\n");
else if (rev <= 5)
- dev_printk(KERN_WARNING, &dev->dev, "pata_sl82c105: Early bridge revision, no DMA available.\n");
+ dev_warn(&dev->dev,
+ "pata_sl82c105: Early bridge revision, no DMA available\n");
else
ppi[0] = &info_dma;
- pci_read_config_dword(dev, 0x40, &val);
- val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
- pci_write_config_dword(dev, 0x40, val);
+ sl82c105_fixup(dev);
+
+ return ata_pci_bmdma_init_one(dev, ppi, &sl82c105_sht, NULL, 0);
+}
- return ata_pci_sff_init_one(dev, ppi, &sl82c105_sht, NULL);
+#ifdef CONFIG_PM_SLEEP
+static int sl82c105_reinit_one(struct pci_dev *pdev)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ sl82c105_fixup(pdev);
+
+ ata_host_resume(host);
+ return 0;
}
+#endif
static const struct pci_device_id sl82c105[] = {
{ PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), },
@@ -330,24 +364,17 @@ static struct pci_driver sl82c105_pci_driver = {
.name = DRV_NAME,
.id_table = sl82c105,
.probe = sl82c105_init_one,
- .remove = ata_pci_remove_one
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = ata_pci_device_suspend,
+ .resume = sl82c105_reinit_one,
+#endif
};
-static int __init sl82c105_init(void)
-{
- return pci_register_driver(&sl82c105_pci_driver);
-}
-
-static void __exit sl82c105_exit(void)
-{
- pci_unregister_driver(&sl82c105_pci_driver);
-}
+module_pci_driver(sl82c105_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Sl82c105");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, sl82c105);
MODULE_VERSION(DRV_VERSION);
-
-module_init(sl82c105_init);
-module_exit(sl82c105_exit);
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index b181261f274..d9364af8eb6 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -1,7 +1,7 @@
/*
* pata_triflex.c - Compaq PATA for new ATA layer
* (C) 2005 Red Hat Inc
- * Alan Cox <alan@redhat.com>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* based upon
*
@@ -30,13 +30,12 @@
* Loosely based on the piix & svwks drivers.
*
* Documentation:
- * Not publically available.
+ * Not publicly available.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <scsi/scsi_host.h>
@@ -191,17 +190,15 @@ static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.port_ops = &triflex_port_ops
};
const struct ata_port_info *ppi[] = { &info, NULL };
- static int printed_version;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&dev->dev, DRV_VERSION);
- return ata_pci_sff_init_one(dev, ppi, &triflex_sht, NULL);
+ return ata_pci_bmdma_init_one(dev, ppi, &triflex_sht, NULL, 0);
}
static const struct pci_device_id triflex[] = {
@@ -210,32 +207,42 @@ static const struct pci_device_id triflex[] = {
{ },
};
+#ifdef CONFIG_PM_SLEEP
+static int triflex_ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+ int rc = 0;
+
+ rc = ata_host_suspend(host, mesg);
+ if (rc)
+ return rc;
+
+ /*
+ * We must not disable or powerdown the device.
+ * APM bios refuses to suspend if IDE is not accessible.
+ */
+ pci_save_state(pdev);
+
+ return 0;
+}
+
+#endif
+
static struct pci_driver triflex_pci_driver = {
.name = DRV_NAME,
.id_table = triflex,
.probe = triflex_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
- .suspend = ata_pci_device_suspend,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = triflex_ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
-static int __init triflex_init(void)
-{
- return pci_register_driver(&triflex_pci_driver);
-}
-
-static void __exit triflex_exit(void)
-{
- pci_unregister_driver(&triflex_pci_driver);
-}
+module_pci_driver(triflex_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Compaq Triflex");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, triflex);
MODULE_VERSION(DRV_VERSION);
-
-module_init(triflex_init);
-module_exit(triflex_exit);
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index d4840748fb5..1ca6bcab369 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -1,7 +1,6 @@
/*
* pata_via.c - VIA PATA for new ATA layer
* (C) 2005-2006 Red Hat Inc
- * Alan Cox <alan@redhat.com>
*
* Documentation
* Most chipset documentation available under NDA only
@@ -23,6 +22,7 @@
* VIA VT8233c - UDMA100
* VIA VT8235 - UDMA133
* VIA VT8237 - UDMA133
+ * VIA VT8237A - UDMA133
* VIA VT8237S - UDMA133
* VIA VT8251 - UDMA133
*
@@ -55,36 +55,29 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
+#include <linux/gfp.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <linux/dmi.h>
#define DRV_NAME "pata_via"
-#define DRV_VERSION "0.3.3"
+#define DRV_VERSION "0.3.4"
-/*
- * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
- * driver.
- */
+enum {
+ VIA_BAD_PREQ = 0x01, /* Crashes if PREQ# till DDACK# set */
+ VIA_BAD_CLK66 = 0x02, /* 66 MHz clock doesn't work correctly */
+ VIA_SET_FIFO = 0x04, /* Needs to have FIFO split set */
+ VIA_NO_UNMASK = 0x08, /* Doesn't work with IRQ unmasking on */
+ VIA_BAD_ID = 0x10, /* Has wrong vendor ID (0x1107) */
+ VIA_BAD_AST = 0x20, /* Don't touch Address Setup Timing */
+ VIA_NO_ENABLES = 0x40, /* Has no enablebits */
+ VIA_SATA_PATA = 0x80, /* SATA/PATA combined configuration */
+};
enum {
- VIA_UDMA = 0x007,
- VIA_UDMA_NONE = 0x000,
- VIA_UDMA_33 = 0x001,
- VIA_UDMA_66 = 0x002,
- VIA_UDMA_100 = 0x003,
- VIA_UDMA_133 = 0x004,
- VIA_BAD_PREQ = 0x010, /* Crashes if PREQ# till DDACK# set */
- VIA_BAD_CLK66 = 0x020, /* 66 MHz clock doesn't work correctly */
- VIA_SET_FIFO = 0x040, /* Needs to have FIFO split set */
- VIA_NO_UNMASK = 0x080, /* Doesn't work with IRQ unmasking on */
- VIA_BAD_ID = 0x100, /* Has wrong vendor ID (0x1107) */
- VIA_BAD_AST = 0x200, /* Don't touch Address Setup Timing */
- VIA_NO_ENABLES = 0x400, /* Has no enablebits */
- VIA_SATA_PATA = 0x800, /* SATA/PATA combined configuration */
+ VIA_IDFLAG_SINGLE = (1 << 0), /* single channel controller) */
};
/*
@@ -96,35 +89,54 @@ static const struct via_isa_bridge {
u16 id;
u8 rev_min;
u8 rev_max;
- u16 flags;
+ u8 udma_mask;
+ u8 flags;
} via_isa_bridges[] = {
- { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
- { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
- { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
- { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA },
- { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES},
- { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
- { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
- { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
- { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
- { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, VIA_UDMA_100 },
- { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, VIA_UDMA_100 },
- { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, VIA_UDMA_100 },
- { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 },
- { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, VIA_UDMA_66 },
- { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
- { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, VIA_UDMA_66 },
- { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
- { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
- { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
- { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
- { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
- { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
- { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
- { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+ { "vx855", PCI_DEVICE_ID_VIA_VX855, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
+ { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
+ { "vt8261", PCI_DEVICE_ID_VIA_8261, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA },
+ { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_NO_ENABLES },
+ { "vt6415", PCI_DEVICE_ID_VIA_6415, 0x00, 0xff, ATA_UDMA6, VIA_BAD_AST | VIA_NO_ENABLES },
+ { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, ATA_UDMA5, },
+ { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, ATA_UDMA5, },
+ { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, ATA_UDMA5, },
+ { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, ATA_UDMA5, },
+ { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, ATA_UDMA4, },
+ { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
+ { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, ATA_UDMA4, },
+ { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, ATA_UDMA2, VIA_SET_FIFO },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, ATA_UDMA2, VIA_SET_FIFO | VIA_BAD_PREQ },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, ATA_UDMA2, VIA_SET_FIFO },
+ { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, ATA_UDMA2, VIA_SET_FIFO },
+ { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, 0x00, VIA_SET_FIFO },
+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK },
+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+ { "vtxxxx", PCI_DEVICE_ID_VIA_ANON, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
{ NULL }
};
+static const struct dmi_system_id no_atapi_dma_dmi_table[] = {
+ {
+ .ident = "AVERATEC 3200",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AVERATEC"),
+ DMI_MATCH(DMI_BOARD_NAME, "3200"),
+ },
+ },
+ { }
+};
+
+struct via_port {
+ u8 cached_device;
+};
/*
* Cable special cases
@@ -177,10 +189,10 @@ static int via_cable_detect(struct ata_port *ap) {
return ATA_CBL_SATA;
/* Early chips are 40 wire */
- if ((config->flags & VIA_UDMA) < VIA_UDMA_66)
+ if (config->udma_mask < ATA_UDMA4)
return ATA_CBL_PATA40;
/* UDMA 66 chips have only drive side logic */
- else if ((config->flags & VIA_UDMA) < VIA_UDMA_100)
+ else if (config->udma_mask < ATA_UDMA5)
return ATA_CBL_PATA_UNK;
/* UDMA 100 or later */
pci_read_config_dword(pdev, 0x50, &ata66);
@@ -215,11 +227,10 @@ static int via_pre_reset(struct ata_link *link, unsigned long deadline)
/**
- * via_do_set_mode - set initial PIO mode data
+ * via_do_set_mode - set transfer mode data
* @ap: ATA interface
* @adev: ATA device
* @mode: ATA mode being programmed
- * @tdiv: Clocks per PCI clock
* @set_ast: Set to program address setup
* @udma_type: UDMA mode/format of registers
*
@@ -230,17 +241,27 @@ static int via_pre_reset(struct ata_link *link, unsigned long deadline)
* on the two channels.
*/
-static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mode, int tdiv, int set_ast, int udma_type)
+static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev,
+ int mode, int set_ast, int udma_type)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct ata_device *peer = ata_dev_pair(adev);
struct ata_timing t, p;
- static int via_clock = 33333; /* Bus clock in kHZ - ought to be tunable one day */
+ static int via_clock = 33333; /* Bus clock in kHZ */
unsigned long T = 1000000000 / via_clock;
- unsigned long UT = T/tdiv;
+ unsigned long UT = T;
int ut;
int offset = 3 - (2*ap->port_no) - adev->devno;
+ switch (udma_type) {
+ case ATA_UDMA4:
+ UT = T / 2; break;
+ case ATA_UDMA5:
+ UT = T / 3; break;
+ case ATA_UDMA6:
+ UT = T / 4; break;
+ }
+
/* Calculate the timing values we require */
ata_timing_compute(adev, mode, &t, T, UT);
@@ -259,44 +280,49 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo
pci_read_config_byte(pdev, 0x4C, &setup);
setup &= ~(3 << shift);
- setup |= FIT(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */
+ setup |= (clamp_val(t.setup, 1, 4) - 1) << shift;
pci_write_config_byte(pdev, 0x4C, setup);
}
/* Load the PIO mode bits */
pci_write_config_byte(pdev, 0x4F - ap->port_no,
- ((FIT(t.act8b, 1, 16) - 1) << 4) | (FIT(t.rec8b, 1, 16) - 1));
+ ((clamp_val(t.act8b, 1, 16) - 1) << 4) | (clamp_val(t.rec8b, 1, 16) - 1));
pci_write_config_byte(pdev, 0x48 + offset,
- ((FIT(t.active, 1, 16) - 1) << 4) | (FIT(t.recover, 1, 16) - 1));
+ ((clamp_val(t.active, 1, 16) - 1) << 4) | (clamp_val(t.recover, 1, 16) - 1));
/* Load the UDMA bits according to type */
- switch(udma_type) {
- default:
- /* BUG() ? */
- /* fall through */
- case 33:
- ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 5) - 2)) : 0x03;
- break;
- case 66:
- ut = t.udma ? (0xe8 | (FIT(t.udma, 2, 9) - 2)) : 0x0f;
- break;
- case 100:
- ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
- break;
- case 133:
- ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
- break;
+ switch (udma_type) {
+ case ATA_UDMA2:
+ default:
+ ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 5) - 2)) : 0x03;
+ break;
+ case ATA_UDMA4:
+ ut = t.udma ? (0xe8 | (clamp_val(t.udma, 2, 9) - 2)) : 0x0f;
+ break;
+ case ATA_UDMA5:
+ ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
+ break;
+ case ATA_UDMA6:
+ ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
+ break;
}
/* Set UDMA unless device is not UDMA capable */
- if (udma_type && t.udma) {
- u8 cable80_status;
+ if (udma_type) {
+ u8 udma_etc;
+
+ pci_read_config_byte(pdev, 0x50 + offset, &udma_etc);
- /* Get 80-wire cable detection bit */
- pci_read_config_byte(pdev, 0x50 + offset, &cable80_status);
- cable80_status &= 0x10;
+ /* clear transfer mode bit */
+ udma_etc &= ~0x20;
- pci_write_config_byte(pdev, 0x50 + offset, ut | cable80_status);
+ if (t.udma) {
+ /* preserve 80-wire cable detection bit */
+ udma_etc &= 0x10;
+ udma_etc |= ut;
+ }
+
+ pci_write_config_byte(pdev, 0x50 + offset, udma_etc);
}
}
@@ -304,22 +330,128 @@ static void via_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
const struct via_isa_bridge *config = ap->host->private_data;
int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1;
- int mode = config->flags & VIA_UDMA;
- static u8 tclock[5] = { 1, 1, 2, 3, 4 };
- static u8 udma[5] = { 0, 33, 66, 100, 133 };
- via_do_set_mode(ap, adev, adev->pio_mode, tclock[mode], set_ast, udma[mode]);
+ via_do_set_mode(ap, adev, adev->pio_mode, set_ast, config->udma_mask);
}
static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
const struct via_isa_bridge *config = ap->host->private_data;
int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1;
- int mode = config->flags & VIA_UDMA;
- static u8 tclock[5] = { 1, 1, 2, 3, 4 };
- static u8 udma[5] = { 0, 33, 66, 100, 133 };
- via_do_set_mode(ap, adev, adev->dma_mode, tclock[mode], set_ast, udma[mode]);
+ via_do_set_mode(ap, adev, adev->dma_mode, set_ast, config->udma_mask);
+}
+
+/**
+ * via_mode_filter - filter buggy device/mode pairs
+ * @dev: ATA device
+ * @mask: Mode bitmask
+ *
+ * We need to apply some minimal filtering for old controllers and at least
+ * one breed of Transcend SSD. Return the updated mask.
+ */
+
+static unsigned long via_mode_filter(struct ata_device *dev, unsigned long mask)
+{
+ struct ata_host *host = dev->link->ap->host;
+ const struct via_isa_bridge *config = host->private_data;
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
+
+ if (config->id == PCI_DEVICE_ID_VIA_82C586_0) {
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
+ if (strcmp(model_num, "TS64GSSD25-M") == 0) {
+ ata_dev_warn(dev,
+ "disabling UDMA mode due to reported lockups with this device\n");
+ mask &= ~ ATA_MASK_UDMA;
+ }
+ }
+
+ if (dev->class == ATA_DEV_ATAPI &&
+ dmi_check_system(no_atapi_dma_dmi_table)) {
+ ata_dev_warn(dev, "controller locks up on ATAPI DMA, forcing PIO\n");
+ mask &= ATA_MASK_PIO;
+ }
+
+ return mask;
+}
+
+/**
+ * via_tf_load - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @tf: ATA taskfile register set
+ *
+ * Outputs ATA taskfile to standard ATA host controller.
+ *
+ * Note: This is to fix the internal bug of via chipsets, which
+ * will reset the device register after changing the IEN bit on
+ * ctl register
+ */
+static void via_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ struct via_port *vp = ap->private_data;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+ int newctl = 0;
+
+ if (tf->ctl != ap->last_ctl) {
+ iowrite8(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ newctl = 1;
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ iowrite8(tf->device, ioaddr->device_addr);
+ vp->cached_device = tf->device;
+ } else if (newctl)
+ iowrite8(vp->cached_device, ioaddr->device_addr);
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ WARN_ON_ONCE(!ioaddr->ctl_addr);
+ iowrite8(tf->hob_feature, ioaddr->feature_addr);
+ iowrite8(tf->hob_nsect, ioaddr->nsect_addr);
+ iowrite8(tf->hob_lbal, ioaddr->lbal_addr);
+ iowrite8(tf->hob_lbam, ioaddr->lbam_addr);
+ iowrite8(tf->hob_lbah, ioaddr->lbah_addr);
+ VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+ tf->hob_feature,
+ tf->hob_nsect,
+ tf->hob_lbal,
+ tf->hob_lbam,
+ tf->hob_lbah);
+ }
+
+ if (is_addr) {
+ iowrite8(tf->feature, ioaddr->feature_addr);
+ iowrite8(tf->nsect, ioaddr->nsect_addr);
+ iowrite8(tf->lbal, ioaddr->lbal_addr);
+ iowrite8(tf->lbam, ioaddr->lbam_addr);
+ iowrite8(tf->lbah, ioaddr->lbah_addr);
+ VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+ tf->feature,
+ tf->nsect,
+ tf->lbal,
+ tf->lbam,
+ tf->lbah);
+ }
+
+ ata_wait_idle(ap);
+}
+
+static int via_port_start(struct ata_port *ap)
+{
+ struct via_port *vp;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ int ret = ata_bmdma_port_start(ap);
+ if (ret < 0)
+ return ret;
+
+ vp = devm_kzalloc(&pdev->dev, sizeof(struct via_port), GFP_KERNEL);
+ if (vp == NULL)
+ return -ENOMEM;
+ ap->private_data = vp;
+ return 0;
}
static struct scsi_host_template via_sht = {
@@ -332,6 +464,9 @@ static struct ata_port_operations via_port_ops = {
.set_piomode = via_set_piomode,
.set_dmamode = via_set_dmamode,
.prereset = via_pre_reset,
+ .sff_tf_load = via_tf_load,
+ .port_start = via_port_start,
+ .mode_filter = via_mode_filter,
};
static struct ata_port_operations via_port_ops_noirq = {
@@ -373,6 +508,27 @@ static void via_config_fifo(struct pci_dev *pdev, unsigned int flags)
}
}
+static void via_fixup(struct pci_dev *pdev, const struct via_isa_bridge *config)
+{
+ u32 timing;
+
+ /* Initialise the FIFO for the enabled channels. */
+ via_config_fifo(pdev, config->flags);
+
+ if (config->udma_mask == ATA_UDMA4) {
+ /* The 66 MHz devices require we enable the clock */
+ pci_read_config_dword(pdev, 0x50, &timing);
+ timing |= 0x80008;
+ pci_write_config_dword(pdev, 0x50, timing);
+ }
+ if (config->flags & VIA_BAD_CLK66) {
+ /* Disable the 66MHz clock on problem devices */
+ pci_read_config_dword(pdev, 0x50, &timing);
+ timing &= ~0x80008;
+ pci_write_config_dword(pdev, 0x50, timing);
+ }
+}
+
/**
* via_init_one - discovery callback
* @pdev: PCI device
@@ -387,134 +543,123 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
/* Early VIA without UDMA support */
static const struct ata_port_info via_mwdma_info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.port_ops = &via_port_ops
};
/* Ditto with IRQ masking required */
static const struct ata_port_info via_mwdma_info_borked = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.port_ops = &via_port_ops_noirq,
};
/* VIA UDMA 33 devices (and borked 66) */
static const struct ata_port_info via_udma33_info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA2,
.port_ops = &via_port_ops
};
/* VIA UDMA 66 devices */
static const struct ata_port_info via_udma66_info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA4,
.port_ops = &via_port_ops
};
/* VIA UDMA 100 devices */
static const struct ata_port_info via_udma100_info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &via_port_ops
};
/* UDMA133 with bad AST (All current 133) */
static const struct ata_port_info via_udma133_info = {
.flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6, /* FIXME: should check north bridge */
.port_ops = &via_port_ops
};
const struct ata_port_info *ppi[] = { NULL, NULL };
- struct pci_dev *isa = NULL;
+ struct pci_dev *isa;
const struct via_isa_bridge *config;
- static int printed_version;
u8 enable;
- u32 timing;
+ unsigned long flags = id->driver_data;
int rc;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
rc = pcim_enable_device(pdev);
if (rc)
return rc;
+ if (flags & VIA_IDFLAG_SINGLE)
+ ppi[1] = &ata_dummy_port_info;
+
/* To find out how the IDE will behave and what features we
actually have to look at the bridge not the IDE controller */
- for (config = via_isa_bridges; config->id; config++)
+ for (config = via_isa_bridges; config->id != PCI_DEVICE_ID_VIA_ANON;
+ config++)
if ((isa = pci_get_device(PCI_VENDOR_ID_VIA +
!!(config->flags & VIA_BAD_ID),
config->id, NULL))) {
+ u8 rev = isa->revision;
+ pci_dev_put(isa);
+
+ if ((id->device == 0x0415 || id->device == 0x3164) &&
+ (config->id != id->device))
+ continue;
- if (isa->revision >= config->rev_min &&
- isa->revision <= config->rev_max)
+ if (rev >= config->rev_min && rev <= config->rev_max)
break;
- pci_dev_put(isa);
}
- if (!config->id) {
- printk(KERN_WARNING "via: Unknown VIA SouthBridge, disabling.\n");
- return -ENODEV;
- }
- pci_dev_put(isa);
-
- /* 0x40 low bits indicate enabled channels */
- pci_read_config_byte(pdev, 0x40 , &enable);
- enable &= 3;
- if (enable == 0) {
- return -ENODEV;
+ if (!(config->flags & VIA_NO_ENABLES)) {
+ /* 0x40 low bits indicate enabled channels */
+ pci_read_config_byte(pdev, 0x40 , &enable);
+ enable &= 3;
+ if (enable == 0)
+ return -ENODEV;
}
- /* Initialise the FIFO for the enabled channels. */
- via_config_fifo(pdev, config->flags);
-
/* Clock set up */
- switch(config->flags & VIA_UDMA) {
- case VIA_UDMA_NONE:
- if (config->flags & VIA_NO_UNMASK)
- ppi[0] = &via_mwdma_info_borked;
- else
- ppi[0] = &via_mwdma_info;
- break;
- case VIA_UDMA_33:
- ppi[0] = &via_udma33_info;
- break;
- case VIA_UDMA_66:
- ppi[0] = &via_udma66_info;
- /* The 66 MHz devices require we enable the clock */
- pci_read_config_dword(pdev, 0x50, &timing);
- timing |= 0x80008;
- pci_write_config_dword(pdev, 0x50, timing);
- break;
- case VIA_UDMA_100:
- ppi[0] = &via_udma100_info;
- break;
- case VIA_UDMA_133:
- ppi[0] = &via_udma133_info;
- break;
- default:
- WARN_ON(1);
- return -ENODEV;
- }
+ switch (config->udma_mask) {
+ case 0x00:
+ if (config->flags & VIA_NO_UNMASK)
+ ppi[0] = &via_mwdma_info_borked;
+ else
+ ppi[0] = &via_mwdma_info;
+ break;
+ case ATA_UDMA2:
+ ppi[0] = &via_udma33_info;
+ break;
+ case ATA_UDMA4:
+ ppi[0] = &via_udma66_info;
+ break;
+ case ATA_UDMA5:
+ ppi[0] = &via_udma100_info;
+ break;
+ case ATA_UDMA6:
+ ppi[0] = &via_udma133_info;
+ break;
+ default:
+ WARN_ON(1);
+ return -ENODEV;
+ }
- if (config->flags & VIA_BAD_CLK66) {
- /* Disable the 66MHz clock on problem devices */
- pci_read_config_dword(pdev, 0x50, &timing);
- timing &= ~0x80008;
- pci_write_config_dword(pdev, 0x50, timing);
- }
+ via_fixup(pdev, config);
/* We have established the device type, now fire it up */
- return ata_pci_sff_init_one(pdev, ppi, &via_sht, (void *)config);
+ return ata_pci_bmdma_init_one(pdev, ppi, &via_sht, (void *)config, 0);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/**
* via_reinit_one - reinit after resume
* @pdev; PCI device
@@ -527,29 +672,14 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
static int via_reinit_one(struct pci_dev *pdev)
{
- u32 timing;
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
- const struct via_isa_bridge *config = host->private_data;
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
if (rc)
return rc;
- via_config_fifo(pdev, config->flags);
-
- if ((config->flags & VIA_UDMA) == VIA_UDMA_66) {
- /* The 66 MHz devices require we enable the clock */
- pci_read_config_dword(pdev, 0x50, &timing);
- timing |= 0x80008;
- pci_write_config_dword(pdev, 0x50, timing);
- }
- if (config->flags & VIA_BAD_CLK66) {
- /* Disable the 66MHz clock on problem devices */
- pci_read_config_dword(pdev, 0x50, &timing);
- timing &= ~0x80008;
- pci_write_config_dword(pdev, 0x50, timing);
- }
+ via_fixup(pdev, host->private_data);
ata_host_resume(host);
return 0;
@@ -557,11 +687,14 @@ static int via_reinit_one(struct pci_dev *pdev)
#endif
static const struct pci_device_id via[] = {
+ { PCI_VDEVICE(VIA, 0x0415), },
{ PCI_VDEVICE(VIA, 0x0571), },
{ PCI_VDEVICE(VIA, 0x0581), },
{ PCI_VDEVICE(VIA, 0x1571), },
{ PCI_VDEVICE(VIA, 0x3164), },
{ PCI_VDEVICE(VIA, 0x5324), },
+ { PCI_VDEVICE(VIA, 0xC409), VIA_IDFLAG_SINGLE },
+ { PCI_VDEVICE(VIA, 0x9001), VIA_IDFLAG_SINGLE },
{ },
};
@@ -571,27 +704,16 @@ static struct pci_driver via_pci_driver = {
.id_table = via,
.probe = via_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = via_reinit_one,
#endif
};
-static int __init via_init(void)
-{
- return pci_register_driver(&via_pci_driver);
-}
-
-static void __exit via_exit(void)
-{
- pci_unregister_driver(&via_pci_driver);
-}
+module_pci_driver(via_pci_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for VIA PATA");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, via);
MODULE_VERSION(DRV_VERSION);
-
-module_init(via_init);
-module_exit(via_exit);
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
deleted file mode 100644
index 6e52a3573fb..00000000000
--- a/drivers/ata/pata_winbond.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * pata_winbond.c - Winbond VLB ATA controllers
- * (C) 2006 Red Hat <alan@redhat.com>
- *
- * Support for the Winbond 83759A when operating in advanced mode.
- * Multichip mode is not currently supported.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <scsi/scsi_host.h>
-#include <linux/libata.h>
-#include <linux/platform_device.h>
-
-#define DRV_NAME "pata_winbond"
-#define DRV_VERSION "0.0.3"
-
-#define NR_HOST 4 /* Two winbond controllers, two channels each */
-
-struct winbond_data {
- unsigned long config;
- struct platform_device *platform_dev;
-};
-
-static struct ata_host *winbond_host[NR_HOST];
-static struct winbond_data winbond_data[NR_HOST];
-static int nr_winbond_host;
-
-#ifdef MODULE
-static int probe_winbond = 1;
-#else
-static int probe_winbond;
-#endif
-
-static DEFINE_SPINLOCK(winbond_lock);
-
-static void winbond_writecfg(unsigned long port, u8 reg, u8 val)
-{
- unsigned long flags;
- spin_lock_irqsave(&winbond_lock, flags);
- outb(reg, port + 0x01);
- outb(val, port + 0x02);
- spin_unlock_irqrestore(&winbond_lock, flags);
-}
-
-static u8 winbond_readcfg(unsigned long port, u8 reg)
-{
- u8 val;
-
- unsigned long flags;
- spin_lock_irqsave(&winbond_lock, flags);
- outb(reg, port + 0x01);
- val = inb(port + 0x02);
- spin_unlock_irqrestore(&winbond_lock, flags);
-
- return val;
-}
-
-static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
-{
- struct ata_timing t;
- struct winbond_data *winbond = ap->host->private_data;
- int active, recovery;
- u8 reg;
- int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2);
-
- reg = winbond_readcfg(winbond->config, 0x81);
-
- /* Get the timing data in cycles */
- if (reg & 0x40) /* Fast VLB bus, assume 50MHz */
- ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
- else
- ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
-
- active = (FIT(t.active, 3, 17) - 1) & 0x0F;
- recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F;
- timing = (active << 4) | recovery;
- winbond_writecfg(winbond->config, timing, reg);
-
- /* Load the setup timing */
-
- reg = 0x35;
- if (adev->class != ATA_DEV_ATA)
- reg |= 0x08; /* FIFO off */
- if (!ata_pio_need_iordy(adev))
- reg |= 0x02; /* IORDY off */
- reg |= (FIT(t.setup, 0, 3) << 6);
- winbond_writecfg(winbond->config, timing + 1, reg);
-}
-
-
-static unsigned int winbond_data_xfer(struct ata_device *dev,
- unsigned char *buf, unsigned int buflen, int rw)
-{
- struct ata_port *ap = dev->link->ap;
- int slop = buflen & 3;
-
- if (ata_id_has_dword_io(dev->id)) {
- if (rw == READ)
- ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
- else
- iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
-
- if (unlikely(slop)) {
- u32 pad;
- if (rw == READ) {
- pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
- memcpy(buf + buflen - slop, &pad, slop);
- } else {
- memcpy(&pad, buf + buflen - slop, slop);
- iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
- }
- buflen += 4 - slop;
- }
- } else
- buflen = ata_sff_data_xfer(dev, buf, buflen, rw);
-
- return buflen;
-}
-
-static struct scsi_host_template winbond_sht = {
- ATA_PIO_SHT(DRV_NAME),
-};
-
-static struct ata_port_operations winbond_port_ops = {
- .inherits = &ata_sff_port_ops,
- .sff_data_xfer = winbond_data_xfer,
- .cable_detect = ata_cable_40wire,
- .set_piomode = winbond_set_piomode,
-};
-
-/**
- * winbond_init_one - attach a winbond interface
- * @type: Type to display
- * @io: I/O port start
- * @irq: interrupt line
- * @fast: True if on a > 33Mhz VLB
- *
- * Register a VLB bus IDE interface. Such interfaces are PIO and we
- * assume do not support IRQ sharing.
- */
-
-static __init int winbond_init_one(unsigned long port)
-{
- struct platform_device *pdev;
- u8 reg;
- int i, rc;
-
- reg = winbond_readcfg(port, 0x81);
- reg |= 0x80; /* jumpered mode off */
- winbond_writecfg(port, 0x81, reg);
- reg = winbond_readcfg(port, 0x83);
- reg |= 0xF0; /* local control */
- winbond_writecfg(port, 0x83, reg);
- reg = winbond_readcfg(port, 0x85);
- reg |= 0xF0; /* programmable timing */
- winbond_writecfg(port, 0x85, reg);
-
- reg = winbond_readcfg(port, 0x81);
-
- if (!(reg & 0x03)) /* Disabled */
- return -ENODEV;
-
- for (i = 0; i < 2 ; i ++) {
- unsigned long cmd_port = 0x1F0 - (0x80 * i);
- unsigned long ctl_port = cmd_port + 0x206;
- struct ata_host *host;
- struct ata_port *ap;
- void __iomem *cmd_addr, *ctl_addr;
-
- if (!(reg & (1 << i)))
- continue;
-
- pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0);
- if (IS_ERR(pdev))
- return PTR_ERR(pdev);
-
- rc = -ENOMEM;
- host = ata_host_alloc(&pdev->dev, 1);
- if (!host)
- goto err_unregister;
- ap = host->ports[0];
-
- rc = -ENOMEM;
- cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
- ctl_addr = devm_ioport_map(&pdev->dev, ctl_port, 1);
- if (!cmd_addr || !ctl_addr)
- goto err_unregister;
-
- ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", cmd_port, ctl_port);
-
- ap->ops = &winbond_port_ops;
- ap->pio_mask = 0x1F;
- ap->flags |= ATA_FLAG_SLAVE_POSS;
- ap->ioaddr.cmd_addr = cmd_addr;
- ap->ioaddr.altstatus_addr = ctl_addr;
- ap->ioaddr.ctl_addr = ctl_addr;
- ata_sff_std_ports(&ap->ioaddr);
-
- /* hook in a private data structure per channel */
- host->private_data = &winbond_data[nr_winbond_host];
- winbond_data[nr_winbond_host].config = port;
- winbond_data[nr_winbond_host].platform_dev = pdev;
-
- /* activate */
- rc = ata_host_activate(host, 14 + i, ata_sff_interrupt, 0,
- &winbond_sht);
- if (rc)
- goto err_unregister;
-
- winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev);
- }
-
- return 0;
-
- err_unregister:
- platform_device_unregister(pdev);
- return rc;
-}
-
-/**
- * winbond_init - attach winbond interfaces
- *
- * Attach winbond IDE interfaces by scanning the ports it may occupy.
- */
-
-static __init int winbond_init(void)
-{
- static const unsigned long config[2] = { 0x130, 0x1B0 };
-
- int ct = 0;
- int i;
-
- if (probe_winbond == 0)
- return -ENODEV;
-
- /*
- * Check both base addresses
- */
-
- for (i = 0; i < 2; i++) {
- if (probe_winbond & (1<<i)) {
- int ret = 0;
- unsigned long port = config[i];
-
- if (request_region(port, 2, "pata_winbond")) {
- ret = winbond_init_one(port);
- if (ret <= 0)
- release_region(port, 2);
- else ct+= ret;
- }
- }
- }
- if (ct != 0)
- return 0;
- return -ENODEV;
-}
-
-static __exit void winbond_exit(void)
-{
- int i;
-
- for (i = 0; i < nr_winbond_host; i++) {
- ata_host_detach(winbond_host[i]);
- release_region(winbond_data[i].config, 2);
- platform_device_unregister(winbond_data[i].platform_dev);
- }
-}
-
-MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("low-level driver for Winbond VL ATA");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
-module_init(winbond_init);
-module_exit(winbond_exit);
-
-module_param(probe_winbond, int, 0);
-
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index be53545c9f6..f10631beffa 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -1,7 +1,7 @@
/*
* pdc_adma.c - Pacific Digital Corporation ADMA
*
- * Maintained by: Mark Lord <mlord@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
*
* Copyright 2005 Mark Lord
*
@@ -34,8 +34,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -148,6 +148,8 @@ static struct scsi_host_template adma_ata_sht = {
static struct ata_port_operations adma_ata_ops = {
.inherits = &ata_sff_port_ops,
+ .lost_interrupt = ATA_OP_NULL,
+
.check_atapi_dma = adma_check_atapi_dma,
.qc_prep = adma_qc_prep,
.qc_issue = adma_qc_issue,
@@ -163,10 +165,8 @@ static struct ata_port_operations adma_ata_ops = {
static struct ata_port_info adma_port_info[] = {
/* board_1841_idx */
{
- .flags = ATA_FLAG_SLAVE_POSS |
- ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
- ATA_FLAG_PIO_POLLING,
- .pio_mask = 0x10, /* pio4 */
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_POLLING,
+ .pio_mask = ATA_PIO4_ONLY,
.udma_mask = ATA_UDMA4,
.port_ops = &adma_ata_ops,
},
@@ -321,10 +321,8 @@ static void adma_qc_prep(struct ata_queued_cmd *qc)
VPRINTK("ENTER\n");
adma_enter_reg_mode(qc->ap);
- if (qc->tf.protocol != ATA_PROT_DMA) {
- ata_sff_qc_prep(qc);
+ if (qc->tf.protocol != ATA_PROT_DMA)
return;
- }
buf[i++] = 0; /* Response flags */
buf[i++] = 0; /* reserved */
@@ -439,8 +437,6 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host)
continue;
handled = 1;
adma_enter_reg_mode(ap);
- if (ap->flags & ATA_FLAG_DISABLED)
- continue;
pp = ap->private_data;
if (!pp || pp->state != adma_state_pkt)
continue;
@@ -481,42 +477,38 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host)
unsigned int handled = 0, port_no;
for (port_no = 0; port_no < host->n_ports; ++port_no) {
- struct ata_port *ap;
- ap = host->ports[port_no];
- if (ap && (!(ap->flags & ATA_FLAG_DISABLED))) {
- struct ata_queued_cmd *qc;
- struct adma_port_priv *pp = ap->private_data;
- if (!pp || pp->state != adma_state_mmio)
+ struct ata_port *ap = host->ports[port_no];
+ struct adma_port_priv *pp = ap->private_data;
+ struct ata_queued_cmd *qc;
+
+ if (!pp || pp->state != adma_state_mmio)
+ continue;
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
+
+ /* check main status, clearing INTRQ */
+ u8 status = ata_sff_check_status(ap);
+ if ((status & ATA_BUSY))
continue;
- qc = ata_qc_from_tag(ap, ap->link.active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
-
- /* check main status, clearing INTRQ */
- u8 status = ata_sff_check_status(ap);
- if ((status & ATA_BUSY))
- continue;
- DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
- ap->print_id, qc->tf.protocol, status);
-
- /* complete taskfile transaction */
- pp->state = adma_state_idle;
- qc->err_mask |= ac_err_mask(status);
- if (!qc->err_mask)
- ata_qc_complete(qc);
- else {
- struct ata_eh_info *ehi =
- &ap->link.eh_info;
- ata_ehi_clear_desc(ehi);
- ata_ehi_push_desc(ehi,
- "status 0x%02X", status);
-
- if (qc->err_mask == AC_ERR_DEV)
- ata_port_abort(ap);
- else
- ata_port_freeze(ap);
- }
- handled = 1;
+ DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
+ ap->print_id, qc->tf.protocol, status);
+
+ /* complete taskfile transaction */
+ pp->state = adma_state_idle;
+ qc->err_mask |= ac_err_mask(status);
+ if (!qc->err_mask)
+ ata_qc_complete(qc);
+ else {
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "status 0x%02X", status);
+
+ if (qc->err_mask == AC_ERR_DEV)
+ ata_port_abort(ap);
+ else
+ ata_port_freeze(ap);
}
+ handled = 1;
}
}
return handled;
@@ -559,11 +551,7 @@ static int adma_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
struct adma_port_priv *pp;
- int rc;
- rc = ata_port_start(ap);
- if (rc)
- return rc;
adma_enter_reg_mode(ap);
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
@@ -605,16 +593,14 @@ static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
{
int rc;
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit DMA enable failed\n");
+ dev_err(&pdev->dev, "32-bit DMA enable failed\n");
return rc;
}
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit consistent DMA enable failed\n");
+ dev_err(&pdev->dev, "32-bit consistent DMA enable failed\n");
return rc;
}
return 0;
@@ -623,15 +609,13 @@ static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
static int adma_ata_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- static int printed_version;
unsigned int board_idx = (unsigned int) ent->driver_data;
const struct ata_port_info *ppi[] = { &adma_port_info[board_idx], NULL };
struct ata_host *host;
void __iomem *mmio_base;
int rc, port_no;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
/* alloc host */
host = ata_host_alloc_pinfo(&pdev->dev, ppi, ADMA_PORTS);
@@ -675,21 +659,10 @@ static int adma_ata_init_one(struct pci_dev *pdev,
&adma_ata_sht);
}
-static int __init adma_ata_init(void)
-{
- return pci_register_driver(&adma_ata_pci_driver);
-}
-
-static void __exit adma_ata_exit(void)
-{
- pci_unregister_driver(&adma_ata_pci_driver);
-}
+module_pci_driver(adma_ata_pci_driver);
MODULE_AUTHOR("Mark Lord");
MODULE_DESCRIPTION("Pacific Digital Corporation ADMA low-level driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, adma_ata_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
-module_init(adma_ata_init);
-module_exit(adma_ata_exit);
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c
new file mode 100644
index 00000000000..0bb2cabd219
--- /dev/null
+++ b/drivers/ata/sata_dwc_460ex.c
@@ -0,0 +1,1822 @@
+/*
+ * drivers/ata/sata_dwc_460ex.c
+ *
+ * Synopsys DesignWare Cores (DWC) SATA host driver
+ *
+ * Author: Mark Miesfeld <mmiesfeld@amcc.com>
+ *
+ * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr@denx.de>
+ * Copyright 2008 DENX Software Engineering
+ *
+ * Based on versions provided by AMCC and Synopsys which are:
+ * Copyright 2006 Applied Micro Circuits Corporation
+ * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifdef CONFIG_SATA_DWC_DEBUG
+#define DEBUG
+#endif
+
+#ifdef CONFIG_SATA_DWC_VDEBUG
+#define VERBOSE_DEBUG
+#define DEBUG_NCQ
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/slab.h>
+#include "libata.h"
+
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+
+/* These two are defined in "libata.h" */
+#undef DRV_NAME
+#undef DRV_VERSION
+
+#define DRV_NAME "sata-dwc"
+#define DRV_VERSION "1.3"
+
+/* SATA DMA driver Globals */
+#define DMA_NUM_CHANS 1
+#define DMA_NUM_CHAN_REGS 8
+
+/* SATA DMA Register definitions */
+#define AHB_DMA_BRST_DFLT 64 /* 16 data items burst length*/
+
+struct dmareg {
+ u32 low; /* Low bits 0-31 */
+ u32 high; /* High bits 32-63 */
+};
+
+/* DMA Per Channel registers */
+struct dma_chan_regs {
+ struct dmareg sar; /* Source Address */
+ struct dmareg dar; /* Destination address */
+ struct dmareg llp; /* Linked List Pointer */
+ struct dmareg ctl; /* Control */
+ struct dmareg sstat; /* Source Status not implemented in core */
+ struct dmareg dstat; /* Destination Status not implemented in core*/
+ struct dmareg sstatar; /* Source Status Address not impl in core */
+ struct dmareg dstatar; /* Destination Status Address not implemente */
+ struct dmareg cfg; /* Config */
+ struct dmareg sgr; /* Source Gather */
+ struct dmareg dsr; /* Destination Scatter */
+};
+
+/* Generic Interrupt Registers */
+struct dma_interrupt_regs {
+ struct dmareg tfr; /* Transfer Interrupt */
+ struct dmareg block; /* Block Interrupt */
+ struct dmareg srctran; /* Source Transfer Interrupt */
+ struct dmareg dsttran; /* Dest Transfer Interrupt */
+ struct dmareg error; /* Error */
+};
+
+struct ahb_dma_regs {
+ struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS];
+ struct dma_interrupt_regs interrupt_raw; /* Raw Interrupt */
+ struct dma_interrupt_regs interrupt_status; /* Interrupt Status */
+ struct dma_interrupt_regs interrupt_mask; /* Interrupt Mask */
+ struct dma_interrupt_regs interrupt_clear; /* Interrupt Clear */
+ struct dmareg statusInt; /* Interrupt combined*/
+ struct dmareg rq_srcreg; /* Src Trans Req */
+ struct dmareg rq_dstreg; /* Dst Trans Req */
+ struct dmareg rq_sgl_srcreg; /* Sngl Src Trans Req*/
+ struct dmareg rq_sgl_dstreg; /* Sngl Dst Trans Req*/
+ struct dmareg rq_lst_srcreg; /* Last Src Trans Req*/
+ struct dmareg rq_lst_dstreg; /* Last Dst Trans Req*/
+ struct dmareg dma_cfg; /* DMA Config */
+ struct dmareg dma_chan_en; /* DMA Channel Enable*/
+ struct dmareg dma_id; /* DMA ID */
+ struct dmareg dma_test; /* DMA Test */
+ struct dmareg res1; /* reserved */
+ struct dmareg res2; /* reserved */
+ /*
+ * DMA Comp Params
+ * Param 6 = dma_param[0], Param 5 = dma_param[1],
+ * Param 4 = dma_param[2] ...
+ */
+ struct dmareg dma_params[6];
+};
+
+/* Data structure for linked list item */
+struct lli {
+ u32 sar; /* Source Address */
+ u32 dar; /* Destination address */
+ u32 llp; /* Linked List Pointer */
+ struct dmareg ctl; /* Control */
+ struct dmareg dstat; /* Destination Status */
+};
+
+enum {
+ SATA_DWC_DMAC_LLI_SZ = (sizeof(struct lli)),
+ SATA_DWC_DMAC_LLI_NUM = 256,
+ SATA_DWC_DMAC_LLI_TBL_SZ = (SATA_DWC_DMAC_LLI_SZ * \
+ SATA_DWC_DMAC_LLI_NUM),
+ SATA_DWC_DMAC_TWIDTH_BYTES = 4,
+ SATA_DWC_DMAC_CTRL_TSIZE_MAX = (0x00000800 * \
+ SATA_DWC_DMAC_TWIDTH_BYTES),
+};
+
+/* DMA Register Operation Bits */
+enum {
+ DMA_EN = 0x00000001, /* Enable AHB DMA */
+ DMA_CTL_LLP_SRCEN = 0x10000000, /* Blk chain enable Src */
+ DMA_CTL_LLP_DSTEN = 0x08000000, /* Blk chain enable Dst */
+};
+
+#define DMA_CTL_BLK_TS(size) ((size) & 0x000000FFF) /* Blk Transfer size */
+#define DMA_CHANNEL(ch) (0x00000001 << (ch)) /* Select channel */
+ /* Enable channel */
+#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \
+ ((0x000000001 << (ch)) << 8))
+ /* Disable channel */
+#define DMA_DISABLE_CHAN(ch) (0x00000000 | ((0x000000001 << (ch)) << 8))
+ /* Transfer Type & Flow Controller */
+#define DMA_CTL_TTFC(type) (((type) & 0x7) << 20)
+#define DMA_CTL_SMS(num) (((num) & 0x3) << 25) /* Src Master Select */
+#define DMA_CTL_DMS(num) (((num) & 0x3) << 23)/* Dst Master Select */
+ /* Src Burst Transaction Length */
+#define DMA_CTL_SRC_MSIZE(size) (((size) & 0x7) << 14)
+ /* Dst Burst Transaction Length */
+#define DMA_CTL_DST_MSIZE(size) (((size) & 0x7) << 11)
+ /* Source Transfer Width */
+#define DMA_CTL_SRC_TRWID(size) (((size) & 0x7) << 4)
+ /* Destination Transfer Width */
+#define DMA_CTL_DST_TRWID(size) (((size) & 0x7) << 1)
+
+/* Assign HW handshaking interface (x) to destination / source peripheral */
+#define DMA_CFG_HW_HS_DEST(int_num) (((int_num) & 0xF) << 11)
+#define DMA_CFG_HW_HS_SRC(int_num) (((int_num) & 0xF) << 7)
+#define DMA_CFG_HW_CH_PRIOR(int_num) (((int_num) & 0xF) << 5)
+#define DMA_LLP_LMS(addr, master) (((addr) & 0xfffffffc) | (master))
+
+/*
+ * This define is used to set block chaining disabled in the control low
+ * register. It is already in little endian format so it can be &'d dirctly.
+ * It is essentially: cpu_to_le32(~(DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN))
+ */
+enum {
+ DMA_CTL_LLP_DISABLE_LE32 = 0xffffffe7,
+ DMA_CTL_TTFC_P2M_DMAC = 0x00000002, /* Per to mem, DMAC cntr */
+ DMA_CTL_TTFC_M2P_PER = 0x00000003, /* Mem to per, peripheral cntr */
+ DMA_CTL_SINC_INC = 0x00000000, /* Source Address Increment */
+ DMA_CTL_SINC_DEC = 0x00000200,
+ DMA_CTL_SINC_NOCHANGE = 0x00000400,
+ DMA_CTL_DINC_INC = 0x00000000, /* Destination Address Increment */
+ DMA_CTL_DINC_DEC = 0x00000080,
+ DMA_CTL_DINC_NOCHANGE = 0x00000100,
+ DMA_CTL_INT_EN = 0x00000001, /* Interrupt Enable */
+
+/* Channel Configuration Register high bits */
+ DMA_CFG_FCMOD_REQ = 0x00000001, /* Flow Control - request based */
+ DMA_CFG_PROTCTL = (0x00000003 << 2),/* Protection Control */
+
+/* Channel Configuration Register low bits */
+ DMA_CFG_RELD_DST = 0x80000000, /* Reload Dest / Src Addr */
+ DMA_CFG_RELD_SRC = 0x40000000,
+ DMA_CFG_HS_SELSRC = 0x00000800, /* Software handshake Src/ Dest */
+ DMA_CFG_HS_SELDST = 0x00000400,
+ DMA_CFG_FIFOEMPTY = (0x00000001 << 9), /* FIFO Empty bit */
+
+/* Channel Linked List Pointer Register */
+ DMA_LLP_AHBMASTER1 = 0, /* List Master Select */
+ DMA_LLP_AHBMASTER2 = 1,
+
+ SATA_DWC_MAX_PORTS = 1,
+
+ SATA_DWC_SCR_OFFSET = 0x24,
+ SATA_DWC_REG_OFFSET = 0x64,
+};
+
+/* DWC SATA Registers */
+struct sata_dwc_regs {
+ u32 fptagr; /* 1st party DMA tag */
+ u32 fpbor; /* 1st party DMA buffer offset */
+ u32 fptcr; /* 1st party DMA Xfr count */
+ u32 dmacr; /* DMA Control */
+ u32 dbtsr; /* DMA Burst Transac size */
+ u32 intpr; /* Interrupt Pending */
+ u32 intmr; /* Interrupt Mask */
+ u32 errmr; /* Error Mask */
+ u32 llcr; /* Link Layer Control */
+ u32 phycr; /* PHY Control */
+ u32 physr; /* PHY Status */
+ u32 rxbistpd; /* Recvd BIST pattern def register */
+ u32 rxbistpd1; /* Recvd BIST data dword1 */
+ u32 rxbistpd2; /* Recvd BIST pattern data dword2 */
+ u32 txbistpd; /* Trans BIST pattern def register */
+ u32 txbistpd1; /* Trans BIST data dword1 */
+ u32 txbistpd2; /* Trans BIST data dword2 */
+ u32 bistcr; /* BIST Control Register */
+ u32 bistfctr; /* BIST FIS Count Register */
+ u32 bistsr; /* BIST Status Register */
+ u32 bistdecr; /* BIST Dword Error count register */
+ u32 res[15]; /* Reserved locations */
+ u32 testr; /* Test Register */
+ u32 versionr; /* Version Register */
+ u32 idr; /* ID Register */
+ u32 unimpl[192]; /* Unimplemented */
+ u32 dmadr[256]; /* FIFO Locations in DMA Mode */
+};
+
+enum {
+ SCR_SCONTROL_DET_ENABLE = 0x00000001,
+ SCR_SSTATUS_DET_PRESENT = 0x00000001,
+ SCR_SERROR_DIAG_X = 0x04000000,
+/* DWC SATA Register Operations */
+ SATA_DWC_TXFIFO_DEPTH = 0x01FF,
+ SATA_DWC_RXFIFO_DEPTH = 0x01FF,
+ SATA_DWC_DMACR_TMOD_TXCHEN = 0x00000004,
+ SATA_DWC_DMACR_TXCHEN = (0x00000001 | SATA_DWC_DMACR_TMOD_TXCHEN),
+ SATA_DWC_DMACR_RXCHEN = (0x00000002 | SATA_DWC_DMACR_TMOD_TXCHEN),
+ SATA_DWC_DMACR_TXRXCH_CLEAR = SATA_DWC_DMACR_TMOD_TXCHEN,
+ SATA_DWC_INTPR_DMAT = 0x00000001,
+ SATA_DWC_INTPR_NEWFP = 0x00000002,
+ SATA_DWC_INTPR_PMABRT = 0x00000004,
+ SATA_DWC_INTPR_ERR = 0x00000008,
+ SATA_DWC_INTPR_NEWBIST = 0x00000010,
+ SATA_DWC_INTPR_IPF = 0x10000000,
+ SATA_DWC_INTMR_DMATM = 0x00000001,
+ SATA_DWC_INTMR_NEWFPM = 0x00000002,
+ SATA_DWC_INTMR_PMABRTM = 0x00000004,
+ SATA_DWC_INTMR_ERRM = 0x00000008,
+ SATA_DWC_INTMR_NEWBISTM = 0x00000010,
+ SATA_DWC_LLCR_SCRAMEN = 0x00000001,
+ SATA_DWC_LLCR_DESCRAMEN = 0x00000002,
+ SATA_DWC_LLCR_RPDEN = 0x00000004,
+/* This is all error bits, zero's are reserved fields. */
+ SATA_DWC_SERROR_ERR_BITS = 0x0FFF0F03
+};
+
+#define SATA_DWC_SCR0_SPD_GET(v) (((v) >> 4) & 0x0000000F)
+#define SATA_DWC_DMACR_TX_CLEAR(v) (((v) & ~SATA_DWC_DMACR_TXCHEN) |\
+ SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DMACR_RX_CLEAR(v) (((v) & ~SATA_DWC_DMACR_RXCHEN) |\
+ SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DBTSR_MWR(size) (((size)/4) & SATA_DWC_TXFIFO_DEPTH)
+#define SATA_DWC_DBTSR_MRD(size) ((((size)/4) & SATA_DWC_RXFIFO_DEPTH)\
+ << 16)
+struct sata_dwc_device {
+ struct device *dev; /* generic device struct */
+ struct ata_probe_ent *pe; /* ptr to probe-ent */
+ struct ata_host *host;
+ u8 *reg_base;
+ struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */
+ int irq_dma;
+};
+
+#define SATA_DWC_QCMD_MAX 32
+
+struct sata_dwc_device_port {
+ struct sata_dwc_device *hsdev;
+ int cmd_issued[SATA_DWC_QCMD_MAX];
+ struct lli *llit[SATA_DWC_QCMD_MAX]; /* DMA LLI table */
+ dma_addr_t llit_dma[SATA_DWC_QCMD_MAX];
+ u32 dma_chan[SATA_DWC_QCMD_MAX];
+ int dma_pending[SATA_DWC_QCMD_MAX];
+};
+
+/*
+ * Commonly used DWC SATA driver Macros
+ */
+#define HSDEV_FROM_HOST(host) ((struct sata_dwc_device *)\
+ (host)->private_data)
+#define HSDEV_FROM_AP(ap) ((struct sata_dwc_device *)\
+ (ap)->host->private_data)
+#define HSDEVP_FROM_AP(ap) ((struct sata_dwc_device_port *)\
+ (ap)->private_data)
+#define HSDEV_FROM_QC(qc) ((struct sata_dwc_device *)\
+ (qc)->ap->host->private_data)
+#define HSDEV_FROM_HSDEVP(p) ((struct sata_dwc_device *)\
+ (hsdevp)->hsdev)
+
+enum {
+ SATA_DWC_CMD_ISSUED_NOT = 0,
+ SATA_DWC_CMD_ISSUED_PEND = 1,
+ SATA_DWC_CMD_ISSUED_EXEC = 2,
+ SATA_DWC_CMD_ISSUED_NODATA = 3,
+
+ SATA_DWC_DMA_PENDING_NONE = 0,
+ SATA_DWC_DMA_PENDING_TX = 1,
+ SATA_DWC_DMA_PENDING_RX = 2,
+};
+
+struct sata_dwc_host_priv {
+ void __iomem *scr_addr_sstatus;
+ u32 sata_dwc_sactive_issued ;
+ u32 sata_dwc_sactive_queued ;
+ u32 dma_interrupt_count;
+ struct ahb_dma_regs *sata_dma_regs;
+ struct device *dwc_dev;
+ int dma_channel;
+};
+struct sata_dwc_host_priv host_pvt;
+/*
+ * Prototypes
+ */
+static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag);
+static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u32 check_status);
+static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status);
+static void sata_dwc_port_stop(struct ata_port *ap);
+static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag);
+static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq);
+static void dma_dwc_exit(struct sata_dwc_device *hsdev);
+static int dma_dwc_xfer_setup(struct scatterlist *sg, int num_elems,
+ struct lli *lli, dma_addr_t dma_lli,
+ void __iomem *addr, int dir);
+static void dma_dwc_xfer_start(int dma_ch);
+
+static const char *get_prot_descript(u8 protocol)
+{
+ switch ((enum ata_tf_protocols)protocol) {
+ case ATA_PROT_NODATA:
+ return "ATA no data";
+ case ATA_PROT_PIO:
+ return "ATA PIO";
+ case ATA_PROT_DMA:
+ return "ATA DMA";
+ case ATA_PROT_NCQ:
+ return "ATA NCQ";
+ case ATAPI_PROT_NODATA:
+ return "ATAPI no data";
+ case ATAPI_PROT_PIO:
+ return "ATAPI PIO";
+ case ATAPI_PROT_DMA:
+ return "ATAPI DMA";
+ default:
+ return "unknown";
+ }
+}
+
+static const char *get_dma_dir_descript(int dma_dir)
+{
+ switch ((enum dma_data_direction)dma_dir) {
+ case DMA_BIDIRECTIONAL:
+ return "bidirectional";
+ case DMA_TO_DEVICE:
+ return "to device";
+ case DMA_FROM_DEVICE:
+ return "from device";
+ default:
+ return "none";
+ }
+}
+
+static void sata_dwc_tf_dump(struct ata_taskfile *tf)
+{
+ dev_vdbg(host_pvt.dwc_dev, "taskfile cmd: 0x%02x protocol: %s flags:"
+ "0x%lx device: %x\n", tf->command,
+ get_prot_descript(tf->protocol), tf->flags, tf->device);
+ dev_vdbg(host_pvt.dwc_dev, "feature: 0x%02x nsect: 0x%x lbal: 0x%x "
+ "lbam: 0x%x lbah: 0x%x\n", tf->feature, tf->nsect, tf->lbal,
+ tf->lbam, tf->lbah);
+ dev_vdbg(host_pvt.dwc_dev, "hob_feature: 0x%02x hob_nsect: 0x%x "
+ "hob_lbal: 0x%x hob_lbam: 0x%x hob_lbah: 0x%x\n",
+ tf->hob_feature, tf->hob_nsect, tf->hob_lbal, tf->hob_lbam,
+ tf->hob_lbah);
+}
+
+/*
+ * Function: get_burst_length_encode
+ * arguments: datalength: length in bytes of data
+ * returns value to be programmed in register corresponding to data length
+ * This value is effectively the log(base 2) of the length
+ */
+static int get_burst_length_encode(int datalength)
+{
+ int items = datalength >> 2; /* div by 4 to get lword count */
+
+ if (items >= 64)
+ return 5;
+
+ if (items >= 32)
+ return 4;
+
+ if (items >= 16)
+ return 3;
+
+ if (items >= 8)
+ return 2;
+
+ if (items >= 4)
+ return 1;
+
+ return 0;
+}
+
+static void clear_chan_interrupts(int c)
+{
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.tfr.low),
+ DMA_CHANNEL(c));
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.block.low),
+ DMA_CHANNEL(c));
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.srctran.low),
+ DMA_CHANNEL(c));
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.dsttran.low),
+ DMA_CHANNEL(c));
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.error.low),
+ DMA_CHANNEL(c));
+}
+
+/*
+ * Function: dma_request_channel
+ * arguments: None
+ * returns channel number if available else -1
+ * This function assigns the next available DMA channel from the list to the
+ * requester
+ */
+static int dma_request_channel(void)
+{
+ /* Check if the channel is not currently in use */
+ if (!(in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low)) &
+ DMA_CHANNEL(host_pvt.dma_channel)))
+ return host_pvt.dma_channel;
+ dev_err(host_pvt.dwc_dev, "%s Channel %d is currently in use\n",
+ __func__, host_pvt.dma_channel);
+ return -1;
+}
+
+/*
+ * Function: dma_dwc_interrupt
+ * arguments: irq, dev_id, pt_regs
+ * returns channel number if available else -1
+ * Interrupt Handler for DW AHB SATA DMA
+ */
+static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance)
+{
+ int chan;
+ u32 tfr_reg, err_reg;
+ unsigned long flags;
+ struct sata_dwc_device *hsdev = hsdev_instance;
+ struct ata_host *host = (struct ata_host *)hsdev->host;
+ struct ata_port *ap;
+ struct sata_dwc_device_port *hsdevp;
+ u8 tag = 0;
+ unsigned int port = 0;
+
+ spin_lock_irqsave(&host->lock, flags);
+ ap = host->ports[port];
+ hsdevp = HSDEVP_FROM_AP(ap);
+ tag = ap->link.active_tag;
+
+ tfr_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.tfr\
+ .low));
+ err_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.error\
+ .low));
+
+ dev_dbg(ap->dev, "eot=0x%08x err=0x%08x pending=%d active port=%d\n",
+ tfr_reg, err_reg, hsdevp->dma_pending[tag], port);
+
+ chan = host_pvt.dma_channel;
+ if (chan >= 0) {
+ /* Check for end-of-transfer interrupt. */
+ if (tfr_reg & DMA_CHANNEL(chan)) {
+ /*
+ * Each DMA command produces 2 interrupts. Only
+ * complete the command after both interrupts have been
+ * seen. (See sata_dwc_isr())
+ */
+ host_pvt.dma_interrupt_count++;
+ sata_dwc_clear_dmacr(hsdevp, tag);
+
+ if (hsdevp->dma_pending[tag] ==
+ SATA_DWC_DMA_PENDING_NONE) {
+ dev_err(ap->dev, "DMA not pending eot=0x%08x "
+ "err=0x%08x tag=0x%02x pending=%d\n",
+ tfr_reg, err_reg, tag,
+ hsdevp->dma_pending[tag]);
+ }
+
+ if ((host_pvt.dma_interrupt_count % 2) == 0)
+ sata_dwc_dma_xfer_complete(ap, 1);
+
+ /* Clear the interrupt */
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear\
+ .tfr.low),
+ DMA_CHANNEL(chan));
+ }
+
+ /* Check for error interrupt. */
+ if (err_reg & DMA_CHANNEL(chan)) {
+ /* TODO Need error handler ! */
+ dev_err(ap->dev, "error interrupt err_reg=0x%08x\n",
+ err_reg);
+
+ /* Clear the interrupt. */
+ out_le32(&(host_pvt.sata_dma_regs->interrupt_clear\
+ .error.low),
+ DMA_CHANNEL(chan));
+ }
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Function: dma_request_interrupts
+ * arguments: hsdev
+ * returns status
+ * This function registers ISR for a particular DMA channel interrupt
+ */
+static int dma_request_interrupts(struct sata_dwc_device *hsdev, int irq)
+{
+ int retval = 0;
+ int chan = host_pvt.dma_channel;
+
+ if (chan >= 0) {
+ /* Unmask error interrupt */
+ out_le32(&(host_pvt.sata_dma_regs)->interrupt_mask.error.low,
+ DMA_ENABLE_CHAN(chan));
+
+ /* Unmask end-of-transfer interrupt */
+ out_le32(&(host_pvt.sata_dma_regs)->interrupt_mask.tfr.low,
+ DMA_ENABLE_CHAN(chan));
+ }
+
+ retval = request_irq(irq, dma_dwc_interrupt, 0, "SATA DMA", hsdev);
+ if (retval) {
+ dev_err(host_pvt.dwc_dev, "%s: could not get IRQ %d\n",
+ __func__, irq);
+ return -ENODEV;
+ }
+
+ /* Mark this interrupt as requested */
+ hsdev->irq_dma = irq;
+ return 0;
+}
+
+/*
+ * Function: map_sg_to_lli
+ * The Synopsis driver has a comment proposing that better performance
+ * is possible by only enabling interrupts on the last item in the linked list.
+ * However, it seems that could be a problem if an error happened on one of the
+ * first items. The transfer would halt, but no error interrupt would occur.
+ * Currently this function sets interrupts enabled for each linked list item:
+ * DMA_CTL_INT_EN.
+ */
+static int map_sg_to_lli(struct scatterlist *sg, int num_elems,
+ struct lli *lli, dma_addr_t dma_lli,
+ void __iomem *dmadr_addr, int dir)
+{
+ int i, idx = 0;
+ int fis_len = 0;
+ dma_addr_t next_llp;
+ int bl;
+ int sms_val, dms_val;
+
+ sms_val = 0;
+ dms_val = 1 + host_pvt.dma_channel;
+ dev_dbg(host_pvt.dwc_dev, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x"
+ " dmadr=0x%08x\n", __func__, sg, num_elems, lli, (u32)dma_lli,
+ (u32)dmadr_addr);
+
+ bl = get_burst_length_encode(AHB_DMA_BRST_DFLT);
+
+ for (i = 0; i < num_elems; i++, sg++) {
+ u32 addr, offset;
+ u32 sg_len, len;
+
+ addr = (u32) sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ dev_dbg(host_pvt.dwc_dev, "%s: elem=%d sg_addr=0x%x sg_len"
+ "=%d\n", __func__, i, addr, sg_len);
+
+ while (sg_len) {
+ if (idx >= SATA_DWC_DMAC_LLI_NUM) {
+ /* The LLI table is not large enough. */
+ dev_err(host_pvt.dwc_dev, "LLI table overrun "
+ "(idx=%d)\n", idx);
+ break;
+ }
+ len = (sg_len > SATA_DWC_DMAC_CTRL_TSIZE_MAX) ?
+ SATA_DWC_DMAC_CTRL_TSIZE_MAX : sg_len;
+
+ offset = addr & 0xffff;
+ if ((offset + sg_len) > 0x10000)
+ len = 0x10000 - offset;
+
+ /*
+ * Make sure a LLI block is not created that will span
+ * 8K max FIS boundary. If the block spans such a FIS
+ * boundary, there is a chance that a DMA burst will
+ * cross that boundary -- this results in an error in
+ * the host controller.
+ */
+ if (fis_len + len > 8192) {
+ dev_dbg(host_pvt.dwc_dev, "SPLITTING: fis_len="
+ "%d(0x%x) len=%d(0x%x)\n", fis_len,
+ fis_len, len, len);
+ len = 8192 - fis_len;
+ fis_len = 0;
+ } else {
+ fis_len += len;
+ }
+ if (fis_len == 8192)
+ fis_len = 0;
+
+ /*
+ * Set DMA addresses and lower half of control register
+ * based on direction.
+ */
+ if (dir == DMA_FROM_DEVICE) {
+ lli[idx].dar = cpu_to_le32(addr);
+ lli[idx].sar = cpu_to_le32((u32)dmadr_addr);
+
+ lli[idx].ctl.low = cpu_to_le32(
+ DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) |
+ DMA_CTL_SMS(sms_val) |
+ DMA_CTL_DMS(dms_val) |
+ DMA_CTL_SRC_MSIZE(bl) |
+ DMA_CTL_DST_MSIZE(bl) |
+ DMA_CTL_SINC_NOCHANGE |
+ DMA_CTL_SRC_TRWID(2) |
+ DMA_CTL_DST_TRWID(2) |
+ DMA_CTL_INT_EN |
+ DMA_CTL_LLP_SRCEN |
+ DMA_CTL_LLP_DSTEN);
+ } else { /* DMA_TO_DEVICE */
+ lli[idx].sar = cpu_to_le32(addr);
+ lli[idx].dar = cpu_to_le32((u32)dmadr_addr);
+
+ lli[idx].ctl.low = cpu_to_le32(
+ DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) |
+ DMA_CTL_SMS(dms_val) |
+ DMA_CTL_DMS(sms_val) |
+ DMA_CTL_SRC_MSIZE(bl) |
+ DMA_CTL_DST_MSIZE(bl) |
+ DMA_CTL_DINC_NOCHANGE |
+ DMA_CTL_SRC_TRWID(2) |
+ DMA_CTL_DST_TRWID(2) |
+ DMA_CTL_INT_EN |
+ DMA_CTL_LLP_SRCEN |
+ DMA_CTL_LLP_DSTEN);
+ }
+
+ dev_dbg(host_pvt.dwc_dev, "%s setting ctl.high len: "
+ "0x%08x val: 0x%08x\n", __func__,
+ len, DMA_CTL_BLK_TS(len / 4));
+
+ /* Program the LLI CTL high register */
+ lli[idx].ctl.high = cpu_to_le32(DMA_CTL_BLK_TS\
+ (len / 4));
+
+ /* Program the next pointer. The next pointer must be
+ * the physical address, not the virtual address.
+ */
+ next_llp = (dma_lli + ((idx + 1) * sizeof(struct \
+ lli)));
+
+ /* The last 2 bits encode the list master select. */
+ next_llp = DMA_LLP_LMS(next_llp, DMA_LLP_AHBMASTER2);
+
+ lli[idx].llp = cpu_to_le32(next_llp);
+ idx++;
+ sg_len -= len;
+ addr += len;
+ }
+ }
+
+ /*
+ * The last next ptr has to be zero and the last control low register
+ * has to have LLP_SRC_EN and LLP_DST_EN (linked list pointer source
+ * and destination enable) set back to 0 (disabled.) This is what tells
+ * the core that this is the last item in the linked list.
+ */
+ if (idx) {
+ lli[idx-1].llp = 0x00000000;
+ lli[idx-1].ctl.low &= DMA_CTL_LLP_DISABLE_LE32;
+
+ /* Flush cache to memory */
+ dma_cache_sync(NULL, lli, (sizeof(struct lli) * idx),
+ DMA_BIDIRECTIONAL);
+ }
+
+ return idx;
+}
+
+/*
+ * Function: dma_dwc_xfer_start
+ * arguments: Channel number
+ * Return : None
+ * Enables the DMA channel
+ */
+static void dma_dwc_xfer_start(int dma_ch)
+{
+ /* Enable the DMA channel */
+ out_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low),
+ in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low)) |
+ DMA_ENABLE_CHAN(dma_ch));
+}
+
+static int dma_dwc_xfer_setup(struct scatterlist *sg, int num_elems,
+ struct lli *lli, dma_addr_t dma_lli,
+ void __iomem *addr, int dir)
+{
+ int dma_ch;
+ int num_lli;
+ /* Acquire DMA channel */
+ dma_ch = dma_request_channel();
+ if (dma_ch == -1) {
+ dev_err(host_pvt.dwc_dev, "%s: dma channel unavailable\n",
+ __func__);
+ return -EAGAIN;
+ }
+
+ /* Convert SG list to linked list of items (LLIs) for AHB DMA */
+ num_lli = map_sg_to_lli(sg, num_elems, lli, dma_lli, addr, dir);
+
+ dev_dbg(host_pvt.dwc_dev, "%s sg: 0x%p, count: %d lli: %p dma_lli:"
+ " 0x%0xlx addr: %p lli count: %d\n", __func__, sg, num_elems,
+ lli, (u32)dma_lli, addr, num_lli);
+
+ clear_chan_interrupts(dma_ch);
+
+ /* Program the CFG register. */
+ out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.high),
+ DMA_CFG_HW_HS_SRC(dma_ch) | DMA_CFG_HW_HS_DEST(dma_ch) |
+ DMA_CFG_PROTCTL | DMA_CFG_FCMOD_REQ);
+ out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.low),
+ DMA_CFG_HW_CH_PRIOR(dma_ch));
+
+ /* Program the address of the linked list */
+ out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].llp.low),
+ DMA_LLP_LMS(dma_lli, DMA_LLP_AHBMASTER2));
+
+ /* Program the CTL register with src enable / dst enable */
+ out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].ctl.low),
+ DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN);
+ return dma_ch;
+}
+
+/*
+ * Function: dma_dwc_exit
+ * arguments: None
+ * returns status
+ * This function exits the SATA DMA driver
+ */
+static void dma_dwc_exit(struct sata_dwc_device *hsdev)
+{
+ dev_dbg(host_pvt.dwc_dev, "%s:\n", __func__);
+ if (host_pvt.sata_dma_regs) {
+ iounmap(host_pvt.sata_dma_regs);
+ host_pvt.sata_dma_regs = NULL;
+ }
+
+ if (hsdev->irq_dma) {
+ free_irq(hsdev->irq_dma, hsdev);
+ hsdev->irq_dma = 0;
+ }
+}
+
+/*
+ * Function: dma_dwc_init
+ * arguments: hsdev
+ * returns status
+ * This function initializes the SATA DMA driver
+ */
+static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq)
+{
+ int err;
+
+ err = dma_request_interrupts(hsdev, irq);
+ if (err) {
+ dev_err(host_pvt.dwc_dev, "%s: dma_request_interrupts returns"
+ " %d\n", __func__, err);
+ goto error_out;
+ }
+
+ /* Enabe DMA */
+ out_le32(&(host_pvt.sata_dma_regs->dma_cfg.low), DMA_EN);
+
+ dev_notice(host_pvt.dwc_dev, "DMA initialized\n");
+ dev_dbg(host_pvt.dwc_dev, "SATA DMA registers=0x%p\n", host_pvt.\
+ sata_dma_regs);
+
+ return 0;
+
+error_out:
+ dma_dwc_exit(hsdev);
+
+ return err;
+}
+
+static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val)
+{
+ if (scr > SCR_NOTIFICATION) {
+ dev_err(link->ap->dev, "%s: Incorrect SCR offset 0x%02x\n",
+ __func__, scr);
+ return -EINVAL;
+ }
+
+ *val = in_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4));
+ dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n",
+ __func__, link->ap->print_id, scr, *val);
+
+ return 0;
+}
+
+static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr, u32 val)
+{
+ dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n",
+ __func__, link->ap->print_id, scr, val);
+ if (scr > SCR_NOTIFICATION) {
+ dev_err(link->ap->dev, "%s: Incorrect SCR offset 0x%02x\n",
+ __func__, scr);
+ return -EINVAL;
+ }
+ out_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4), val);
+
+ return 0;
+}
+
+static u32 core_scr_read(unsigned int scr)
+{
+ return in_le32((void __iomem *)(host_pvt.scr_addr_sstatus) +\
+ (scr * 4));
+}
+
+static void core_scr_write(unsigned int scr, u32 val)
+{
+ out_le32((void __iomem *)(host_pvt.scr_addr_sstatus) + (scr * 4),
+ val);
+}
+
+static void clear_serror(void)
+{
+ u32 val;
+ val = core_scr_read(SCR_ERROR);
+ core_scr_write(SCR_ERROR, val);
+
+}
+
+static void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit)
+{
+ out_le32(&hsdev->sata_dwc_regs->intpr,
+ in_le32(&hsdev->sata_dwc_regs->intpr));
+}
+
+static u32 qcmd_tag_to_mask(u8 tag)
+{
+ return 0x00000001 << (tag & 0x1f);
+}
+
+/* See ahci.c */
+static void sata_dwc_error_intr(struct ata_port *ap,
+ struct sata_dwc_device *hsdev, uint intpr)
+{
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ unsigned int err_mask = 0, action = 0;
+ struct ata_queued_cmd *qc;
+ u32 serror;
+ u8 status, tag;
+ u32 err_reg;
+
+ ata_ehi_clear_desc(ehi);
+
+ serror = core_scr_read(SCR_ERROR);
+ status = ap->ops->sff_check_status(ap);
+
+ err_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.error.\
+ low));
+ tag = ap->link.active_tag;
+
+ dev_err(ap->dev, "%s SCR_ERROR=0x%08x intpr=0x%08x status=0x%08x "
+ "dma_intp=%d pending=%d issued=%d dma_err_status=0x%08x\n",
+ __func__, serror, intpr, status, host_pvt.dma_interrupt_count,
+ hsdevp->dma_pending[tag], hsdevp->cmd_issued[tag], err_reg);
+
+ /* Clear error register and interrupt bit */
+ clear_serror();
+ clear_interrupt_bit(hsdev, SATA_DWC_INTPR_ERR);
+
+ /* This is the only error happening now. TODO check for exact error */
+
+ err_mask |= AC_ERR_HOST_BUS;
+ action |= ATA_EH_RESET;
+
+ /* Pass this on to EH */
+ ehi->serror |= serror;
+ ehi->action |= action;
+
+ qc = ata_qc_from_tag(ap, tag);
+ if (qc)
+ qc->err_mask |= err_mask;
+ else
+ ehi->err_mask |= err_mask;
+
+ ata_port_abort(ap);
+}
+
+/*
+ * Function : sata_dwc_isr
+ * arguments : irq, void *dev_instance, struct pt_regs *regs
+ * Return value : irqreturn_t - status of IRQ
+ * This Interrupt handler called via port ops registered function.
+ * .irq_handler = sata_dwc_isr
+ */
+static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
+{
+ struct ata_host *host = (struct ata_host *)dev_instance;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_HOST(host);
+ struct ata_port *ap;
+ struct ata_queued_cmd *qc;
+ unsigned long flags;
+ u8 status, tag;
+ int handled, num_processed, port = 0;
+ uint intpr, sactive, sactive2, tag_mask;
+ struct sata_dwc_device_port *hsdevp;
+ host_pvt.sata_dwc_sactive_issued = 0;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* Read the interrupt register */
+ intpr = in_le32(&hsdev->sata_dwc_regs->intpr);
+
+ ap = host->ports[port];
+ hsdevp = HSDEVP_FROM_AP(ap);
+
+ dev_dbg(ap->dev, "%s intpr=0x%08x active_tag=%d\n", __func__, intpr,
+ ap->link.active_tag);
+
+ /* Check for error interrupt */
+ if (intpr & SATA_DWC_INTPR_ERR) {
+ sata_dwc_error_intr(ap, hsdev, intpr);
+ handled = 1;
+ goto DONE;
+ }
+
+ /* Check for DMA SETUP FIS (FP DMA) interrupt */
+ if (intpr & SATA_DWC_INTPR_NEWFP) {
+ clear_interrupt_bit(hsdev, SATA_DWC_INTPR_NEWFP);
+
+ tag = (u8)(in_le32(&hsdev->sata_dwc_regs->fptagr));
+ dev_dbg(ap->dev, "%s: NEWFP tag=%d\n", __func__, tag);
+ if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_PEND)
+ dev_warn(ap->dev, "CMD tag=%d not pending?\n", tag);
+
+ host_pvt.sata_dwc_sactive_issued |= qcmd_tag_to_mask(tag);
+
+ qc = ata_qc_from_tag(ap, tag);
+ /*
+ * Start FP DMA for NCQ command. At this point the tag is the
+ * active tag. It is the tag that matches the command about to
+ * be completed.
+ */
+ qc->ap->link.active_tag = tag;
+ sata_dwc_bmdma_start_by_tag(qc, tag);
+
+ handled = 1;
+ goto DONE;
+ }
+ sactive = core_scr_read(SCR_ACTIVE);
+ tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive;
+
+ /* If no sactive issued and tag_mask is zero then this is not NCQ */
+ if (host_pvt.sata_dwc_sactive_issued == 0 && tag_mask == 0) {
+ if (ap->link.active_tag == ATA_TAG_POISON)
+ tag = 0;
+ else
+ tag = ap->link.active_tag;
+ qc = ata_qc_from_tag(ap, tag);
+
+ /* DEV interrupt w/ no active qc? */
+ if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
+ dev_err(ap->dev, "%s interrupt with no active qc "
+ "qc=%p\n", __func__, qc);
+ ap->ops->sff_check_status(ap);
+ handled = 1;
+ goto DONE;
+ }
+ status = ap->ops->sff_check_status(ap);
+
+ qc->ap->link.active_tag = tag;
+ hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT;
+
+ if (status & ATA_ERR) {
+ dev_dbg(ap->dev, "interrupt ATA_ERR (0x%x)\n", status);
+ sata_dwc_qc_complete(ap, qc, 1);
+ handled = 1;
+ goto DONE;
+ }
+
+ dev_dbg(ap->dev, "%s non-NCQ cmd interrupt, protocol: %s\n",
+ __func__, get_prot_descript(qc->tf.protocol));
+DRVSTILLBUSY:
+ if (ata_is_dma(qc->tf.protocol)) {
+ /*
+ * Each DMA transaction produces 2 interrupts. The DMAC
+ * transfer complete interrupt and the SATA controller
+ * operation done interrupt. The command should be
+ * completed only after both interrupts are seen.
+ */
+ host_pvt.dma_interrupt_count++;
+ if (hsdevp->dma_pending[tag] == \
+ SATA_DWC_DMA_PENDING_NONE) {
+ dev_err(ap->dev, "%s: DMA not pending "
+ "intpr=0x%08x status=0x%08x pending"
+ "=%d\n", __func__, intpr, status,
+ hsdevp->dma_pending[tag]);
+ }
+
+ if ((host_pvt.dma_interrupt_count % 2) == 0)
+ sata_dwc_dma_xfer_complete(ap, 1);
+ } else if (ata_is_pio(qc->tf.protocol)) {
+ ata_sff_hsm_move(ap, qc, status, 0);
+ handled = 1;
+ goto DONE;
+ } else {
+ if (unlikely(sata_dwc_qc_complete(ap, qc, 1)))
+ goto DRVSTILLBUSY;
+ }
+
+ handled = 1;
+ goto DONE;
+ }
+
+ /*
+ * This is a NCQ command. At this point we need to figure out for which
+ * tags we have gotten a completion interrupt. One interrupt may serve
+ * as completion for more than one operation when commands are queued
+ * (NCQ). We need to process each completed command.
+ */
+
+ /* process completed commands */
+ sactive = core_scr_read(SCR_ACTIVE);
+ tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive;
+
+ if (sactive != 0 || (host_pvt.sata_dwc_sactive_issued) > 1 || \
+ tag_mask > 1) {
+ dev_dbg(ap->dev, "%s NCQ:sactive=0x%08x sactive_issued=0x%08x"
+ "tag_mask=0x%08x\n", __func__, sactive,
+ host_pvt.sata_dwc_sactive_issued, tag_mask);
+ }
+
+ if ((tag_mask | (host_pvt.sata_dwc_sactive_issued)) != \
+ (host_pvt.sata_dwc_sactive_issued)) {
+ dev_warn(ap->dev, "Bad tag mask? sactive=0x%08x "
+ "(host_pvt.sata_dwc_sactive_issued)=0x%08x tag_mask"
+ "=0x%08x\n", sactive, host_pvt.sata_dwc_sactive_issued,
+ tag_mask);
+ }
+
+ /* read just to clear ... not bad if currently still busy */
+ status = ap->ops->sff_check_status(ap);
+ dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status);
+
+ tag = 0;
+ num_processed = 0;
+ while (tag_mask) {
+ num_processed++;
+ while (!(tag_mask & 0x00000001)) {
+ tag++;
+ tag_mask <<= 1;
+ }
+
+ tag_mask &= (~0x00000001);
+ qc = ata_qc_from_tag(ap, tag);
+
+ /* To be picked up by completion functions */
+ qc->ap->link.active_tag = tag;
+ hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT;
+
+ /* Let libata/scsi layers handle error */
+ if (status & ATA_ERR) {
+ dev_dbg(ap->dev, "%s ATA_ERR (0x%x)\n", __func__,
+ status);
+ sata_dwc_qc_complete(ap, qc, 1);
+ handled = 1;
+ goto DONE;
+ }
+
+ /* Process completed command */
+ dev_dbg(ap->dev, "%s NCQ command, protocol: %s\n", __func__,
+ get_prot_descript(qc->tf.protocol));
+ if (ata_is_dma(qc->tf.protocol)) {
+ host_pvt.dma_interrupt_count++;
+ if (hsdevp->dma_pending[tag] == \
+ SATA_DWC_DMA_PENDING_NONE)
+ dev_warn(ap->dev, "%s: DMA not pending?\n",
+ __func__);
+ if ((host_pvt.dma_interrupt_count % 2) == 0)
+ sata_dwc_dma_xfer_complete(ap, 1);
+ } else {
+ if (unlikely(sata_dwc_qc_complete(ap, qc, 1)))
+ goto STILLBUSY;
+ }
+ continue;
+
+STILLBUSY:
+ ap->stats.idle_irq++;
+ dev_warn(ap->dev, "STILL BUSY IRQ ata%d: irq trap\n",
+ ap->print_id);
+ } /* while tag_mask */
+
+ /*
+ * Check to see if any commands completed while we were processing our
+ * initial set of completed commands (read status clears interrupts,
+ * so we might miss a completed command interrupt if one came in while
+ * we were processing --we read status as part of processing a completed
+ * command).
+ */
+ sactive2 = core_scr_read(SCR_ACTIVE);
+ if (sactive2 != sactive) {
+ dev_dbg(ap->dev, "More completed - sactive=0x%x sactive2"
+ "=0x%x\n", sactive, sactive2);
+ }
+ handled = 1;
+
+DONE:
+ spin_unlock_irqrestore(&host->lock, flags);
+ return IRQ_RETVAL(handled);
+}
+
+static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_HSDEVP(hsdevp);
+
+ if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX) {
+ out_le32(&(hsdev->sata_dwc_regs->dmacr),
+ SATA_DWC_DMACR_RX_CLEAR(
+ in_le32(&(hsdev->sata_dwc_regs->dmacr))));
+ } else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX) {
+ out_le32(&(hsdev->sata_dwc_regs->dmacr),
+ SATA_DWC_DMACR_TX_CLEAR(
+ in_le32(&(hsdev->sata_dwc_regs->dmacr))));
+ } else {
+ /*
+ * This should not happen, it indicates the driver is out of
+ * sync. If it does happen, clear dmacr anyway.
+ */
+ dev_err(host_pvt.dwc_dev, "%s DMA protocol RX and"
+ "TX DMA not pending tag=0x%02x pending=%d"
+ " dmacr: 0x%08x\n", __func__, tag,
+ hsdevp->dma_pending[tag],
+ in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+ out_le32(&(hsdev->sata_dwc_regs->dmacr),
+ SATA_DWC_DMACR_TXRXCH_CLEAR);
+ }
+}
+
+static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status)
+{
+ struct ata_queued_cmd *qc;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ u8 tag = 0;
+
+ tag = ap->link.active_tag;
+ qc = ata_qc_from_tag(ap, tag);
+ if (!qc) {
+ dev_err(ap->dev, "failed to get qc");
+ return;
+ }
+
+#ifdef DEBUG_NCQ
+ if (tag > 0) {
+ dev_info(ap->dev, "%s tag=%u cmd=0x%02x dma dir=%s proto=%s "
+ "dmacr=0x%08x\n", __func__, qc->tag, qc->tf.command,
+ get_dma_dir_descript(qc->dma_dir),
+ get_prot_descript(qc->tf.protocol),
+ in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+ }
+#endif
+
+ if (ata_is_dma(qc->tf.protocol)) {
+ if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_NONE) {
+ dev_err(ap->dev, "%s DMA protocol RX and TX DMA not "
+ "pending dmacr: 0x%08x\n", __func__,
+ in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+ }
+
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_NONE;
+ sata_dwc_qc_complete(ap, qc, check_status);
+ ap->link.active_tag = ATA_TAG_POISON;
+ } else {
+ sata_dwc_qc_complete(ap, qc, check_status);
+ }
+}
+
+static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u32 check_status)
+{
+ u8 status = 0;
+ u32 mask = 0x0;
+ u8 tag = qc->tag;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ host_pvt.sata_dwc_sactive_queued = 0;
+ dev_dbg(ap->dev, "%s checkstatus? %x\n", __func__, check_status);
+
+ if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX)
+ dev_err(ap->dev, "TX DMA PENDING\n");
+ else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX)
+ dev_err(ap->dev, "RX DMA PENDING\n");
+ dev_dbg(ap->dev, "QC complete cmd=0x%02x status=0x%02x ata%u:"
+ " protocol=%d\n", qc->tf.command, status, ap->print_id,
+ qc->tf.protocol);
+
+ /* clear active bit */
+ mask = (~(qcmd_tag_to_mask(tag)));
+ host_pvt.sata_dwc_sactive_queued = (host_pvt.sata_dwc_sactive_queued) \
+ & mask;
+ host_pvt.sata_dwc_sactive_issued = (host_pvt.sata_dwc_sactive_issued) \
+ & mask;
+ ata_qc_complete(qc);
+ return 0;
+}
+
+static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev)
+{
+ /* Enable selective interrupts by setting the interrupt maskregister*/
+ out_le32(&hsdev->sata_dwc_regs->intmr,
+ SATA_DWC_INTMR_ERRM |
+ SATA_DWC_INTMR_NEWFPM |
+ SATA_DWC_INTMR_PMABRTM |
+ SATA_DWC_INTMR_DMATM);
+ /*
+ * Unmask the error bits that should trigger an error interrupt by
+ * setting the error mask register.
+ */
+ out_le32(&hsdev->sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS);
+
+ dev_dbg(host_pvt.dwc_dev, "%s: INTMR = 0x%08x, ERRMR = 0x%08x\n",
+ __func__, in_le32(&hsdev->sata_dwc_regs->intmr),
+ in_le32(&hsdev->sata_dwc_regs->errmr));
+}
+
+static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base)
+{
+ port->cmd_addr = (void *)base + 0x00;
+ port->data_addr = (void *)base + 0x00;
+
+ port->error_addr = (void *)base + 0x04;
+ port->feature_addr = (void *)base + 0x04;
+
+ port->nsect_addr = (void *)base + 0x08;
+
+ port->lbal_addr = (void *)base + 0x0c;
+ port->lbam_addr = (void *)base + 0x10;
+ port->lbah_addr = (void *)base + 0x14;
+
+ port->device_addr = (void *)base + 0x18;
+ port->command_addr = (void *)base + 0x1c;
+ port->status_addr = (void *)base + 0x1c;
+
+ port->altstatus_addr = (void *)base + 0x20;
+ port->ctl_addr = (void *)base + 0x20;
+}
+
+/*
+ * Function : sata_dwc_port_start
+ * arguments : struct ata_ioports *port
+ * Return value : returns 0 if success, error code otherwise
+ * This function allocates the scatter gather LLI table for AHB DMA
+ */
+static int sata_dwc_port_start(struct ata_port *ap)
+{
+ int err = 0;
+ struct sata_dwc_device *hsdev;
+ struct sata_dwc_device_port *hsdevp = NULL;
+ struct device *pdev;
+ int i;
+
+ hsdev = HSDEV_FROM_AP(ap);
+
+ dev_dbg(ap->dev, "%s: port_no=%d\n", __func__, ap->port_no);
+
+ hsdev->host = ap->host;
+ pdev = ap->host->dev;
+ if (!pdev) {
+ dev_err(ap->dev, "%s: no ap->host->dev\n", __func__);
+ err = -ENODEV;
+ goto CLEANUP;
+ }
+
+ /* Allocate Port Struct */
+ hsdevp = kzalloc(sizeof(*hsdevp), GFP_KERNEL);
+ if (!hsdevp) {
+ dev_err(ap->dev, "%s: kmalloc failed for hsdevp\n", __func__);
+ err = -ENOMEM;
+ goto CLEANUP;
+ }
+ hsdevp->hsdev = hsdev;
+
+ for (i = 0; i < SATA_DWC_QCMD_MAX; i++)
+ hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT;
+
+ ap->bmdma_prd = 0; /* set these so libata doesn't use them */
+ ap->bmdma_prd_dma = 0;
+
+ /*
+ * DMA - Assign scatter gather LLI table. We can't use the libata
+ * version since it's PRD is IDE PCI specific.
+ */
+ for (i = 0; i < SATA_DWC_QCMD_MAX; i++) {
+ hsdevp->llit[i] = dma_alloc_coherent(pdev,
+ SATA_DWC_DMAC_LLI_TBL_SZ,
+ &(hsdevp->llit_dma[i]),
+ GFP_ATOMIC);
+ if (!hsdevp->llit[i]) {
+ dev_err(ap->dev, "%s: dma_alloc_coherent failed\n",
+ __func__);
+ err = -ENOMEM;
+ goto CLEANUP_ALLOC;
+ }
+ }
+
+ if (ap->port_no == 0) {
+ dev_dbg(ap->dev, "%s: clearing TXCHEN, RXCHEN in DMAC\n",
+ __func__);
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_TXRXCH_CLEAR);
+
+ dev_dbg(ap->dev, "%s: setting burst size in DBTSR\n",
+ __func__);
+ out_le32(&hsdev->sata_dwc_regs->dbtsr,
+ (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) |
+ SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT)));
+ }
+
+ /* Clear any error bits before libata starts issuing commands */
+ clear_serror();
+ ap->private_data = hsdevp;
+ dev_dbg(ap->dev, "%s: done\n", __func__);
+ return 0;
+
+CLEANUP_ALLOC:
+ kfree(hsdevp);
+CLEANUP:
+ dev_dbg(ap->dev, "%s: fail. ap->id = %d\n", __func__, ap->print_id);
+ return err;
+}
+
+static void sata_dwc_port_stop(struct ata_port *ap)
+{
+ int i;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+
+ dev_dbg(ap->dev, "%s: ap->id = %d\n", __func__, ap->print_id);
+
+ if (hsdevp && hsdev) {
+ /* deallocate LLI table */
+ for (i = 0; i < SATA_DWC_QCMD_MAX; i++) {
+ dma_free_coherent(ap->host->dev,
+ SATA_DWC_DMAC_LLI_TBL_SZ,
+ hsdevp->llit[i], hsdevp->llit_dma[i]);
+ }
+
+ kfree(hsdevp);
+ }
+ ap->private_data = NULL;
+}
+
+/*
+ * Function : sata_dwc_exec_command_by_tag
+ * arguments : ata_port *ap, ata_taskfile *tf, u8 tag, u32 cmd_issued
+ * Return value : None
+ * This function keeps track of individual command tag ids and calls
+ * ata_exec_command in libata
+ */
+static void sata_dwc_exec_command_by_tag(struct ata_port *ap,
+ struct ata_taskfile *tf,
+ u8 tag, u32 cmd_issued)
+{
+ unsigned long flags;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+
+ dev_dbg(ap->dev, "%s cmd(0x%02x): %s tag=%d\n", __func__, tf->command,
+ ata_get_cmd_descript(tf->command), tag);
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ hsdevp->cmd_issued[tag] = cmd_issued;
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+ /*
+ * Clear SError before executing a new command.
+ * sata_dwc_scr_write and read can not be used here. Clearing the PM
+ * managed SError register for the disk needs to be done before the
+ * task file is loaded.
+ */
+ clear_serror();
+ ata_sff_exec_command(ap, tf);
+}
+
+static void sata_dwc_bmdma_setup_by_tag(struct ata_queued_cmd *qc, u8 tag)
+{
+ sata_dwc_exec_command_by_tag(qc->ap, &qc->tf, tag,
+ SATA_DWC_CMD_ISSUED_PEND);
+}
+
+static void sata_dwc_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ u8 tag = qc->tag;
+
+ if (ata_is_ncq(qc->tf.protocol)) {
+ dev_dbg(qc->ap->dev, "%s: ap->link.sactive=0x%08x tag=%d\n",
+ __func__, qc->ap->link.sactive, tag);
+ } else {
+ tag = 0;
+ }
+ sata_dwc_bmdma_setup_by_tag(qc, tag);
+}
+
+static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag)
+{
+ int start_dma;
+ u32 reg, dma_chan;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_QC(qc);
+ struct ata_port *ap = qc->ap;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ int dir = qc->dma_dir;
+ dma_chan = hsdevp->dma_chan[tag];
+
+ if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_NOT) {
+ start_dma = 1;
+ if (dir == DMA_TO_DEVICE)
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_TX;
+ else
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_RX;
+ } else {
+ dev_err(ap->dev, "%s: Command not pending cmd_issued=%d "
+ "(tag=%d) DMA NOT started\n", __func__,
+ hsdevp->cmd_issued[tag], tag);
+ start_dma = 0;
+ }
+
+ dev_dbg(ap->dev, "%s qc=%p tag: %x cmd: 0x%02x dma_dir: %s "
+ "start_dma? %x\n", __func__, qc, tag, qc->tf.command,
+ get_dma_dir_descript(qc->dma_dir), start_dma);
+ sata_dwc_tf_dump(&(qc->tf));
+
+ if (start_dma) {
+ reg = core_scr_read(SCR_ERROR);
+ if (reg & SATA_DWC_SERROR_ERR_BITS) {
+ dev_err(ap->dev, "%s: ****** SError=0x%08x ******\n",
+ __func__, reg);
+ }
+
+ if (dir == DMA_TO_DEVICE)
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_TXCHEN);
+ else
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_RXCHEN);
+
+ /* Enable AHB DMA transfer on the specified channel */
+ dma_dwc_xfer_start(dma_chan);
+ }
+}
+
+static void sata_dwc_bmdma_start(struct ata_queued_cmd *qc)
+{
+ u8 tag = qc->tag;
+
+ if (ata_is_ncq(qc->tf.protocol)) {
+ dev_dbg(qc->ap->dev, "%s: ap->link.sactive=0x%08x tag=%d\n",
+ __func__, qc->ap->link.sactive, tag);
+ } else {
+ tag = 0;
+ }
+ dev_dbg(qc->ap->dev, "%s\n", __func__);
+ sata_dwc_bmdma_start_by_tag(qc, tag);
+}
+
+/*
+ * Function : sata_dwc_qc_prep_by_tag
+ * arguments : ata_queued_cmd *qc, u8 tag
+ * Return value : None
+ * qc_prep for a particular queued command based on tag
+ */
+static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag)
+{
+ struct scatterlist *sg = qc->sg;
+ struct ata_port *ap = qc->ap;
+ int dma_chan;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+
+ dev_dbg(ap->dev, "%s: port=%d dma dir=%s n_elem=%d\n",
+ __func__, ap->port_no, get_dma_dir_descript(qc->dma_dir),
+ qc->n_elem);
+
+ dma_chan = dma_dwc_xfer_setup(sg, qc->n_elem, hsdevp->llit[tag],
+ hsdevp->llit_dma[tag],
+ (void *__iomem)(&hsdev->sata_dwc_regs->\
+ dmadr), qc->dma_dir);
+ if (dma_chan < 0) {
+ dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns err %d\n",
+ __func__, dma_chan);
+ return;
+ }
+ hsdevp->dma_chan[tag] = dma_chan;
+}
+
+static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc)
+{
+ u32 sactive;
+ u8 tag = qc->tag;
+ struct ata_port *ap = qc->ap;
+
+#ifdef DEBUG_NCQ
+ if (qc->tag > 0 || ap->link.sactive > 1)
+ dev_info(ap->dev, "%s ap id=%d cmd(0x%02x)=%s qc tag=%d "
+ "prot=%s ap active_tag=0x%08x ap sactive=0x%08x\n",
+ __func__, ap->print_id, qc->tf.command,
+ ata_get_cmd_descript(qc->tf.command),
+ qc->tag, get_prot_descript(qc->tf.protocol),
+ ap->link.active_tag, ap->link.sactive);
+#endif
+
+ if (!ata_is_ncq(qc->tf.protocol))
+ tag = 0;
+ sata_dwc_qc_prep_by_tag(qc, tag);
+
+ if (ata_is_ncq(qc->tf.protocol)) {
+ sactive = core_scr_read(SCR_ACTIVE);
+ sactive |= (0x00000001 << tag);
+ core_scr_write(SCR_ACTIVE, sactive);
+
+ dev_dbg(qc->ap->dev, "%s: tag=%d ap->link.sactive = 0x%08x "
+ "sactive=0x%08x\n", __func__, tag, qc->ap->link.sactive,
+ sactive);
+
+ ap->ops->sff_tf_load(ap, &qc->tf);
+ sata_dwc_exec_command_by_tag(ap, &qc->tf, qc->tag,
+ SATA_DWC_CMD_ISSUED_PEND);
+ } else {
+ ata_sff_qc_issue(qc);
+ }
+ return 0;
+}
+
+/*
+ * Function : sata_dwc_qc_prep
+ * arguments : ata_queued_cmd *qc
+ * Return value : None
+ * qc_prep for a particular queued command
+ */
+
+static void sata_dwc_qc_prep(struct ata_queued_cmd *qc)
+{
+ if ((qc->dma_dir == DMA_NONE) || (qc->tf.protocol == ATA_PROT_PIO))
+ return;
+
+#ifdef DEBUG_NCQ
+ if (qc->tag > 0)
+ dev_info(qc->ap->dev, "%s: qc->tag=%d ap->active_tag=0x%08x\n",
+ __func__, qc->tag, qc->ap->link.active_tag);
+
+ return ;
+#endif
+}
+
+static void sata_dwc_error_handler(struct ata_port *ap)
+{
+ ata_sff_error_handler(ap);
+}
+
+int sata_dwc_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(link->ap);
+ int ret;
+
+ ret = sata_sff_hardreset(link, class, deadline);
+
+ sata_dwc_enable_interrupts(hsdev);
+
+ /* Reconfigure the DMA control register */
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_TXRXCH_CLEAR);
+
+ /* Reconfigure the DMA Burst Transaction Size register */
+ out_le32(&hsdev->sata_dwc_regs->dbtsr,
+ SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) |
+ SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT));
+
+ return ret;
+}
+
+/*
+ * scsi mid-layer and libata interface structures
+ */
+static struct scsi_host_template sata_dwc_sht = {
+ ATA_NCQ_SHT(DRV_NAME),
+ /*
+ * test-only: Currently this driver doesn't handle NCQ
+ * correctly. We enable NCQ but set the queue depth to a
+ * max of 1. This will get fixed in in a future release.
+ */
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .can_queue = ATA_DEF_QUEUE, /* ATA_MAX_QUEUE */
+ .dma_boundary = ATA_DMA_BOUNDARY,
+};
+
+static struct ata_port_operations sata_dwc_ops = {
+ .inherits = &ata_sff_port_ops,
+
+ .error_handler = sata_dwc_error_handler,
+ .hardreset = sata_dwc_hardreset,
+
+ .qc_prep = sata_dwc_qc_prep,
+ .qc_issue = sata_dwc_qc_issue,
+
+ .scr_read = sata_dwc_scr_read,
+ .scr_write = sata_dwc_scr_write,
+
+ .port_start = sata_dwc_port_start,
+ .port_stop = sata_dwc_port_stop,
+
+ .bmdma_setup = sata_dwc_bmdma_setup,
+ .bmdma_start = sata_dwc_bmdma_start,
+};
+
+static const struct ata_port_info sata_dwc_port_info[] = {
+ {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NCQ,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &sata_dwc_ops,
+ },
+};
+
+static int sata_dwc_probe(struct platform_device *ofdev)
+{
+ struct sata_dwc_device *hsdev;
+ u32 idr, versionr;
+ char *ver = (char *)&versionr;
+ u8 *base = NULL;
+ int err = 0;
+ int irq, rc;
+ struct ata_host *host;
+ struct ata_port_info pi = sata_dwc_port_info[0];
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+ struct device_node *np = ofdev->dev.of_node;
+ u32 dma_chan;
+
+ /* Allocate DWC SATA device */
+ hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL);
+ if (hsdev == NULL) {
+ dev_err(&ofdev->dev, "kmalloc failed for hsdev\n");
+ err = -ENOMEM;
+ goto error;
+ }
+
+ if (of_property_read_u32(np, "dma-channel", &dma_chan)) {
+ dev_warn(&ofdev->dev, "no dma-channel property set."
+ " Use channel 0\n");
+ dma_chan = 0;
+ }
+ host_pvt.dma_channel = dma_chan;
+
+ /* Ioremap SATA registers */
+ base = of_iomap(ofdev->dev.of_node, 0);
+ if (!base) {
+ dev_err(&ofdev->dev, "ioremap failed for SATA register"
+ " address\n");
+ err = -ENODEV;
+ goto error_kmalloc;
+ }
+ hsdev->reg_base = base;
+ dev_dbg(&ofdev->dev, "ioremap done for SATA register address\n");
+
+ /* Synopsys DWC SATA specific Registers */
+ hsdev->sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET);
+
+ /* Allocate and fill host */
+ host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS);
+ if (!host) {
+ dev_err(&ofdev->dev, "ata_host_alloc_pinfo failed\n");
+ err = -ENOMEM;
+ goto error_iomap;
+ }
+
+ host->private_data = hsdev;
+
+ /* Setup port */
+ host->ports[0]->ioaddr.cmd_addr = base;
+ host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET;
+ host_pvt.scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET;
+ sata_dwc_setup_port(&host->ports[0]->ioaddr, (unsigned long)base);
+
+ /* Read the ID and Version Registers */
+ idr = in_le32(&hsdev->sata_dwc_regs->idr);
+ versionr = in_le32(&hsdev->sata_dwc_regs->versionr);
+ dev_notice(&ofdev->dev, "id %d, controller version %c.%c%c\n",
+ idr, ver[0], ver[1], ver[2]);
+
+ /* Get SATA DMA interrupt number */
+ irq = irq_of_parse_and_map(ofdev->dev.of_node, 1);
+ if (irq == NO_IRQ) {
+ dev_err(&ofdev->dev, "no SATA DMA irq\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+
+ /* Get physical SATA DMA register base address */
+ host_pvt.sata_dma_regs = of_iomap(ofdev->dev.of_node, 1);
+ if (!(host_pvt.sata_dma_regs)) {
+ dev_err(&ofdev->dev, "ioremap failed for AHBDMA register"
+ " address\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+
+ /* Save dev for later use in dev_xxx() routines */
+ host_pvt.dwc_dev = &ofdev->dev;
+
+ /* Initialize AHB DMAC */
+ dma_dwc_init(hsdev, irq);
+
+ /* Enable SATA Interrupts */
+ sata_dwc_enable_interrupts(hsdev);
+
+ /* Get SATA interrupt number */
+ irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
+ if (irq == NO_IRQ) {
+ dev_err(&ofdev->dev, "no SATA DMA irq\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+
+ /*
+ * Now, register with libATA core, this will also initiate the
+ * device discovery process, invoking our port_start() handler &
+ * error_handler() to execute a dummy Softreset EH session
+ */
+ rc = ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht);
+
+ if (rc != 0)
+ dev_err(&ofdev->dev, "failed to activate host");
+
+ dev_set_drvdata(&ofdev->dev, host);
+ return 0;
+
+error_out:
+ /* Free SATA DMA resources */
+ dma_dwc_exit(hsdev);
+
+error_iomap:
+ iounmap(base);
+error_kmalloc:
+ kfree(hsdev);
+error:
+ return err;
+}
+
+static int sata_dwc_remove(struct platform_device *ofdev)
+{
+ struct device *dev = &ofdev->dev;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_dwc_device *hsdev = host->private_data;
+
+ ata_host_detach(host);
+ dev_set_drvdata(dev, NULL);
+
+ /* Free SATA DMA resources */
+ dma_dwc_exit(hsdev);
+
+ iounmap(hsdev->reg_base);
+ kfree(hsdev);
+ kfree(host);
+ dev_dbg(&ofdev->dev, "done\n");
+ return 0;
+}
+
+static const struct of_device_id sata_dwc_match[] = {
+ { .compatible = "amcc,sata-460ex", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sata_dwc_match);
+
+static struct platform_driver sata_dwc_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = sata_dwc_match,
+ },
+ .probe = sata_dwc_probe,
+ .remove = sata_dwc_remove,
+};
+
+module_platform_driver(sata_dwc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Miesfeld <mmiesfeld@amcc.com>");
+MODULE_DESCRIPTION("DesignWare Cores SATA controller low lever driver");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/sata_dwc_pmp.c b/drivers/ata/sata_dwc_pmp.c
new file mode 100644
index 00000000000..3ff190af8d2
--- /dev/null
+++ b/drivers/ata/sata_dwc_pmp.c
@@ -0,0 +1,3041 @@
+/*
+ * drivers/ata/sata_dwc.c
+ *
+ * Synopsys DesignWare Cores (DWC) SATA host driver
+ *
+ * Author: Mark Miesfeld <mmiesfeld@amcc.com>
+ *
+ * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr@denx.de>
+ * Copyright 2008 DENX Software Engineering
+ *
+ * Based on versions provided by AMCC and Synopsys which are:
+ * Copyright 2006 Applied Micro Circuits Corporation
+ * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/libata.h>
+#include <linux/rtc.h>
+
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+
+
+#ifdef CONFIG_SATA_DWC_DEBUG
+#define dwc_dev_dbg(dev, format, arg...) \
+ ({ if (0) dev_printk(KERN_INFO, dev, format, ##arg); 0; })
+#define dwc_port_dbg(ap, format, arg...) \
+ ata_port_printk(ap, KERN_INFO, format, ##arg)
+#define dwc_link_dbg(link, format, arg...) \
+ ata_link_printk(link, KERN_INFO, format, ##arg)
+#else
+#define dwc_dev_dbg(dev, format, arg...) \
+ ({ 0; })
+#define dwc_port_dbg(ap, format, arg...) \
+ ({ 0; })
+#define dwc_link_dbg(link, format, arg...) \
+ ({ 0; })
+#endif
+
+#ifdef CONFIG_SATA_DWC_VDEBUG
+#define DEBUG_NCQ
+#define dwc_dev_vdbg(dev, format, arg...) \
+ ({ if (0) dev_printk(KERN_INFO, dev, format, ##arg); 0; })
+#define dwc_port_vdbg(ap, format, arg...) \
+ ata_port_printk(ap, KERN_INFO, format, ##arg)
+#define dwc_link_vdbg(link, format, arg...) \
+ ata_link_printk(link, KERN_INFO, format, ##arg)
+#else
+#define dwc_dev_vdbg(dev, format, arg...) \
+ ({ 0; })
+#define dwc_port_vdbg(ap, format, arg...) \
+ ({ 0; })
+#define dwc_link_vdbg(link, format, arg...) \
+ ({ 0; })
+#endif
+
+#define dwc_dev_info(dev, format, arg...) \
+ ({ if (0) dev_printk(KERN_INFO, dev, format, ##arg); 0; })
+#define dwc_port_info(ap, format, arg...) \
+ ata_port_printk(ap, KERN_INFO, format, ##arg)
+#define dwc_link_info(link, format, arg...) \
+ ata_link_printk(link, KERN_INFO, format, ##arg)
+
+/* These two are defined in "libata.h" */
+#undef DRV_NAME
+#undef DRV_VERSION
+#define DRV_NAME "sata-dwc"
+#define DRV_VERSION "2.0"
+
+/* Port Multiplier discovery Signature */
+#define PSCR_SCONTROL_DET_ENABLE 0x00000001
+#define PSCR_SSTATUS_DET_PRESENT 0x00000001
+#define PSCR_SERROR_DIAG_X 0x04000000
+
+/* Port multiplier port entry in SCONTROL register */
+#define SCONTROL_PMP_MASK 0x000f0000
+#define PMP_TO_SCONTROL(p) ((p << 16) & 0x000f0000)
+#define SCONTROL_TO_PMP(p) (((p) & 0x000f0000) >> 16)
+
+
+/* SATA DMA driver Globals */
+#if defined(CONFIG_APM821xx)
+#define DMA_NUM_CHANS 2
+#else
+#define DMA_NUM_CHANS 1
+#endif
+
+#define DMA_NUM_CHAN_REGS 8
+
+/* SATA DMA Register definitions */
+#if defined(CONFIG_APM821xx)
+#define AHB_DMA_BRST_DFLT 64 /* 16 data items burst length */
+#else
+#define AHB_DMA_BRST_DFLT 64 /* 16 data items burst length */
+#endif
+
+#if defined(CONFIG_APOLLO3G)
+extern void signal_hdd_led(int, int);
+#endif
+struct dmareg {
+ u32 low; /* Low bits 0-31 */
+ u32 high; /* High bits 32-63 */
+};
+
+/* DMA Per Channel registers */
+
+struct dma_chan_regs {
+ struct dmareg sar; /* Source Address */
+ struct dmareg dar; /* Destination address */
+ struct dmareg llp; /* Linked List Pointer */
+ struct dmareg ctl; /* Control */
+ struct dmareg sstat; /* Source Status not implemented in core */
+ struct dmareg dstat; /* Destination Status not implemented in core */
+ struct dmareg sstatar; /* Source Status Address not impl in core */
+ struct dmareg dstatar; /* Destination Status Address not implemented */
+ struct dmareg cfg; /* Config */
+ struct dmareg sgr; /* Source Gather */
+ struct dmareg dsr; /* Destination Scatter */
+};
+
+/* Generic Interrupt Registers */
+struct dma_interrupt_regs {
+ struct dmareg tfr; /* Transfer Interrupt */
+ struct dmareg block; /* Block Interrupt */
+ struct dmareg srctran; /* Source Transfer Interrupt */
+ struct dmareg dsttran; /* Dest Transfer Interrupt */
+ struct dmareg error; /* Error */
+};
+
+struct ahb_dma_regs {
+ struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS];
+ struct dma_interrupt_regs interrupt_raw; /* Raw Interrupt */
+ struct dma_interrupt_regs interrupt_status; /* Interrupt Status */
+ struct dma_interrupt_regs interrupt_mask; /* Interrupt Mask */
+ struct dma_interrupt_regs interrupt_clear; /* Interrupt Clear */
+ struct dmareg statusInt; /* Interrupt combined */
+ struct dmareg rq_srcreg; /* Src Trans Req */
+ struct dmareg rq_dstreg; /* Dst Trans Req */
+ struct dmareg rq_sgl_srcreg; /* Sngl Src Trans Req */
+ struct dmareg rq_sgl_dstreg; /* Sngl Dst Trans Req */
+ struct dmareg rq_lst_srcreg; /* Last Src Trans Req */
+ struct dmareg rq_lst_dstreg; /* Last Dst Trans Req */
+ struct dmareg dma_cfg; /* DMA Config */
+ struct dmareg dma_chan_en; /* DMA Channel Enable */
+ struct dmareg dma_id; /* DMA ID */
+ struct dmareg dma_test; /* DMA Test */
+ struct dmareg res1; /* reserved */
+ struct dmareg res2; /* reserved */
+
+ /* DMA Comp Params
+ * Param 6 = dma_param[0], Param 5 = dma_param[1],
+ * Param 4 = dma_param[2] ...
+ */
+ struct dmareg dma_params[6];
+};
+
+/* Data structure for linked list item */
+struct lli {
+ u32 sar; /* Source Address */
+ u32 dar; /* Destination address */
+ u32 llp; /* Linked List Pointer */
+ struct dmareg ctl; /* Control */
+#if defined(CONFIG_APM821xx)
+ u32 dstat; /* Source status is not supported */
+#else
+ struct dmareg dstat; /* Destination Status */
+#endif
+};
+
+#define SATA_DWC_DMAC_LLI_SZ (sizeof(struct lli))
+#define SATA_DWC_DMAC_LLI_NUM 256
+#define SATA_DWC_DMAC_TWIDTH_BYTES 4
+#define SATA_DWC_DMAC_LLI_TBL_SZ \
+ (SATA_DWC_DMAC_LLI_SZ * SATA_DWC_DMAC_LLI_NUM)
+#if defined(CONFIG_APM821xx)
+#define SATA_DWC_DMAC_CTRL_TSIZE_MAX \
+ (0x00000800 * SATA_DWC_DMAC_TWIDTH_BYTES)
+#else
+#define SATA_DWC_DMAC_CTRL_TSIZE_MAX \
+ (0x00000800 * SATA_DWC_DMAC_TWIDTH_BYTES)
+#endif
+/* DMA Register Operation Bits */
+#define DMA_EN 0x00000001 /* Enable AHB DMA */
+#define DMA_CHANNEL(ch) (0x00000001 << (ch)) /* Select channel */
+#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \
+ ((0x000000001 << (ch)) << 8))
+#define DMA_DISABLE_CHAN(ch) (0x00000000 | ((0x000000001 << (ch)) << 8))
+
+/* Channel Control Register */
+#define DMA_CTL_BLK_TS(size) ((size) & 0x000000FFF) /* Blk Transfer size */
+#define DMA_CTL_LLP_SRCEN 0x10000000 /* Blk chain enable Src */
+#define DMA_CTL_LLP_DSTEN 0x08000000 /* Blk chain enable Dst */
+/*
+ * This define is used to set block chaining disabled in the control low
+ * register. It is already in little endian format so it can be &'d dirctly.
+ * It is essentially: cpu_to_le32(~(DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN))
+ */
+#define DMA_CTL_LLP_DISABLE_LE32 0xffffffe7
+#define DMA_CTL_SMS(num) ((num & 0x3) << 25) /*Src Master Select*/
+#define DMA_CTL_DMS(num) ((num & 0x3) << 23) /*Dst Master Select*/
+#define DMA_CTL_TTFC(type) ((type & 0x7) << 20) /*Type&Flow cntr*/
+#define DMA_CTL_TTFC_P2M_DMAC 0x00000002 /*Per mem,DMAC cntr*/
+#define DMA_CTL_TTFC_M2P_PER 0x00000003 /*Mem per,peri cntr*/
+#define DMA_CTL_SRC_MSIZE(size) ((size & 0x7) << 14) /*Src Burst Len*/
+#define DMA_CTL_DST_MSIZE(size) ((size & 0x7) << 11) /*Dst Burst Len*/
+#define DMA_CTL_SINC_INC 0x00000000 /*Src addr incr*/
+#define DMA_CTL_SINC_DEC 0x00000200
+#define DMA_CTL_SINC_NOCHANGE 0x00000400
+#define DMA_CTL_DINC_INC 0x00000000 /*Dst addr incr*/
+#define DMA_CTL_DINC_DEC 0x00000080
+#define DMA_CTL_DINC_NOCHANGE 0x00000100
+#define DMA_CTL_SRC_TRWID(size) ((size & 0x7) << 4) /*Src Trnsfr Width*/
+#define DMA_CTL_DST_TRWID(size) ((size & 0x7) << 1) /*Dst Trnsfr Width*/
+#define DMA_CTL_INT_EN 0x00000001 /*Interrupt Enable*/
+
+/* Channel Configuration Register high bits */
+#define DMA_CFG_FCMOD_REQ 0x00000001 /*Flow cntrl req*/
+#define DMA_CFG_PROTCTL (0x00000003 << 2) /*Protection cntrl*/
+
+/* Channel Configuration Register low bits */
+#define DMA_CFG_RELD_DST 0x80000000 /*Reload Dst/Src Addr*/
+#define DMA_CFG_RELD_SRC 0x40000000
+#define DMA_CFG_HS_SELSRC 0x00000800 /*SW hndshk Src/Dst*/
+#define DMA_CFG_HS_SELDST 0x00000400
+#define DMA_CFG_FIFOEMPTY (0x00000001 << 9) /*FIFO Empty bit*/
+
+/* Assign hardware handshaking interface (x) to dst / sre peripheral */
+#define DMA_CFG_HW_HS_DEST(int_num) ((int_num & 0xF) << 11)
+#define DMA_CFG_HW_HS_SRC(int_num) ((int_num & 0xF) << 7)
+
+/* Channel Linked List Pointer Register */
+#define DMA_LLP_LMS(addr, master) (((addr) & 0xfffffffc) | (master))
+#define DMA_LLP_AHBMASTER1 0 /* List Master Select */
+#define DMA_LLP_AHBMASTER2 1
+
+#define SATA_DWC_MAX_PORTS 1
+
+#define SATA_DWC_SCR_OFFSET 0x24
+#define SATA_DWC_REG_OFFSET 0x64
+
+/* DWC SATA Registers */
+struct sata_dwc_regs {
+ u32 fptagr; /* 1st party DMA tag */
+ u32 fpbor; /* 1st party DMA buffer offset */
+ u32 fptcr; /* 1st party DMA Xfr count */
+ u32 dmacr; /* DMA Control */
+ u32 dbtsr; /* DMA Burst Transac size */
+ u32 intpr; /* Interrupt Pending */
+ u32 intmr; /* Interrupt Mask */
+ u32 errmr; /* Error Mask */
+ u32 llcr; /* Link Layer Control */
+ u32 phycr; /* PHY Control */
+ u32 physr; /* PHY Status */
+ u32 rxbistpd; /* Recvd BIST pattern def register */
+ u32 rxbistpd1; /* Recvd BIST data dword1 */
+ u32 rxbistpd2; /* Recvd BIST pattern data dword2 */
+ u32 txbistpd; /* Trans BIST pattern def register */
+ u32 txbistpd1; /* Trans BIST data dword1 */
+ u32 txbistpd2; /* Trans BIST data dword2 */
+ u32 bistcr; /* BIST Control Register */
+ u32 bistfctr; /* BIST FIS Count Register */
+ u32 bistsr; /* BIST Status Register */
+ u32 bistdecr; /* BIST Dword Error count register */
+ u32 res[15]; /* Reserved locations */
+ u32 testr; /* Test Register */
+ u32 versionr; /* Version Register */
+ u32 idr; /* ID Register */
+ u32 unimpl[192]; /* Unimplemented */
+ u32 dmadr[256]; /* FIFO Locations in DMA Mode */
+};
+
+#define SCR_SCONTROL_DET_ENABLE 0x00000001
+#define SCR_SSTATUS_DET_PRESENT 0x00000001
+#define SCR_SERROR_DIAG_X 0x04000000
+
+/* DWC SATA Register Operations */
+#define SATA_DWC_TXFIFO_DEPTH 0x01FF
+#define SATA_DWC_RXFIFO_DEPTH 0x01FF
+
+#define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004
+#define SATA_DWC_DMACR_TXCHEN (0x00000001 | \
+ SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DMACR_RXCHEN (0x00000002 | \
+ SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DMACR_TX_CLEAR(v) (((v) & ~SATA_DWC_DMACR_TXCHEN) | \
+ SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DMACR_RX_CLEAR(v) (((v) & ~SATA_DWC_DMACR_RXCHEN) | \
+ SATA_DWC_DMACR_TMOD_TXCHEN)
+#define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN
+
+#define SATA_DWC_DBTSR_MWR(size) ((size/4) & \
+ SATA_DWC_TXFIFO_DEPTH)
+#define SATA_DWC_DBTSR_MRD(size) (((size/4) & \
+ SATA_DWC_RXFIFO_DEPTH) << 16)
+
+// SATA DWC Interrupts
+#define SATA_DWC_INTPR_DMAT 0x00000001
+#define SATA_DWC_INTPR_NEWFP 0x00000002
+#define SATA_DWC_INTPR_PMABRT 0x00000004
+#define SATA_DWC_INTPR_ERR 0x00000008
+#define SATA_DWC_INTPR_NEWBIST 0x00000010
+#define SATA_DWC_INTPR_IPF 0x80000000
+// Interrupt masks
+#define SATA_DWC_INTMR_DMATM 0x00000001
+#define SATA_DWC_INTMR_NEWFPM 0x00000002
+#define SATA_DWC_INTMR_PMABRTM 0x00000004
+#define SATA_DWC_INTMR_ERRM 0x00000008
+#define SATA_DWC_INTMR_NEWBISTM 0x00000010
+#define SATA_DWC_INTMR_PRIMERRM 0x00000020
+#define SATA_DWC_INTPR_CMDGOOD 0x00000080
+#define SATA_DWC_INTPR_CMDABORT 0x00000040
+
+#define SATA_DWC_LLCR_SCRAMEN 0x00000001
+#define SATA_DWC_LLCR_DESCRAMEN 0x00000002
+#define SATA_DWC_LLCR_RPDEN 0x00000004
+
+// Defines for SError register
+#define SATA_DWC_SERR_ERRI 0x00000001 // Recovered data integrity error
+#define SATA_DWC_SERR_ERRM 0x00000002 // Recovered communication error
+#define SATA_DWC_SERR_ERRT 0x00000100 // Non-recovered transient data integrity error
+#define SATA_DWC_SERR_ERRC 0x00000200 // Non-recovered persistent communication or data integrity error
+#define SATA_DWC_SERR_ERRP 0x00000400 // Protocol error
+#define SATA_DWC_SERR_ERRE 0x00000800 // Internal host adapter error
+#define SATA_DWC_SERR_DIAGN 0x00010000 // PHYRdy change
+#define SATA_DWC_SERR_DIAGI 0x00020000 // PHY internal error
+#define SATA_DWC_SERR_DIAGW 0x00040000 // Phy COMWAKE signal is detected
+#define SATA_DWC_SERR_DIAGB 0x00080000 // 10b to 8b decoder err
+#define SATA_DWC_SERR_DIAGT 0x00100000 // Disparity error
+#define SATA_DWC_SERR_DIAGC 0x00200000 // CRC error
+#define SATA_DWC_SERR_DIAGH 0x00400000 // Handshake error
+#define SATA_DWC_SERR_DIAGL 0x00800000 // Link sequence (illegal transition) error
+#define SATA_DWC_SERR_DIAGS 0x01000000 // Transport state transition error
+#define SATA_DWC_SERR_DIAGF 0x02000000 // Unrecognized FIS type
+#define SATA_DWC_SERR_DIAGX 0x04000000 // Exchanged error - Set when PHY COMINIT signal is detected.
+#define SATA_DWC_SERR_DIAGA 0x08000000 // Port Selector Presence detected
+
+/* This is all error bits, zero's are reserved fields. */
+#define SATA_DWC_SERR_ERR_BITS 0x0FFF0F03
+
+#define SATA_DWC_SCR0_SPD_GET(v) ((v >> 4) & 0x0000000F)
+
+struct sata_dwc_device {
+ struct resource reg; /* Resource for register */
+ struct device *dev; /* generic device struct */
+ struct ata_probe_ent *pe; /* ptr to probe-ent */
+ struct ata_host *host;
+ u8 *reg_base;
+ struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */
+ u8 *scr_base;
+ int dma_channel; /* DWC SATA DMA channel */
+ int irq_dma;
+ struct timer_list an_timer;
+};
+
+#define SATA_DWC_QCMD_MAX 32
+
+struct sata_dwc_device_port {
+ struct sata_dwc_device *hsdev;
+ int cmd_issued[SATA_DWC_QCMD_MAX];
+ struct lli *llit[SATA_DWC_QCMD_MAX];
+ dma_addr_t llit_dma[SATA_DWC_QCMD_MAX];
+ u32 dma_chan[SATA_DWC_QCMD_MAX];
+ int dma_pending[SATA_DWC_QCMD_MAX];
+ u32 sata_dwc_sactive_issued; /* issued queued ops */
+ u32 sata_dwc_sactive_queued; /* queued ops */
+ u32 dma_interrupt_count;
+
+};
+
+static struct sata_dwc_device* dwc_dev_list[2];
+static int dma_intr_registered = 0;
+/*
+ * Commonly used DWC SATA driver Macros
+ */
+#define HSDEV_FROM_HOST(host) ((struct sata_dwc_device *) \
+ (host)->private_data)
+#define HSDEV_FROM_AP(ap) ((struct sata_dwc_device *) \
+ (ap)->host->private_data)
+#define HSDEVP_FROM_AP(ap) ((struct sata_dwc_device_port *) \
+ (ap)->private_data)
+#define HSDEV_FROM_QC(qc) ((struct sata_dwc_device *) \
+ (qc)->ap->host->private_data)
+#define HSDEV_FROM_HSDEVP(p) ((struct sata_dwc_device *) \
+ (hsdevp)->hsdev)
+
+enum {
+ SATA_DWC_CMD_ISSUED_NOT = 0,
+ SATA_DWC_CMD_ISSUED_PENDING = 1,
+ SATA_DWC_CMD_ISSUED_EXEC = 2,
+ SATA_DWC_CMD_ISSUED_NODATA = 3,
+
+ SATA_DWC_DMA_PENDING_NONE = 0,
+ SATA_DWC_DMA_PENDING_TX = 1,
+ SATA_DWC_DMA_PENDING_RX = 2,
+};
+
+/*
+ * Globals
+ */
+static struct ahb_dma_regs *sata_dma_regs = 0;
+
+/*
+ * Prototypes
+ */
+static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag);
+static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u32 check_status);
+static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status);
+static void sata_dwc_port_stop(struct ata_port *ap);
+static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag);
+
+static int dma_dwc_init(struct sata_dwc_device *hsdev);
+static void dma_dwc_exit(struct sata_dwc_device *hsdev);
+static int dma_dwc_xfer_setup(struct ata_queued_cmd *qc,
+ struct lli *lli, dma_addr_t dma_lli,
+ void __iomem *addr);
+static void dma_dwc_xfer_start(int dma_ch);
+static void dma_dwc_terminate_dma(struct ata_port *ap, int dma_ch);
+static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev);
+static void sata_dwc_init_port ( struct ata_port *ap );
+u8 sata_dwc_check_status(struct ata_port *ap);
+
+
+
+
+static const char *dir_2_txt(enum dma_data_direction dir)
+{
+ switch (dir) {
+ case DMA_BIDIRECTIONAL:
+ return "bi";
+ case DMA_FROM_DEVICE:
+ return "from";
+ case DMA_TO_DEVICE:
+ return "to";
+ case DMA_NONE:
+ return "none";
+ default:
+ return "err";
+ }
+}
+
+static const char *prot_2_txt(enum ata_tf_protocols protocol)
+{
+ switch (protocol) {
+ case ATA_PROT_UNKNOWN:
+ return "unknown";
+ case ATA_PROT_NODATA:
+ return "nodata";
+ case ATA_PROT_PIO:
+ return "pio";
+ case ATA_PROT_DMA:
+ return "dma";
+ case ATA_PROT_NCQ:
+ return "ncq";
+ case ATAPI_PROT_PIO:
+ return "atapi pio";
+ case ATAPI_PROT_NODATA:
+ return "atapi nodata";
+ case ATAPI_PROT_DMA:
+ return "atapi dma";
+ default:
+ return "err";
+ }
+}
+
+inline const char *ata_cmd_2_txt(const struct ata_taskfile *tf)
+{
+ switch (tf->command) {
+ case ATA_CMD_CHK_POWER:
+ return "ATA_CMD_CHK_POWER";
+ case ATA_CMD_EDD:
+ return "ATA_CMD_EDD";
+ case ATA_CMD_FLUSH:
+ return "ATA_CMD_FLUSH";
+ case ATA_CMD_FLUSH_EXT:
+ return "ATA_CMD_FLUSH_EXT";
+ case ATA_CMD_ID_ATA:
+ return "ATA_CMD_ID_ATA";
+ case ATA_CMD_ID_ATAPI:
+ return "ATA_CMD_ID_ATAPI";
+ case ATA_CMD_FPDMA_READ:
+ return "ATA_CMD_FPDMA_READ";
+ case ATA_CMD_FPDMA_WRITE:
+ return "ATA_CMD_FPDMA_WRITE";
+ case ATA_CMD_READ:
+ return "ATA_CMD_READ";
+ case ATA_CMD_READ_EXT:
+ return "ATA_CMD_READ_EXT";
+ case ATA_CMD_READ_NATIVE_MAX_EXT :
+ return "ATA_CMD_READ_NATIVE_MAX_EXT";
+ case ATA_CMD_VERIFY_EXT :
+ return "ATA_CMD_VERIFY_EXT";
+ case ATA_CMD_WRITE:
+ return "ATA_CMD_WRITE";
+ case ATA_CMD_WRITE_EXT:
+ return "ATA_CMD_WRITE_EXT";
+ case ATA_CMD_PIO_READ:
+ return "ATA_CMD_PIO_READ";
+ case ATA_CMD_PIO_READ_EXT:
+ return "ATA_CMD_PIO_READ_EXT";
+ case ATA_CMD_PIO_WRITE:
+ return "ATA_CMD_PIO_WRITE";
+ case ATA_CMD_PIO_WRITE_EXT:
+ return "ATA_CMD_PIO_WRITE_EXT";
+ case ATA_CMD_SET_FEATURES:
+ return "ATA_CMD_SET_FEATURES";
+ case ATA_CMD_PACKET:
+ return "ATA_CMD_PACKET";
+ case ATA_CMD_PMP_READ:
+ return "ATA_CMD_PMP_READ";
+ case ATA_CMD_PMP_WRITE:
+ return "ATA_CMD_PMP_WRITE";
+ default:
+ return "ATA_CMD_???";
+ }
+}
+
+/*
+ * Dump content of the taskfile
+ */
+static void sata_dwc_tf_dump(struct device *dwc_dev, struct ata_taskfile *tf)
+{
+ dwc_dev_vdbg(dwc_dev, "taskfile cmd: 0x%02x protocol: %s flags: 0x%lx"
+ "device: %x\n", tf->command, prot_2_txt(tf->protocol),
+ tf->flags, tf->device);
+ dwc_dev_vdbg(dwc_dev, "feature: 0x%02x nsect: 0x%x lbal: 0x%x lbam:"
+ "0x%x lbah: 0x%x\n", tf->feature, tf->nsect, tf->lbal,
+ tf->lbam, tf->lbah);
+ dwc_dev_vdbg(dwc_dev, "hob_feature: 0x%02x hob_nsect: 0x%x hob_lbal: 0x%x "
+ "hob_lbam: 0x%x hob_lbah: 0x%x\n", tf->hob_feature,
+ tf->hob_nsect, tf->hob_lbal, tf->hob_lbam,
+ tf->hob_lbah);
+}
+
+/*
+ * Function: get_burst_length_encode
+ * arguments: datalength: length in bytes of data
+ * returns value to be programmed in register corresponding to data length
+ * This value is effectively the log(base 2) of the length
+ */
+static inline int get_burst_length_encode(int datalength)
+{
+ int items = datalength >> 2; /* div by 4 to get lword count */
+
+ if (items >= 64)
+ return 5;
+
+ if (items >= 32)
+ return 4;
+
+ if (items >= 16)
+ return 3;
+
+ if (items >= 8)
+ return 2;
+
+ if (items >= 4)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Clear Interrupts on a DMA channel
+ */
+static inline void clear_chan_interrupts(int c)
+{
+ out_le32(&(sata_dma_regs->interrupt_clear.tfr.low), DMA_CHANNEL(c));
+ out_le32(&(sata_dma_regs->interrupt_clear.block.low), DMA_CHANNEL(c));
+ out_le32(&(sata_dma_regs->interrupt_clear.srctran.low), DMA_CHANNEL(c));
+ out_le32(&(sata_dma_regs->interrupt_clear.dsttran.low), DMA_CHANNEL(c));
+ out_le32(&(sata_dma_regs->interrupt_clear.error.low), DMA_CHANNEL(c));
+}
+
+/*
+ * Function: dma_request_channel
+ * arguments: None
+ * returns channel number if available else -1
+ * This function assigns the next available DMA channel from the list to the
+ * requester
+ */
+static int dma_request_channel(struct ata_port *ap)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+
+ if (!(in_le32(&(sata_dma_regs->dma_chan_en.low)) & DMA_CHANNEL(hsdev->dma_channel))) {
+ dwc_port_vdbg(ap, "%s Successfully requested DMA channel %d\n",
+ __func__, hsdev->dma_channel);
+ return (hsdev->dma_channel);
+ }
+
+ return -1;
+}
+
+
+
+/*
+ * Function: dma_dwc_interrupt
+ * arguments: irq, dev_id, pt_regs
+ * returns channel number if available else -1
+ * Interrupt Handler for DW AHB SATA DMA
+ */
+static int dma_dwc_interrupt(int irq, void *hsdev_instance)
+{
+ volatile u32 tfr_reg, err_reg;
+ unsigned long flags;
+ struct sata_dwc_device *hsdev = hsdev_instance;
+ struct ata_host *host = (struct ata_host *)hsdev->host;
+ struct ata_port *ap;
+ struct sata_dwc_device_port *hsdevp;
+ u8 tag = 0;
+ int chan;
+ unsigned int port = 0;
+ spin_lock_irqsave(&host->lock, flags);
+
+ ap = host->ports[port];
+ hsdevp = HSDEVP_FROM_AP(ap);
+ tag = ap->link.active_tag;
+
+ dwc_port_vdbg(ap, "%s: DMA interrupt in channel %d\n", __func__, hsdev->dma_channel);
+
+ tfr_reg = in_le32(&(sata_dma_regs->interrupt_status.tfr.low));
+ err_reg = in_le32(&(sata_dma_regs->interrupt_status.error.low));
+
+ dwc_port_vdbg(ap, "eot=0x%08x err=0x%08x pending=%d active port=%d\n",
+ tfr_reg, err_reg, hsdevp->dma_pending[tag], port);
+ chan = hsdev->dma_channel;
+
+ if (tfr_reg & DMA_CHANNEL(chan)) {
+ /*
+ *Each DMA command produces 2 interrupts. Only
+ * complete the command after both interrupts have been
+ * seen. (See sata_dwc_isr())
+ */
+ hsdevp->dma_interrupt_count++;
+ sata_dwc_clear_dmacr(hsdevp, tag);
+
+ if (unlikely(hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_NONE)) {
+ dev_err(ap->dev, "DMA not pending eot=0x%08x "
+ "err=0x%08x tag=0x%02x pending=%d\n",
+ tfr_reg, err_reg, tag,
+ hsdevp->dma_pending[tag]);
+ }
+
+ // Do remain jobs after DMA transfer complete
+ if ((hsdevp->dma_interrupt_count % 2) == 0)
+ sata_dwc_dma_xfer_complete(ap, 1);
+
+ /* Clear the interrupt */
+ out_le32(&(sata_dma_regs->interrupt_clear.tfr.low),
+ DMA_CHANNEL(chan));
+ }
+
+ /* Process error interrupt. */
+ // We do not expect error happen
+ if (unlikely(err_reg & DMA_CHANNEL(chan))) {
+ /* TODO Need error handler ! */
+ dev_err(ap->dev, "error interrupt err_reg=0x%08x\n",
+ err_reg);
+
+ spin_lock_irqsave(ap->lock, flags);
+ //if (ata_is_dma(qc->tf.protocol)) {
+ /* disable DMAC */
+ dma_dwc_terminate_dma(ap, chan);
+ //}
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* Clear the interrupt. */
+ out_le32(&(sata_dma_regs->interrupt_clear.error.low),
+ DMA_CHANNEL(chan));
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dma_dwc_handler(int irq, void *hsdev_instance)
+{
+ volatile u32 tfr_reg, err_reg;
+ int chan;
+
+ tfr_reg = in_le32(&(sata_dma_regs->interrupt_status.tfr.low));
+ err_reg = in_le32(&(sata_dma_regs->interrupt_status.error.low));
+
+ for (chan = 0; chan < DMA_NUM_CHANS; chan++) {
+ /* Check for end-of-transfer interrupt. */
+
+ if (tfr_reg & DMA_CHANNEL(chan)) {
+ dma_dwc_interrupt(0, dwc_dev_list[chan]);
+ }
+ else
+
+ /* Check for error interrupt. */
+ if (err_reg & DMA_CHANNEL(chan)) {
+ dma_dwc_interrupt(0, dwc_dev_list[chan]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int dma_register_interrupt (struct sata_dwc_device *hsdev)
+{
+ int retval = 0;
+ int irq = hsdev->irq_dma;
+ /*
+ * FIXME: 2 SATA controllers share the same DMA engine so
+ * currently, they also share same DMA interrupt
+ */
+ if (!dma_intr_registered) {
+ printk("%s register irq (%d)\n", __func__, irq);
+ retval = request_irq(irq, dma_dwc_handler, IRQF_SHARED, "SATA DMA", hsdev);
+ //retval = request_irq(irq, dma_dwc_handler, IRQF_DISABLED, "SATA DMA", NULL);
+ if (retval) {
+ dev_err(hsdev->dev, "%s: could not get IRQ %d\n", __func__, irq);
+ return -ENODEV;
+ }
+ //dma_intr_registered = 1;
+ }
+ return retval;
+}
+
+/*
+ * Function: dma_request_interrupts
+ * arguments: hsdev
+ * returns status
+ * This function registers ISR for a particular DMA channel interrupt
+ */
+static int dma_request_interrupts(struct sata_dwc_device *hsdev, int irq)
+{
+ int retval = 0;
+ int dma_chan = hsdev->dma_channel;
+
+ /* Unmask error interrupt */
+ out_le32(&sata_dma_regs->interrupt_mask.error.low,
+ in_le32(&sata_dma_regs->interrupt_mask.error.low) | DMA_ENABLE_CHAN(dma_chan));
+
+ /* Unmask end-of-transfer interrupt */
+ out_le32(&sata_dma_regs->interrupt_mask.tfr.low,
+ in_le32(&sata_dma_regs->interrupt_mask.tfr.low) | DMA_ENABLE_CHAN(dma_chan));
+
+ dwc_dev_vdbg(hsdev->dev, "Current value of interrupt_mask.error=0x%0x\n", in_le32(&sata_dma_regs->interrupt_mask.error.low));
+ dwc_dev_vdbg(hsdev->dev, "Current value of interrupt_mask.tfr=0x%0x\n", in_le32(&sata_dma_regs->interrupt_mask.tfr.low));
+#if 0
+ out_le32(&sata_dma_regs->interrupt_mask.block.low,
+ DMA_ENABLE_CHAN(dma_chan));
+
+ out_le32(&sata_dma_regs->interrupt_mask.srctran.low,
+ DMA_ENABLE_CHAN(dma_chan));
+
+ out_le32(&sata_dma_regs->interrupt_mask.dsttran.low,
+ DMA_ENABLE_CHAN(dma_chan));
+#endif
+ return retval;
+}
+
+/*
+ * Function: map_sg_to_lli
+ * arguments: sg: scatter/gather list(sg)
+ * num_elems: no of elements in sg list
+ * dma_lli: LLI table
+ * dest: destination address
+ * read: whether the transfer is read or write
+ * returns array of AHB DMA Linked List Items
+ * This function creates a list of LLIs for DMA Xfr and returns the number
+ * of elements in the DMA linked list.
+ *
+ * Note that the Synopsis driver has a comment proposing that better performance
+ * is possible by only enabling interrupts on the last item in the linked list.
+ * However, it seems that could be a problem if an error happened on one of the
+ * first items. The transfer would halt, but no error interrupt would occur.
+ *
+ * Currently this function sets interrupts enabled for each linked list item:
+ * DMA_CTL_INT_EN.
+ */
+static int map_sg_to_lli(struct ata_queued_cmd *qc, struct lli *lli,
+ dma_addr_t dma_lli, void __iomem *dmadr_addr)
+{
+ struct scatterlist *sg = qc->sg;
+ struct device *dwc_dev = qc->ap->dev;
+ int num_elems = qc->n_elem;
+ int dir = qc->dma_dir;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(qc->ap);
+
+ int i, idx = 0;
+ int fis_len = 0;
+ dma_addr_t next_llp;
+ int bl;
+ unsigned int dma_ts = 0;
+
+ dwc_port_vdbg(qc->ap, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x "
+ "dmadr=0x%08x\n", __func__, sg, num_elems, lli, (u32)dma_lli,
+ (u32)dmadr_addr);
+
+ bl = get_burst_length_encode(AHB_DMA_BRST_DFLT);
+
+ for (i = 0; i < num_elems; i++, sg++) {
+ u32 addr, offset;
+ u32 sg_len, len;
+
+ addr = (u32) sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ dwc_port_vdbg(qc->ap, "%s: elem=%d sg_addr=0x%x sg_len=%d\n",
+ __func__, i, addr, sg_len);
+
+ while (sg_len) {
+
+ if (unlikely(idx >= SATA_DWC_DMAC_LLI_NUM)) {
+ /* The LLI table is not large enough. */
+ dev_err(dwc_dev, "LLI table overrun (idx=%d)\n",
+ idx);
+ break;
+ }
+ len = (sg_len > SATA_DWC_DMAC_CTRL_TSIZE_MAX) ?
+ SATA_DWC_DMAC_CTRL_TSIZE_MAX : sg_len;
+
+ offset = addr & 0xffff;
+ if ((offset + sg_len) > 0x10000)
+ len = 0x10000 - offset;
+
+ /*
+ * Make sure a LLI block is not created that will span a
+ * 8K max FIS boundary. If the block spans such a FIS
+ * boundary, there is a chance that a DMA burst will
+ * cross that boundary -- this results in an error in
+ * the host controller.
+ */
+ if (unlikely(fis_len + len > 8192)) {
+ dwc_port_vdbg(qc->ap, "SPLITTING: fis_len=%d(0x%x) "
+ "len=%d(0x%x)\n", fis_len, fis_len,
+ len, len);
+ len = 8192 - fis_len;
+ fis_len = 0;
+ } else {
+ fis_len += len;
+ }
+ if (fis_len == 8192)
+ fis_len = 0;
+
+ /*
+ * Set DMA addresses and lower half of control register
+ * based on direction.
+ */
+ dwc_port_vdbg(qc->ap, "%s: sg_len = %d, len = %d\n", __func__, sg_len, len);
+
+#if defined(CONFIG_APM821xx)
+ if (dir == DMA_FROM_DEVICE) {
+ lli[idx].dar = cpu_to_le32(addr);
+ lli[idx].sar = cpu_to_le32((u32)dmadr_addr);
+ if (hsdevp->hsdev->dma_channel == 0) {/* DMA channel 0 */
+ lli[idx].ctl.low = cpu_to_le32(
+ DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) |
+ DMA_CTL_SMS(1) | /* Source: Master 2 */
+ DMA_CTL_DMS(0) | /* Dest: Master 1 */
+ DMA_CTL_SRC_MSIZE(bl) |
+ DMA_CTL_DST_MSIZE(bl) |
+ DMA_CTL_SINC_NOCHANGE |
+ DMA_CTL_SRC_TRWID(2) |
+ DMA_CTL_DST_TRWID(2) |
+ DMA_CTL_INT_EN |
+ DMA_CTL_LLP_SRCEN |
+ DMA_CTL_LLP_DSTEN);
+ } else if (hsdevp->hsdev->dma_channel == 1) {/* DMA channel 1 */
+ lli[idx].ctl.low = cpu_to_le32(
+ DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) |
+ DMA_CTL_SMS(2) | /* Source: Master 3 */
+ DMA_CTL_DMS(0) | /* Dest: Master 1 */
+ DMA_CTL_SRC_MSIZE(bl) |
+ DMA_CTL_DST_MSIZE(bl) |
+ DMA_CTL_SINC_NOCHANGE |
+ DMA_CTL_SRC_TRWID(2) |
+ DMA_CTL_DST_TRWID(2) |
+ DMA_CTL_INT_EN |
+ DMA_CTL_LLP_SRCEN |
+ DMA_CTL_LLP_DSTEN);
+ }
+ } else { /* DMA_TO_DEVICE */
+ lli[idx].sar = cpu_to_le32(addr);
+ lli[idx].dar = cpu_to_le32((u32)dmadr_addr);
+ if (hsdevp->hsdev->dma_channel == 0) {/* DMA channel 0 */
+ lli[idx].ctl.low = cpu_to_le32(
+ DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) |
+ DMA_CTL_SMS(0) |
+ DMA_CTL_DMS(1) |
+ DMA_CTL_SRC_MSIZE(bl) |
+ DMA_CTL_DST_MSIZE(bl) |
+ DMA_CTL_DINC_NOCHANGE |
+ DMA_CTL_SRC_TRWID(2) |
+ DMA_CTL_DST_TRWID(2) |
+ DMA_CTL_INT_EN |
+ DMA_CTL_LLP_SRCEN |
+ DMA_CTL_LLP_DSTEN);
+ } else if (hsdevp->hsdev->dma_channel == 1) {/* DMA channel 1 */
+ lli[idx].ctl.low = cpu_to_le32(
+ DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) |
+ DMA_CTL_SMS(0) |
+ DMA_CTL_DMS(2) |
+ DMA_CTL_SRC_MSIZE(bl) |
+ DMA_CTL_DST_MSIZE(bl) |
+ DMA_CTL_DINC_NOCHANGE |
+ DMA_CTL_SRC_TRWID(2) |
+ DMA_CTL_DST_TRWID(2) |
+ DMA_CTL_INT_EN |
+ DMA_CTL_LLP_SRCEN |
+ DMA_CTL_LLP_DSTEN);
+ }
+ }
+#else
+ if (dir == DMA_FROM_DEVICE) {
+ lli[idx].dar = cpu_to_le32(addr);
+ lli[idx].sar = cpu_to_le32((u32)dmadr_addr);
+
+ lli[idx].ctl.low = cpu_to_le32(
+ DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) |
+ DMA_CTL_SMS(0) |
+ DMA_CTL_DMS(1) |
+ DMA_CTL_SRC_MSIZE(bl) |
+ DMA_CTL_DST_MSIZE(bl) |
+ DMA_CTL_SINC_NOCHANGE |
+ DMA_CTL_SRC_TRWID(2) |
+ DMA_CTL_DST_TRWID(2) |
+ DMA_CTL_INT_EN |
+ DMA_CTL_LLP_SRCEN |
+ DMA_CTL_LLP_DSTEN);
+ } else { /* DMA_TO_DEVICE */
+ lli[idx].sar = cpu_to_le32(addr);
+ lli[idx].dar = cpu_to_le32((u32)dmadr_addr);
+
+ lli[idx].ctl.low = cpu_to_le32(
+ DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) |
+ DMA_CTL_SMS(1) |
+ DMA_CTL_DMS(0) |
+ DMA_CTL_SRC_MSIZE(bl) |
+ DMA_CTL_DST_MSIZE(bl) |
+ DMA_CTL_DINC_NOCHANGE |
+ DMA_CTL_SRC_TRWID(2) |
+ DMA_CTL_DST_TRWID(2) |
+ DMA_CTL_INT_EN |
+ DMA_CTL_LLP_SRCEN |
+ DMA_CTL_LLP_DSTEN);
+ }
+#endif
+ dwc_port_vdbg(qc->ap, "%s setting ctl.high len: 0x%08x val: "
+ "0x%08x\n", __func__, len,
+ DMA_CTL_BLK_TS(len / 4));
+
+ /* Program the LLI CTL high register */
+ dma_ts = DMA_CTL_BLK_TS(len / 4);
+ lli[idx].ctl.high = cpu_to_le32(dma_ts);
+
+ /*
+ *Program the next pointer. The next pointer must be
+ * the physical address, not the virtual address.
+ */
+ next_llp = (dma_lli + ((idx + 1) * sizeof(struct lli)));
+
+ /* The last 2 bits encode the list master select. */
+#if defined(CONFIG_APM821xx)
+ next_llp = DMA_LLP_LMS(next_llp, DMA_LLP_AHBMASTER1);
+#else
+ next_llp = DMA_LLP_LMS(next_llp, DMA_LLP_AHBMASTER2);
+#endif
+
+ lli[idx].llp = cpu_to_le32(next_llp);
+
+ dwc_port_vdbg(qc->ap, "%s: index %d\n", __func__, idx);
+ dwc_port_vdbg(qc->ap, "%s setting ctl.high with val: 0x%08x\n", __func__, lli[idx].ctl.high);
+ dwc_port_vdbg(qc->ap, "%s setting ctl.low with val: 0x%08x\n", __func__, lli[idx].ctl.low);
+ dwc_port_vdbg(qc->ap, "%s setting lli.dar with val: 0x%08x\n", __func__, lli[idx].dar);
+ dwc_port_vdbg(qc->ap, "%s setting lli.sar with val: 0x%08x\n", __func__, lli[idx].sar);
+ dwc_port_vdbg(qc->ap, "%s setting next_llp with val: 0x%08x\n", __func__, lli[idx].llp);
+
+ idx++;
+ sg_len -= len;
+ addr += len;
+ }
+ }
+
+ /*
+ * The last next ptr has to be zero and the last control low register
+ * has to have LLP_SRC_EN and LLP_DST_EN (linked list pointer source
+ * and destination enable) set back to 0 (disabled.) This is what tells
+ * the core that this is the last item in the linked list.
+ */
+ if (likely(idx)) {
+ lli[idx-1].llp = 0x00000000;
+ lli[idx-1].ctl.low &= DMA_CTL_LLP_DISABLE_LE32;
+
+ /* Flush cache to memory */
+ dma_cache_sync(NULL, lli, (sizeof(struct lli) * idx),
+ DMA_BIDIRECTIONAL);
+ }
+
+ dwc_port_vdbg(qc->ap, "%s: Final index %d\n", __func__, idx-1);
+ dwc_port_vdbg(qc->ap, "%s setting ctl.high with val: 0x%08x\n", __func__, lli[idx-1].ctl.high);
+ dwc_port_vdbg(qc->ap, "%s setting ctl.low with val: 0x%08x\n", __func__, lli[idx-1].ctl.low);
+ dwc_port_vdbg(qc->ap, "%s setting lli.dar with val: 0x%08x\n", __func__, lli[idx-1].dar);
+ dwc_port_vdbg(qc->ap, "%s setting lli.sar with val: 0x%08x\n", __func__, lli[idx-1].sar);
+ dwc_port_vdbg(qc->ap, "%s setting next_llp with val: 0x%08x\n", __func__, lli[idx-1].llp);
+
+ return idx;
+}
+
+/*
+ * Function: dma_dwc_xfer_start
+ * arguments: Channel number
+ * Return : None
+ * Enables the DMA channel
+ */
+static void dma_dwc_xfer_start(int dma_ch)
+{
+ /* Enable the DMA channel */
+ out_le32(&(sata_dma_regs->dma_chan_en.low),
+ in_le32(&(sata_dma_regs->dma_chan_en.low)) |
+ DMA_ENABLE_CHAN(dma_ch));
+
+#if defined(CONFIG_SATA_DWC_VDEBUG)
+ printk("DMA CFG = 0x%08x\n", in_le32(&(sata_dma_regs->dma_cfg.low)));
+ printk("%s: setting sata_dma_regs->dma_chan_en.low with val: 0x%08x\n",
+ __func__, in_le32(&(sata_dma_regs->dma_chan_en.low)));
+#endif
+
+
+#if defined(CONFIG_APOLLO3G)
+ signal_hdd_led(1 /*blink=yes*/, 2 /* _3G_LED_GREEN */);
+#endif
+
+}
+
+/*
+ * Check if the selected DMA channel is currently enabled.
+ */
+static int dma_dwc_channel_enabled(int ch)
+{
+ u32 dma_chan;
+
+ // Read the DMA channel register
+ dma_chan = in_le32(&(sata_dma_regs->dma_chan_en.low));
+ if (dma_chan & DMA_CHANNEL(ch))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Terminate the current DMA transaction
+ */
+static void dma_dwc_terminate_dma(struct ata_port *ap, int dma_ch)
+{
+ int enabled = dma_dwc_channel_enabled(dma_ch);
+
+ dev_info(ap->dev, "%s terminate DMA on channel=%d enabled=%d\n",
+ __func__, dma_ch, enabled);
+
+ if (enabled) {
+ // Disable the selected channel
+ out_le32(&(sata_dma_regs->dma_chan_en.low),
+ in_le32(&(sata_dma_regs->dma_chan_en.low)) | DMA_DISABLE_CHAN(dma_ch));
+
+ // Wait for the channel is disabled
+ do {
+ enabled = dma_dwc_channel_enabled(dma_ch);
+ msleep(10);
+ } while (enabled);
+ }
+}
+
+
+/*
+ * Setup data and DMA configuration ready for DMA transfer
+ */
+static int dma_dwc_xfer_setup(struct ata_queued_cmd *qc,
+ struct lli *lli, dma_addr_t dma_lli,
+ void __iomem *addr)
+{
+ int dma_ch;
+ int num_lli;
+
+ /* Acquire DMA channel */
+ dma_ch = dma_request_channel(qc->ap);
+ if (unlikely(dma_ch == -1)) {
+ dev_err(qc->ap->dev, "%s: dma channel unavailable\n", __func__);
+ return -EAGAIN;
+ }
+ dwc_port_vdbg(qc->ap, "%s: Got channel %d\n", __func__, dma_ch);
+
+ /* Convert SG list to linked list of items (LLIs) for AHB DMA */
+ num_lli = map_sg_to_lli(qc, lli, dma_lli, addr);
+
+ dwc_port_vdbg(qc->ap, "%s sg: 0x%p, count: %d lli: %p dma_lli: 0x%0xlx addr:"
+ " %p lli count: %d\n", __func__, qc->sg, qc->n_elem, lli,
+ (u32)dma_lli, addr, num_lli);
+
+ /* Clear channel interrupts */
+ clear_chan_interrupts(dma_ch);
+
+ /* Program the CFG register. */
+#if defined(CONFIG_APM821xx)
+ if (dma_ch == 0) {
+ /* Buffer mode enabled, FIFO_MODE=0 */
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.high), 0x0000009);
+ /* Channel 0 bit[7:5] */
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.low), 0x00000020);
+ } else if (dma_ch == 1) {
+ /* Buffer mode enabled, FIFO_MODE=0 */
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.high), 0x0000088d);
+ /* Channel 1 bit[7:5] */
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.low), 0x00000020);
+ }
+#else
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.high),
+ DMA_CFG_PROTCTL | DMA_CFG_FCMOD_REQ);
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.low), 0);
+#endif
+
+ /* Program the address of the linked list */
+#if defined(CONFIG_APM821xx)
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].llp.low),
+ DMA_LLP_LMS(dma_lli, DMA_LLP_AHBMASTER1));
+#else
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].llp.low),
+ DMA_LLP_LMS(dma_lli, DMA_LLP_AHBMASTER2));
+#endif
+
+ /* Program the CTL register with src enable / dst enable */
+ //out_le32(&(sata_dma_regs->chan_regs[dma_ch].ctl.low),
+ // DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN);
+ out_le32(&(sata_dma_regs->chan_regs[dma_ch].ctl.low), 0x18000000);
+
+ dwc_port_vdbg(qc->ap, "%s DMA channel %d is ready\n", __func__, dma_ch);
+ dwc_port_vdbg(qc->ap, "%s setting cfg.high of channel %d with val: 0x%08x\n", __func__, dma_ch, in_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.high)));
+ dwc_port_vdbg(qc->ap, "%s setting cfg.low of channel %d with val: 0x%08x\n", __func__, dma_ch, in_le32(&(sata_dma_regs->chan_regs[dma_ch].cfg.low)));
+ dwc_port_vdbg(qc->ap, "%s setting llp.low of channel %d with val: 0x%08x\n", __func__, dma_ch, in_le32(&(sata_dma_regs->chan_regs[dma_ch].llp.low)));
+ dwc_port_vdbg(qc->ap, "%s setting ctl.low of channel %d with val: 0x%08x\n", __func__, dma_ch, in_le32(&(sata_dma_regs->chan_regs[dma_ch].ctl.low)));
+
+ return dma_ch;
+}
+
+/*
+ * Function: dma_dwc_exit
+ * arguments: None
+ * returns status
+ * This function exits the SATA DMA driver
+ */
+static void dma_dwc_exit(struct sata_dwc_device *hsdev)
+{
+ dwc_dev_vdbg(hsdev->dev, "%s:\n", __func__);
+ if (sata_dma_regs)
+ iounmap(sata_dma_regs);
+
+ if (hsdev->irq_dma)
+ free_irq(hsdev->irq_dma, hsdev);
+}
+
+/*
+ * Function: dma_dwc_init
+ * arguments: hsdev
+ * returns status
+ * This function initializes the SATA DMA driver
+ */
+static int dma_dwc_init(struct sata_dwc_device *hsdev)
+{
+ int err;
+ int irq = hsdev->irq_dma;
+
+ err = dma_request_interrupts(hsdev, irq);
+ if (err) {
+ dev_err(hsdev->dev, "%s: dma_request_interrupts returns %d\n",
+ __func__, err);
+ goto error_out;
+ }
+
+ /* Enabe DMA */
+ out_le32(&(sata_dma_regs->dma_cfg.low), DMA_EN);
+
+ dev_notice(hsdev->dev, "DMA initialized\n");
+ dev_notice(hsdev->dev, "DMA CFG = 0x%08x\n", in_le32(&(sata_dma_regs->dma_cfg.low)));
+ dwc_dev_vdbg(hsdev->dev, "SATA DMA registers=0x%p\n", sata_dma_regs);
+
+ return 0;
+
+error_out:
+ dma_dwc_exit(hsdev);
+
+ return err;
+}
+
+
+static void sata_dwc_dev_config(struct ata_device *adev)
+{
+ /*
+ * Does not support NCQ over a port multiplier
+ * (no FIS-based switching).
+ */
+ if (adev->flags & ATA_DFLAG_NCQ) {
+ /*
+ * TODO: debug why enabling NCQ makes the linux crashed
+ * in hot plug after the first hot unplug action.
+ * --> need to investigate more
+ */
+ adev->flags &= ~ATA_DFLAG_NCQ;
+ if (sata_pmp_attached(adev->link->ap)) {
+ adev->flags &= ~ATA_DFLAG_NCQ;
+ ata_dev_printk(adev, KERN_INFO,
+ "NCQ disabled for command-based switching\n");
+ }
+ }
+
+ /*
+ * Since the sata_pmp_error_handler function in libata-pmp
+ * make FLAG_AN disabled in the first time SATA port is configured.
+ * Asynchronous notification is not configured.
+ * This will enable the AN feature manually.
+ */
+ adev->flags |= ATA_DFLAG_AN;
+}
+
+
+static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val)
+{
+ if (unlikely(scr > SCR_NOTIFICATION)) {
+ dev_err(link->ap->dev, "%s: Incorrect SCR offset 0x%02x\n",
+ __func__, scr);
+ return -EINVAL;
+ }
+
+ *val = in_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4));
+ dwc_dev_vdbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n",
+ __func__, link->ap->print_id, scr, *val);
+
+ return 0;
+}
+
+static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr, u32 val)
+{
+ dwc_dev_vdbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n",
+ __func__, link->ap->print_id, scr, val);
+ if (unlikely(scr > SCR_NOTIFICATION)) {
+ dev_err(link->ap->dev, "%s: Incorrect SCR offset 0x%02x\n",
+ __func__, scr);
+ return -EINVAL;
+ }
+ out_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4), val);
+
+ return 0;
+}
+
+static inline u32 sata_dwc_core_scr_read ( struct ata_port *ap, unsigned int scr)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ return in_le32((void __iomem *)hsdev->scr_base + (scr * 4));
+}
+
+
+static inline void sata_dwc_core_scr_write ( struct ata_port *ap, unsigned int scr, u32 val)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ out_le32((void __iomem *)hsdev->scr_base + (scr * 4), val);
+}
+
+static inline void clear_serror(struct ata_port *ap)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ out_le32( (void __iomem *)hsdev->scr_base + 4,
+ in_le32((void __iomem *)hsdev->scr_base + 4));
+}
+
+static inline void clear_intpr(struct sata_dwc_device *hsdev)
+{
+ out_le32(&hsdev->sata_dwc_regs->intpr,
+ in_le32(&hsdev->sata_dwc_regs->intpr));
+}
+
+static inline void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit)
+{
+ out_le32(&hsdev->sata_dwc_regs->intpr, bit);
+ // in_le32(&hsdev->sata_dwc_regs->intpr));
+}
+
+
+static inline void enable_err_irq(struct sata_dwc_device *hsdev)
+{
+ out_le32(&hsdev->sata_dwc_regs->intmr,
+ in_le32(&hsdev->sata_dwc_regs->intmr) | SATA_DWC_INTMR_ERRM);
+ out_le32(&hsdev->sata_dwc_regs->errmr, SATA_DWC_SERR_ERR_BITS);
+}
+
+static inline u32 qcmd_tag_to_mask(u8 tag)
+{
+ return 0x00000001 << (tag & 0x1f);
+}
+
+
+/*
+ * Timer to monitor SCR_NOTIFICATION registers on the
+ * SATA port
+ */
+static void sata_dwc_an_chk(unsigned long arg)
+{
+ struct ata_port *ap = (void *)arg;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ unsigned long flags;
+ int rc = 0x0;
+ u32 sntf = 0x0;
+
+ spin_lock_irqsave(ap->lock, flags);
+ rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+
+ // If some changes on the SCR4, call asynchronous notification
+ if ( (rc == 0) & (sntf != 0)) {
+ dwc_port_dbg(ap, "Call assynchronous notification sntf=0x%08x\n", sntf);
+ sata_async_notification(ap);
+ hsdev->an_timer.expires = jiffies + msecs_to_jiffies(8000);
+ } else {
+ hsdev->an_timer.expires = jiffies + msecs_to_jiffies(3000);
+ }
+ add_timer(&hsdev->an_timer);
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+
+/*
+ * sata_dwc_pmp_select - Set the PMP field in SControl to the specified port number.
+ *
+ * @port: The value (port number) to set the PMP field to.
+ *
+ * @return: The old value of the PMP field.
+ */
+static u32 sata_dwc_pmp_select(struct ata_port *ap, u32 port)
+{
+ u32 scontrol, old_port;
+ if (sata_pmp_supported(ap)) {
+ scontrol = sata_dwc_core_scr_read(ap, SCR_CONTROL);
+ old_port = SCONTROL_TO_PMP(scontrol);
+
+ // Select new PMP port
+ if ( port != old_port ) {
+ scontrol &= ~SCONTROL_PMP_MASK;
+ sata_dwc_core_scr_write(ap, SCR_CONTROL, scontrol | PMP_TO_SCONTROL(port));
+ dwc_port_dbg(ap, "%s: old port=%d new port=%d\n", __func__, old_port, port);
+ }
+ return old_port;
+ }
+ else
+ return port;
+}
+
+/*
+ * Get the current PMP port
+ */
+static inline u32 current_pmp(struct ata_port *ap)
+{
+ return SCONTROL_TO_PMP(sata_dwc_core_scr_read(ap, SCR_CONTROL));
+}
+
+
+/*
+ * Process when a PMP card is attached in the SATA port.
+ * Since our SATA port support command base switching only,
+ * NCQ will not be available.
+ * We disable the NCQ feature in SATA port.
+ */
+static void sata_dwc_pmp_attach ( struct ata_port *ap)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+
+ dev_info(ap->dev, "Attach SATA port multiplier with %d ports\n", ap->nr_pmp_links);
+ // Disable NCQ
+ ap->flags &= ~ATA_FLAG_NCQ;
+
+ // Initialize timer for checking AN
+ init_timer(&hsdev->an_timer);
+ hsdev->an_timer.expires = jiffies + msecs_to_jiffies(20000);
+ hsdev->an_timer.function = sata_dwc_an_chk;
+ hsdev->an_timer.data = (unsigned long)(ap);
+ add_timer(&hsdev->an_timer);
+}
+
+/*
+ * Process when PMP card is removed from the SATA port.
+ * Re-enable NCQ for using by the SATA drive in the future
+ */
+static void sata_dwc_pmp_detach ( struct ata_port *ap)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+
+ dev_info(ap->dev, "Detach SATA port\n");
+ // Re-enable NCQ
+ // TODO: remove the below comment out when NCQ problem fixed
+ //ap->flags |= ATA_FLAG_NCQ;
+
+ sata_dwc_pmp_select(ap, 0);
+
+ // Delete timer since PMP card is detached
+ del_timer(&hsdev->an_timer);
+}
+
+
+
+// Check the link to be ready
+int sata_dwc_check_ready ( struct ata_link *link ) {
+ u8 status;
+ struct ata_port *ap = link->ap;
+ status = ioread8(ap->ioaddr.status_addr);
+ return ata_check_ready(status);
+}
+
+
+/*
+ * Do soft reset on the current SATA link.
+ */
+static int sata_dwc_softreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
+{
+ int rc;
+ struct ata_port *ap = link->ap;
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ struct ata_taskfile tf;
+
+ sata_dwc_pmp_select(link->ap, sata_srst_pmp(link));
+
+ /* Issue bus reset */
+ iowrite8(ap->ctl, ioaddr->ctl_addr);
+ udelay(20); /* FIXME: flush */
+ iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+ udelay(20); /* FIXME: flush */
+ iowrite8(ap->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = ap->ctl;
+
+ /* Always check readiness of the master device */
+ rc = ata_wait_after_reset(link, deadline, sata_dwc_check_ready);
+
+ // Classify the ata_port
+ *classes = ATA_DEV_NONE;
+ /* Verify if SStatus indicates device presence */
+ if (ata_link_online(link)) {
+ memset(&tf, 0, sizeof(tf));
+ ata_sff_tf_read(ap, &tf);
+ *classes = ata_dev_classify(&tf);
+ }
+
+ if ( *classes == ATA_DEV_PMP)
+ dwc_link_dbg(link, "-->found PMP device by sig\n");
+
+ clear_serror(link->ap);
+
+ return rc;
+}
+
+
+
+
+/*
+ * sata_dwc_hardreset - Do hardreset the SATA controller
+ */
+static int sata_dwc_hardreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
+{
+ int rc;
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+ bool online;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(link->ap);
+
+ dwc_link_dbg(link, "%s\n", __func__);
+ sata_dwc_pmp_select(link->ap, sata_srst_pmp(link));
+ dwc_port_vdbg(link->ap, "dmacr=0x%08x\n",in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+
+ // Call standard hard reset
+ rc = sata_link_hardreset(link, timing, deadline, &online, NULL);
+
+ // Reconfigure the port after hard reset
+ if ( ata_link_online(link) )
+ sata_dwc_init_port(link->ap);
+
+ return online ? -EAGAIN : rc;
+}
+
+/*
+ * Do hard reset on each PMP link
+ */
+static int sata_dwc_pmp_hardreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
+{
+ int rc = 0;
+ sata_dwc_pmp_select(link->ap, sata_srst_pmp(link));
+ rc = sata_std_hardreset(link, classes, deadline);
+ return rc;
+}
+
+/* See ahci.c */
+/*
+ * Process error when the SATAn_INTPR's ERR bit is set
+ * The processing is based on SCR_ERROR register content
+ */
+static void sata_dwc_error_intr(struct ata_port *ap,
+ struct sata_dwc_device *hsdev, uint intpr)
+{
+ struct ata_eh_info *ehi;
+ struct ata_link *link;
+ struct ata_queued_cmd *active_qc = NULL;
+ u32 serror;
+ bool freeze = false, abort = false;
+ int pmp, ret;
+ unsigned int err_mask = 0, action = 0;
+#if defined(CONFIG_SATA_DWC_VDEBUG)
+ int dma_chan = hsdev->dma_channel;
+#endif
+
+ link = &ap->link;
+ ehi = &link->eh_info;
+
+ /* Record irq stat */
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "irq_stat 0x%08x", intpr);
+
+ // Record SERROR
+ serror = sata_dwc_core_scr_read(ap, SCR_ERROR);
+ dwc_port_dbg(ap, "%s serror = 0x%08x\n", __func__, serror);
+
+ // Clear SERROR and interrupt bit
+ clear_serror(ap);
+ clear_intpr(hsdev);
+
+ // Print out for test only
+ if ( serror ) {
+ dwc_port_info(ap, "Detect errors:");
+ if ( serror & SATA_DWC_SERR_ERRI )
+ printk(" ERRI");
+ if ( serror & SATA_DWC_SERR_ERRM )
+ printk(" ERRM");
+ if ( serror & SATA_DWC_SERR_ERRT )
+ printk(" ERRT");
+ if ( serror & SATA_DWC_SERR_ERRC )
+ printk(" ERRC");
+ if ( serror & SATA_DWC_SERR_ERRP )
+ printk(" ERRP");
+ if ( serror & SATA_DWC_SERR_ERRE )
+ printk(" ERRE");
+ if ( serror & SATA_DWC_SERR_DIAGN )
+ printk(" DIAGN");
+ if ( serror & SATA_DWC_SERR_DIAGI )
+ printk(" DIAGI");
+ if ( serror & SATA_DWC_SERR_DIAGW )
+ printk(" DIAGW");
+ if ( serror & SATA_DWC_SERR_DIAGB )
+ printk(" DIAGB");
+ if ( serror & SATA_DWC_SERR_DIAGT )
+ printk(" DIAGT");
+ if ( serror & SATA_DWC_SERR_DIAGC )
+ printk(" DIAGC");
+ if ( serror & SATA_DWC_SERR_DIAGH )
+ printk(" DIAGH");
+ if ( serror & SATA_DWC_SERR_DIAGL )
+ printk(" DIAGL");
+ if ( serror & SATA_DWC_SERR_DIAGS )
+ printk(" DIAGS");
+ if ( serror & SATA_DWC_SERR_DIAGF )
+ printk(" DIAGF");
+ if ( serror & SATA_DWC_SERR_DIAGX )
+ printk(" DIAGX");
+ if ( serror & SATA_DWC_SERR_DIAGA )
+ printk(" DIAGA");
+ printk("\n");
+ }
+
+#if defined(CONFIG_SATA_DWC_VDEBUG)
+ printk("%s reading cfg.high of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].cfg.high)));
+ printk("%s reading cfg.low of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].cfg.low)));
+ printk("%s reading llp.low of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].llp.low)));
+ printk("%s reading ctl.low of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].ctl.low)));
+ printk("%s reading sar.low of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].sar.low)));
+ printk("%s reading sar.high of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].sar.high)));
+ printk("%s reading dar.low of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].dar.low)));
+ printk("%s reading dar.high of channel %d with val: 0x%08x\n", __func__, dma_chan, in_le32(&(sata_dma_regs->chan_regs[dma_chan].dar.high)));
+#endif
+
+ // Process hotplug for SATA port
+ if ( serror & (SATA_DWC_SERR_DIAGX | SATA_DWC_SERR_DIAGW)) {
+ dwc_port_info(ap, "Detect hot plug signal\n");
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, serror & SATA_DWC_SERR_DIAGN ? "PHY RDY changed" : "device exchanged");
+ freeze = true;
+ }
+
+ // Process PHY internal error / Link sequence (illegal transition) error
+ if ( serror & (SATA_DWC_SERR_DIAGI | SATA_DWC_SERR_DIAGL)) {
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_RESET;
+ freeze = true;
+ }
+
+ // Process Internal host adapter error
+ if ( serror & SATA_DWC_SERR_ERRE ) {
+ dev_err(ap->dev, "Detect Internal host adapter error\n");
+ // --> need to review
+ ehi->err_mask |= AC_ERR_HOST_BUS;
+ ehi->action |= ATA_EH_RESET;
+ freeze = true;
+ }
+
+ // Process Protocol Error
+ if ( serror & SATA_DWC_SERR_ERRP ) {
+ dev_err(ap->dev, "Detect Protocol error\n");
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_RESET;
+ freeze = true;
+ }
+
+ // Process non-recovered persistent communication error
+ if ( serror & SATA_DWC_SERR_ERRC ) {
+ dev_err(ap->dev, "Detect non-recovered persistent communication error\n");
+ // --> TODO: review processing error
+ ehi->err_mask |= AC_ERR_ATA_BUS;
+ ehi->action |= ATA_EH_SOFTRESET;
+ //ehi->flags |= ATA_EHI_NO_AUTOPSY;
+ //freeze = true;
+ }
+
+ // Non-recovered transient data integrity error
+ if ( serror & SATA_DWC_SERR_ERRT ) {
+ dev_err(ap->dev, "Detect non-recovered transient data integrity error\n");
+ ehi->err_mask |= AC_ERR_ATA_BUS;
+ //ehi->err_mask |= AC_ERR_DEV;
+ ehi->action |= ATA_EH_SOFTRESET;
+ //ehi->flags |= ATA_EHI_NO_AUTOPSY;
+ }
+
+ // Since below errors have been recovered by hardware
+ // they don't need any error processing.
+ if ( serror & SATA_DWC_SERR_ERRM ) {
+ dev_warn(ap->dev, "Detect recovered communication error");
+ }
+ if ( serror & SATA_DWC_SERR_ERRI ) {
+ dev_warn(ap->dev, "Detect recovered data integrity error");
+ }
+
+ // If any error occur, process the qc
+ if (serror & (SATA_DWC_SERR_ERRT | SATA_DWC_SERR_ERRC)) {
+ //if (serror & 0x03f60f0) {
+ abort = true;
+ /* find out the offending link and qc */
+ if (sata_pmp_attached(ap)) {
+ pmp = current_pmp(ap);
+ // If we are working on the PMP port
+ if ( pmp < ap->nr_pmp_links ) {
+ link = &ap->pmp_link[pmp];
+ ehi = &link->eh_info;
+ active_qc = ata_qc_from_tag(ap, link->active_tag);
+ err_mask |= AC_ERR_DEV;
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+ } else {
+ err_mask |= AC_ERR_HSM;
+ action |= ATA_EH_RESET;
+ freeze = true;
+ }
+
+ }
+ // Work on SATA port
+ else {
+ freeze = true;
+ active_qc = ata_qc_from_tag(ap, link->active_tag);
+ }
+
+ if ( active_qc) {
+ active_qc->err_mask |= err_mask;
+ } else {
+ ehi->err_mask = err_mask;
+ }
+ }
+
+ if ( freeze | abort ) {
+ //sata_dwc_qc_complete(ap, active_qc, 1);
+ // Terminate DMA channel if it is currenly in use
+ if ( dma_request_channel(ap) != -1 ) {
+ dwc_port_dbg(ap, "Terminate DMA channel %d for handling error\n", hsdev->dma_channel);
+ dma_dwc_terminate_dma(ap, hsdev->dma_channel);
+ }
+ }
+
+ if (freeze) {
+ ret = ata_port_freeze(ap);
+ ata_port_printk(ap, KERN_INFO, "Freeze port with %d QCs aborted\n", ret);
+ }
+ else if (abort) {
+ if (active_qc) {
+ ret = ata_link_abort(active_qc->dev->link);
+ ata_link_printk(link, KERN_INFO, "Abort %d QCs\n", ret);
+ } else {
+ ret = ata_port_abort(ap);
+ ata_port_printk(ap, KERN_INFO, "Abort %d QCs on the SATA port\n", ret);
+ }
+ }
+}
+
+
+/*
+ * Function : sata_dwc_isr
+ * arguments : irq, void *dev_instance, struct pt_regs *regs
+ * Return value : irqreturn_t - status of IRQ
+ * This Interrupt handler called via port ops registered function.
+ * .irq_handler = sata_dwc_isr
+ */
+static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
+{
+ struct ata_host *host = (struct ata_host *)dev_instance;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_HOST(host);
+ struct ata_port *ap;
+ struct ata_queued_cmd *qc;
+ unsigned long flags;
+ u8 status, tag;
+ int handled, num_processed, port = 0;
+ u32 intpr, sactive, sactive2, tag_mask;
+ struct sata_dwc_device_port *hsdevp;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* Read the interrupt register */
+ intpr = in_le32(&hsdev->sata_dwc_regs->intpr);
+
+ ap = host->ports[port];
+ hsdevp = HSDEVP_FROM_AP(ap);
+
+ dwc_port_dbg(ap,"%s\n",__func__);
+ if ( intpr != 0x80000080)
+ dwc_port_dbg(ap, "%s intpr=0x%08x active_tag=%d\n", __func__, intpr, ap->link.active_tag);
+ //dwc_port_dbg(ap, "%s: INTMR=0x%08x, ERRMR=0x%08x\n", __func__, in_le32(&hsdev->sata_dwc_regs->intmr), in_le32(&hsdev->sata_dwc_regs->errmr));
+
+ /* Check for error interrupt */
+ if (intpr & SATA_DWC_INTPR_ERR) {
+ sata_dwc_error_intr(ap, hsdev, intpr);
+ handled = 1;
+#if defined(CONFIG_APOLLO3G)
+ signal_hdd_led(0 /*off blink*/, 1 /*red color*/);
+#endif
+ goto done_irqrestore;
+ }
+
+ /* Check for DMA SETUP FIS (FP DMA) interrupt */
+ if (intpr & SATA_DWC_INTPR_NEWFP) {
+ dwc_port_dbg(ap, "%s: NEWFP INTERRUPT in HSDEV with DMA channel %d\n", __func__, hsdev->dma_channel);
+ clear_interrupt_bit(hsdev, SATA_DWC_INTPR_NEWFP);
+
+ tag = (u8)(in_le32(&hsdev->sata_dwc_regs->fptagr));
+ dwc_dev_dbg(ap->dev, "%s: NEWFP tag=%d\n", __func__, tag);
+ if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_PENDING)
+ dev_warn(ap->dev, "CMD tag=%d not pending?\n", tag);
+
+ hsdevp->sata_dwc_sactive_issued |= qcmd_tag_to_mask(tag);
+
+ qc = ata_qc_from_tag(ap, tag);
+ /*
+ * Start FP DMA for NCQ command. At this point the tag is the
+ * active tag. It is the tag that matches the command about to
+ * be completed.
+ */
+ qc->ap->link.active_tag = tag;
+ sata_dwc_bmdma_start_by_tag(qc, tag);
+ qc->ap->hsm_task_state = HSM_ST_LAST;
+
+ handled = 1;
+ goto done_irqrestore;
+ }
+
+ sactive = sata_dwc_core_scr_read(ap, SCR_ACTIVE);
+ tag_mask = (hsdevp->sata_dwc_sactive_issued | sactive) ^ sactive;
+
+ /* If no sactive issued and tag_mask is zero then this is not NCQ */
+ if (hsdevp->sata_dwc_sactive_issued == 0 && tag_mask == 0) {
+ if (ap->link.active_tag == ATA_TAG_POISON)
+ tag = 0;
+ else
+ tag = ap->link.active_tag;
+ qc = ata_qc_from_tag(ap, tag);
+
+ /* DEV interrupt w/ no active qc? */
+ if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
+ dev_err(ap->dev, "%s intr with no active qc qc=%p\n",
+ __func__, qc);
+ ap->ops->sff_check_status(ap);
+ handled = 1;
+ goto done_irqrestore;
+ }
+
+ status = ap->ops->sff_check_status(ap);
+
+ qc->ap->link.active_tag = tag;
+ hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT;
+
+ if (status & ATA_ERR) {
+ dwc_dev_dbg(ap->dev, "interrupt ATA_ERR (0x%x)\n", status);
+ sata_dwc_qc_complete(ap, qc, 1);
+ handled = 1;
+ goto done_irqrestore;
+ }
+
+ dwc_dev_dbg(ap->dev, "%s non-NCQ cmd interrupt, protocol: %s\n",
+ __func__, prot_2_txt(qc->tf.protocol));
+drv_still_busy:
+ if (ata_is_dma(qc->tf.protocol)) {
+ int dma_flag = hsdevp->dma_pending[tag];
+ /*
+ * Each DMA transaction produces 2 interrupts. The DMAC
+ * transfer complete interrupt and the SATA controller
+ * operation done interrupt. The command should be
+ * completed only after both interrupts are seen.
+ */
+ hsdevp->dma_interrupt_count++;
+ if (unlikely(dma_flag == SATA_DWC_DMA_PENDING_NONE)) {
+ dev_err(ap->dev, "%s: DMA not pending "
+ "intpr=0x%08x status=0x%08x pend=%d\n",
+ __func__, intpr, status, dma_flag);
+ }
+
+ if ((hsdevp->dma_interrupt_count % 2) == 0)
+ sata_dwc_dma_xfer_complete(ap, 1);
+ } else if (ata_is_pio(qc->tf.protocol)) {
+ ata_sff_hsm_move(ap, qc, status, 0);
+ handled = 1;
+ goto done_irqrestore;
+ } else {
+ if (unlikely(sata_dwc_qc_complete(ap, qc, 1)))
+ goto drv_still_busy;
+ }
+
+ handled = 1;
+ goto done_irqrestore;
+ }
+
+ /*
+ * This is a NCQ command. At this point we need to figure out for which
+ * tags we have gotten a completion interrupt. One interrupt may serve
+ * as completion for more than one operation when commands are queued
+ * (NCQ). We need to process each completed command.
+ */
+
+process_cmd: /* process completed commands */
+ sactive = sata_dwc_core_scr_read(ap, SCR_ACTIVE);
+ tag_mask = (hsdevp->sata_dwc_sactive_issued | sactive) ^ sactive;
+
+ if (sactive != 0 || hsdevp->sata_dwc_sactive_issued > 1 || tag_mask > 1) {
+ dwc_dev_dbg(ap->dev, "%s NCQ: sactive=0x%08x sactive_issued=0x%08x"
+ " tag_mask=0x%08x\n", __func__, sactive,
+ hsdevp->sata_dwc_sactive_issued, tag_mask);
+ }
+
+ if (unlikely((tag_mask | hsdevp->sata_dwc_sactive_issued) != hsdevp->sata_dwc_sactive_issued)) {
+ dev_warn(ap->dev, "Bad tag mask? sactive=0x%08x "
+ "sata_dwc_sactive_issued=0x%08x tag_mask=0x%08x\n",
+ sactive, hsdevp->sata_dwc_sactive_issued, tag_mask);
+ }
+
+ /* read just to clear ... not bad if currently still busy */
+ status = ap->ops->sff_check_status(ap);
+ dwc_dev_dbg(ap->dev, "%s ATA status register=0x%x, tag_mask=0x%x\n", __func__, status, tag_mask);
+
+ tag = 0;
+ num_processed = 0;
+ while (tag_mask) {
+ num_processed++;
+ while (!(tag_mask & 0x00000001)) {
+ tag++;
+ tag_mask <<= 1;
+ }
+ tag_mask &= (~0x00000001);
+ qc = ata_qc_from_tag(ap, tag);
+
+ /* To be picked up by completion functions */
+ qc->ap->link.active_tag = tag;
+ hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT;
+
+ /* Let libata/scsi layers handle error */
+ if (unlikely(status & ATA_ERR)) {
+ dwc_dev_vdbg(ap->dev, "%s ATA_ERR (0x%x)\n",
+ __func__, status);
+
+ sata_dwc_qc_complete(ap, qc, 1);
+ handled = 1;
+ goto done_irqrestore;
+ }
+
+ /* Process completed command */
+ dwc_dev_dbg(ap->dev, "%s NCQ command, protocol: %s\n", __func__,
+ prot_2_txt(qc->tf.protocol));
+ if (ata_is_dma(qc->tf.protocol)) {
+ hsdevp->dma_interrupt_count++;
+ if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_NONE)
+ dev_warn(ap->dev,
+ "%s: DMA not pending?\n", __func__);
+ if ((hsdevp->dma_interrupt_count % 2) == 0)
+ sata_dwc_dma_xfer_complete(ap, 1);
+ } else {
+ if (unlikely(sata_dwc_qc_complete(ap, qc, 1)))
+ goto still_busy;
+ }
+ continue;
+
+still_busy:
+ ap->stats.idle_irq++;
+ dev_warn(ap->dev, "STILL BUSY IRQ ata%d: irq trap\n",
+ ap->print_id);
+ } /* while tag_mask */
+
+ /*
+ * Check to see if any commands completed while we were processing our
+ * initial set of completed commands (reading of status clears
+ * interrupts, so we might miss a completed command interrupt if one
+ * came in while we were processing:
+ * we read status as part of processing a completed command).
+ */
+ sactive2 = sata_dwc_core_scr_read(ap, SCR_ACTIVE);
+ if (sactive2 != sactive) {
+ dwc_dev_dbg(ap->dev, "More finished - sactive=0x%x sactive2=0x%x\n",
+ sactive, sactive2);
+ goto process_cmd;
+ }
+ handled = 1;
+
+done_irqrestore:
+ spin_unlock_irqrestore(&host->lock, flags);
+#if defined(CONFIG_APOLLO3G)
+ signal_hdd_led(0 /*off blink*/, -1 /* no color */);
+#endif
+ return IRQ_RETVAL(handled);
+}
+
+
+/*
+ * Clear DMA Control Register after completing transferring data
+ * using AHB DMA.
+ */
+static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_HSDEVP(hsdevp);
+
+ if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX) {
+ // Clear receive channel enable bit
+ out_le32(&(hsdev->sata_dwc_regs->dmacr),
+ SATA_DWC_DMACR_RX_CLEAR(
+ in_le32(&(hsdev->sata_dwc_regs->dmacr))));
+ } else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX) {
+ // Clear transmit channel enable bit
+ out_le32(&(hsdev->sata_dwc_regs->dmacr),
+ SATA_DWC_DMACR_TX_CLEAR(
+ in_le32(&(hsdev->sata_dwc_regs->dmacr))));
+ } else {
+ /*
+ * This should not happen, it indicates the driver is out of
+ * sync. If it does happen, clear dmacr anyway.
+ */
+ dev_err(hsdev->dev, "%s DMA protocol RX and TX DMA not pending "
+ "tag=0x%02x pending=%d dmacr: 0x%08x\n",
+ __func__, tag, hsdevp->dma_pending[tag],
+ in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+
+ // Clear all transmit and receive bit, but TXMOD bit is set to 1
+ out_le32(&(hsdev->sata_dwc_regs->dmacr),
+ SATA_DWC_DMACR_TXRXCH_CLEAR);
+ }
+}
+
+/*
+ *
+ */
+static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status)
+{
+ struct ata_queued_cmd *qc;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ u8 tag = 0;
+
+ tag = ap->link.active_tag;
+ qc = ata_qc_from_tag(ap, tag);
+
+#ifdef DEBUG_NCQ
+ if (tag > 0) {
+ dev_info(ap->dev, "%s tag=%u cmd=0x%02x dma dir=%s proto=%s "
+ "dmacr=0x%08x\n", __func__, qc->tag, qc->tf.command,
+ dir_2_txt(qc->dma_dir), prot_2_txt(qc->tf.protocol),
+ in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+ }
+#endif
+
+ if (ata_is_dma(qc->tf.protocol)) {
+ // DMA out of sync error
+ if (unlikely(hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_NONE)) {
+ dev_err(ap->dev, "%s DMA protocol RX and TX DMA not "
+ "pending dmacr: 0x%08x\n", __func__,
+ in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+ }
+
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_NONE;
+ sata_dwc_qc_complete(ap, qc, check_status);
+ ap->link.active_tag = ATA_TAG_POISON;
+ } else {
+ sata_dwc_qc_complete(ap, qc, check_status);
+ }
+}
+
+/*
+ *
+ */
+static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u32 check_status)
+{
+ u8 status = 0;
+ int i = 0;
+ u32 mask = 0x0;
+ u8 tag = qc->tag;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ u32 serror;
+ int dma_ch;
+
+ dwc_dev_vdbg(ap->dev, "%s checkstatus? %x\n", __func__, check_status);
+
+ if (unlikely(hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX))
+ dev_err(ap->dev, "TX DMA PENDINGING\n");
+ else if (unlikely(hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX))
+ dev_err(ap->dev, "RX DMA PENDINGING\n");
+
+ if (check_status) {
+ i = 0;
+ do {
+ /* check main status, clearing INTRQ */
+ status = ap->ops->sff_check_status(ap);
+ if (status & ATA_BUSY) {
+ dwc_dev_vdbg(ap->dev, "STATUS BUSY (0x%02x) [%d]\n",
+ status, i);
+ }
+ if (++i > 10)
+ break;
+ } while (status & ATA_BUSY);
+
+ status = ap->ops->sff_check_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ dev_err(ap->dev, "QC complete cmd=0x%02x STATUS BUSY "
+ "(0x%02x) [%d]\n", qc->tf.command, status, i);
+
+
+ // Check error ==> need to process error here
+ serror = sata_dwc_core_scr_read(ap, SCR_ERROR);
+ if (unlikely(serror & SATA_DWC_SERR_ERR_BITS))
+ {
+ dev_err(ap->dev, "****** SERROR=0x%08x ******\n", serror);
+ ap->link.eh_context.i.action |= ATA_EH_RESET;
+ if (ata_is_dma(qc->tf.protocol)) {
+ dma_ch = hsdevp->dma_chan[tag];
+ dma_dwc_terminate_dma(ap, dma_ch);
+ } else {
+ dma_ch = hsdevp->dma_chan[0];
+ dma_dwc_terminate_dma(ap, dma_ch);
+ }
+ }
+ }
+ dwc_dev_vdbg(ap->dev, "QC complete cmd=0x%02x status=0x%02x ata%u: "
+ "protocol=%d\n", qc->tf.command, status, ap->print_id,
+ qc->tf.protocol);
+
+ /* clear active bit */
+ mask = (~(qcmd_tag_to_mask(tag)));
+ hsdevp->sata_dwc_sactive_queued = hsdevp->sata_dwc_sactive_queued & mask;
+ hsdevp->sata_dwc_sactive_issued = hsdevp->sata_dwc_sactive_issued & mask;
+ dwc_port_vdbg(ap, "%s - sata_dwc_sactive_queued=0x%08x, sata_dwc_sactive_issued=0x%08x\n",__func__, hsdevp->sata_dwc_sactive_queued, hsdevp->sata_dwc_sactive_issued);
+ dwc_port_vdbg(ap, "dmacr=0x%08x\n",in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+
+ /* Complete taskfile transaction (does not read SCR registers) */
+ ata_qc_complete(qc);
+
+ return 0;
+}
+
+/*
+ * Clear interrupt and error flags in DMA status register.
+ */
+void sata_dwc_irq_clear (struct ata_port *ap)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ dwc_port_dbg(ap,"%s\n",__func__);
+
+ // Clear DMA interrupts
+ clear_chan_interrupts(hsdev->dma_channel);
+ //sata_dma_regs
+ //out_le32(&hsdev->sata_dwc_regs->intmr,
+ // in_le32(&hsdev->sata_dwc_regs->intmr) & ~SATA_DWC_INTMR_ERRM);
+ //out_le32(&hsdev->sata_dwc_regs->errmr, 0x0);
+ //sata_dwc_check_status(ap);
+}
+
+/*
+ * Turn on IRQ
+ */
+void sata_dwc_irq_on(struct ata_port *ap)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ u8 tmp;
+
+ dwc_port_dbg(ap,"%s\n",__func__);
+ ap->ctl &= ~ATA_NIEN;
+ ap->last_ctl = ap->ctl;
+
+ if (ioaddr->ctl_addr)
+ iowrite8(ap->ctl, ioaddr->ctl_addr);
+ tmp = ata_wait_idle(ap);
+
+ ap->ops->sff_irq_clear(ap);
+ enable_err_irq(hsdev);
+}
+
+
+/*
+ * This function enables the interrupts in IMR and unmasks them in ERRMR
+ *
+ */
+static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev)
+{
+ // Enable interrupts
+ out_le32(&hsdev->sata_dwc_regs->intmr,
+ SATA_DWC_INTMR_ERRM |
+ SATA_DWC_INTMR_NEWFPM |
+ SATA_DWC_INTMR_PMABRTM |
+ SATA_DWC_INTMR_DMATM);
+
+ /*
+ * Unmask the error bits that should trigger an error interrupt by
+ * setting the error mask register.
+ */
+ out_le32(&hsdev->sata_dwc_regs->errmr, SATA_DWC_SERR_ERR_BITS);
+
+ dwc_dev_dbg(hsdev->dev, "%s: INTMR = 0x%08x, ERRMR = 0x%08x\n", __func__,
+ in_le32(&hsdev->sata_dwc_regs->intmr),
+ in_le32(&hsdev->sata_dwc_regs->errmr));
+}
+
+/*
+ * Configure DMA and interrupts on SATA port. This should be called after
+ * hardreset is executed on the SATA port.
+ */
+static void sata_dwc_init_port ( struct ata_port *ap ) {
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+
+ // Configure DMA
+ if (ap->port_no == 0) {
+ dwc_dev_dbg(ap->dev, "%s: clearing TXCHEN, RXCHEN in DMAC\n",
+ __func__);
+
+ // Clear all transmit/receive bits
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_TXRXCH_CLEAR);
+
+ dwc_dev_dbg(ap->dev, "%s: setting burst size in DBTSR\n", __func__);
+ out_le32(&hsdev->sata_dwc_regs->dbtsr,
+ (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) |
+ SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT)));
+ }
+
+ // Enable interrupts
+ sata_dwc_enable_interrupts(hsdev);
+}
+
+
+/*
+ * Setup SATA ioport with corresponding register addresses
+ */
+static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base)
+{
+ port->cmd_addr = (void *)base + 0x00;
+ port->data_addr = (void *)base + 0x00;
+
+ port->error_addr = (void *)base + 0x04;
+ port->feature_addr = (void *)base + 0x04;
+
+ port->nsect_addr = (void *)base + 0x08;
+
+ port->lbal_addr = (void *)base + 0x0c;
+ port->lbam_addr = (void *)base + 0x10;
+ port->lbah_addr = (void *)base + 0x14;
+
+ port->device_addr = (void *)base + 0x18;
+ port->command_addr = (void *)base + 0x1c;
+ port->status_addr = (void *)base + 0x1c;
+
+ port->altstatus_addr = (void *)base + 0x20;
+ port->ctl_addr = (void *)base + 0x20;
+}
+
+
+/*
+ * Function : sata_dwc_port_start
+ * arguments : struct ata_ioports *port
+ * Return value : returns 0 if success, error code otherwise
+ * This function allocates the scatter gather LLI table for AHB DMA
+ */
+static int sata_dwc_port_start(struct ata_port *ap)
+{
+ int err = 0;
+ struct sata_dwc_device *hsdev;
+ struct sata_dwc_device_port *hsdevp = NULL;
+ struct device *pdev;
+ u32 sstatus;
+ int i;
+
+ hsdev = HSDEV_FROM_AP(ap);
+
+ dwc_dev_dbg(ap->dev, "%s: port_no=%d\n", __func__, ap->port_no);
+
+ hsdev->host = ap->host;
+ pdev = ap->host->dev;
+ if (!pdev) {
+ dev_err(ap->dev, "%s: no ap->host->dev\n", __func__);
+ err = -ENODEV;
+ goto cleanup_exit;
+ }
+
+ /* Allocate Port Struct */
+ hsdevp = kzalloc(sizeof(*hsdevp), GFP_KERNEL);
+ if (!hsdevp) {
+ dev_err(ap->dev, "%s: kmalloc failed for hsdevp\n", __func__);
+ err = -ENOMEM;
+ goto cleanup_exit;
+ }
+ hsdevp->hsdev = hsdev;
+
+ for (i = 0; i < SATA_DWC_QCMD_MAX; i++)
+ hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT;
+
+ ap->bmdma_prd = 0; /* set these so libata doesn't use them */
+ ap->bmdma_prd_dma = 0;
+
+ /*
+ * DMA - Assign scatter gather LLI table. We can't use the libata
+ * version since it's PRD is IDE PCI specific.
+ */
+ for (i = 0; i < SATA_DWC_QCMD_MAX; i++) {
+ hsdevp->llit[i] = dma_alloc_coherent(pdev,
+ SATA_DWC_DMAC_LLI_TBL_SZ,
+ &(hsdevp->llit_dma[i]),
+ GFP_ATOMIC);
+ if (!hsdevp->llit[i]) {
+ dev_err(ap->dev, "%s: dma_alloc_coherent failed size "
+ "0x%x\n", __func__, SATA_DWC_DMAC_LLI_TBL_SZ);
+ err = -ENOMEM;
+ goto cleanup_exit;
+ }
+ }
+
+ if (ap->port_no == 0) {
+ dwc_dev_vdbg(ap->dev, "%s: clearing TXCHEN, RXCHEN in DMAC\n",
+ __func__);
+
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_TXRXCH_CLEAR);
+
+ dwc_dev_vdbg(ap->dev, "%s: setting burst size in DBTSR\n", __func__);
+ out_le32(&hsdev->sata_dwc_regs->dbtsr,
+ (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) |
+ SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT)));
+ ata_port_printk(ap, KERN_INFO, "%s: setting burst size in DBTSR: 0x%08x\n",
+ __func__, in_le32(&hsdev->sata_dwc_regs->dbtsr));
+ }
+
+ /* Clear any error bits before libata starts issuing commands */
+ clear_serror(ap);
+
+ ap->private_data = hsdevp;
+
+ /* Are we in Gen I or II */
+ sstatus = sata_dwc_core_scr_read(ap, SCR_STATUS);
+ switch (SATA_DWC_SCR0_SPD_GET(sstatus)) {
+ case 0x0:
+ dev_info(ap->dev, "**** No neg speed (nothing attached?) \n");
+ break;
+ case 0x1:
+ dev_info(ap->dev, "**** GEN I speed rate negotiated \n");
+ break;
+ case 0x2:
+ dev_info(ap->dev, "**** GEN II speed rate negotiated \n");
+ break;
+ }
+
+cleanup_exit:
+ if (err) {
+ kfree(hsdevp);
+ sata_dwc_port_stop(ap);
+ dwc_dev_vdbg(ap->dev, "%s: fail\n", __func__);
+ } else {
+ dwc_dev_vdbg(ap->dev, "%s: done\n", __func__);
+ }
+
+ return err;
+}
+
+
+static void sata_dwc_port_stop(struct ata_port *ap)
+{
+ int i;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+
+ dwc_port_dbg(ap, "%s: stop port\n", __func__);
+
+ if (hsdevp && hsdev) {
+ /* deallocate LLI table */
+ for (i = 0; i < SATA_DWC_QCMD_MAX; i++) {
+ dma_free_coherent(ap->host->dev,
+ SATA_DWC_DMAC_LLI_TBL_SZ,
+ hsdevp->llit[i], hsdevp->llit_dma[i]);
+ }
+
+ kfree(hsdevp);
+ }
+ ap->private_data = NULL;
+}
+
+/*
+ * Since the SATA DWC is master only. The dev select operation will
+ * be removed.
+ */
+void sata_dwc_dev_select(struct ata_port *ap, unsigned int device)
+{
+ // Do nothing
+ ndelay(100);
+}
+
+/*
+ * Function : sata_dwc_exec_command_by_tag
+ * arguments : ata_port *ap, ata_taskfile *tf, u8 tag, u32 cmd_issued
+ * Return value : None
+ * This function keeps track of individual command tag ids and calls
+ * ata_exec_command in libata
+ */
+static void sata_dwc_exec_command_by_tag(struct ata_port *ap,
+ struct ata_taskfile *tf,
+ u8 tag, u32 cmd_issued)
+{
+ unsigned long flags;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+
+ dwc_dev_dbg(ap->dev, "%s cmd(0x%02x): %s tag=%d, ap->link->tag=0x%08x\n", __func__, tf->command,
+ ata_cmd_2_txt(tf), tag, ap->link.active_tag);
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ hsdevp->cmd_issued[tag] = cmd_issued;
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+
+ /*
+ * Clear SError before executing a new command.
+ *
+ * TODO if we read a PM's registers now, we will throw away the task
+ * file values loaded into the shadow registers for this command.
+ *
+ * sata_dwc_scr_write and read can not be used here. Clearing the PM
+ * managed SError register for the disk needs to be done before the
+ * task file is loaded.
+ */
+ clear_serror(ap);
+ ata_sff_exec_command(ap, tf);
+}
+
+static void sata_dwc_bmdma_setup_by_tag(struct ata_queued_cmd *qc, u8 tag)
+{
+ sata_dwc_exec_command_by_tag(qc->ap, &qc->tf, tag,
+ SATA_DWC_CMD_ISSUED_PENDING);
+}
+
+static void sata_dwc_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ u8 tag = qc->tag;
+
+ dwc_port_dbg(qc->ap, "%s\n", __func__);
+ if (ata_is_ncq(qc->tf.protocol)) {
+ dwc_dev_vdbg(qc->ap->dev, "%s: ap->link.sactive=0x%08x tag=%d\n",
+ __func__, qc->ap->link.sactive, tag);
+ } else {
+ tag = 0;
+ }
+
+ sata_dwc_bmdma_setup_by_tag(qc, tag);
+}
+
+static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag)
+{
+ volatile int start_dma;
+ u32 reg, dma_chan;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_QC(qc);
+ struct ata_port *ap = qc->ap;
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ int dir = qc->dma_dir;
+ dma_chan = hsdevp->dma_chan[tag];
+
+ /* Used for ata_bmdma_start(qc) -- we are not BMDMA compatible */
+
+ if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_NOT) {
+ start_dma = 1;
+ if (dir == DMA_TO_DEVICE)
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_TX;
+ else
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_RX;
+ } else {
+ dev_err(ap->dev, "%s: Command not pending cmd_issued=%d "
+ "(tag=%d) - DMA NOT started\n", __func__,
+ hsdevp->cmd_issued[tag], tag);
+ start_dma = 0;
+ }
+
+ dwc_dev_dbg(ap->dev, "%s qc=%p tag: %x cmd: 0x%02x dma_dir: %s "
+ "start_dma? %x\n", __func__, qc, tag, qc->tf.command,
+ dir_2_txt(qc->dma_dir), start_dma);
+ sata_dwc_tf_dump(hsdev->dev, &(qc->tf));
+
+ // Start DMA transfer
+ if (start_dma) {
+ reg = sata_dwc_core_scr_read(ap, SCR_ERROR);
+ if (unlikely(reg & SATA_DWC_SERR_ERR_BITS)) {
+ dev_err(ap->dev, "%s: ****** SError=0x%08x ******\n",
+ __func__, reg);
+ //sata_async_notification(ap);
+ //return;
+ }
+
+ // Set DMA control registers
+ if (dir == DMA_TO_DEVICE)
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_TXCHEN);
+ else
+ out_le32(&hsdev->sata_dwc_regs->dmacr,
+ SATA_DWC_DMACR_RXCHEN);
+
+ dwc_dev_vdbg(ap->dev, "%s: setting DMACR: 0x%08x\n", __func__, in_le32(&hsdev->sata_dwc_regs->dmacr));
+ /* Enable AHB DMA transfer on the specified channel */
+ dma_dwc_xfer_start(dma_chan);
+ }
+}
+
+
+static void sata_dwc_bmdma_start(struct ata_queued_cmd *qc)
+{
+ u8 tag = qc->tag;
+
+ if (ata_is_ncq(qc->tf.protocol)) {
+ dwc_dev_vdbg(qc->ap->dev, "%s: ap->link.sactive=0x%08x tag=%d\n",
+ __func__, qc->ap->link.sactive, tag);
+ } else {
+ tag = 0;
+ }
+
+ dwc_port_dbg(qc->ap, "%s, tag=0x%08x\n", __func__, tag);
+ sata_dwc_bmdma_start_by_tag(qc, tag);
+}
+
+/*
+ * Function : sata_dwc_qc_prep_by_tag
+ * arguments : ata_queued_cmd *qc, u8 tag
+ * Return value : None
+ * qc_prep for a particular queued command based on tag
+ */
+static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag)
+{
+ struct ata_port *ap = qc->ap;
+ int dma_chan;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ int dir;
+
+ // DMA direction
+ dir = qc->dma_dir;
+
+ if ((dir == DMA_NONE) || (qc->tf.protocol == ATA_PROT_PIO))
+ return;
+
+ dwc_dev_vdbg(ap->dev, "%s: port=%d dma dir=%s n_elem=%d\n",
+ __func__, ap->port_no, dir_2_txt(dir), qc->n_elem);
+
+ // Setup DMA for transfer
+ dma_chan = dma_dwc_xfer_setup(qc, hsdevp->llit[tag],
+ hsdevp->llit_dma[tag],
+ (void *__iomem)(&hsdev->sata_dwc_regs->dmadr));
+
+ if (unlikely(dma_chan < 0)) {
+ dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns err %d\n",
+ __func__, dma_chan);
+ return;
+ }
+
+ hsdevp->dma_chan[tag] = dma_chan;
+}
+
+
+
+/**
+ * ata_sff_exec_command - issue ATA command to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Issues ATA command, with proper synchronization with interrupt
+ * handler / other threads.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void sata_dwc_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ iowrite8(tf->command, ap->ioaddr.command_addr);
+ /* If we have an mmio device with no ctl and no altstatus
+ * method this will fail. No such devices are known to exist.
+ */
+ if (ap->ioaddr.altstatus_addr)
+ ioread8(ap->ioaddr.altstatus_addr);
+ ndelay(400);
+}
+
+/**
+ * sata_dwc_tf_to_host - issue ATA taskfile to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Issues ATA taskfile register set to ATA host controller,
+ * with proper synchronization with interrupt handler and
+ * other threads.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+static inline void sata_dwc_tf_to_host(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ dwc_port_dbg(ap,"%s\n",__func__);
+ ap->ops->sff_tf_load(ap, tf);
+ sata_dwc_exec_command(ap, tf);
+}
+
+
+/*
+ * Process command queue issue
+ */
+static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ int ret = 0;
+ struct ata_eh_info *ehi;
+ u32 scontrol, sstatus;
+ scontrol = sata_dwc_core_scr_read(ap, SCR_CONTROL);
+
+ ehi = &ap->link.eh_info;
+ /*
+ * Fix the problem when PMP card is unplugged from the SATA port.
+ * QC is still issued but no device present. Ignore the current QC.
+ * and pass error to error handler
+ */
+ sstatus = sata_dwc_core_scr_read(ap, SCR_STATUS);
+ if ( sstatus == 0x0) {
+ ata_port_printk(ap, KERN_INFO, "Detect connection lost while commands are executing --> ignore current command\n");
+ ata_ehi_hotplugged(ehi);
+ ap->link.eh_context.i.action |= ATA_EH_RESET;
+ return ret;
+ }
+
+ // Set PMP field in the SCONTROL register
+ if ( sata_pmp_attached(ap) )
+ sata_dwc_pmp_select(ap, qc->dev->link->pmp);
+
+#ifdef DEBUG_NCQ
+ if (qc->tag > 0 || ap->link.sactive > 1) {
+ dev_info(ap->dev, "%s ap id=%d cmd(0x%02x)=%s qc tag=%d prot=%s"
+ " ap active_tag=0x%08x ap sactive=0x%08x\n",
+ __func__, ap->print_id, qc->tf.command,
+ ata_cmd_2_txt(&qc->tf), qc->tag,
+ prot_2_txt(qc->tf.protocol), ap->link.active_tag,
+ ap->link.sactive);
+ }
+#endif
+
+ // Process NCQ
+ if (ata_is_ncq(qc->tf.protocol)) {
+ dwc_link_dbg(qc->dev->link, "%s --> process NCQ , ap->link.active_tag=0x%08x, active_tag=0%08x\n", __func__, ap->link.active_tag, qc->tag);
+ ap->link.active_tag = qc->tag;
+ ap->ops->sff_tf_load(ap, &qc->tf);
+ sata_dwc_exec_command_by_tag(ap, &qc->tf, qc->tag,
+ SATA_DWC_CMD_ISSUED_PENDING);
+ } else {
+ dwc_link_dbg(qc->dev->link, "%s --> non NCQ process, ap->link.active_tag=%d, active_tag=0%08x\n", __func__, ap->link.active_tag, qc->tag);
+ // Sync ata_port with qc->tag
+ ap->link.active_tag = qc->tag;
+ ret = ata_bmdma_qc_issue(qc);
+ }
+
+ return ret;
+}
+
+#if 0
+/*
+ * Function : sata_dwc_eng_timeout
+ * arguments : ata_port *ap
+ * Return value : None
+ * error handler for DMA time out
+ * ata_eng_timeout(ap) -- this does bmdma stuff which can not be done by this
+ * driver. SEE ALSO ata_qc_timeout(ap)
+ */
+static void sata_dwc_eng_timeout(struct ata_port *ap)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+ struct ata_queued_cmd *qc;
+ u8 tag;
+ uint mask = 0x0;
+ unsigned long flags;
+ u32 serror, intpr, dma_ch;
+
+ tag = ap->link.active_tag;
+ dma_ch = hsdevp->dma_chan[tag];
+ qc = ata_qc_from_tag(ap, tag);
+
+ dev_err(ap->dev, "%s: id=%d active_tag=%d qc=%p dma_chan=%d\n",
+ __func__, ap->print_id, tag, qc, dma_ch);
+
+ intpr = in_le32(&hsdev->sata_dwc_regs->intpr);
+ serror = sata_dwc_core_scr_read(ap, SCR_ERROR);
+
+ dev_err(ap->dev, "intpr=0x%08x serror=0x%08x\n", intpr, serror);
+
+ /* If there are no error bits set, can we just pass this on to eh? */
+ if (!(serror & SATA_DWC_SERR_ERR_BITS) &&
+ !(intpr & SATA_DWC_INTPR_ERR)) {
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ if (dma_dwc_channel_enabled(dma_ch))
+ dma_dwc_terminate_dma(ap, dma_ch);
+
+ hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_NONE;
+
+ /* clear active bit */
+ mask = (~(qcmd_tag_to_mask(tag)));
+ hsdevp->sata_dwc_sactive_queued = hsdevp->sata_dwc_sactive_queued & mask;
+ hsdevp->sata_dwc_sactive_issued = hsdevp->sata_dwc_sactive_issued & mask;
+
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+ } else {
+ /* This is wrong, what really needs to be done is a reset. */
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ if (ata_is_dma(qc->tf.protocol)) {
+ /* disable DMAC */
+ dma_dwc_terminate_dma(ap, dma_ch);
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+ WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+ if (qc->flags & ATA_QCFLAG_ACTIVE) {
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ /*
+ * test-only: The original code (AMCC: 2.6.19) called
+ * ata_eng_timeout(ap) here. This function is not available
+ * anymore. So what to do now?
+ */
+ }
+}
+#endif
+/*
+ * Function : sata_dwc_qc_prep
+ * arguments : ata_queued_cmd *qc
+ * Return value : None
+ * qc_prep for a particular queued command
+ */
+static void sata_dwc_qc_prep(struct ata_queued_cmd *qc)
+{
+ u32 sactive;
+ u8 tag = qc->tag;
+
+ if ((qc->dma_dir == DMA_NONE) || (qc->tf.protocol == ATA_PROT_PIO))
+ return;
+
+#ifdef DEBUG_NCQ
+ if (qc->tag > 0) {
+ dev_info(qc->ap->dev, "%s: qc->tag=%d ap->active_tag=0x%08x\n",
+ __func__, qc->tag, qc->ap->link.active_tag);
+ }
+#endif
+
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
+ sactive = sata_dwc_core_scr_read(qc->ap, SCR_ACTIVE);
+ sactive |= (0x00000001 << tag);
+ sata_dwc_core_scr_write(qc->ap, SCR_ACTIVE, sactive);
+ dwc_dev_vdbg(qc->ap->dev, "%s: tag=%d ap->link.sactive = 0x%08x "
+ "sactive=0x%08x\n", __func__, tag, qc->ap->link.sactive,
+ sactive);
+ } else {
+ tag = 0;
+ }
+
+ sata_dwc_qc_prep_by_tag(qc, tag);
+}
+
+
+
+static void sata_dwc_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ ata_eh_freeze_port(qc->ap);
+}
+
+static void sata_dwc_error_handler(struct ata_port *ap)
+{
+ u32 serror;
+ u32 intmr, errmr;
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap);
+
+ serror = sata_dwc_core_scr_read(ap, SCR_ERROR);
+ intmr = in_le32(&hsdev->sata_dwc_regs->intmr);
+ errmr = in_le32(&hsdev->sata_dwc_regs->errmr);
+
+ //sata_dwc_dma_xfer_complete(ap,1);
+ dwc_port_dbg(ap, "%s: SERROR=0x%08x, INTMR=0x%08x, ERRMR=0x%08x\n", __func__, serror, intmr, errmr);
+
+ dwc_port_vdbg(ap, "%s - sata_dwc_sactive_queued=0x%08x, sata_dwc_sactive_issued=0x%08x\n",__func__, hsdevp->sata_dwc_sactive_queued, hsdevp->sata_dwc_sactive_issued);
+ dwc_port_vdbg(ap, "dmacr=0x%08x\n",in_le32(&(hsdev->sata_dwc_regs->dmacr)));
+ dwc_port_vdbg(ap, "qc_active=0x%08x, qc_allocated=0x%08x, active_tag=%d\n", ap->qc_active, ap->qc_allocated, ap->link.active_tag);
+
+ sata_pmp_error_handler(ap);
+}
+
+/*
+ * sata_dwc_check_status - Get value of the Status Register
+ * @ap: Port to check
+ *
+ * Output content of the status register (CDR7)
+ */
+u8 sata_dwc_check_status(struct ata_port *ap)
+{
+ return ioread8(ap->ioaddr.status_addr);
+}
+
+
+/*
+ * Freeze the port by clear interrupt
+ * @ap: Port to freeze
+ */
+void sata_dwc_freeze(struct ata_port *ap)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+ dwc_port_dbg(ap, "call %s ...\n",__func__);
+ // turn IRQ off
+ clear_intpr(hsdev);
+ clear_serror(ap);
+ out_le32(&hsdev->sata_dwc_regs->intmr, 0x0);
+}
+
+/*
+ * Thaw the port by turning IRQ on
+ */
+void sata_dwc_thaw(struct ata_port *ap)
+{
+ struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap);
+
+ dwc_port_dbg(ap, "call %s ...\n",__func__);
+ // Clear IRQ
+ clear_intpr(hsdev);
+ // Turn IRQ back on
+ sata_dwc_enable_interrupts(hsdev);
+}
+
+
+/*
+ * scsi mid-layer and libata interface structures
+ */
+static struct scsi_host_template sata_dwc_sht = {
+ ATA_NCQ_SHT(DRV_NAME),
+ /*
+ * test-only: Currently this driver doesn't handle NCQ
+ * correctly. We enable NCQ but set the queue depth to a
+ * max of 1. This will get fixed in in a future release.
+ */
+// .sg_tablesize = LIBATA_MAX_PRD,
+ .can_queue = ATA_DEF_QUEUE, /* ATA_MAX_QUEUE */
+ .dma_boundary = ATA_DMA_BOUNDARY,
+};
+
+
+static struct ata_port_operations sata_dwc_ops = {
+ .inherits = &sata_pmp_port_ops,
+ .dev_config = sata_dwc_dev_config,
+
+ .error_handler = sata_dwc_error_handler,
+ .softreset = sata_dwc_softreset,
+ .hardreset = sata_dwc_hardreset,
+ .pmp_softreset = sata_dwc_softreset,
+ .pmp_hardreset = sata_dwc_pmp_hardreset,
+
+ .qc_defer = sata_pmp_qc_defer_cmd_switch,
+ .qc_prep = sata_dwc_qc_prep,
+ .qc_issue = sata_dwc_qc_issue,
+ .qc_fill_rtf = ata_sff_qc_fill_rtf,
+
+ .scr_read = sata_dwc_scr_read,
+ .scr_write = sata_dwc_scr_write,
+
+ .port_start = sata_dwc_port_start,
+ .port_stop = sata_dwc_port_stop,
+
+ .bmdma_setup = sata_dwc_bmdma_setup,
+ .bmdma_start = sata_dwc_bmdma_start,
+ // Reuse some SFF functions
+ .sff_check_status = sata_dwc_check_status,
+ .sff_tf_read = ata_sff_tf_read,
+ .sff_data_xfer = ata_sff_data_xfer,
+ .sff_tf_load = ata_sff_tf_load,
+ .sff_dev_select = sata_dwc_dev_select,
+ .sff_exec_command = sata_dwc_exec_command,
+
+ .sff_irq_on = sata_dwc_irq_on,
+/* .sff_irq_clear = sata_dwc_irq_clear,
+ .freeze = sata_dwc_freeze,
+ .thaw = sata_dwc_thaw,
+ .sff_irq_on = ata_sff_irq_on,
+ */
+ .sff_irq_clear = ata_bmdma_irq_clear,
+ .freeze = ata_sff_freeze,
+ .thaw = ata_sff_thaw,
+ .pmp_attach = sata_dwc_pmp_attach,
+ .pmp_detach = sata_dwc_pmp_detach,
+ .post_internal_cmd = sata_dwc_post_internal_cmd,
+
+ /* test-only: really needed? */
+ //.eng_timeout = sata_dwc_eng_timeout,
+};
+
+static const struct ata_port_info sata_dwc_port_info[] = {
+ {
+ /*
+ * test-only: Currently this driver doesn't handle NCQ
+ * correctly. So we disable NCQ here for now. To enable
+ * it ATA_FLAG_NCQ needs to be added to the flags below.
+ */
+ .flags = ATA_FLAG_SATA |
+ ATA_FLAG_NCQ |
+ ATA_FLAG_PMP | ATA_FLAG_AN,
+ .pio_mask = ATA_PIO4, /* pio 0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &sata_dwc_ops,
+ },
+};
+
+static int sata_dwc_probe(struct platform_device *ofdev)
+{
+ struct sata_dwc_device *hsdev;
+ u32 idr, versionr;
+ char *ver = (char *)&versionr;
+ u8 *base = NULL;
+ int err = 0;
+ int irq;
+ struct ata_host *host;
+ struct ata_port_info pi = sata_dwc_port_info[0];
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+ struct device_node *np = ofdev->dev.of_node;
+ const unsigned int *dma_channel;
+ /*
+ * Check if device is enabled
+ */
+ if (!of_device_is_available(np)) {
+ printk(KERN_INFO "%s: Port disabled via device-tree\n",
+ np->full_name);
+ return 0;
+ }
+
+ /* Allocate DWC SATA device */
+ hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL);
+ if (hsdev == NULL) {
+ dev_err(&ofdev->dev, "kmalloc failed for hsdev\n");
+ err = -ENOMEM;
+ goto error;
+ }
+
+
+ // Identify SATA DMA channel used for the current SATA device
+ dma_channel = of_get_property(np, "dma-channel", NULL);
+ if ( dma_channel ) {
+ dev_notice(&ofdev->dev, "Gettting DMA channel %d\n", *dma_channel);
+ hsdev->dma_channel = *dma_channel;
+ } else
+ hsdev->dma_channel = 0;
+
+ /* Ioremap SATA registers */
+ base = of_iomap(np, 0);
+ if (!base) {
+ dev_err(&ofdev->dev, "ioremap failed for SATA register address\n");
+ err = -ENODEV;
+ goto error_kmalloc;
+ }
+ hsdev->reg_base = base;
+ dwc_dev_vdbg(&ofdev->dev, "ioremap done for SATA register address\n");
+
+ /* Synopsys DWC SATA specific Registers */
+ hsdev->sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET);
+
+ /* Allocate and fill host */
+ host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS);
+ if (!host) {
+ dev_err(&ofdev->dev, "ata_host_alloc_pinfo failed\n");
+ err = -ENOMEM;
+ goto error_iomap;
+ }
+
+ host->private_data = hsdev;
+
+ /* Setup port */
+ host->ports[0]->ioaddr.cmd_addr = base;
+ host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET;
+ hsdev->scr_base = (u8 *)(base + SATA_DWC_SCR_OFFSET);
+ sata_dwc_setup_port(&host->ports[0]->ioaddr, (unsigned long)base);
+
+ /* Read the ID and Version Registers */
+ idr = in_le32(&hsdev->sata_dwc_regs->idr);
+ versionr = in_le32(&hsdev->sata_dwc_regs->versionr);
+ dev_notice(&ofdev->dev, "id %d, controller version %c.%c%c\n",
+ idr, ver[0], ver[1], ver[2]);
+
+ /* Get SATA DMA interrupt number */
+ irq = irq_of_parse_and_map(np, 1);
+ if (irq == NO_IRQ) {
+ dev_err(&ofdev->dev, "no SATA DMA irq\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+
+ /* Get physical SATA DMA register base address */
+ if (!sata_dma_regs) {
+ sata_dma_regs = of_iomap(np, 1);
+ if (!sata_dma_regs) {
+ dev_err(&ofdev->dev, "ioremap failed for AHBDMA register address\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+ }
+ /* Save dev for later use in dev_xxx() routines */
+ hsdev->dev = &ofdev->dev;
+
+ /* Init glovbal dev list */
+ dwc_dev_list[hsdev->dma_channel] = hsdev;
+
+ /* Initialize AHB DMAC */
+ hsdev->irq_dma = irq;
+ dma_dwc_init(hsdev);
+ dma_register_interrupt(hsdev);
+
+
+ /* Enable SATA Interrupts */
+ sata_dwc_enable_interrupts(hsdev);
+
+ /* Get SATA interrupt number */
+ irq = irq_of_parse_and_map(np, 0);
+ if (irq == NO_IRQ) {
+ dev_err(&ofdev->dev, "no SATA irq\n");
+ err = -ENODEV;
+ goto error_out;
+ }
+
+ /*
+ * Now, register with libATA core, this will also initiate the
+ * device discovery process, invoking our port_start() handler &
+ * error_handler() to execute a dummy Softreset EH session
+ */
+ ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht);
+
+ dev_set_drvdata(&ofdev->dev, host);
+
+ /* Everything is fine */
+ return 0;
+
+error_out:
+ /* Free SATA DMA resources */
+ dma_dwc_exit(hsdev);
+
+error_iomap:
+ iounmap(base);
+error_kmalloc:
+ kfree(hsdev);
+error:
+ return err;
+}
+
+static int sata_dwc_remove(struct platform_device *ofdev)
+{
+ struct device *dev = &ofdev->dev;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_dwc_device *hsdev = host->private_data;
+
+ ata_host_detach(host);
+
+ dev_set_drvdata(dev, NULL);
+
+ /* Free SATA DMA resources */
+ dma_dwc_exit(hsdev);
+
+ iounmap(hsdev->reg_base);
+ kfree(hsdev);
+ kfree(host);
+
+ dwc_dev_vdbg(&ofdev->dev, "done\n");
+
+ return 0;
+}
+
+static const struct of_device_id sata_dwc_match[] = {
+ { .compatible = "amcc,sata-460ex", },
+ { .compatible = "amcc,sata-apm82181", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sata_dwc_match);
+
+static struct platform_driver sata_dwc_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = sata_dwc_match,
+ },
+ .probe = sata_dwc_probe,
+ .remove = sata_dwc_remove,
+};
+
+module_platform_driver(sata_dwc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Miesfeld <mmiesfeld@amcc.com>");
+MODULE_DESCRIPTION("DesignWare Cores SATA controller driver");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index fddd346b1d5..616a6d2ac20 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -6,7 +6,7 @@
* Author: Ashish Kalra <ashish.kalra@freescale.com>
* Li Yang <leoli@freescale.com>
*
- * Copyright (c) 2006-2007 Freescale Semiconductor, Inc.
+ * Copyright (c) 2006-2007, 2011-2012 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -18,13 +18,25 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
#include <asm/io.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
+static unsigned int intr_coalescing_count;
+module_param(intr_coalescing_count, int, S_IRUGO);
+MODULE_PARM_DESC(intr_coalescing_count,
+ "INT coalescing count threshold (1..31)");
+
+static unsigned int intr_coalescing_ticks;
+module_param(intr_coalescing_ticks, int, S_IRUGO);
+MODULE_PARM_DESC(intr_coalescing_ticks,
+ "INT coalescing timer threshold in AHB ticks");
/* Controller information */
enum {
SATA_FSL_QUEUE_DEPTH = 16,
@@ -32,9 +44,8 @@ enum {
SATA_FSL_MAX_PRD_USABLE = SATA_FSL_MAX_PRD - 1,
SATA_FSL_MAX_PRD_DIRECT = 16, /* Direct PRDT entries */
- SATA_FSL_HOST_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_NCQ),
+ SATA_FSL_HOST_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_PMP | ATA_FLAG_NCQ | ATA_FLAG_AN),
SATA_FSL_MAX_CMDS = SATA_FSL_QUEUE_DEPTH,
SATA_FSL_CMD_HDR_SIZE = 16, /* 4 DWORDS */
@@ -42,10 +53,10 @@ enum {
/*
* SATA-FSL host controller supports a max. of (15+1) direct PRDEs, and
- * chained indirect PRDEs upto a max count of 63.
- * We are allocating an array of 63 PRDEs contigiously, but PRDE#15 will
+ * chained indirect PRDEs up to a max count of 63.
+ * We are allocating an array of 63 PRDEs contiguously, but PRDE#15 will
* be setup as an indirect descriptor, pointing to it's next
- * (contigious) PRDE. Though chained indirect PRDE arrays are
+ * (contiguous) PRDE. Though chained indirect PRDE arrays are
* supported,it will be more efficient to use a direct PRDT and
* a single chain/link to indirect PRDE array/PRDT.
*/
@@ -83,6 +94,16 @@ enum {
};
/*
+ * Interrupt Coalescing Control Register bitdefs */
+enum {
+ ICC_MIN_INT_COUNT_THRESHOLD = 1,
+ ICC_MAX_INT_COUNT_THRESHOLD = ((1 << 5) - 1),
+ ICC_MIN_INT_TICKS_THRESHOLD = 0,
+ ICC_MAX_INT_TICKS_THRESHOLD = ((1 << 19) - 1),
+ ICC_SAFE_INT_TICKS = 1,
+};
+
+/*
* Host Controller command register set - per port
*/
enum {
@@ -104,6 +125,7 @@ enum {
ONLINE = (1 << 31),
GOING_OFFLINE = (1 << 30),
BIST_ERR = (1 << 29),
+ CLEAR_ERROR = (1 << 27),
FATAL_ERR_HC_MASTER_ERR = (1 << 18),
FATAL_ERR_PARITY_ERR_TX = (1 << 17),
@@ -124,6 +146,7 @@ enum {
FATAL_ERR_CRC_ERR_RX |
FATAL_ERR_FIFO_OVRFL_TX | FATAL_ERR_FIFO_OVRFL_RX,
+ INT_ON_DATA_LENGTH_MISMATCH = (1 << 12),
INT_ON_FATAL_ERR = (1 << 5),
INT_ON_PHYRDY_CHG = (1 << 4),
@@ -132,7 +155,7 @@ enum {
INT_ON_SINGL_DEVICE_ERR = (1 << 1),
INT_ON_CMD_COMPLETE = 1,
- INT_ON_ERROR = INT_ON_FATAL_ERR |
+ INT_ON_ERROR = INT_ON_FATAL_ERR | INT_ON_SNOTIFY_UPDATE |
INT_ON_PHYRDY_CHG | INT_ON_SINGL_DEVICE_ERR,
/*
@@ -140,6 +163,7 @@ enum {
*/
HCONTROL_ONLINE_PHY_RST = (1 << 31),
HCONTROL_FORCE_OFFLINE = (1 << 30),
+ HCONTROL_LEGACY = (1 << 28),
HCONTROL_PARITY_PROT_MOD = (1 << 14),
HCONTROL_DPATH_PARITY = (1 << 12),
HCONTROL_SNOOP_ENABLE = (1 << 10),
@@ -153,11 +177,12 @@ enum {
IE_ON_CMD_COMPLETE = 1,
DEFAULT_PORT_IRQ_ENABLE_MASK = IE_ON_FATAL_ERR | IE_ON_PHYRDY_CHG |
- IE_ON_SIGNATURE_UPDATE |
+ IE_ON_SIGNATURE_UPDATE | IE_ON_SNOTIFY_UPDATE |
IE_ON_SINGL_DEVICE_ERR | IE_ON_CMD_COMPLETE,
EXT_INDIRECT_SEG_PRD_FLAG = (1 << 31),
- DATA_SNOOP_ENABLE = (1 << 22),
+ DATA_SNOOP_ENABLE_V1 = (1 << 22),
+ DATA_SNOOP_ENABLE_V2 = (1 << 28),
};
/*
@@ -185,6 +210,11 @@ enum {
COMMANDSTAT = 0x20,
};
+/* TRANSCFG (transport-layer) configuration control */
+enum {
+ TRANSCFG_RX_WATER_MARK = (1 << 4),
+};
+
/* PHY (link-layer) configuration control */
enum {
PHY_BIST_ENABLE = 0x01,
@@ -205,6 +235,7 @@ struct cmdhdr_tbl_entry {
* Description information bitdefs
*/
enum {
+ CMD_DESC_RES = (1 << 11),
VENDOR_SPECIFIC_BIST = (1 << 10),
CMD_DESC_SNOOP_ENABLE = (1 << 9),
FPDMA_QUEUED_CMD = (1 << 8),
@@ -254,8 +285,110 @@ struct sata_fsl_host_priv {
void __iomem *ssr_base;
void __iomem *csr_base;
int irq;
+ int data_snoop;
+ struct device_attribute intr_coalescing;
+ struct device_attribute rx_watermark;
};
+static void fsl_sata_set_irq_coalescing(struct ata_host *host,
+ unsigned int count, unsigned int ticks)
+{
+ struct sata_fsl_host_priv *host_priv = host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ unsigned long flags;
+
+ if (count > ICC_MAX_INT_COUNT_THRESHOLD)
+ count = ICC_MAX_INT_COUNT_THRESHOLD;
+ else if (count < ICC_MIN_INT_COUNT_THRESHOLD)
+ count = ICC_MIN_INT_COUNT_THRESHOLD;
+
+ if (ticks > ICC_MAX_INT_TICKS_THRESHOLD)
+ ticks = ICC_MAX_INT_TICKS_THRESHOLD;
+ else if ((ICC_MIN_INT_TICKS_THRESHOLD == ticks) &&
+ (count > ICC_MIN_INT_COUNT_THRESHOLD))
+ ticks = ICC_SAFE_INT_TICKS;
+
+ spin_lock_irqsave(&host->lock, flags);
+ iowrite32((count << 24 | ticks), hcr_base + ICC);
+
+ intr_coalescing_count = count;
+ intr_coalescing_ticks = ticks;
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ DPRINTK("interrupt coalescing, count = 0x%x, ticks = %x\n",
+ intr_coalescing_count, intr_coalescing_ticks);
+ DPRINTK("ICC register status: (hcr base: 0x%x) = 0x%x\n",
+ hcr_base, ioread32(hcr_base + ICC));
+}
+
+static ssize_t fsl_sata_intr_coalescing_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d %d\n",
+ intr_coalescing_count, intr_coalescing_ticks);
+}
+
+static ssize_t fsl_sata_intr_coalescing_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned int coalescing_count, coalescing_ticks;
+
+ if (sscanf(buf, "%d%d",
+ &coalescing_count,
+ &coalescing_ticks) != 2) {
+ printk(KERN_ERR "fsl-sata: wrong parameter format.\n");
+ return -EINVAL;
+ }
+
+ fsl_sata_set_irq_coalescing(dev_get_drvdata(dev),
+ coalescing_count, coalescing_ticks);
+
+ return strlen(buf);
+}
+
+static ssize_t fsl_sata_rx_watermark_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned int rx_watermark;
+ unsigned long flags;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_fsl_host_priv *host_priv = host->private_data;
+ void __iomem *csr_base = host_priv->csr_base;
+
+ spin_lock_irqsave(&host->lock, flags);
+ rx_watermark = ioread32(csr_base + TRANSCFG);
+ rx_watermark &= 0x1f;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ return sprintf(buf, "%d\n", rx_watermark);
+}
+
+static ssize_t fsl_sata_rx_watermark_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned int rx_watermark;
+ unsigned long flags;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_fsl_host_priv *host_priv = host->private_data;
+ void __iomem *csr_base = host_priv->csr_base;
+ u32 temp;
+
+ if (sscanf(buf, "%d", &rx_watermark) != 1) {
+ printk(KERN_ERR "fsl-sata: wrong parameter format.\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&host->lock, flags);
+ temp = ioread32(csr_base + TRANSCFG);
+ temp &= 0xffffffe0;
+ iowrite32(temp | rx_watermark, csr_base + TRANSCFG);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ return strlen(buf);
+}
+
static inline unsigned int sata_fsl_tag(unsigned int tag,
void __iomem *hcr_base)
{
@@ -306,14 +439,15 @@ static void sata_fsl_setup_cmd_hdr_entry(struct sata_fsl_port_priv *pp,
}
static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
- u32 *ttl, dma_addr_t cmd_desc_paddr)
+ u32 *ttl, dma_addr_t cmd_desc_paddr,
+ int data_snoop)
{
struct scatterlist *sg;
unsigned int num_prde = 0;
u32 ttl_dwords = 0;
/*
- * NOTE : direct & indirect prdt's are contigiously allocated
+ * NOTE : direct & indirect prdt's are contiguously allocated
*/
struct prde *prd = (struct prde *)&((struct command_desc *)
cmd_desc)->prdt;
@@ -332,16 +466,16 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
dma_addr_t sg_addr = sg_dma_address(sg);
u32 sg_len = sg_dma_len(sg);
- VPRINTK("SATA FSL : fill_sg, sg_addr = 0x%x, sg_len = %d\n",
- sg_addr, sg_len);
+ VPRINTK("SATA FSL : fill_sg, sg_addr = 0x%llx, sg_len = %d\n",
+ (unsigned long long)sg_addr, sg_len);
/* warn if each s/g element is not dword aligned */
- if (sg_addr & 0x03)
- ata_port_printk(qc->ap, KERN_ERR,
- "s/g addr unaligned : 0x%x\n", sg_addr);
- if (sg_len & 0x03)
- ata_port_printk(qc->ap, KERN_ERR,
- "s/g len unaligned : 0x%x\n", sg_len);
+ if (unlikely(sg_addr & 0x03))
+ ata_port_err(qc->ap, "s/g addr unaligned : 0x%llx\n",
+ (unsigned long long)sg_addr);
+ if (unlikely(sg_len & 0x03))
+ ata_port_err(qc->ap, "s/g len unaligned : 0x%x\n",
+ sg_len);
if (num_prde == (SATA_FSL_MAX_PRD_DIRECT - 1) &&
sg_next(sg) != NULL) {
@@ -355,8 +489,7 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
ttl_dwords += sg_len;
prd->dba = cpu_to_le32(sg_addr);
- prd->ddc_and_ext =
- cpu_to_le32(DATA_SNOOP_ENABLE | (sg_len & ~0x03));
+ prd->ddc_and_ext = cpu_to_le32(data_snoop | (sg_len & ~0x03));
VPRINTK("sg_fill, ttl=%d, dba=0x%x, ddc=0x%x\n",
ttl_dwords, prd->dba, prd->ddc_and_ext);
@@ -371,7 +504,7 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
/* set indirect extension flag along with indirect ext. size */
prd_ptr_to_indirect_ext->ddc_and_ext =
cpu_to_le32((EXT_INDIRECT_SEG_PRD_FLAG |
- DATA_SNOOP_ENABLE |
+ data_snoop |
(indirect_ext_segment_sz & ~0x03)));
}
@@ -387,7 +520,7 @@ static void sata_fsl_qc_prep(struct ata_queued_cmd *qc)
void __iomem *hcr_base = host_priv->hcr_base;
unsigned int tag = sata_fsl_tag(qc->tag, hcr_base);
struct command_desc *cd;
- u32 desc_info = CMD_DESC_SNOOP_ENABLE;
+ u32 desc_info = CMD_DESC_RES | CMD_DESC_SNOOP_ENABLE;
u32 num_prde = 0;
u32 ttl_dwords = 0;
dma_addr_t cd_paddr;
@@ -395,7 +528,7 @@ static void sata_fsl_qc_prep(struct ata_queued_cmd *qc)
cd = (struct command_desc *)pp->cmdentry + tag;
cd_paddr = pp->cmdentry_paddr + tag * SATA_FSL_CMD_DESC_SIZE;
- ata_tf_to_fis(&qc->tf, 0, 1, (u8 *) &cd->cfis);
+ ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, (u8 *) &cd->cfis);
VPRINTK("Dumping cfis : 0x%x, 0x%x, 0x%x\n",
cd->cfis[0], cd->cfis[1], cd->cfis[2]);
@@ -414,7 +547,8 @@ static void sata_fsl_qc_prep(struct ata_queued_cmd *qc)
if (qc->flags & ATA_QCFLAG_DMAMAP)
num_prde = sata_fsl_fill_sg(qc, (void *)cd,
- &ttl_dwords, cd_paddr);
+ &ttl_dwords, cd_paddr,
+ host_priv->data_snoop);
if (qc->tf.protocol == ATA_PROT_NCQ)
desc_info |= FPDMA_QUEUED_CMD;
@@ -438,6 +572,8 @@ static unsigned int sata_fsl_qc_issue(struct ata_queued_cmd *qc)
ioread32(CA + hcr_base),
ioread32(CE + hcr_base), ioread32(CC + hcr_base));
+ iowrite32(qc->dev->link->pmp, CQPMP + hcr_base);
+
/* Simply queue command to the controller/device */
iowrite32(1 << tag, CQ + hcr_base);
@@ -467,10 +603,10 @@ static bool sata_fsl_qc_fill_rtf(struct ata_queued_cmd *qc)
return true;
}
-static int sata_fsl_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
- u32 val)
+static int sata_fsl_scr_write(struct ata_link *link,
+ unsigned int sc_reg_in, u32 val)
{
- struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ struct sata_fsl_host_priv *host_priv = link->ap->host->private_data;
void __iomem *ssr_base = host_priv->ssr_base;
unsigned int sc_reg;
@@ -491,10 +627,10 @@ static int sata_fsl_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
return 0;
}
-static int sata_fsl_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
- u32 *val)
+static int sata_fsl_scr_read(struct ata_link *link,
+ unsigned int sc_reg_in, u32 *val)
{
- struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ struct sata_fsl_host_priv *host_priv = link->ap->host->private_data;
void __iomem *ssr_base = host_priv->ssr_base;
unsigned int sc_reg;
@@ -558,11 +694,36 @@ static void sata_fsl_thaw(struct ata_port *ap)
ioread32(hcr_base + HCONTROL), ioread32(hcr_base + HSTATUS));
}
+static void sata_fsl_pmp_attach(struct ata_port *ap)
+{
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 temp;
+
+ temp = ioread32(hcr_base + HCONTROL);
+ iowrite32((temp | HCONTROL_PMP_ATTACHED), hcr_base + HCONTROL);
+}
+
+static void sata_fsl_pmp_detach(struct ata_port *ap)
+{
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 temp;
+
+ temp = ioread32(hcr_base + HCONTROL);
+ temp &= ~HCONTROL_PMP_ATTACHED;
+ iowrite32(temp, hcr_base + HCONTROL);
+
+ /* enable interrupts on the controller/port */
+ temp = ioread32(hcr_base + HCONTROL);
+ iowrite32((temp | DEFAULT_PORT_IRQ_ENABLE_MASK), hcr_base + HCONTROL);
+
+}
+
static int sata_fsl_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
struct sata_fsl_port_priv *pp;
- int retval;
void *mem;
dma_addr_t mem_dma;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
@@ -613,21 +774,6 @@ static int sata_fsl_port_start(struct ata_port *ap)
VPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
VPRINTK("CHBA = 0x%x\n", ioread32(hcr_base + CHBA));
-#ifdef CONFIG_MPC8315_DS
- /*
- * Workaround for 8315DS board 3gbps link-up issue,
- * currently limit SATA port to GEN1 speed
- */
- sata_fsl_scr_read(ap, SCR_CONTROL, &temp);
- temp &= ~(0xF << 4);
- temp |= (0x1 << 4);
- sata_fsl_scr_write(ap, SCR_CONTROL, temp);
-
- sata_fsl_scr_read(ap, SCR_CONTROL, &temp);
- dev_printk(KERN_WARNING, dev, "scr_control, speed limited to %x\n",
- temp);
-#endif
-
return 0;
}
@@ -648,7 +794,7 @@ static void sata_fsl_port_stop(struct ata_port *ap)
iowrite32(temp, hcr_base + HCONTROL);
/* Poll for controller to go offline - should happen immediately */
- ata_wait_register(hcr_base + HSTATUS, ONLINE, ONLINE, 1, 1);
+ ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, ONLINE, 1, 1);
ap->private_data = NULL;
dma_free_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ,
@@ -678,30 +824,17 @@ static unsigned int sata_fsl_dev_classify(struct ata_port *ap)
return ata_dev_classify(&tf);
}
-static int sata_fsl_prereset(struct ata_linke *link, unsigned long deadline)
-{
- /* FIXME: Never skip softreset, sata_fsl_softreset() is
- * combination of soft and hard resets. sata_fsl_softreset()
- * needs to be splitted into soft and hard resets.
- */
- return 0;
-}
-
-static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
+static int sata_fsl_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
{
struct ata_port *ap = link->ap;
- struct sata_fsl_port_priv *pp = ap->private_data;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
void __iomem *hcr_base = host_priv->hcr_base;
u32 temp;
- struct ata_taskfile tf;
- u8 *cfis;
- u32 Serror;
int i = 0;
unsigned long start_jiffies;
- DPRINTK("in xx_softreset\n");
+ DPRINTK("in xx_hardreset\n");
try_offline_again:
/*
@@ -712,11 +845,11 @@ try_offline_again:
iowrite32(temp, hcr_base + HCONTROL);
/* Poll for controller to go offline */
- temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, ONLINE, 1, 500);
+ temp = ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, ONLINE,
+ 1, 500);
if (temp & ONLINE) {
- ata_port_printk(ap, KERN_ERR,
- "Softreset failed, not off-lined %d\n", i);
+ ata_port_err(ap, "Hardreset failed, not off-lined %d\n", i);
/*
* Try to offline controller atleast twice
@@ -728,14 +861,14 @@ try_offline_again:
goto try_offline_again;
}
- DPRINTK("softreset, controller off-lined\n");
+ DPRINTK("hardreset, controller off-lined\n");
VPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
VPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
/*
* PHY reset should remain asserted for atleast 1ms
*/
- msleep(1);
+ ata_msleep(ap, 1);
/*
* Now, bring the host controller online again, this can take time
@@ -746,17 +879,17 @@ try_offline_again:
temp = ioread32(hcr_base + HCONTROL);
temp |= (HCONTROL_ONLINE_PHY_RST | HCONTROL_SNOOP_ENABLE);
+ temp |= HCONTROL_PMP_ATTACHED;
iowrite32(temp, hcr_base + HCONTROL);
- temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, 0, 1, 500);
+ temp = ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, 0, 1, 500);
if (!(temp & ONLINE)) {
- ata_port_printk(ap, KERN_ERR,
- "Softreset failed, not on-lined\n");
+ ata_port_err(ap, "Hardreset failed, not on-lined\n");
goto err;
}
- DPRINTK("softreset, controller off-lined & on-lined\n");
+ DPRINTK("hardreset, controller off-lined & on-lined\n");
VPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
VPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
@@ -766,28 +899,61 @@ try_offline_again:
* presence
*/
- temp = ata_wait_register(hcr_base + HSTATUS, 0xFF, 0, 1, 500);
+ temp = ata_wait_register(ap, hcr_base + HSTATUS, 0xFF, 0, 1, 500);
if ((!(temp & 0x10)) || ata_link_offline(link)) {
- ata_port_printk(ap, KERN_WARNING,
- "No Device OR PHYRDY change,Hstatus = 0x%x\n",
- ioread32(hcr_base + HSTATUS));
- goto err;
+ ata_port_warn(ap, "No Device OR PHYRDY change,Hstatus = 0x%x\n",
+ ioread32(hcr_base + HSTATUS));
+ *class = ATA_DEV_NONE;
+ return 0;
}
/*
* Wait for the first D2H from device,i.e,signature update notification
*/
start_jiffies = jiffies;
- temp = ata_wait_register(hcr_base + HSTATUS, 0xFF, 0x10,
+ temp = ata_wait_register(ap, hcr_base + HSTATUS, 0xFF, 0x10,
500, jiffies_to_msecs(deadline - start_jiffies));
if ((temp & 0xFF) != 0x18) {
- ata_port_printk(ap, KERN_WARNING, "No Signature Update\n");
- goto err;
+ ata_port_warn(ap, "No Signature Update\n");
+ *class = ATA_DEV_NONE;
+ goto do_followup_srst;
} else {
- ata_port_printk(ap, KERN_INFO,
- "Signature Update detected @ %d msecs\n",
- jiffies_to_msecs(jiffies - start_jiffies));
+ ata_port_info(ap, "Signature Update detected @ %d msecs\n",
+ jiffies_to_msecs(jiffies - start_jiffies));
+ *class = sata_fsl_dev_classify(ap);
+ return 0;
+ }
+
+do_followup_srst:
+ /*
+ * request libATA to perform follow-up softreset
+ */
+ return -EAGAIN;
+
+err:
+ return -EIO;
+}
+
+static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct sata_fsl_port_priv *pp = ap->private_data;
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ int pmp = sata_srst_pmp(link);
+ u32 temp;
+ struct ata_taskfile tf;
+ u8 *cfis;
+ u32 Serror;
+
+ DPRINTK("in xx_softreset\n");
+
+ if (ata_link_offline(link)) {
+ DPRINTK("PHY reports no device\n");
+ *class = ATA_DEV_NONE;
+ return 0;
}
/*
@@ -805,10 +971,10 @@ try_offline_again:
/* device reset/SRST is a control register update FIS, uses tag0 */
sata_fsl_setup_cmd_hdr_entry(pp, 0,
- SRST_CMD | CMD_DESC_SNOOP_ENABLE, 0, 0, 5);
+ SRST_CMD | CMD_DESC_RES | CMD_DESC_SNOOP_ENABLE, 0, 0, 5);
tf.ctl |= ATA_SRST; /* setup SRST bit in taskfile control reg */
- ata_tf_to_fis(&tf, 0, 0, cfis);
+ ata_tf_to_fis(&tf, pmp, 0, cfis);
DPRINTK("Dumping cfis : 0x%x, 0x%x, 0x%x, 0x%x\n",
cfis[0], cfis[1], cfis[2], cfis[3]);
@@ -823,17 +989,19 @@ try_offline_again:
ioread32(CA + hcr_base), ioread32(CC + hcr_base));
iowrite32(0xFFFF, CC + hcr_base);
+ if (pmp != SATA_PMP_CTRL_PORT)
+ iowrite32(pmp, CQPMP + hcr_base);
iowrite32(1, CQ + hcr_base);
- temp = ata_wait_register(CQ + hcr_base, 0x1, 0x1, 1, 5000);
+ temp = ata_wait_register(ap, CQ + hcr_base, 0x1, 0x1, 1, 5000);
if (temp & 0x1) {
- ata_port_printk(ap, KERN_WARNING, "ATA_SRST issue failed\n");
+ ata_port_warn(ap, "ATA_SRST issue failed\n");
DPRINTK("Softreset@5000,CQ=0x%x,CA=0x%x,CC=0x%x\n",
ioread32(CQ + hcr_base),
ioread32(CA + hcr_base), ioread32(CC + hcr_base));
- sata_fsl_scr_read(ap, SCR_ERROR, &Serror);
+ sata_fsl_scr_read(&ap->link, SCR_ERROR, &Serror);
DPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
DPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
@@ -841,23 +1009,26 @@ try_offline_again:
goto err;
}
- msleep(1);
+ ata_msleep(ap, 1);
/*
- * SATA device enters reset state after receving a Control register
+ * SATA device enters reset state after receiving a Control register
* FIS with SRST bit asserted and it awaits another H2D Control reg.
* FIS with SRST bit cleared, then the device does internal diags &
* initialization, followed by indicating it's initialization status
* using ATA signature D2H register FIS to the host controller.
*/
- sata_fsl_setup_cmd_hdr_entry(pp, 0, CMD_DESC_SNOOP_ENABLE, 0, 0, 5);
+ sata_fsl_setup_cmd_hdr_entry(pp, 0, CMD_DESC_RES | CMD_DESC_SNOOP_ENABLE,
+ 0, 0, 5);
tf.ctl &= ~ATA_SRST; /* 2nd H2D Ctl. register FIS */
- ata_tf_to_fis(&tf, 0, 0, cfis);
+ ata_tf_to_fis(&tf, pmp, 0, cfis);
+ if (pmp != SATA_PMP_CTRL_PORT)
+ iowrite32(pmp, CQPMP + hcr_base);
iowrite32(1, CQ + hcr_base);
- msleep(150); /* ?? */
+ ata_msleep(ap, 150); /* ?? */
/*
* The above command would have signalled an interrupt on command
@@ -892,6 +1063,14 @@ err:
return -EIO;
}
+static void sata_fsl_error_handler(struct ata_port *ap)
+{
+
+ DPRINTK("in xx_error_handler\n");
+ sata_pmp_error_handler(ap);
+
+}
+
static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc)
{
if (qc->flags & ATA_QCFLAG_FAILED)
@@ -905,33 +1084,56 @@ static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc)
static void sata_fsl_error_intr(struct ata_port *ap)
{
- struct ata_link *link = &ap->link;
- struct ata_eh_info *ehi = &link->eh_info;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
void __iomem *hcr_base = host_priv->hcr_base;
- u32 hstatus, dereg, cereg = 0, SError = 0;
+ u32 hstatus, dereg=0, cereg = 0, SError = 0;
unsigned int err_mask = 0, action = 0;
- struct ata_queued_cmd *qc;
- int freeze = 0;
+ int freeze = 0, abort=0;
+ struct ata_link *link = NULL;
+ struct ata_queued_cmd *qc = NULL;
+ struct ata_eh_info *ehi;
hstatus = ioread32(hcr_base + HSTATUS);
cereg = ioread32(hcr_base + CE);
+ /* first, analyze and record host port events */
+ link = &ap->link;
+ ehi = &link->eh_info;
ata_ehi_clear_desc(ehi);
/*
* Handle & Clear SError
*/
- sata_fsl_scr_read(ap, SCR_ERROR, &SError);
- if (unlikely(SError & 0xFFFF0000)) {
- sata_fsl_scr_write(ap, SCR_ERROR, SError);
- err_mask |= AC_ERR_ATA_BUS;
- }
+ sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError);
+ if (unlikely(SError & 0xFFFF0000))
+ sata_fsl_scr_write(&ap->link, SCR_ERROR, SError);
DPRINTK("error_intr,hStat=0x%x,CE=0x%x,DE =0x%x,SErr=0x%x\n",
hstatus, cereg, ioread32(hcr_base + DE), SError);
+ /* handle fatal errors */
+ if (hstatus & FATAL_ERROR_DECODE) {
+ ehi->err_mask |= AC_ERR_ATA_BUS;
+ ehi->action |= ATA_EH_SOFTRESET;
+
+ freeze = 1;
+ }
+
+ /* Handle SDB FIS receive & notify update */
+ if (hstatus & INT_ON_SNOTIFY_UPDATE)
+ sata_async_notification(ap);
+
+ /* Handle PHYRDY change notification */
+ if (hstatus & INT_ON_PHYRDY_CHG) {
+ DPRINTK("SATA FSL: PHYRDY change indication\n");
+
+ /* Setup a soft-reset EH action */
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, "%s", "PHY RDY changed");
+ freeze = 1;
+ }
+
/* handle single device errors */
if (cereg) {
/*
@@ -943,118 +1145,167 @@ static void sata_fsl_error_intr(struct ata_port *ap)
* clearing the device error, we can issue commands to the
* device to interrogate it to find the source of the error.
*/
- dereg = ioread32(hcr_base + DE);
- iowrite32(dereg, hcr_base + DE);
- iowrite32(cereg, hcr_base + CE);
+ abort = 1;
DPRINTK("single device error, CE=0x%x, DE=0x%x\n",
ioread32(hcr_base + CE), ioread32(hcr_base + DE));
- /*
- * We should consider this as non fatal error, and TF must
- * be updated as done below.
- */
-
- err_mask |= AC_ERR_DEV;
- }
- /* handle fatal errors */
- if (hstatus & FATAL_ERROR_DECODE) {
- err_mask |= AC_ERR_ATA_BUS;
- action |= ATA_EH_RESET;
- /* how will fatal error interrupts be completed ?? */
- freeze = 1;
- }
-
- /* Handle PHYRDY change notification */
- if (hstatus & INT_ON_PHYRDY_CHG) {
- DPRINTK("SATA FSL: PHYRDY change indication\n");
-
- /* Setup a soft-reset EH action */
- ata_ehi_hotplugged(ehi);
- freeze = 1;
+ /* find out the offending link and qc */
+ if (ap->nr_pmp_links) {
+ unsigned int dev_num;
+
+ dereg = ioread32(hcr_base + DE);
+ iowrite32(dereg, hcr_base + DE);
+ iowrite32(cereg, hcr_base + CE);
+
+ dev_num = ffs(dereg) - 1;
+ if (dev_num < ap->nr_pmp_links && dereg != 0) {
+ link = &ap->pmp_link[dev_num];
+ ehi = &link->eh_info;
+ qc = ata_qc_from_tag(ap, link->active_tag);
+ /*
+ * We should consider this as non fatal error,
+ * and TF must be updated as done below.
+ */
+
+ err_mask |= AC_ERR_DEV;
+
+ } else {
+ err_mask |= AC_ERR_HSM;
+ action |= ATA_EH_HARDRESET;
+ freeze = 1;
+ }
+ } else {
+ dereg = ioread32(hcr_base + DE);
+ iowrite32(dereg, hcr_base + DE);
+ iowrite32(cereg, hcr_base + CE);
+
+ qc = ata_qc_from_tag(ap, link->active_tag);
+ /*
+ * We should consider this as non fatal error,
+ * and TF must be updated as done below.
+ */
+ err_mask |= AC_ERR_DEV;
+ }
}
/* record error info */
- qc = ata_qc_from_tag(ap, link->active_tag);
-
if (qc)
qc->err_mask |= err_mask;
else
ehi->err_mask |= err_mask;
ehi->action |= action;
- ehi->serror |= SError;
/* freeze or abort */
if (freeze)
ata_port_freeze(ap);
- else
- ata_port_abort(ap);
+ else if (abort) {
+ if (qc)
+ ata_link_abort(qc->dev->link);
+ else
+ ata_port_abort(ap);
+ }
}
static void sata_fsl_host_intr(struct ata_port *ap)
{
- struct ata_link *link = &ap->link;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
void __iomem *hcr_base = host_priv->hcr_base;
- u32 hstatus, qc_active = 0;
+ u32 hstatus, done_mask = 0;
struct ata_queued_cmd *qc;
u32 SError;
+ u32 tag;
+ u32 status_mask = INT_ON_ERROR;
hstatus = ioread32(hcr_base + HSTATUS);
- sata_fsl_scr_read(ap, SCR_ERROR, &SError);
+ sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError);
+
+ /* Read command completed register */
+ done_mask = ioread32(hcr_base + CC);
+
+ /* Workaround for data length mismatch errata */
+ if (unlikely(hstatus & INT_ON_DATA_LENGTH_MISMATCH)) {
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ qc = ata_qc_from_tag(ap, tag);
+ if (qc && ata_is_atapi(qc->tf.protocol)) {
+ u32 hcontrol;
+ /* Set HControl[27] to clear error registers */
+ hcontrol = ioread32(hcr_base + HCONTROL);
+ iowrite32(hcontrol | CLEAR_ERROR,
+ hcr_base + HCONTROL);
+
+ /* Clear HControl[27] */
+ iowrite32(hcontrol & ~CLEAR_ERROR,
+ hcr_base + HCONTROL);
+
+ /* Clear SError[E] bit */
+ sata_fsl_scr_write(&ap->link, SCR_ERROR,
+ SError);
+
+ /* Ignore fatal error and device error */
+ status_mask &= ~(INT_ON_SINGL_DEVICE_ERR
+ | INT_ON_FATAL_ERR);
+ break;
+ }
+ }
+ }
if (unlikely(SError & 0xFFFF0000)) {
DPRINTK("serror @host_intr : 0x%x\n", SError);
sata_fsl_error_intr(ap);
-
}
- if (unlikely(hstatus & INT_ON_ERROR)) {
+ if (unlikely(hstatus & status_mask)) {
DPRINTK("error interrupt!!\n");
sata_fsl_error_intr(ap);
return;
}
- if (link->sactive) { /* only true for NCQ commands */
+ VPRINTK("Status of all queues :\n");
+ VPRINTK("done_mask/CC = 0x%x, CA = 0x%x, CE=0x%x,CQ=0x%x,apqa=0x%x\n",
+ done_mask,
+ ioread32(hcr_base + CA),
+ ioread32(hcr_base + CE),
+ ioread32(hcr_base + CQ),
+ ap->qc_active);
+
+ if (done_mask & ap->qc_active) {
int i;
- /* Read command completed register */
- qc_active = ioread32(hcr_base + CC);
/* clear CC bit, this will also complete the interrupt */
- iowrite32(qc_active, hcr_base + CC);
+ iowrite32(done_mask, hcr_base + CC);
DPRINTK("Status of all queues :\n");
- DPRINTK("qc_active/CC = 0x%x, CA = 0x%x, CE=0x%x\n",
- qc_active, ioread32(hcr_base + CA),
+ DPRINTK("done_mask/CC = 0x%x, CA = 0x%x, CE=0x%x\n",
+ done_mask, ioread32(hcr_base + CA),
ioread32(hcr_base + CE));
for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) {
- if (qc_active & (1 << i)) {
- qc = ata_qc_from_tag(ap, i);
- if (qc)
- ata_qc_complete(qc);
+ if (done_mask & (1 << i))
DPRINTK
("completing ncq cmd,tag=%d,CC=0x%x,CA=0x%x\n",
i, ioread32(hcr_base + CC),
ioread32(hcr_base + CA));
- }
}
+ ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
return;
- } else if (ap->qc_active) {
+ } else if ((ap->qc_active & (1 << ATA_TAG_INTERNAL))) {
iowrite32(1, hcr_base + CC);
- qc = ata_qc_from_tag(ap, link->active_tag);
+ qc = ata_qc_from_tag(ap, ATA_TAG_INTERNAL);
- DPRINTK("completing non-ncq cmd, tag=%d,CC=0x%x\n",
- link->active_tag, ioread32(hcr_base + CC));
+ DPRINTK("completing non-ncq cmd, CC=0x%x\n",
+ ioread32(hcr_base + CC));
- if (qc)
+ if (qc) {
ata_qc_complete(qc);
+ }
} else {
/* Spurious Interrupt!! */
DPRINTK("spurious interrupt!!, CC = 0x%x\n",
ioread32(hcr_base + CC));
+ iowrite32(done_mask, hcr_base + CC);
return;
}
}
@@ -1085,8 +1336,7 @@ static irqreturn_t sata_fsl_interrupt(int irq, void *dev_instance)
if (ap) {
sata_fsl_host_intr(ap);
} else {
- dev_printk(KERN_WARNING, host->dev,
- "interrupt on disabled port 0\n");
+ dev_warn(host->dev, "interrupt on disabled port 0\n");
}
iowrite32(interrupt_enables, hcr_base + HSTATUS);
@@ -1113,6 +1363,10 @@ static int sata_fsl_init_controller(struct ata_host *host)
* part of the port_start() callback
*/
+ /* sata controller to operate in enterprise mode */
+ temp = ioread32(hcr_base + HCONTROL);
+ iowrite32(temp & ~HCONTROL_LEGACY, hcr_base + HCONTROL);
+
/* ack. any pending IRQs for this controller/port */
temp = ioread32(hcr_base + HSTATUS);
if (temp & 0x3F)
@@ -1130,8 +1384,12 @@ static int sata_fsl_init_controller(struct ata_host *host)
iowrite32(0x00000FFFF, hcr_base + CE);
iowrite32(0x00000FFFF, hcr_base + DE);
- /* initially assuming no Port multiplier, set CQPMP to 0 */
- iowrite32(0x0, hcr_base + CQPMP);
+ /*
+ * reset the number of command complete bits which will cause the
+ * interrupt to be signaled
+ */
+ fsl_sata_set_irq_coalescing(host, intr_coalescing_count,
+ intr_coalescing_ticks);
/*
* host controller will be brought on-line, during xx_port_start()
@@ -1154,9 +1412,10 @@ static struct scsi_host_template sata_fsl_sht = {
.dma_boundary = ATA_DMA_BOUNDARY,
};
-static const struct ata_port_operations sata_fsl_ops = {
- .inherits = &sata_port_ops,
+static struct ata_port_operations sata_fsl_ops = {
+ .inherits = &sata_pmp_port_ops,
+ .qc_defer = ata_std_qc_defer,
.qc_prep = sata_fsl_qc_prep,
.qc_issue = sata_fsl_qc_issue,
.qc_fill_rtf = sata_fsl_qc_fill_rtf,
@@ -1166,47 +1425,57 @@ static const struct ata_port_operations sata_fsl_ops = {
.freeze = sata_fsl_freeze,
.thaw = sata_fsl_thaw,
- .prereset = sata_fsl_prereset,
.softreset = sata_fsl_softreset,
+ .hardreset = sata_fsl_hardreset,
+ .pmp_softreset = sata_fsl_softreset,
+ .error_handler = sata_fsl_error_handler,
.post_internal_cmd = sata_fsl_post_internal_cmd,
.port_start = sata_fsl_port_start,
.port_stop = sata_fsl_port_stop,
+
+ .pmp_attach = sata_fsl_pmp_attach,
+ .pmp_detach = sata_fsl_pmp_detach,
};
static const struct ata_port_info sata_fsl_port_info[] = {
{
.flags = SATA_FSL_HOST_FLAGS,
- .pio_mask = 0x1f, /* pio 0-4 */
- .udma_mask = 0x7f, /* udma 0-6 */
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
.port_ops = &sata_fsl_ops,
},
};
-static int sata_fsl_probe(struct of_device *ofdev,
- const struct of_device_id *match)
+static int sata_fsl_probe(struct platform_device *ofdev)
{
- int retval = 0;
+ int retval = -ENXIO;
void __iomem *hcr_base = NULL;
void __iomem *ssr_base = NULL;
void __iomem *csr_base = NULL;
struct sata_fsl_host_priv *host_priv = NULL;
int irq;
- struct ata_host *host;
+ struct ata_host *host = NULL;
+ u32 temp;
struct ata_port_info pi = sata_fsl_port_info[0];
const struct ata_port_info *ppi[] = { &pi, NULL };
- dev_printk(KERN_INFO, &ofdev->dev,
- "Sata FSL Platform/CSB Driver init\n");
+ dev_info(&ofdev->dev, "Sata FSL Platform/CSB Driver init\n");
- hcr_base = of_iomap(ofdev->node, 0);
+ hcr_base = of_iomap(ofdev->dev.of_node, 0);
if (!hcr_base)
goto error_exit_with_cleanup;
ssr_base = hcr_base + 0x100;
csr_base = hcr_base + 0x140;
+ if (!of_device_is_compatible(ofdev->dev.of_node, "fsl,mpc8315-sata")) {
+ temp = ioread32(csr_base + TRANSCFG);
+ temp = temp & 0xffffffe0;
+ iowrite32(temp | TRANSCFG_RX_WATER_MARK, csr_base + TRANSCFG);
+ }
+
DPRINTK("@reset i/o = 0x%x\n", ioread32(csr_base + TRANSCFG));
DPRINTK("sizeof(cmd_desc) = %d\n", sizeof(struct command_desc));
DPRINTK("sizeof(#define cmd_desc) = %d\n", SATA_FSL_CMD_DESC_SIZE);
@@ -1219,15 +1488,24 @@ static int sata_fsl_probe(struct of_device *ofdev,
host_priv->ssr_base = ssr_base;
host_priv->csr_base = csr_base;
- irq = irq_of_parse_and_map(ofdev->node, 0);
+ irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
if (irq < 0) {
- dev_printk(KERN_ERR, &ofdev->dev, "invalid irq from platform\n");
+ dev_err(&ofdev->dev, "invalid irq from platform\n");
goto error_exit_with_cleanup;
}
host_priv->irq = irq;
+ if (of_device_is_compatible(ofdev->dev.of_node, "fsl,pq-sata-v2"))
+ host_priv->data_snoop = DATA_SNOOP_ENABLE_V2;
+ else
+ host_priv->data_snoop = DATA_SNOOP_ENABLE_V1;
+
/* allocate host structure */
host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_FSL_MAX_PORTS);
+ if (!host) {
+ retval = -ENOMEM;
+ goto error_exit_with_cleanup;
+ }
/* host->iomap is not used currently */
host->private_data = host_priv;
@@ -1243,28 +1521,51 @@ static int sata_fsl_probe(struct of_device *ofdev,
ata_host_activate(host, irq, sata_fsl_interrupt, SATA_FSL_IRQ_FLAG,
&sata_fsl_sht);
- dev_set_drvdata(&ofdev->dev, host);
+ platform_set_drvdata(ofdev, host);
+
+ host_priv->intr_coalescing.show = fsl_sata_intr_coalescing_show;
+ host_priv->intr_coalescing.store = fsl_sata_intr_coalescing_store;
+ sysfs_attr_init(&host_priv->intr_coalescing.attr);
+ host_priv->intr_coalescing.attr.name = "intr_coalescing";
+ host_priv->intr_coalescing.attr.mode = S_IRUGO | S_IWUSR;
+ retval = device_create_file(host->dev, &host_priv->intr_coalescing);
+ if (retval)
+ goto error_exit_with_cleanup;
+
+ host_priv->rx_watermark.show = fsl_sata_rx_watermark_show;
+ host_priv->rx_watermark.store = fsl_sata_rx_watermark_store;
+ sysfs_attr_init(&host_priv->rx_watermark.attr);
+ host_priv->rx_watermark.attr.name = "rx_watermark";
+ host_priv->rx_watermark.attr.mode = S_IRUGO | S_IWUSR;
+ retval = device_create_file(host->dev, &host_priv->rx_watermark);
+ if (retval) {
+ device_remove_file(&ofdev->dev, &host_priv->intr_coalescing);
+ goto error_exit_with_cleanup;
+ }
return 0;
error_exit_with_cleanup:
+ if (host)
+ ata_host_detach(host);
+
if (hcr_base)
iounmap(hcr_base);
- if (host_priv)
- kfree(host_priv);
+ kfree(host_priv);
return retval;
}
-static int sata_fsl_remove(struct of_device *ofdev)
+static int sata_fsl_remove(struct platform_device *ofdev)
{
- struct ata_host *host = dev_get_drvdata(&ofdev->dev);
+ struct ata_host *host = platform_get_drvdata(ofdev);
struct sata_fsl_host_priv *host_priv = host->private_data;
- ata_host_detach(host);
+ device_remove_file(&ofdev->dev, &host_priv->intr_coalescing);
+ device_remove_file(&ofdev->dev, &host_priv->rx_watermark);
- dev_set_drvdata(&ofdev->dev, NULL);
+ ata_host_detach(host);
irq_dispose_mapping(host_priv->irq);
iounmap(host_priv->hcr_base);
@@ -1273,37 +1574,71 @@ static int sata_fsl_remove(struct of_device *ofdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int sata_fsl_suspend(struct platform_device *op, pm_message_t state)
+{
+ struct ata_host *host = platform_get_drvdata(op);
+ return ata_host_suspend(host, state);
+}
+
+static int sata_fsl_resume(struct platform_device *op)
+{
+ struct ata_host *host = platform_get_drvdata(op);
+ struct sata_fsl_host_priv *host_priv = host->private_data;
+ int ret;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ struct ata_port *ap = host->ports[0];
+ struct sata_fsl_port_priv *pp = ap->private_data;
+
+ ret = sata_fsl_init_controller(host);
+ if (ret) {
+ dev_err(&op->dev, "Error initializing hardware\n");
+ return ret;
+ }
+
+ /* Recovery the CHBA register in host controller cmd register set */
+ iowrite32(pp->cmdslot_paddr & 0xffffffff, hcr_base + CHBA);
+
+ iowrite32((ioread32(hcr_base + HCONTROL)
+ | HCONTROL_ONLINE_PHY_RST
+ | HCONTROL_SNOOP_ENABLE
+ | HCONTROL_PMP_ATTACHED),
+ hcr_base + HCONTROL);
+
+ ata_host_resume(host);
+ return 0;
+}
+#endif
+
static struct of_device_id fsl_sata_match[] = {
{
.compatible = "fsl,pq-sata",
},
+ {
+ .compatible = "fsl,pq-sata-v2",
+ },
{},
};
MODULE_DEVICE_TABLE(of, fsl_sata_match);
-static struct of_platform_driver fsl_sata_driver = {
- .name = "fsl-sata",
- .match_table = fsl_sata_match,
+static struct platform_driver fsl_sata_driver = {
+ .driver = {
+ .name = "fsl-sata",
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_sata_match,
+ },
.probe = sata_fsl_probe,
.remove = sata_fsl_remove,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = sata_fsl_suspend,
+ .resume = sata_fsl_resume,
+#endif
};
-static int __init sata_fsl_init(void)
-{
- of_register_platform_driver(&fsl_sata_driver);
- return 0;
-}
-
-static void __exit sata_fsl_exit(void)
-{
- of_unregister_platform_driver(&fsl_sata_driver);
-}
+module_platform_driver(fsl_sata_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ashish Kalra, Freescale Semiconductor");
MODULE_DESCRIPTION("Freescale 3.0Gbps SATA controller low level driver");
MODULE_VERSION("1.10");
-
-module_init(sata_fsl_init);
-module_exit(sata_fsl_exit);
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
new file mode 100644
index 00000000000..65965cf5af0
--- /dev/null
+++ b/drivers/ata/sata_highbank.c
@@ -0,0 +1,650 @@
+/*
+ * Calxeda Highbank AHCI SATA platform driver
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/libata.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include "ahci.h"
+
+#define CPHY_MAP(dev, addr) ((((dev) & 0x1f) << 7) | (((addr) >> 9) & 0x7f))
+#define CPHY_ADDR(addr) (((addr) & 0x1ff) << 2)
+#define SERDES_CR_CTL 0x80a0
+#define SERDES_CR_ADDR 0x80a1
+#define SERDES_CR_DATA 0x80a2
+#define CR_BUSY 0x0001
+#define CR_START 0x0001
+#define CR_WR_RDN 0x0002
+#define CPHY_TX_INPUT_STS 0x2001
+#define CPHY_RX_INPUT_STS 0x2002
+#define CPHY_SATA_TX_OVERRIDE 0x8000
+#define CPHY_SATA_RX_OVERRIDE 0x4000
+#define CPHY_TX_OVERRIDE 0x2004
+#define CPHY_RX_OVERRIDE 0x2005
+#define SPHY_LANE 0x100
+#define SPHY_HALF_RATE 0x0001
+#define CPHY_SATA_DPLL_MODE 0x0700
+#define CPHY_SATA_DPLL_SHIFT 8
+#define CPHY_SATA_DPLL_RESET (1 << 11)
+#define CPHY_SATA_TX_ATTEN 0x1c00
+#define CPHY_SATA_TX_ATTEN_SHIFT 10
+#define CPHY_PHY_COUNT 6
+#define CPHY_LANE_COUNT 4
+#define CPHY_PORT_COUNT (CPHY_PHY_COUNT * CPHY_LANE_COUNT)
+
+static DEFINE_SPINLOCK(cphy_lock);
+/* Each of the 6 phys can have up to 4 sata ports attached to i. Map 0-based
+ * sata ports to their phys and then to their lanes within the phys
+ */
+struct phy_lane_info {
+ void __iomem *phy_base;
+ u8 lane_mapping;
+ u8 phy_devs;
+ u8 tx_atten;
+};
+static struct phy_lane_info port_data[CPHY_PORT_COUNT];
+
+static DEFINE_SPINLOCK(sgpio_lock);
+#define SCLOCK 0
+#define SLOAD 1
+#define SDATA 2
+#define SGPIO_PINS 3
+#define SGPIO_PORTS 8
+
+struct ecx_plat_data {
+ u32 n_ports;
+ /* number of extra clocks that the SGPIO PIC controller expects */
+ u32 pre_clocks;
+ u32 post_clocks;
+ unsigned sgpio_gpio[SGPIO_PINS];
+ u32 sgpio_pattern;
+ u32 port_to_sgpio[SGPIO_PORTS];
+};
+
+#define SGPIO_SIGNALS 3
+#define ECX_ACTIVITY_BITS 0x300000
+#define ECX_ACTIVITY_SHIFT 0
+#define ECX_LOCATE_BITS 0x80000
+#define ECX_LOCATE_SHIFT 1
+#define ECX_FAULT_BITS 0x400000
+#define ECX_FAULT_SHIFT 2
+static inline int sgpio_bit_shift(struct ecx_plat_data *pdata, u32 port,
+ u32 shift)
+{
+ return 1 << (3 * pdata->port_to_sgpio[port] + shift);
+}
+
+static void ecx_parse_sgpio(struct ecx_plat_data *pdata, u32 port, u32 state)
+{
+ if (state & ECX_ACTIVITY_BITS)
+ pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
+ ECX_ACTIVITY_SHIFT);
+ else
+ pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
+ ECX_ACTIVITY_SHIFT);
+ if (state & ECX_LOCATE_BITS)
+ pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
+ ECX_LOCATE_SHIFT);
+ else
+ pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
+ ECX_LOCATE_SHIFT);
+ if (state & ECX_FAULT_BITS)
+ pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
+ ECX_FAULT_SHIFT);
+ else
+ pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
+ ECX_FAULT_SHIFT);
+}
+
+/*
+ * Tell the LED controller that the signal has changed by raising the clock
+ * line for 50 uS and then lowering it for 50 uS.
+ */
+static void ecx_led_cycle_clock(struct ecx_plat_data *pdata)
+{
+ gpio_set_value(pdata->sgpio_gpio[SCLOCK], 1);
+ udelay(50);
+ gpio_set_value(pdata->sgpio_gpio[SCLOCK], 0);
+ udelay(50);
+}
+
+static ssize_t ecx_transmit_led_message(struct ata_port *ap, u32 state,
+ ssize_t size)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ecx_plat_data *pdata = hpriv->plat_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ unsigned long flags;
+ int pmp, i;
+ struct ahci_em_priv *emp;
+ u32 sgpio_out;
+
+ /* get the slot number from the message */
+ pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
+ if (pmp < EM_MAX_SLOTS)
+ emp = &pp->em_priv[pmp];
+ else
+ return -EINVAL;
+
+ if (!(hpriv->em_msg_type & EM_MSG_TYPE_LED))
+ return size;
+
+ spin_lock_irqsave(&sgpio_lock, flags);
+ ecx_parse_sgpio(pdata, ap->port_no, state);
+ sgpio_out = pdata->sgpio_pattern;
+ for (i = 0; i < pdata->pre_clocks; i++)
+ ecx_led_cycle_clock(pdata);
+
+ gpio_set_value(pdata->sgpio_gpio[SLOAD], 1);
+ ecx_led_cycle_clock(pdata);
+ gpio_set_value(pdata->sgpio_gpio[SLOAD], 0);
+ /*
+ * bit-bang out the SGPIO pattern, by consuming a bit and then
+ * clocking it out.
+ */
+ for (i = 0; i < (SGPIO_SIGNALS * pdata->n_ports); i++) {
+ gpio_set_value(pdata->sgpio_gpio[SDATA], sgpio_out & 1);
+ sgpio_out >>= 1;
+ ecx_led_cycle_clock(pdata);
+ }
+ for (i = 0; i < pdata->post_clocks; i++)
+ ecx_led_cycle_clock(pdata);
+
+ /* save off new led state for port/slot */
+ emp->led_state = state;
+
+ spin_unlock_irqrestore(&sgpio_lock, flags);
+ return size;
+}
+
+static void highbank_set_em_messages(struct device *dev,
+ struct ahci_host_priv *hpriv,
+ struct ata_port_info *pi)
+{
+ struct device_node *np = dev->of_node;
+ struct ecx_plat_data *pdata = hpriv->plat_data;
+ int i;
+ int err;
+
+ for (i = 0; i < SGPIO_PINS; i++) {
+ err = of_get_named_gpio(np, "calxeda,sgpio-gpio", i);
+ if (IS_ERR_VALUE(err))
+ return;
+
+ pdata->sgpio_gpio[i] = err;
+ err = gpio_request(pdata->sgpio_gpio[i], "CX SGPIO");
+ if (err) {
+ pr_err("sata_highbank gpio_request %d failed: %d\n",
+ i, err);
+ return;
+ }
+ gpio_direction_output(pdata->sgpio_gpio[i], 1);
+ }
+ of_property_read_u32_array(np, "calxeda,led-order",
+ pdata->port_to_sgpio,
+ pdata->n_ports);
+ if (of_property_read_u32(np, "calxeda,pre-clocks", &pdata->pre_clocks))
+ pdata->pre_clocks = 0;
+ if (of_property_read_u32(np, "calxeda,post-clocks",
+ &pdata->post_clocks))
+ pdata->post_clocks = 0;
+
+ /* store em_loc */
+ hpriv->em_loc = 0;
+ hpriv->em_buf_sz = 4;
+ hpriv->em_msg_type = EM_MSG_TYPE_LED;
+ pi->flags |= ATA_FLAG_EM | ATA_FLAG_SW_ACTIVITY;
+}
+
+static u32 __combo_phy_reg_read(u8 sata_port, u32 addr)
+{
+ u32 data;
+ u8 dev = port_data[sata_port].phy_devs;
+ spin_lock(&cphy_lock);
+ writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800);
+ data = readl(port_data[sata_port].phy_base + CPHY_ADDR(addr));
+ spin_unlock(&cphy_lock);
+ return data;
+}
+
+static void __combo_phy_reg_write(u8 sata_port, u32 addr, u32 data)
+{
+ u8 dev = port_data[sata_port].phy_devs;
+ spin_lock(&cphy_lock);
+ writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800);
+ writel(data, port_data[sata_port].phy_base + CPHY_ADDR(addr));
+ spin_unlock(&cphy_lock);
+}
+
+static void combo_phy_wait_for_ready(u8 sata_port)
+{
+ while (__combo_phy_reg_read(sata_port, SERDES_CR_CTL) & CR_BUSY)
+ udelay(5);
+}
+
+static u32 combo_phy_read(u8 sata_port, u32 addr)
+{
+ combo_phy_wait_for_ready(sata_port);
+ __combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr);
+ __combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_START);
+ combo_phy_wait_for_ready(sata_port);
+ return __combo_phy_reg_read(sata_port, SERDES_CR_DATA);
+}
+
+static void combo_phy_write(u8 sata_port, u32 addr, u32 data)
+{
+ combo_phy_wait_for_ready(sata_port);
+ __combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr);
+ __combo_phy_reg_write(sata_port, SERDES_CR_DATA, data);
+ __combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_WR_RDN | CR_START);
+}
+
+static void highbank_cphy_disable_overrides(u8 sata_port)
+{
+ u8 lane = port_data[sata_port].lane_mapping;
+ u32 tmp;
+ if (unlikely(port_data[sata_port].phy_base == NULL))
+ return;
+ tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
+ tmp &= ~CPHY_SATA_RX_OVERRIDE;
+ combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
+}
+
+static void cphy_override_tx_attenuation(u8 sata_port, u32 val)
+{
+ u8 lane = port_data[sata_port].lane_mapping;
+ u32 tmp;
+
+ if (val & 0x8)
+ return;
+
+ tmp = combo_phy_read(sata_port, CPHY_TX_INPUT_STS + lane * SPHY_LANE);
+ tmp &= ~CPHY_SATA_TX_OVERRIDE;
+ combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
+
+ tmp |= CPHY_SATA_TX_OVERRIDE;
+ combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
+
+ tmp |= (val << CPHY_SATA_TX_ATTEN_SHIFT) & CPHY_SATA_TX_ATTEN;
+ combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
+}
+
+static void cphy_override_rx_mode(u8 sata_port, u32 val)
+{
+ u8 lane = port_data[sata_port].lane_mapping;
+ u32 tmp;
+ tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
+ tmp &= ~CPHY_SATA_RX_OVERRIDE;
+ combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
+
+ tmp |= CPHY_SATA_RX_OVERRIDE;
+ combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
+
+ tmp &= ~CPHY_SATA_DPLL_MODE;
+ tmp |= val << CPHY_SATA_DPLL_SHIFT;
+ combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
+
+ tmp |= CPHY_SATA_DPLL_RESET;
+ combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
+
+ tmp &= ~CPHY_SATA_DPLL_RESET;
+ combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
+
+ msleep(15);
+}
+
+static void highbank_cphy_override_lane(u8 sata_port)
+{
+ u8 lane = port_data[sata_port].lane_mapping;
+ u32 tmp, k = 0;
+
+ if (unlikely(port_data[sata_port].phy_base == NULL))
+ return;
+ do {
+ tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS +
+ lane * SPHY_LANE);
+ } while ((tmp & SPHY_HALF_RATE) && (k++ < 1000));
+ cphy_override_rx_mode(sata_port, 3);
+ cphy_override_tx_attenuation(sata_port, port_data[sata_port].tx_atten);
+}
+
+static int highbank_initialize_phys(struct device *dev, void __iomem *addr)
+{
+ struct device_node *sata_node = dev->of_node;
+ int phy_count = 0, phy, port = 0, i;
+ void __iomem *cphy_base[CPHY_PHY_COUNT] = {};
+ struct device_node *phy_nodes[CPHY_PHY_COUNT] = {};
+ u32 tx_atten[CPHY_PORT_COUNT] = {};
+
+ memset(port_data, 0, sizeof(struct phy_lane_info) * CPHY_PORT_COUNT);
+
+ do {
+ u32 tmp;
+ struct of_phandle_args phy_data;
+ if (of_parse_phandle_with_args(sata_node,
+ "calxeda,port-phys", "#phy-cells",
+ port, &phy_data))
+ break;
+ for (phy = 0; phy < phy_count; phy++) {
+ if (phy_nodes[phy] == phy_data.np)
+ break;
+ }
+ if (phy_nodes[phy] == NULL) {
+ phy_nodes[phy] = phy_data.np;
+ cphy_base[phy] = of_iomap(phy_nodes[phy], 0);
+ if (cphy_base[phy] == NULL) {
+ return 0;
+ }
+ phy_count += 1;
+ }
+ port_data[port].lane_mapping = phy_data.args[0];
+ of_property_read_u32(phy_nodes[phy], "phydev", &tmp);
+ port_data[port].phy_devs = tmp;
+ port_data[port].phy_base = cphy_base[phy];
+ of_node_put(phy_data.np);
+ port += 1;
+ } while (port < CPHY_PORT_COUNT);
+ of_property_read_u32_array(sata_node, "calxeda,tx-atten",
+ tx_atten, port);
+ for (i = 0; i < port; i++)
+ port_data[i].tx_atten = (u8) tx_atten[i];
+ return 0;
+}
+
+/*
+ * The Calxeda SATA phy intermittently fails to bring up a link with Gen3
+ * Retrying the phy hard reset can work around the issue, but the drive
+ * may fail again. In less than 150 out of 15000 test runs, it took more
+ * than 10 tries for the link to be established (but never more than 35).
+ * Triple the maximum observed retry count to provide plenty of margin for
+ * rare events and to guarantee that the link is established.
+ *
+ * Also, the default 2 second time-out on a failed drive is too long in
+ * this situation. The uboot implementation of the same driver function
+ * uses a much shorter time-out period and never experiences a time out
+ * issue. Reducing the time-out to 500ms improves the responsiveness.
+ * The other timing constants were kept the same as the stock AHCI driver.
+ * This change was also tested 15000 times on 24 drives and none of them
+ * experienced a time out.
+ */
+static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ static const unsigned long timing[] = { 5, 100, 500};
+ struct ata_port *ap = link->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ struct ata_taskfile tf;
+ bool online;
+ u32 sstatus;
+ int rc;
+ int retry = 100;
+
+ ahci_stop_engine(ap);
+
+ /* clear D2H reception area to properly wait for D2H FIS */
+ ata_tf_init(link->device, &tf);
+ tf.command = ATA_BUSY;
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+
+ do {
+ highbank_cphy_disable_overrides(link->ap->port_no);
+ rc = sata_link_hardreset(link, timing, deadline, &online, NULL);
+ highbank_cphy_override_lane(link->ap->port_no);
+
+ /* If the status is 1, we are connected, but the link did not
+ * come up. So retry resetting the link again.
+ */
+ if (sata_scr_read(link, SCR_STATUS, &sstatus))
+ break;
+ if (!(sstatus & 0x3))
+ break;
+ } while (!online && retry--);
+
+ hpriv->start_engine(ap);
+
+ if (online)
+ *class = ahci_dev_classify(ap);
+
+ return rc;
+}
+
+static struct ata_port_operations ahci_highbank_ops = {
+ .inherits = &ahci_ops,
+ .hardreset = ahci_highbank_hardreset,
+ .transmit_led_message = ecx_transmit_led_message,
+};
+
+static const struct ata_port_info ahci_highbank_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_highbank_ops,
+};
+
+static struct scsi_host_template ahci_highbank_platform_sht = {
+ AHCI_SHT("sata_highbank"),
+};
+
+static const struct of_device_id ahci_of_match[] = {
+ { .compatible = "calxeda,hb-ahci" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ahci_of_match);
+
+static int ahci_highbank_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct ecx_plat_data *pdata;
+ struct ata_host *host;
+ struct resource *mem;
+ int irq;
+ int i;
+ int rc;
+ u32 n_ports;
+ struct ata_port_info pi = ahci_highbank_port_info;
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(dev, "no mmio space\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(dev, "no irq\n");
+ return -EINVAL;
+ }
+
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv) {
+ dev_err(dev, "can't alloc ahci_host_priv\n");
+ return -ENOMEM;
+ }
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "can't alloc ecx_plat_data\n");
+ return -ENOMEM;
+ }
+
+ hpriv->flags |= (unsigned long)pi.private_data;
+
+ hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
+ if (!hpriv->mmio) {
+ dev_err(dev, "can't map %pR\n", mem);
+ return -ENOMEM;
+ }
+
+ rc = highbank_initialize_phys(dev, hpriv->mmio);
+ if (rc)
+ return rc;
+
+
+ ahci_save_initial_config(dev, hpriv, 0, 0);
+
+ /* prepare host */
+ if (hpriv->cap & HOST_CAP_NCQ)
+ pi.flags |= ATA_FLAG_NCQ;
+
+ if (hpriv->cap & HOST_CAP_PMP)
+ pi.flags |= ATA_FLAG_PMP;
+
+ if (hpriv->cap & HOST_CAP_64)
+ dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
+
+ /* CAP.NP sometimes indicate the index of the last enabled
+ * port, at other times, that of the last possible port, so
+ * determining the maximum port number requires looking at
+ * both CAP.NP and port_map.
+ */
+ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+ pdata->n_ports = n_ports;
+ hpriv->plat_data = pdata;
+ highbank_set_em_messages(dev, hpriv, &pi);
+
+ host = ata_host_alloc_pinfo(dev, ppi, n_ports);
+ if (!host) {
+ rc = -ENOMEM;
+ goto err0;
+ }
+
+ host->private_data = hpriv;
+
+ if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ ata_port_desc(ap, "mmio %pR", mem);
+ ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
+
+ /* set enclosure management message type */
+ if (ap->flags & ATA_FLAG_EM)
+ ap->em_message_type = hpriv->em_msg_type;
+
+ /* disabled/not-implemented port */
+ if (!(hpriv->port_map & (1 << i)))
+ ap->ops = &ata_dummy_port_ops;
+ }
+
+ rc = ahci_reset_controller(host);
+ if (rc)
+ goto err0;
+
+ ahci_init_controller(host);
+ ahci_print_info(host, "platform");
+
+ rc = ata_host_activate(host, irq, ahci_interrupt, 0,
+ &ahci_highbank_platform_sht);
+ if (rc)
+ goto err0;
+
+ return 0;
+err0:
+ return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ahci_highbank_suspend(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ u32 ctl;
+ int rc;
+
+ if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
+ dev_err(dev, "firmware update required for suspend/resume\n");
+ return -EIO;
+ }
+
+ /*
+ * AHCI spec rev1.1 section 8.3.3:
+ * Software must disable interrupts prior to requesting a
+ * transition of the HBA to D3 state.
+ */
+ ctl = readl(mmio + HOST_CTL);
+ ctl &= ~HOST_IRQ_EN;
+ writel(ctl, mmio + HOST_CTL);
+ readl(mmio + HOST_CTL); /* flush */
+
+ rc = ata_host_suspend(host, PMSG_SUSPEND);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static int ahci_highbank_resume(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ int rc;
+
+ if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(host);
+ }
+
+ ata_host_resume(host);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ahci_highbank_pm_ops,
+ ahci_highbank_suspend, ahci_highbank_resume);
+
+static struct platform_driver ahci_highbank_driver = {
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "highbank-ahci",
+ .owner = THIS_MODULE,
+ .of_match_table = ahci_of_match,
+ .pm = &ahci_highbank_pm_ops,
+ },
+ .probe = ahci_highbank_probe,
+};
+
+module_platform_driver(ahci_highbank_driver);
+
+MODULE_DESCRIPTION("Calxeda Highbank AHCI SATA platform driver");
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("sata:highbank");
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index d27bb9a2568..069827826b2 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -6,19 +6,52 @@
*
* This file is released under GPL v2.
*
+ * **** WARNING ****
+ *
+ * This driver never worked properly and unfortunately data corruption is
+ * relatively common. There isn't anyone working on the driver and there's
+ * no support from the vendor. Do not use this driver in any production
+ * environment.
+ *
+ * http://thread.gmane.org/gmane.linux.debian.devel.bugs.rc/378525/focus=54491
+ * https://bugzilla.kernel.org/show_bug.cgi?id=60565
+ *
+ * *****************
+ *
* This controller is eccentric and easily locks up if something isn't
* right. Documentation is available at initio's website but it only
* documents registers (not programming model).
*
- * - ATA disks work.
- * - Hotplug works.
- * - ATAPI read works but burning doesn't. This thing is really
- * peculiar about ATAPI and I couldn't figure out how ATAPI PIO and
- * ATAPI DMA WRITE should be programmed. If you've got a clue, be
- * my guest.
- * - Both STR and STD work.
+ * This driver has interesting history. The first version was written
+ * from the documentation and a 2.4 IDE driver posted on a Taiwan
+ * company, which didn't use any IDMA features and couldn't handle
+ * LBA48. The resulting driver couldn't handle LBA48 devices either
+ * making it pretty useless.
+ *
+ * After a while, initio picked the driver up, renamed it to
+ * sata_initio162x, updated it to use IDMA for ATA DMA commands and
+ * posted it on their website. It only used ATA_PROT_DMA for IDMA and
+ * attaching both devices and issuing IDMA and !IDMA commands
+ * simultaneously broke it due to PIRQ masking interaction but it did
+ * show how to use the IDMA (ADMA + some initio specific twists)
+ * engine.
+ *
+ * Then, I picked up their changes again and here's the usable driver
+ * which uses IDMA for everything. Everything works now including
+ * LBA48, CD/DVD burning, suspend/resume and hotplug. There are some
+ * issues tho. Result Tf is not resported properly, NCQ isn't
+ * supported yet and CD/DVD writing works with DMA assisted PIO
+ * protocol (which, for native SATA devices, shouldn't cause any
+ * noticeable difference).
+ *
+ * Anyways, so, here's finally a working driver for inic162x. Enjoy!
+ *
+ * initio: If you guys wanna improve the driver regarding result TF
+ * access and other stuff, please feel free to contact me. I'll be
+ * happy to assist.
*/
+#include <linux/gfp.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -28,13 +61,19 @@
#include <scsi/scsi_device.h>
#define DRV_NAME "sata_inic162x"
-#define DRV_VERSION "0.3"
+#define DRV_VERSION "0.4"
enum {
- MMIO_BAR = 5,
+ MMIO_BAR_PCI = 5,
+ MMIO_BAR_CARDBUS = 1,
NR_PORTS = 2,
+ IDMA_CPB_TBL_SIZE = 4 * 32,
+
+ INIC_DMA_BOUNDARY = 0xffffff,
+
+ HOST_ACTRL = 0x08,
HOST_CTL = 0x7c,
HOST_STAT = 0x7e,
HOST_IRQ_STAT = 0xbc,
@@ -43,22 +82,38 @@ enum {
PORT_SIZE = 0x40,
/* registers for ATA TF operation */
- PORT_TF = 0x00,
- PORT_ALT_STAT = 0x08,
+ PORT_TF_DATA = 0x00,
+ PORT_TF_FEATURE = 0x01,
+ PORT_TF_NSECT = 0x02,
+ PORT_TF_LBAL = 0x03,
+ PORT_TF_LBAM = 0x04,
+ PORT_TF_LBAH = 0x05,
+ PORT_TF_DEVICE = 0x06,
+ PORT_TF_COMMAND = 0x07,
+ PORT_TF_ALT_STAT = 0x08,
PORT_IRQ_STAT = 0x09,
PORT_IRQ_MASK = 0x0a,
PORT_PRD_CTL = 0x0b,
PORT_PRD_ADDR = 0x0c,
PORT_PRD_XFERLEN = 0x10,
+ PORT_CPB_CPBLAR = 0x18,
+ PORT_CPB_PTQFIFO = 0x1c,
/* IDMA register */
PORT_IDMA_CTL = 0x14,
+ PORT_IDMA_STAT = 0x16,
+
+ PORT_RPQ_FIFO = 0x1e,
+ PORT_RPQ_CNT = 0x1f,
PORT_SCR = 0x20,
/* HOST_CTL bits */
+ HCTL_LEDEN = (1 << 3), /* enable LED operation */
HCTL_IRQOFF = (1 << 8), /* global IRQ off */
- HCTL_PWRDWN = (1 << 13), /* power down PHYs */
+ HCTL_FTHD0 = (1 << 10), /* fifo threshold 0 */
+ HCTL_FTHD1 = (1 << 11), /* fifo threshold 1*/
+ HCTL_PWRDWN = (1 << 12), /* power down PHYs */
HCTL_SOFTRST = (1 << 13), /* global reset (no phy reset) */
HCTL_RPGSEL = (1 << 15), /* register page select */
@@ -81,9 +136,7 @@ enum {
PIRQ_PENDING = (1 << 7), /* port IRQ pending (STAT only) */
PIRQ_ERR = PIRQ_OFFLINE | PIRQ_ONLINE | PIRQ_FATAL,
-
- PIRQ_MASK_DMA_READ = PIRQ_REPLY | PIRQ_ATA,
- PIRQ_MASK_OTHER = PIRQ_REPLY | PIRQ_COMPLETE,
+ PIRQ_MASK_DEFAULT = PIRQ_REPLY | PIRQ_ATA,
PIRQ_MASK_FREEZE = 0xff,
/* PORT_PRD_CTL bits */
@@ -96,20 +149,104 @@ enum {
IDMA_CTL_RST_IDMA = (1 << 5), /* reset IDMA machinary */
IDMA_CTL_GO = (1 << 7), /* IDMA mode go */
IDMA_CTL_ATA_NIEN = (1 << 8), /* ATA IRQ disable */
+
+ /* PORT_IDMA_STAT bits */
+ IDMA_STAT_PERR = (1 << 0), /* PCI ERROR MODE */
+ IDMA_STAT_CPBERR = (1 << 1), /* ADMA CPB error */
+ IDMA_STAT_LGCY = (1 << 3), /* ADMA legacy */
+ IDMA_STAT_UIRQ = (1 << 4), /* ADMA unsolicited irq */
+ IDMA_STAT_STPD = (1 << 5), /* ADMA stopped */
+ IDMA_STAT_PSD = (1 << 6), /* ADMA pause */
+ IDMA_STAT_DONE = (1 << 7), /* ADMA done */
+
+ IDMA_STAT_ERR = IDMA_STAT_PERR | IDMA_STAT_CPBERR,
+
+ /* CPB Control Flags*/
+ CPB_CTL_VALID = (1 << 0), /* CPB valid */
+ CPB_CTL_QUEUED = (1 << 1), /* queued command */
+ CPB_CTL_DATA = (1 << 2), /* data, rsvd in datasheet */
+ CPB_CTL_IEN = (1 << 3), /* PCI interrupt enable */
+ CPB_CTL_DEVDIR = (1 << 4), /* device direction control */
+
+ /* CPB Response Flags */
+ CPB_RESP_DONE = (1 << 0), /* ATA command complete */
+ CPB_RESP_REL = (1 << 1), /* ATA release */
+ CPB_RESP_IGNORED = (1 << 2), /* CPB ignored */
+ CPB_RESP_ATA_ERR = (1 << 3), /* ATA command error */
+ CPB_RESP_SPURIOUS = (1 << 4), /* ATA spurious interrupt error */
+ CPB_RESP_UNDERFLOW = (1 << 5), /* APRD deficiency length error */
+ CPB_RESP_OVERFLOW = (1 << 6), /* APRD exccess length error */
+ CPB_RESP_CPB_ERR = (1 << 7), /* CPB error flag */
+
+ /* PRD Control Flags */
+ PRD_DRAIN = (1 << 1), /* ignore data excess */
+ PRD_CDB = (1 << 2), /* atapi packet command pointer */
+ PRD_DIRECT_INTR = (1 << 3), /* direct interrupt */
+ PRD_DMA = (1 << 4), /* data transfer method */
+ PRD_WRITE = (1 << 5), /* data dir, rsvd in datasheet */
+ PRD_IOM = (1 << 6), /* io/memory transfer */
+ PRD_END = (1 << 7), /* APRD chain end */
};
+/* Comman Parameter Block */
+struct inic_cpb {
+ u8 resp_flags; /* Response Flags */
+ u8 error; /* ATA Error */
+ u8 status; /* ATA Status */
+ u8 ctl_flags; /* Control Flags */
+ __le32 len; /* Total Transfer Length */
+ __le32 prd; /* First PRD pointer */
+ u8 rsvd[4];
+ /* 16 bytes */
+ u8 feature; /* ATA Feature */
+ u8 hob_feature; /* ATA Ex. Feature */
+ u8 device; /* ATA Device/Head */
+ u8 mirctl; /* Mirror Control */
+ u8 nsect; /* ATA Sector Count */
+ u8 hob_nsect; /* ATA Ex. Sector Count */
+ u8 lbal; /* ATA Sector Number */
+ u8 hob_lbal; /* ATA Ex. Sector Number */
+ u8 lbam; /* ATA Cylinder Low */
+ u8 hob_lbam; /* ATA Ex. Cylinder Low */
+ u8 lbah; /* ATA Cylinder High */
+ u8 hob_lbah; /* ATA Ex. Cylinder High */
+ u8 command; /* ATA Command */
+ u8 ctl; /* ATA Control */
+ u8 slave_error; /* Slave ATA Error */
+ u8 slave_status; /* Slave ATA Status */
+ /* 32 bytes */
+} __packed;
+
+/* Physical Region Descriptor */
+struct inic_prd {
+ __le32 mad; /* Physical Memory Address */
+ __le16 len; /* Transfer Length */
+ u8 rsvd;
+ u8 flags; /* Control Flags */
+} __packed;
+
+struct inic_pkt {
+ struct inic_cpb cpb;
+ struct inic_prd prd[LIBATA_MAX_PRD + 1]; /* + 1 for cdb */
+ u8 cdb[ATAPI_CDB_LEN];
+} __packed;
+
struct inic_host_priv {
- u16 cached_hctl;
+ void __iomem *mmio_base;
+ u16 cached_hctl;
};
struct inic_port_priv {
- u8 dfl_prdctl;
- u8 cached_prdctl;
- u8 cached_pirq_mask;
+ struct inic_pkt *pkt;
+ dma_addr_t pkt_dma;
+ u32 *cpb_tbl;
+ dma_addr_t cpb_tbl_dma;
};
static struct scsi_host_template inic_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
+ ATA_BASE_SHT(DRV_NAME),
+ .sg_tablesize = LIBATA_MAX_PRD, /* maybe it can be larger? */
+ .dma_boundary = INIC_DMA_BOUNDARY,
};
static const int scr_map[] = {
@@ -120,60 +257,38 @@ static const int scr_map[] = {
static void __iomem *inic_port_base(struct ata_port *ap)
{
- return ap->host->iomap[MMIO_BAR] + ap->port_no * PORT_SIZE;
-}
-
-static void __inic_set_pirq_mask(struct ata_port *ap, u8 mask)
-{
- void __iomem *port_base = inic_port_base(ap);
- struct inic_port_priv *pp = ap->private_data;
+ struct inic_host_priv *hpriv = ap->host->private_data;
- writeb(mask, port_base + PORT_IRQ_MASK);
- pp->cached_pirq_mask = mask;
-}
-
-static void inic_set_pirq_mask(struct ata_port *ap, u8 mask)
-{
- struct inic_port_priv *pp = ap->private_data;
-
- if (pp->cached_pirq_mask != mask)
- __inic_set_pirq_mask(ap, mask);
+ return hpriv->mmio_base + ap->port_no * PORT_SIZE;
}
static void inic_reset_port(void __iomem *port_base)
{
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
- u16 ctl;
- ctl = readw(idma_ctl);
- ctl &= ~(IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN | IDMA_CTL_GO);
+ /* stop IDMA engine */
+ readw(idma_ctl); /* flush */
+ msleep(1);
/* mask IRQ and assert reset */
- writew(ctl | IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN, idma_ctl);
+ writew(IDMA_CTL_RST_IDMA, idma_ctl);
readw(idma_ctl); /* flush */
-
- /* give it some time */
msleep(1);
/* release reset */
- writew(ctl | IDMA_CTL_ATA_NIEN, idma_ctl);
+ writew(0, idma_ctl);
/* clear irq */
writeb(0xff, port_base + PORT_IRQ_STAT);
-
- /* reenable ATA IRQ, turn off IDMA mode */
- writew(ctl, idma_ctl);
}
-static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
+static int inic_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val)
{
- void __iomem *scr_addr = ap->ioaddr.scr_addr;
- void __iomem *addr;
+ void __iomem *scr_addr = inic_port_base(link->ap) + PORT_SCR;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
return -EINVAL;
- addr = scr_addr + scr_map[sc_reg] * 4;
*val = readl(scr_addr + scr_map[sc_reg] * 4);
/* this controller has stuck DIAG.N, ignore it */
@@ -182,144 +297,138 @@ static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
return 0;
}
-static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int inic_scr_write(struct ata_link *link, unsigned sc_reg, u32 val)
{
- void __iomem *scr_addr = ap->ioaddr.scr_addr;
- void __iomem *addr;
+ void __iomem *scr_addr = inic_port_base(link->ap) + PORT_SCR;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
return -EINVAL;
- addr = scr_addr + scr_map[sc_reg] * 4;
writel(val, scr_addr + scr_map[sc_reg] * 4);
return 0;
}
-/*
- * In TF mode, inic162x is very similar to SFF device. TF registers
- * function the same. DMA engine behaves similary using the same PRD
- * format as BMDMA but different command register, interrupt and event
- * notification methods are used. The following inic_bmdma_*()
- * functions do the impedance matching.
- */
-static void inic_bmdma_setup(struct ata_queued_cmd *qc)
+static void inic_stop_idma(struct ata_port *ap)
{
- struct ata_port *ap = qc->ap;
- struct inic_port_priv *pp = ap->private_data;
void __iomem *port_base = inic_port_base(ap);
- int rw = qc->tf.flags & ATA_TFLAG_WRITE;
-
- /* make sure device sees PRD table writes */
- wmb();
- /* load transfer length */
- writel(qc->nbytes, port_base + PORT_PRD_XFERLEN);
-
- /* turn on DMA and specify data direction */
- pp->cached_prdctl = pp->dfl_prdctl | PRD_CTL_DMAEN;
- if (!rw)
- pp->cached_prdctl |= PRD_CTL_WR;
- writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
-
- /* issue r/w command */
- ap->ops->sff_exec_command(ap, &qc->tf);
+ readb(port_base + PORT_RPQ_FIFO);
+ readb(port_base + PORT_RPQ_CNT);
+ writew(0, port_base + PORT_IDMA_CTL);
}
-static void inic_bmdma_start(struct ata_queued_cmd *qc)
+static void inic_host_err_intr(struct ata_port *ap, u8 irq_stat, u16 idma_stat)
{
- struct ata_port *ap = qc->ap;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
struct inic_port_priv *pp = ap->private_data;
- void __iomem *port_base = inic_port_base(ap);
+ struct inic_cpb *cpb = &pp->pkt->cpb;
+ bool freeze = false;
- /* start host DMA transaction */
- pp->cached_prdctl |= PRD_CTL_START;
- writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
-}
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "irq_stat=0x%x idma_stat=0x%x",
+ irq_stat, idma_stat);
-static void inic_bmdma_stop(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct inic_port_priv *pp = ap->private_data;
- void __iomem *port_base = inic_port_base(ap);
+ inic_stop_idma(ap);
- /* stop DMA engine */
- writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
-}
+ if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) {
+ ata_ehi_push_desc(ehi, "hotplug");
+ ata_ehi_hotplugged(ehi);
+ freeze = true;
+ }
-static u8 inic_bmdma_status(struct ata_port *ap)
-{
- /* event is already verified by the interrupt handler */
- return ATA_DMA_INTR;
+ if (idma_stat & IDMA_STAT_PERR) {
+ ata_ehi_push_desc(ehi, "PCI error");
+ freeze = true;
+ }
+
+ if (idma_stat & IDMA_STAT_CPBERR) {
+ ata_ehi_push_desc(ehi, "CPB error");
+
+ if (cpb->resp_flags & CPB_RESP_IGNORED) {
+ __ata_ehi_push_desc(ehi, " ignored");
+ ehi->err_mask |= AC_ERR_INVALID;
+ freeze = true;
+ }
+
+ if (cpb->resp_flags & CPB_RESP_ATA_ERR)
+ ehi->err_mask |= AC_ERR_DEV;
+
+ if (cpb->resp_flags & CPB_RESP_SPURIOUS) {
+ __ata_ehi_push_desc(ehi, " spurious-intr");
+ ehi->err_mask |= AC_ERR_HSM;
+ freeze = true;
+ }
+
+ if (cpb->resp_flags &
+ (CPB_RESP_UNDERFLOW | CPB_RESP_OVERFLOW)) {
+ __ata_ehi_push_desc(ehi, " data-over/underflow");
+ ehi->err_mask |= AC_ERR_HSM;
+ freeze = true;
+ }
+ }
+
+ if (freeze)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
}
static void inic_host_intr(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- struct ata_eh_info *ehi = &ap->link.eh_info;
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
u8 irq_stat;
+ u16 idma_stat;
- /* fetch and clear irq */
+ /* read and clear IRQ status */
irq_stat = readb(port_base + PORT_IRQ_STAT);
writeb(irq_stat, port_base + PORT_IRQ_STAT);
+ idma_stat = readw(port_base + PORT_IDMA_STAT);
- if (likely(!(irq_stat & PIRQ_ERR))) {
- struct ata_queued_cmd *qc =
- ata_qc_from_tag(ap, ap->link.active_tag);
+ if (unlikely((irq_stat & PIRQ_ERR) || (idma_stat & IDMA_STAT_ERR)))
+ inic_host_err_intr(ap, irq_stat, idma_stat);
- if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
- ap->ops->sff_check_status(ap); /* clear ATA interrupt */
- return;
- }
+ if (unlikely(!qc))
+ goto spurious;
+
+ if (likely(idma_stat & IDMA_STAT_DONE)) {
+ inic_stop_idma(ap);
- if (likely(ata_sff_host_intr(ap, qc)))
- return;
+ /* Depending on circumstances, device error
+ * isn't reported by IDMA, check it explicitly.
+ */
+ if (unlikely(readb(port_base + PORT_TF_COMMAND) &
+ (ATA_DF | ATA_ERR)))
+ qc->err_mask |= AC_ERR_DEV;
- ap->ops->sff_check_status(ap); /* clear ATA interrupt */
- ata_port_printk(ap, KERN_WARNING, "unhandled "
- "interrupt, irq_stat=%x\n", irq_stat);
+ ata_qc_complete(qc);
return;
}
- /* error */
- ata_ehi_push_desc(ehi, "irq_stat=0x%x", irq_stat);
-
- if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) {
- ata_ehi_hotplugged(ehi);
- ata_port_freeze(ap);
- } else
- ata_port_abort(ap);
+ spurious:
+ ata_port_warn(ap, "unhandled interrupt: cmd=0x%x irq_stat=0x%x idma_stat=0x%x\n",
+ qc ? qc->tf.command : 0xff, irq_stat, idma_stat);
}
static irqreturn_t inic_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
- void __iomem *mmio_base = host->iomap[MMIO_BAR];
+ struct inic_host_priv *hpriv = host->private_data;
u16 host_irq_stat;
- int i, handled = 0;;
+ int i, handled = 0;
- host_irq_stat = readw(mmio_base + HOST_IRQ_STAT);
+ host_irq_stat = readw(hpriv->mmio_base + HOST_IRQ_STAT);
if (unlikely(!(host_irq_stat & HIRQ_GLOBAL)))
goto out;
spin_lock(&host->lock);
- for (i = 0; i < NR_PORTS; i++) {
- struct ata_port *ap = host->ports[i];
-
- if (!(host_irq_stat & (HIRQ_PORT0 << i)))
- continue;
-
- if (likely(ap && !(ap->flags & ATA_FLAG_DISABLED))) {
- inic_host_intr(ap);
+ for (i = 0; i < NR_PORTS; i++)
+ if (host_irq_stat & (HIRQ_PORT0 << i)) {
+ inic_host_intr(host->ports[i]);
handled++;
- } else {
- if (ata_ratelimit())
- dev_printk(KERN_ERR, host->dev, "interrupt "
- "from disabled port %d (0x%x)\n",
- i, host_irq_stat);
}
- }
spin_unlock(&host->lock);
@@ -327,60 +436,173 @@ static irqreturn_t inic_interrupt(int irq, void *dev_instance)
return IRQ_RETVAL(handled);
}
+static int inic_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ /* For some reason ATAPI_PROT_DMA doesn't work for some
+ * commands including writes and other misc ops. Use PIO
+ * protocol instead, which BTW is driven by the DMA engine
+ * anyway, so it shouldn't make much difference for native
+ * SATA devices.
+ */
+ if (atapi_cmd_type(qc->cdb[0]) == READ)
+ return 0;
+ return 1;
+}
+
+static void inic_fill_sg(struct inic_prd *prd, struct ata_queued_cmd *qc)
+{
+ struct scatterlist *sg;
+ unsigned int si;
+ u8 flags = 0;
+
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ flags |= PRD_WRITE;
+
+ if (ata_is_dma(qc->tf.protocol))
+ flags |= PRD_DMA;
+
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ prd->mad = cpu_to_le32(sg_dma_address(sg));
+ prd->len = cpu_to_le16(sg_dma_len(sg));
+ prd->flags = flags;
+ prd++;
+ }
+
+ WARN_ON(!si);
+ prd[-1].flags |= PRD_END;
+}
+
+static void inic_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct inic_port_priv *pp = qc->ap->private_data;
+ struct inic_pkt *pkt = pp->pkt;
+ struct inic_cpb *cpb = &pkt->cpb;
+ struct inic_prd *prd = pkt->prd;
+ bool is_atapi = ata_is_atapi(qc->tf.protocol);
+ bool is_data = ata_is_data(qc->tf.protocol);
+ unsigned int cdb_len = 0;
+
+ VPRINTK("ENTER\n");
+
+ if (is_atapi)
+ cdb_len = qc->dev->cdb_len;
+
+ /* prepare packet, based on initio driver */
+ memset(pkt, 0, sizeof(struct inic_pkt));
+
+ cpb->ctl_flags = CPB_CTL_VALID | CPB_CTL_IEN;
+ if (is_atapi || is_data)
+ cpb->ctl_flags |= CPB_CTL_DATA;
+
+ cpb->len = cpu_to_le32(qc->nbytes + cdb_len);
+ cpb->prd = cpu_to_le32(pp->pkt_dma + offsetof(struct inic_pkt, prd));
+
+ cpb->device = qc->tf.device;
+ cpb->feature = qc->tf.feature;
+ cpb->nsect = qc->tf.nsect;
+ cpb->lbal = qc->tf.lbal;
+ cpb->lbam = qc->tf.lbam;
+ cpb->lbah = qc->tf.lbah;
+
+ if (qc->tf.flags & ATA_TFLAG_LBA48) {
+ cpb->hob_feature = qc->tf.hob_feature;
+ cpb->hob_nsect = qc->tf.hob_nsect;
+ cpb->hob_lbal = qc->tf.hob_lbal;
+ cpb->hob_lbam = qc->tf.hob_lbam;
+ cpb->hob_lbah = qc->tf.hob_lbah;
+ }
+
+ cpb->command = qc->tf.command;
+ /* don't load ctl - dunno why. it's like that in the initio driver */
+
+ /* setup PRD for CDB */
+ if (is_atapi) {
+ memcpy(pkt->cdb, qc->cdb, ATAPI_CDB_LEN);
+ prd->mad = cpu_to_le32(pp->pkt_dma +
+ offsetof(struct inic_pkt, cdb));
+ prd->len = cpu_to_le16(cdb_len);
+ prd->flags = PRD_CDB | PRD_WRITE;
+ if (!is_data)
+ prd->flags |= PRD_END;
+ prd++;
+ }
+
+ /* setup sg table */
+ if (is_data)
+ inic_fill_sg(prd, qc);
+
+ pp->cpb_tbl[0] = pp->pkt_dma;
+}
+
static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ void __iomem *port_base = inic_port_base(ap);
- /* ATA IRQ doesn't wait for DMA transfer completion and vice
- * versa. Mask IRQ selectively to detect command completion.
- * Without it, ATA DMA read command can cause data corruption.
- *
- * Something similar might be needed for ATAPI writes. I
- * tried a lot of combinations but couldn't find the solution.
- */
- if (qc->tf.protocol == ATA_PROT_DMA &&
- !(qc->tf.flags & ATA_TFLAG_WRITE))
- inic_set_pirq_mask(ap, PIRQ_MASK_DMA_READ);
- else
- inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
+ /* fire up the ADMA engine */
+ writew(HCTL_FTHD0 | HCTL_LEDEN, port_base + HOST_CTL);
+ writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL);
+ writeb(0, port_base + PORT_CPB_PTQFIFO);
+
+ return 0;
+}
- /* Issuing a command to yet uninitialized port locks up the
- * controller. Most of the time, this happens for the first
- * command after reset which are ATA and ATAPI IDENTIFYs.
- * Fast fail if stat is 0x7f or 0xff for those commands.
+static void inic_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ void __iomem *port_base = inic_port_base(ap);
+
+ tf->feature = readb(port_base + PORT_TF_FEATURE);
+ tf->nsect = readb(port_base + PORT_TF_NSECT);
+ tf->lbal = readb(port_base + PORT_TF_LBAL);
+ tf->lbam = readb(port_base + PORT_TF_LBAM);
+ tf->lbah = readb(port_base + PORT_TF_LBAH);
+ tf->device = readb(port_base + PORT_TF_DEVICE);
+ tf->command = readb(port_base + PORT_TF_COMMAND);
+}
+
+static bool inic_qc_fill_rtf(struct ata_queued_cmd *qc)
+{
+ struct ata_taskfile *rtf = &qc->result_tf;
+ struct ata_taskfile tf;
+
+ /* FIXME: Except for status and error, result TF access
+ * doesn't work. I tried reading from BAR0/2, CPB and BAR5.
+ * None works regardless of which command interface is used.
+ * For now return true iff status indicates device error.
+ * This means that we're reporting bogus sector for RW
+ * failures. Eeekk....
*/
- if (unlikely(qc->tf.command == ATA_CMD_ID_ATA ||
- qc->tf.command == ATA_CMD_ID_ATAPI)) {
- u8 stat = ap->ops->sff_check_status(ap);
- if (stat == 0x7f || stat == 0xff)
- return AC_ERR_HSM;
- }
+ inic_tf_read(qc->ap, &tf);
- return ata_sff_qc_issue(qc);
+ if (!(tf.command & ATA_ERR))
+ return false;
+
+ rtf->command = tf.command;
+ rtf->feature = tf.feature;
+ return true;
}
static void inic_freeze(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- __inic_set_pirq_mask(ap, PIRQ_MASK_FREEZE);
-
- ap->ops->sff_check_status(ap);
+ writeb(PIRQ_MASK_FREEZE, port_base + PORT_IRQ_MASK);
writeb(0xff, port_base + PORT_IRQ_STAT);
-
- readb(port_base + PORT_IRQ_STAT); /* flush */
}
static void inic_thaw(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- ap->ops->sff_check_status(ap);
writeb(0xff, port_base + PORT_IRQ_STAT);
+ writeb(PIRQ_MASK_DEFAULT, port_base + PORT_IRQ_MASK);
+}
- __inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
+static int inic_check_ready(struct ata_link *link)
+{
+ void __iomem *port_base = inic_port_base(link->ap);
- readb(port_base + PORT_IRQ_STAT); /* flush */
+ return ata_check_ready(readb(port_base + PORT_TF_COMMAND));
}
/*
@@ -394,22 +616,21 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
void __iomem *port_base = inic_port_base(ap);
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
- u16 val;
int rc;
/* hammer it into sane state */
inic_reset_port(port_base);
- val = readw(idma_ctl);
- writew(val | IDMA_CTL_RST_ATA, idma_ctl);
+ writew(IDMA_CTL_RST_ATA, idma_ctl);
readw(idma_ctl); /* flush */
- msleep(1);
- writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
+ ata_msleep(ap, 1);
+ writew(0, idma_ctl);
rc = sata_link_resume(link, timing, deadline);
if (rc) {
- ata_link_printk(link, KERN_WARNING, "failed to resume "
- "link after reset (errno=%d)\n", rc);
+ ata_link_warn(link,
+ "failed to resume link after reset (errno=%d)\n",
+ rc);
return rc;
}
@@ -418,15 +639,16 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
struct ata_taskfile tf;
/* wait for link to become ready */
- rc = ata_sff_wait_after_reset(link, 1, deadline);
+ rc = ata_wait_after_reset(link, deadline, inic_check_ready);
/* link occupied, -ENODEV too is an error */
if (rc) {
- ata_link_printk(link, KERN_WARNING, "device not ready "
- "after hardreset (errno=%d)\n", rc);
+ ata_link_warn(link,
+ "device not ready after hardreset (errno=%d)\n",
+ rc);
return rc;
}
- ata_sff_tf_read(ap, &tf);
+ inic_tf_read(ap, &tf);
*class = ata_dev_classify(&tf);
}
@@ -436,18 +658,8 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
static void inic_error_handler(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- struct inic_port_priv *pp = ap->private_data;
- unsigned long flags;
- /* reset PIO HSM and stop DMA engine */
inic_reset_port(port_base);
-
- spin_lock_irqsave(ap->lock, flags);
- ap->hsm_task_state = HSM_ST_IDLE;
- writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
- spin_unlock_irqrestore(ap->lock, flags);
-
- /* PIO and DMA engines have been stopped, perform recovery */
ata_std_error_handler(ap);
}
@@ -458,26 +670,17 @@ static void inic_post_internal_cmd(struct ata_queued_cmd *qc)
inic_reset_port(inic_port_base(qc->ap));
}
-static void inic_dev_config(struct ata_device *dev)
-{
- /* inic can only handle upto LBA28 max sectors */
- if (dev->max_sectors > ATA_MAX_SECTORS)
- dev->max_sectors = ATA_MAX_SECTORS;
-
- if (dev->n_sectors >= 1 << 28) {
- ata_dev_printk(dev, KERN_ERR,
- "ERROR: This driver doesn't support LBA48 yet and may cause\n"
- " data corruption on such devices. Disabling.\n");
- ata_dev_disable(dev);
- }
-}
-
static void init_port(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
+ struct inic_port_priv *pp = ap->private_data;
+
+ /* clear packet and CPB table */
+ memset(pp->pkt, 0, sizeof(struct inic_pkt));
+ memset(pp->cpb_tbl, 0, IDMA_CPB_TBL_SIZE);
- /* Setup PRD address */
- writel(ap->prd_dma, port_base + PORT_PRD_ADDR);
+ /* setup CPB lookup table addresses */
+ writel(pp->cpb_tbl_dma, port_base + PORT_CPB_CPBLAR);
}
static int inic_port_resume(struct ata_port *ap)
@@ -488,28 +691,25 @@ static int inic_port_resume(struct ata_port *ap)
static int inic_port_start(struct ata_port *ap)
{
- void __iomem *port_base = inic_port_base(ap);
+ struct device *dev = ap->host->dev;
struct inic_port_priv *pp;
- u8 tmp;
- int rc;
/* alloc and initialize private data */
- pp = devm_kzalloc(ap->host->dev, sizeof(*pp), GFP_KERNEL);
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
ap->private_data = pp;
- /* default PRD_CTL value, DMAEN, WR and START off */
- tmp = readb(port_base + PORT_PRD_CTL);
- tmp &= ~(PRD_CTL_DMAEN | PRD_CTL_WR | PRD_CTL_START);
- pp->dfl_prdctl = tmp;
-
/* Alloc resources */
- rc = ata_port_start(ap);
- if (rc) {
- kfree(pp);
- return rc;
- }
+ pp->pkt = dmam_alloc_coherent(dev, sizeof(struct inic_pkt),
+ &pp->pkt_dma, GFP_KERNEL);
+ if (!pp->pkt)
+ return -ENOMEM;
+
+ pp->cpb_tbl = dmam_alloc_coherent(dev, IDMA_CPB_TBL_SIZE,
+ &pp->cpb_tbl_dma, GFP_KERNEL);
+ if (!pp->cpb_tbl)
+ return -ENOMEM;
init_port(ap);
@@ -517,21 +717,18 @@ static int inic_port_start(struct ata_port *ap)
}
static struct ata_port_operations inic_port_ops = {
- .inherits = &ata_sff_port_ops,
+ .inherits = &sata_port_ops,
- .bmdma_setup = inic_bmdma_setup,
- .bmdma_start = inic_bmdma_start,
- .bmdma_stop = inic_bmdma_stop,
- .bmdma_status = inic_bmdma_status,
+ .check_atapi_dma = inic_check_atapi_dma,
+ .qc_prep = inic_qc_prep,
.qc_issue = inic_qc_issue,
+ .qc_fill_rtf = inic_qc_fill_rtf,
.freeze = inic_freeze,
.thaw = inic_thaw,
- .softreset = ATA_OP_NULL, /* softreset is broken */
.hardreset = inic_hardreset,
.error_handler = inic_error_handler,
.post_internal_cmd = inic_post_internal_cmd,
- .dev_config = inic_dev_config,
.scr_read = inic_scr_read,
.scr_write = inic_scr_write,
@@ -541,15 +738,9 @@ static struct ata_port_operations inic_port_ops = {
};
static struct ata_port_info inic_port_info = {
- /* For some reason, ATAPI_PROT_PIO is broken on this
- * controller, and no, PIO_POLLING does't fix it. It somehow
- * manages to report the wrong ireason and ignoring ireason
- * results in machine lock up. Tell libata to always prefer
- * DMA.
- */
.flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &inic_port_ops
};
@@ -594,12 +785,11 @@ static int init_controller(void __iomem *mmio_base, u16 hctl)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int inic_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
struct inic_host_priv *hpriv = host->private_data;
- void __iomem *mmio_base = host->iomap[MMIO_BAR];
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -607,7 +797,7 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
return rc;
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
- rc = init_controller(mmio_base, hpriv->cached_hctl);
+ rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl);
if (rc)
return rc;
}
@@ -620,15 +810,16 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
const struct ata_port_info *ppi[] = { &inic_port_info, NULL };
struct ata_host *host;
struct inic_host_priv *hpriv;
void __iomem * const *iomap;
+ int mmio_bar;
int i, rc;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
+
+ dev_alert(&pdev->dev, "inic162x support is broken with common data corruption issues and will be disabled by default, contact linux-ide@vger.kernel.org if in production use\n");
/* alloc host */
host = ata_host_alloc_pinfo(&pdev->dev, ppi, NR_PORTS);
@@ -638,51 +829,42 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
host->private_data = hpriv;
- /* acquire resources and fill host */
+ /* Acquire resources and fill host. Note that PCI and cardbus
+ * use different BARs.
+ */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME);
+ if (pci_resource_flags(pdev, MMIO_BAR_PCI) & IORESOURCE_MEM)
+ mmio_bar = MMIO_BAR_PCI;
+ else
+ mmio_bar = MMIO_BAR_CARDBUS;
+
+ rc = pcim_iomap_regions(pdev, 1 << mmio_bar, DRV_NAME);
if (rc)
return rc;
host->iomap = iomap = pcim_iomap_table(pdev);
+ hpriv->mmio_base = iomap[mmio_bar];
+ hpriv->cached_hctl = readw(hpriv->mmio_base + HOST_CTL);
for (i = 0; i < NR_PORTS; i++) {
struct ata_port *ap = host->ports[i];
- struct ata_ioports *port = &ap->ioaddr;
- unsigned int offset = i * PORT_SIZE;
-
- port->cmd_addr = iomap[2 * i];
- port->altstatus_addr =
- port->ctl_addr = (void __iomem *)
- ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
- port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR;
-
- ata_sff_std_ports(port);
-
- ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio");
- ata_port_pbar_desc(ap, MMIO_BAR, offset, "port");
- ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
- (unsigned long long)pci_resource_start(pdev, 2 * i),
- (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) |
- ATA_PCI_CTL_OFS);
- }
- hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
+ ata_port_pbar_desc(ap, mmio_bar, -1, "mmio");
+ ata_port_pbar_desc(ap, mmio_bar, i * PORT_SIZE, "port");
+ }
/* Set dma_mask. This devices doesn't support 64bit addressing. */
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit DMA enable failed\n");
+ dev_err(&pdev->dev, "32-bit DMA enable failed\n");
return rc;
}
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit consistent DMA enable failed\n");
+ dev_err(&pdev->dev, "32-bit consistent DMA enable failed\n");
return rc;
}
@@ -693,15 +875,13 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
rc = pci_set_dma_max_seg_size(pdev, 65536 - 512);
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to set the maximum segment size.\n");
+ dev_err(&pdev->dev, "failed to set the maximum segment size\n");
return rc;
}
- rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
+ rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl);
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to initialize controller\n");
+ dev_err(&pdev->dev, "failed to initialize controller\n");
return rc;
}
@@ -718,7 +898,7 @@ static const struct pci_device_id inic_pci_tbl[] = {
static struct pci_driver inic_pci_driver = {
.name = DRV_NAME,
.id_table = inic_pci_tbl,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = inic_pci_device_resume,
#endif
@@ -726,21 +906,10 @@ static struct pci_driver inic_pci_driver = {
.remove = ata_pci_remove_one,
};
-static int __init inic_init(void)
-{
- return pci_register_driver(&inic_pci_driver);
-}
-
-static void __exit inic_exit(void)
-{
- pci_unregister_driver(&inic_pci_driver);
-}
+module_pci_driver(inic_pci_driver);
MODULE_AUTHOR("Tejun Heo");
MODULE_DESCRIPTION("low-level driver for Initio 162x SATA");
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(pci, inic_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
-module_init(inic_init);
-module_exit(inic_exit);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index d52ce118832..391cfda1e83 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -1,10 +1,13 @@
/*
* sata_mv.c - Marvell SATA support
*
- * Copyright 2008: Marvell Corporation, all rights reserved.
+ * Copyright 2008-2009: Marvell Corporation, all rights reserved.
* Copyright 2005: EMC Corporation, all rights reserved.
* Copyright 2005 Red Hat, Inc. All rights reserved.
*
+ * Originally written by Brett Russ.
+ * Extensive overhaul and enhancement by Mark Lord <mlord@pobox.com>.
+ *
* Please ALWAYS copy linux-ide@vger.kernel.org on emails.
*
* This program is free software; you can redistribute it and/or modify
@@ -23,46 +26,28 @@
*/
/*
- sata_mv TODO list:
-
- 1) Needs a full errata audit for all chipsets. I implemented most
- of the errata workarounds found in the Marvell vendor driver, but
- I distinctly remember a couple workarounds (one related to PCI-X)
- are still needed.
-
- 2) Improve/fix IRQ and error handling sequences.
-
- 3) ATAPI support (Marvell claims the 60xx/70xx chips can do it).
-
- 4) Think about TCQ support here, and for libata in general
- with controllers that suppport it via host-queuing hardware
- (a software-only implementation could be a nightmare).
-
- 5) Investigate problems with PCI Message Signalled Interrupts (MSI).
-
- 6) Cache frequently-accessed registers in mv_port_priv to reduce overhead.
-
- 7) Fix/reenable hot plug/unplug (should happen as a side-effect of (2) above).
-
- 8) Develop a low-power-consumption strategy, and implement it.
-
- 9) [Experiment, low priority] See if ATAPI can be supported using
- "unknown FIS" or "vendor-specific FIS" support, or something creative
- like that.
-
- 10) [Experiment, low priority] Investigate interrupt coalescing.
- Quite often, especially with PCI Message Signalled Interrupts (MSI),
- the overhead reduced by interrupt mitigation is quite often not
- worth the latency cost.
-
- 11) [Experiment, Marvell value added] Is it possible to use target
- mode to cross-connect two Linux boxes with Marvell cards? If so,
- creating LibATA target mode support would be very interesting.
-
- Target mode, for those without docs, is the ability to directly
- connect two SATA controllers.
+ * sata_mv TODO list:
+ *
+ * --> Develop a low-power-consumption strategy, and implement it.
+ *
+ * --> Add sysfs attributes for per-chip / per-HC IRQ coalescing thresholds.
+ *
+ * --> [Experiment, Marvell value added] Is it possible to use target
+ * mode to cross-connect two Linux boxes with Marvell cards? If so,
+ * creating LibATA target mode support would be very interesting.
+ *
+ * Target mode, for those without docs, is the ability to directly
+ * connect two SATA ports.
+ */
-*/
+/*
+ * 80x1-B2 errata PCI#11:
+ *
+ * Users of the 6041/6081 Rev.B2 chips (current is C0)
+ * should be careful to insert those cards only onto PCI-X bus #0,
+ * and only in device slots 0..7, not higher. The chips may not
+ * work correctly otherwise (note: this is a pretty rare condition).
+ */
#include <linux/kernel.h>
#include <linux/module.h>
@@ -74,16 +59,42 @@
#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/ata_platform.h>
#include <linux/mbus.h>
+#include <linux/bitops.h>
+#include <linux/gfp.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <linux/libata.h>
#define DRV_NAME "sata_mv"
-#define DRV_VERSION "1.20"
+#define DRV_VERSION "1.28"
+
+/*
+ * module options
+ */
+
+#ifdef CONFIG_PCI
+static int msi;
+module_param(msi, int, S_IRUGO);
+MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
+#endif
+
+static int irq_coalescing_io_count;
+module_param(irq_coalescing_io_count, int, S_IRUGO);
+MODULE_PARM_DESC(irq_coalescing_io_count,
+ "IRQ coalescing I/O count threshold (0..255)");
+
+static int irq_coalescing_usecs;
+module_param(irq_coalescing_usecs, int, S_IRUGO);
+MODULE_PARM_DESC(irq_coalescing_usecs,
+ "IRQ coalescing time threshold in usecs");
enum {
/* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -94,18 +105,37 @@ enum {
MV_MAJOR_REG_AREA_SZ = 0x10000, /* 64KB */
MV_MINOR_REG_AREA_SZ = 0x2000, /* 8KB */
+ /* For use with both IRQ coalescing methods ("all ports" or "per-HC" */
+ COAL_CLOCKS_PER_USEC = 150, /* for calculating COAL_TIMEs */
+ MAX_COAL_TIME_THRESHOLD = ((1 << 24) - 1), /* internal clocks count */
+ MAX_COAL_IO_COUNT = 255, /* completed I/O count */
+
MV_PCI_REG_BASE = 0,
- MV_IRQ_COAL_REG_BASE = 0x18000, /* 6xxx part only */
- MV_IRQ_COAL_CAUSE = (MV_IRQ_COAL_REG_BASE + 0x08),
- MV_IRQ_COAL_CAUSE_LO = (MV_IRQ_COAL_REG_BASE + 0x88),
- MV_IRQ_COAL_CAUSE_HI = (MV_IRQ_COAL_REG_BASE + 0x8c),
- MV_IRQ_COAL_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xcc),
- MV_IRQ_COAL_TIME_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xd0),
-
- MV_SATAHC0_REG_BASE = 0x20000,
- MV_FLASH_CTL = 0x1046c,
- MV_GPIO_PORT_CTL = 0x104f0,
- MV_RESET_CFG = 0x180d8,
+
+ /*
+ * Per-chip ("all ports") interrupt coalescing feature.
+ * This is only for GEN_II / GEN_IIE hardware.
+ *
+ * Coalescing defers the interrupt until either the IO_THRESHOLD
+ * (count of completed I/Os) is met, or the TIME_THRESHOLD is met.
+ */
+ COAL_REG_BASE = 0x18000,
+ IRQ_COAL_CAUSE = (COAL_REG_BASE + 0x08),
+ ALL_PORTS_COAL_IRQ = (1 << 4), /* all ports irq event */
+
+ IRQ_COAL_IO_THRESHOLD = (COAL_REG_BASE + 0xcc),
+ IRQ_COAL_TIME_THRESHOLD = (COAL_REG_BASE + 0xd0),
+
+ /*
+ * Registers for the (unused here) transaction coalescing feature:
+ */
+ TRAN_COAL_CAUSE_LO = (COAL_REG_BASE + 0x88),
+ TRAN_COAL_CAUSE_HI = (COAL_REG_BASE + 0x8c),
+
+ SATAHC0_REG_BASE = 0x20000,
+ FLASH_CTL = 0x1046c,
+ GPIO_PORT_CTL = 0x104f0,
+ RESET_CFG = 0x180d8,
MV_PCI_REG_SZ = MV_MAJOR_REG_AREA_SZ,
MV_SATAHC_REG_SZ = MV_MAJOR_REG_AREA_SZ,
@@ -124,22 +154,23 @@ enum {
MV_MAX_SG_CT = 256,
MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT),
- MV_PORTS_PER_HC = 4,
- /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
+ /* Determine hc from 0-7 port: hc = port >> MV_PORT_HC_SHIFT */
MV_PORT_HC_SHIFT = 2,
- /* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */
- MV_PORT_MASK = 3,
+ MV_PORTS_PER_HC = (1 << MV_PORT_HC_SHIFT), /* 4 */
+ /* Determine hc port from 0-7 port: hardport = port & MV_PORT_MASK */
+ MV_PORT_MASK = (MV_PORTS_PER_HC - 1), /* 3 */
/* Host Flags */
MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */
- MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */
- /* SoC integrated controllers, no PCI interface */
- MV_FLAG_SOC = (1 << 28),
- MV_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
- ATA_FLAG_PIO_POLLING,
- MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE,
+ MV_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_PIO_POLLING,
+
+ MV_GEN_I_FLAGS = MV_COMMON_FLAGS | ATA_FLAG_NO_ATAPI,
+
+ MV_GEN_II_FLAGS = MV_COMMON_FLAGS | ATA_FLAG_NCQ |
+ ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA,
+
+ MV_GEN_IIE_FLAGS = MV_GEN_II_FLAGS | ATA_FLAG_AN,
CRQB_FLAG_READ = (1 << 0),
CRQB_TAG_SHIFT = 1,
@@ -158,14 +189,18 @@ enum {
/* PCI interface registers */
- PCI_COMMAND_OFS = 0xc00,
+ MV_PCI_COMMAND = 0xc00,
+ MV_PCI_COMMAND_MWRCOM = (1 << 4), /* PCI Master Write Combining */
+ MV_PCI_COMMAND_MRDTRIG = (1 << 7), /* PCI Master Read Trigger */
- PCI_MAIN_CMD_STS_OFS = 0xd30,
+ PCI_MAIN_CMD_STS = 0xd30,
STOP_PCI_MASTER = (1 << 2),
PCI_MASTER_EMPTY = (1 << 3),
GLOB_SFT_RST = (1 << 4),
MV_PCI_MODE = 0xd00,
+ MV_PCI_MODE_MASK = 0x30,
+
MV_PCI_EXP_ROM_BAR_CTL = 0xd2c,
MV_PCI_DISC_TIMER = 0xd04,
MV_PCI_MSI_TRIGGER = 0xc38,
@@ -176,80 +211,106 @@ enum {
MV_PCI_ERR_ATTRIBUTE = 0x1d48,
MV_PCI_ERR_COMMAND = 0x1d50,
- PCI_IRQ_CAUSE_OFS = 0x1d58,
- PCI_IRQ_MASK_OFS = 0x1d5c,
+ PCI_IRQ_CAUSE = 0x1d58,
+ PCI_IRQ_MASK = 0x1d5c,
PCI_UNMASK_ALL_IRQS = 0x7fffff, /* bits 22-0 */
- PCIE_IRQ_CAUSE_OFS = 0x1900,
- PCIE_IRQ_MASK_OFS = 0x1910,
+ PCIE_IRQ_CAUSE = 0x1900,
+ PCIE_IRQ_MASK = 0x1910,
PCIE_UNMASK_ALL_IRQS = 0x40a, /* assorted bits */
- HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
- HC_MAIN_IRQ_MASK_OFS = 0x1d64,
- HC_SOC_MAIN_IRQ_CAUSE_OFS = 0x20020,
- HC_SOC_MAIN_IRQ_MASK_OFS = 0x20024,
- PORT0_ERR = (1 << 0), /* shift by port # */
- PORT0_DONE = (1 << 1), /* shift by port # */
+ /* Host Controller Main Interrupt Cause/Mask registers (1 per-chip) */
+ PCI_HC_MAIN_IRQ_CAUSE = 0x1d60,
+ PCI_HC_MAIN_IRQ_MASK = 0x1d64,
+ SOC_HC_MAIN_IRQ_CAUSE = 0x20020,
+ SOC_HC_MAIN_IRQ_MASK = 0x20024,
+ ERR_IRQ = (1 << 0), /* shift by (2 * port #) */
+ DONE_IRQ = (1 << 1), /* shift by (2 * port #) */
HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */
HC_SHIFT = 9, /* bits 9-17 = HC1's ports */
+ DONE_IRQ_0_3 = 0x000000aa, /* DONE_IRQ ports 0,1,2,3 */
+ DONE_IRQ_4_7 = (DONE_IRQ_0_3 << HC_SHIFT), /* 4,5,6,7 */
PCI_ERR = (1 << 18),
- TRAN_LO_DONE = (1 << 19), /* 6xxx: IRQ coalescing */
- TRAN_HI_DONE = (1 << 20), /* 6xxx: IRQ coalescing */
- PORTS_0_3_COAL_DONE = (1 << 8),
- PORTS_4_7_COAL_DONE = (1 << 17),
- PORTS_0_7_COAL_DONE = (1 << 21), /* 6xxx: IRQ coalescing */
+ TRAN_COAL_LO_DONE = (1 << 19), /* transaction coalescing */
+ TRAN_COAL_HI_DONE = (1 << 20), /* transaction coalescing */
+ PORTS_0_3_COAL_DONE = (1 << 8), /* HC0 IRQ coalescing */
+ PORTS_4_7_COAL_DONE = (1 << 17), /* HC1 IRQ coalescing */
+ ALL_PORTS_COAL_DONE = (1 << 21), /* GEN_II(E) IRQ coalescing */
GPIO_INT = (1 << 22),
SELF_INT = (1 << 23),
TWSI_INT = (1 << 24),
HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */
HC_MAIN_RSVD_5 = (0x1fff << 19), /* bits 31-19 */
HC_MAIN_RSVD_SOC = (0x3fffffb << 6), /* bits 31-9, 7-6 */
- HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE |
- PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
- HC_MAIN_RSVD),
- HC_MAIN_MASKED_IRQS_5 = (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
- HC_MAIN_RSVD_5),
- HC_MAIN_MASKED_IRQS_SOC = (PORTS_0_3_COAL_DONE | HC_MAIN_RSVD_SOC),
/* SATAHC registers */
- HC_CFG_OFS = 0,
+ HC_CFG = 0x00,
- HC_IRQ_CAUSE_OFS = 0x14,
- CRPB_DMA_DONE = (1 << 0), /* shift by port # */
- HC_IRQ_COAL = (1 << 4), /* IRQ coalescing */
+ HC_IRQ_CAUSE = 0x14,
+ DMA_IRQ = (1 << 0), /* shift by port # */
+ HC_COAL_IRQ = (1 << 4), /* IRQ coalescing */
DEV_IRQ = (1 << 8), /* shift by port # */
+ /*
+ * Per-HC (Host-Controller) interrupt coalescing feature.
+ * This is present on all chip generations.
+ *
+ * Coalescing defers the interrupt until either the IO_THRESHOLD
+ * (count of completed I/Os) is met, or the TIME_THRESHOLD is met.
+ */
+ HC_IRQ_COAL_IO_THRESHOLD = 0x000c,
+ HC_IRQ_COAL_TIME_THRESHOLD = 0x0010,
+
+ SOC_LED_CTRL = 0x2c,
+ SOC_LED_CTRL_BLINK = (1 << 0), /* Active LED blink */
+ SOC_LED_CTRL_ACT_PRESENCE = (1 << 2), /* Multiplex dev presence */
+ /* with dev activity LED */
+
/* Shadow block registers */
- SHD_BLK_OFS = 0x100,
- SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */
+ SHD_BLK = 0x100,
+ SHD_CTL_AST = 0x20, /* ofs from SHD_BLK */
/* SATA registers */
- SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */
- SATA_ACTIVE_OFS = 0x350,
- SATA_FIS_IRQ_CAUSE_OFS = 0x364,
+ SATA_STATUS = 0x300, /* ctrl, err regs follow status */
+ SATA_ACTIVE = 0x350,
+ FIS_IRQ_CAUSE = 0x364,
+ FIS_IRQ_CAUSE_AN = (1 << 9), /* async notification */
- LTMODE_OFS = 0x30c,
+ LTMODE = 0x30c, /* requires read-after-write */
LTMODE_BIT8 = (1 << 8), /* unknown, but necessary */
- PHY_MODE3 = 0x310,
- PHY_MODE4 = 0x314,
PHY_MODE2 = 0x330,
- SATA_IFCTL_OFS = 0x344,
- SATA_IFSTAT_OFS = 0x34c,
- VENDOR_UNIQUE_FIS_OFS = 0x35c,
+ PHY_MODE3 = 0x310,
+
+ PHY_MODE4 = 0x314, /* requires read-after-write */
+ PHY_MODE4_CFG_MASK = 0x00000003, /* phy internal config field */
+ PHY_MODE4_CFG_VALUE = 0x00000001, /* phy internal config field */
+ PHY_MODE4_RSVD_ZEROS = 0x5de3fffa, /* Gen2e always write zeros */
+ PHY_MODE4_RSVD_ONES = 0x00000005, /* Gen2e always write ones */
+
+ SATA_IFCTL = 0x344,
+ SATA_TESTCTL = 0x348,
+ SATA_IFSTAT = 0x34c,
+ VENDOR_UNIQUE_FIS = 0x35c,
+
+ FISCFG = 0x360,
+ FISCFG_WAIT_DEV_ERR = (1 << 8), /* wait for host on DevErr */
+ FISCFG_SINGLE_SYNC = (1 << 16), /* SYNC on DMA activation */
- FIS_CFG_OFS = 0x360,
- FIS_CFG_SINGLE_SYNC = (1 << 16), /* SYNC on DMA activation */
+ PHY_MODE9_GEN2 = 0x398,
+ PHY_MODE9_GEN1 = 0x39c,
+ PHYCFG_OFS = 0x3a0, /* only in 65n devices */
MV5_PHY_MODE = 0x74,
- MV5_LT_MODE = 0x30,
+ MV5_LTMODE = 0x30,
MV5_PHY_CTL = 0x0C,
- SATA_INTERFACE_CFG = 0x050,
+ SATA_IFCFG = 0x050,
+ LP_PHY_CTL = 0x058,
MV_M2_PREAMP_MASK = 0x7e0,
/* Port registers */
- EDMA_CFG_OFS = 0,
+ EDMA_CFG = 0,
EDMA_CFG_Q_DEPTH = 0x1f, /* max device queue depth */
EDMA_CFG_NCQ = (1 << 5), /* for R/W FPDMA queued */
EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */
@@ -258,8 +319,8 @@ enum {
EDMA_CFG_EDMA_FBS = (1 << 16), /* EDMA FIS-Based Switching */
EDMA_CFG_FBS = (1 << 26), /* FIS-Based Switching */
- EDMA_ERR_IRQ_CAUSE_OFS = 0x8,
- EDMA_ERR_IRQ_MASK_OFS = 0xc,
+ EDMA_ERR_IRQ_CAUSE = 0x8,
+ EDMA_ERR_IRQ_MASK = 0xc,
EDMA_ERR_D_PAR = (1 << 0), /* UDMA data parity err */
EDMA_ERR_PRD_PAR = (1 << 1), /* UDMA PRD parity err */
EDMA_ERR_DEV = (1 << 2), /* device error */
@@ -299,9 +360,7 @@ enum {
EDMA_ERR_IRQ_TRANSIENT = EDMA_ERR_LNK_CTRL_RX_0 |
EDMA_ERR_LNK_CTRL_RX_1 |
EDMA_ERR_LNK_CTRL_RX_3 |
- EDMA_ERR_LNK_CTRL_TX |
- /* temporary, until we fix hotplug: */
- (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON),
+ EDMA_ERR_LNK_CTRL_TX,
EDMA_EH_FREEZE = EDMA_ERR_D_PAR |
EDMA_ERR_PRD_PAR |
@@ -330,46 +389,65 @@ enum {
EDMA_ERR_INTRL_PAR |
EDMA_ERR_IORDY,
- EDMA_REQ_Q_BASE_HI_OFS = 0x10,
- EDMA_REQ_Q_IN_PTR_OFS = 0x14, /* also contains BASE_LO */
+ EDMA_REQ_Q_BASE_HI = 0x10,
+ EDMA_REQ_Q_IN_PTR = 0x14, /* also contains BASE_LO */
- EDMA_REQ_Q_OUT_PTR_OFS = 0x18,
+ EDMA_REQ_Q_OUT_PTR = 0x18,
EDMA_REQ_Q_PTR_SHIFT = 5,
- EDMA_RSP_Q_BASE_HI_OFS = 0x1c,
- EDMA_RSP_Q_IN_PTR_OFS = 0x20,
- EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */
+ EDMA_RSP_Q_BASE_HI = 0x1c,
+ EDMA_RSP_Q_IN_PTR = 0x20,
+ EDMA_RSP_Q_OUT_PTR = 0x24, /* also contains BASE_LO */
EDMA_RSP_Q_PTR_SHIFT = 3,
- EDMA_CMD_OFS = 0x28, /* EDMA command register */
+ EDMA_CMD = 0x28, /* EDMA command register */
EDMA_EN = (1 << 0), /* enable EDMA */
EDMA_DS = (1 << 1), /* disable EDMA; self-negated */
- ATA_RST = (1 << 2), /* reset trans/link/phy */
+ EDMA_RESET = (1 << 2), /* reset eng/trans/link/phy */
+
+ EDMA_STATUS = 0x30, /* EDMA engine status */
+ EDMA_STATUS_CACHE_EMPTY = (1 << 6), /* GenIIe command cache empty */
+ EDMA_STATUS_IDLE = (1 << 7), /* GenIIe EDMA enabled/idle */
EDMA_IORDY_TMOUT = 0x34,
EDMA_ARB_CFG = 0x38,
+ EDMA_HALTCOND = 0x60, /* GenIIe halt conditions */
+ EDMA_UNKNOWN_RSVD = 0x6C, /* GenIIe unknown/reserved */
+
+ BMDMA_CMD = 0x224, /* bmdma command register */
+ BMDMA_STATUS = 0x228, /* bmdma status register */
+ BMDMA_PRD_LOW = 0x22c, /* bmdma PRD addr 31:0 */
+ BMDMA_PRD_HIGH = 0x230, /* bmdma PRD addr 63:32 */
+
/* Host private flags (hp_flags) */
MV_HP_FLAG_MSI = (1 << 0),
MV_HP_ERRATA_50XXB0 = (1 << 1),
MV_HP_ERRATA_50XXB2 = (1 << 2),
MV_HP_ERRATA_60X1B2 = (1 << 3),
MV_HP_ERRATA_60X1C0 = (1 << 4),
- MV_HP_ERRATA_XX42A0 = (1 << 5),
MV_HP_GEN_I = (1 << 6), /* Generation I: 50xx */
MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */
MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */
MV_HP_PCIE = (1 << 9), /* PCIe bus/regs: 7042 */
+ MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */
+ MV_HP_FLAG_SOC = (1 << 11), /* SystemOnChip, no PCI */
+ MV_HP_QUIRK_LED_BLINK_EN = (1 << 12), /* is led blinking enabled? */
+ MV_HP_FIX_LP_PHY_CTL = (1 << 13), /* fix speed in LP_PHY_CTL ? */
/* Port private flags (pp_flags) */
MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */
MV_PP_FLAG_NCQ_EN = (1 << 1), /* is EDMA set up for NCQ? */
+ MV_PP_FLAG_FBS_EN = (1 << 2), /* is EDMA set up for FBS? */
+ MV_PP_FLAG_DELAYED_EH = (1 << 3), /* delayed dev err handling */
+ MV_PP_FLAG_FAKE_ATA_BUSY = (1 << 4), /* ignore initial ATA_DRDY */
};
#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
#define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
-#define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC))
+#define IS_PCIE(hpriv) ((hpriv)->hp_flags & MV_HP_PCIE)
+#define IS_SOC(hpriv) ((hpriv)->hp_flags & MV_HP_FLAG_SOC)
#define WINDOW_CTRL(i) (0x20030 + ((i) << 4))
#define WINDOW_BASE(i) (0x20034 + ((i) << 4))
@@ -431,6 +509,18 @@ struct mv_sg {
__le32 reserved;
};
+/*
+ * We keep a local cache of a few frequently accessed port
+ * registers here, to avoid having to read them (very slow)
+ * when switching between EDMA and non-EDMA modes.
+ */
+struct mv_cached_regs {
+ u32 fiscfg;
+ u32 ltmode;
+ u32 haltcond;
+ u32 unknown_rsvd;
+};
+
struct mv_port_priv {
struct mv_crqb *crqb;
dma_addr_t crqb_dma;
@@ -443,6 +533,8 @@ struct mv_port_priv {
unsigned int resp_idx;
u32 pp_flags;
+ struct mv_cached_regs cached;
+ unsigned int delayed_eh_pmp_map;
};
struct mv_port_signal {
@@ -452,15 +544,33 @@ struct mv_port_signal {
struct mv_host_priv {
u32 hp_flags;
+ unsigned int board_idx;
+ u32 main_irq_mask;
struct mv_port_signal signal[8];
const struct mv_hw_ops *ops;
int n_ports;
void __iomem *base;
- void __iomem *main_cause_reg_addr;
- void __iomem *main_mask_reg_addr;
- u32 irq_cause_ofs;
- u32 irq_mask_ofs;
+ void __iomem *main_irq_cause_addr;
+ void __iomem *main_irq_mask_addr;
+ u32 irq_cause_offset;
+ u32 irq_mask_offset;
u32 unmask_all_irqs;
+
+ /*
+ * Needed on some devices that require their clocks to be enabled.
+ * These are optional: if the platform device does not have any
+ * clocks, they won't be used. Also, if the underlying hardware
+ * does not support the common clock framework (CONFIG_HAVE_CLK=n),
+ * all the clock operations become no-ops (see clk.h).
+ */
+ struct clk *clk;
+ struct clk **port_clks;
+ /*
+ * Some devices have a SATA PHY which can be enabled/disabled
+ * in order to save power. These are optional: if the platform
+ * devices does not have any phy, they won't be used.
+ */
+ struct phy **port_phys;
/*
* These consistent DMA memory pools give us guaranteed
* alignment for hardware-accessed data structures,
@@ -483,12 +593,13 @@ struct mv_hw_ops {
void (*reset_bus)(struct ata_host *host, void __iomem *mmio);
};
-static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
-static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
-static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val);
+static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val);
+static int mv5_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val);
+static int mv5_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val);
static int mv_port_start(struct ata_port *ap);
static void mv_port_stop(struct ata_port *ap);
+static int mv_qc_defer(struct ata_queued_cmd *qc);
static void mv_qc_prep(struct ata_queued_cmd *qc);
static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
@@ -525,29 +636,43 @@ static int mv_soc_reset_hc(struct mv_host_priv *hpriv,
static void mv_soc_reset_flash(struct mv_host_priv *hpriv,
void __iomem *mmio);
static void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio);
+static void mv_soc_65n_phy_errata(struct mv_host_priv *hpriv,
+ void __iomem *mmio, unsigned int port);
static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio);
static void mv_reset_channel(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int port_no);
static int mv_stop_edma(struct ata_port *ap);
static int mv_stop_edma_engine(void __iomem *port_mmio);
-static void mv_edma_cfg(struct ata_port *ap, int want_ncq);
+static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma);
static void mv_pmp_select(struct ata_port *ap, int pmp);
static int mv_pmp_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static int mv_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
+static void mv_pmp_error_handler(struct ata_port *ap);
+static void mv_process_crpb_entries(struct ata_port *ap,
+ struct mv_port_priv *pp);
+
+static void mv_sff_irq_clear(struct ata_port *ap);
+static int mv_check_atapi_dma(struct ata_queued_cmd *qc);
+static void mv_bmdma_setup(struct ata_queued_cmd *qc);
+static void mv_bmdma_start(struct ata_queued_cmd *qc);
+static void mv_bmdma_stop(struct ata_queued_cmd *qc);
+static u8 mv_bmdma_status(struct ata_port *ap);
+static u8 mv_sff_check_status(struct ata_port *ap);
/* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below
* because we have to allow room for worst case splitting of
* PRDs for 64K boundaries in mv_fill_sg().
*/
+#ifdef CONFIG_PCI
static struct scsi_host_template mv5_sht = {
ATA_BASE_SHT(DRV_NAME),
.sg_tablesize = MV_MAX_SG_CT / 2,
.dma_boundary = MV_DMA_BOUNDARY,
};
-
+#endif
static struct scsi_host_template mv6_sht = {
ATA_NCQ_SHT(DRV_NAME),
.can_queue = MV_MAX_Q_DEPTH - 1,
@@ -558,14 +683,15 @@ static struct scsi_host_template mv6_sht = {
static struct ata_port_operations mv5_ops = {
.inherits = &ata_sff_port_ops,
+ .lost_interrupt = ATA_OP_NULL,
+
+ .qc_defer = mv_qc_defer,
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
.freeze = mv_eh_freeze,
.thaw = mv_eh_thaw,
.hardreset = mv_hardreset,
- .error_handler = ata_std_error_handler, /* avoid SFF EH */
- .post_internal_cmd = ATA_OP_NULL,
.scr_read = mv5_scr_read,
.scr_write = mv5_scr_write,
@@ -575,81 +701,91 @@ static struct ata_port_operations mv5_ops = {
};
static struct ata_port_operations mv6_ops = {
- .inherits = &mv5_ops,
- .qc_defer = sata_pmp_qc_defer_cmd_switch,
+ .inherits = &ata_bmdma_port_ops,
+
+ .lost_interrupt = ATA_OP_NULL,
+
+ .qc_defer = mv_qc_defer,
+ .qc_prep = mv_qc_prep,
+ .qc_issue = mv_qc_issue,
+
.dev_config = mv6_dev_config,
- .scr_read = mv_scr_read,
- .scr_write = mv_scr_write,
+ .freeze = mv_eh_freeze,
+ .thaw = mv_eh_thaw,
+ .hardreset = mv_hardreset,
+ .softreset = mv_softreset,
.pmp_hardreset = mv_pmp_hardreset,
.pmp_softreset = mv_softreset,
- .softreset = mv_softreset,
- .error_handler = sata_pmp_error_handler,
+ .error_handler = mv_pmp_error_handler,
+
+ .scr_read = mv_scr_read,
+ .scr_write = mv_scr_write,
+
+ .sff_check_status = mv_sff_check_status,
+ .sff_irq_clear = mv_sff_irq_clear,
+ .check_atapi_dma = mv_check_atapi_dma,
+ .bmdma_setup = mv_bmdma_setup,
+ .bmdma_start = mv_bmdma_start,
+ .bmdma_stop = mv_bmdma_stop,
+ .bmdma_status = mv_bmdma_status,
+
+ .port_start = mv_port_start,
+ .port_stop = mv_port_stop,
};
static struct ata_port_operations mv_iie_ops = {
.inherits = &mv6_ops,
- .qc_defer = ata_std_qc_defer, /* FIS-based switching */
.dev_config = ATA_OP_NULL,
.qc_prep = mv_qc_prep_iie,
};
static const struct ata_port_info mv_port_info[] = {
{ /* chip_504x */
- .flags = MV_COMMON_FLAGS,
- .pio_mask = 0x1f, /* pio0-4 */
+ .flags = MV_GEN_I_FLAGS,
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &mv5_ops,
},
{ /* chip_508x */
- .flags = MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
- .pio_mask = 0x1f, /* pio0-4 */
+ .flags = MV_GEN_I_FLAGS | MV_FLAG_DUAL_HC,
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &mv5_ops,
},
{ /* chip_5080 */
- .flags = MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
- .pio_mask = 0x1f, /* pio0-4 */
+ .flags = MV_GEN_I_FLAGS | MV_FLAG_DUAL_HC,
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &mv5_ops,
},
{ /* chip_604x */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
- ATA_FLAG_NCQ,
- .pio_mask = 0x1f, /* pio0-4 */
+ .flags = MV_GEN_II_FLAGS,
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &mv6_ops,
},
{ /* chip_608x */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
- ATA_FLAG_NCQ | MV_FLAG_DUAL_HC,
- .pio_mask = 0x1f, /* pio0-4 */
+ .flags = MV_GEN_II_FLAGS | MV_FLAG_DUAL_HC,
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &mv6_ops,
},
{ /* chip_6042 */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
- ATA_FLAG_NCQ,
- .pio_mask = 0x1f, /* pio0-4 */
+ .flags = MV_GEN_IIE_FLAGS,
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
},
{ /* chip_7042 */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
- ATA_FLAG_NCQ,
- .pio_mask = 0x1f, /* pio0-4 */
+ .flags = MV_GEN_IIE_FLAGS,
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
},
{ /* chip_soc */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
- ATA_FLAG_NCQ | MV_FLAG_SOC,
- .pio_mask = 0x1f, /* pio0-4 */
+ .flags = MV_GEN_IIE_FLAGS,
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
},
@@ -660,9 +796,10 @@ static const struct pci_device_id mv_pci_tbl[] = {
{ PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
{ PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
{ PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
- /* RocketRAID 1740/174x have different identifiers */
- { PCI_VDEVICE(TTI, 0x1740), chip_508x },
- { PCI_VDEVICE(TTI, 0x1742), chip_508x },
+ /* RocketRAID 1720/174x have different identifiers */
+ { PCI_VDEVICE(TTI, 0x1720), chip_6042 },
+ { PCI_VDEVICE(TTI, 0x1740), chip_6042 },
+ { PCI_VDEVICE(TTI, 0x1742), chip_6042 },
{ PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
{ PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
@@ -712,6 +849,14 @@ static const struct mv_hw_ops mv_soc_ops = {
.reset_bus = mv_soc_reset_bus,
};
+static const struct mv_hw_ops mv_soc_65n_ops = {
+ .phy_errata = mv_soc_65n_phy_errata,
+ .enable_leds = mv_soc_enable_leds,
+ .reset_hc = mv_soc_reset_hc,
+ .reset_flash = mv_soc_reset_flash,
+ .reset_bus = mv_soc_reset_bus,
+};
+
/*
* Functions
*/
@@ -722,11 +867,6 @@ static inline void writelfl(unsigned long data, void __iomem *addr)
(void) readl(addr); /* flush to avoid PCI posted write */
}
-static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
-{
- return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
-}
-
static inline unsigned int mv_hc_from_port(unsigned int port)
{
return port >> MV_PORT_HC_SHIFT;
@@ -737,6 +877,29 @@ static inline unsigned int mv_hardport_from_port(unsigned int port)
return port & MV_PORT_MASK;
}
+/*
+ * Consolidate some rather tricky bit shift calculations.
+ * This is hot-path stuff, so not a function.
+ * Simple code, with two return values, so macro rather than inline.
+ *
+ * port is the sole input, in range 0..7.
+ * shift is one output, for use with main_irq_cause / main_irq_mask registers.
+ * hardport is the other output, in range 0..3.
+ *
+ * Note that port and hardport may be the same variable in some cases.
+ */
+#define MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport) \
+{ \
+ shift = mv_hc_from_port(port) * HC_SHIFT; \
+ hardport = mv_hardport_from_port(port); \
+ shift += hardport * 2; \
+}
+
+static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
+{
+ return (base + SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
+}
+
static inline void __iomem *mv_hc_base_from_port(void __iomem *base,
unsigned int port)
{
@@ -774,6 +937,62 @@ static inline int mv_get_hc_count(unsigned long port_flags)
return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
}
+/**
+ * mv_save_cached_regs - (re-)initialize cached port registers
+ * @ap: the port whose registers we are caching
+ *
+ * Initialize the local cache of port registers,
+ * so that reading them over and over again can
+ * be avoided on the hotter paths of this driver.
+ * This saves a few microseconds each time we switch
+ * to/from EDMA mode to perform (eg.) a drive cache flush.
+ */
+static void mv_save_cached_regs(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ struct mv_port_priv *pp = ap->private_data;
+
+ pp->cached.fiscfg = readl(port_mmio + FISCFG);
+ pp->cached.ltmode = readl(port_mmio + LTMODE);
+ pp->cached.haltcond = readl(port_mmio + EDMA_HALTCOND);
+ pp->cached.unknown_rsvd = readl(port_mmio + EDMA_UNKNOWN_RSVD);
+}
+
+/**
+ * mv_write_cached_reg - write to a cached port register
+ * @addr: hardware address of the register
+ * @old: pointer to cached value of the register
+ * @new: new value for the register
+ *
+ * Write a new value to a cached register,
+ * but only if the value is different from before.
+ */
+static inline void mv_write_cached_reg(void __iomem *addr, u32 *old, u32 new)
+{
+ if (new != *old) {
+ unsigned long laddr;
+ *old = new;
+ /*
+ * Workaround for 88SX60x1-B2 FEr SATA#13:
+ * Read-after-write is needed to prevent generating 64-bit
+ * write cycles on the PCI bus for SATA interface registers
+ * at offsets ending in 0x4 or 0xc.
+ *
+ * Looks like a lot of fuss, but it avoids an unnecessary
+ * +1 usec read-after-write delay for unaffected registers.
+ */
+ laddr = (long)addr & 0xffff;
+ if (laddr >= 0x300 && laddr <= 0x33c) {
+ laddr &= 0x000f;
+ if (laddr == 0x4 || laddr == 0xc) {
+ writelfl(new, addr); /* read after write */
+ return;
+ }
+ }
+ writel(new, addr); /* unaffected by the errata */
+ }
+}
+
static void mv_set_edma_ptrs(void __iomem *port_mmio,
struct mv_host_priv *hpriv,
struct mv_port_priv *pp)
@@ -783,39 +1002,160 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
/*
* initialize request queue
*/
- index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
+ pp->req_idx &= MV_MAX_Q_DEPTH_MASK; /* paranoia */
+ index = pp->req_idx << EDMA_REQ_Q_PTR_SHIFT;
WARN_ON(pp->crqb_dma & 0x3ff);
- writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
+ writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI);
writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | index,
- port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
-
- if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
- writelfl((pp->crqb_dma & 0xffffffff) | index,
- port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
- else
- writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+ port_mmio + EDMA_REQ_Q_IN_PTR);
+ writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR);
/*
* initialize response queue
*/
- index = (pp->resp_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_RSP_Q_PTR_SHIFT;
+ pp->resp_idx &= MV_MAX_Q_DEPTH_MASK; /* paranoia */
+ index = pp->resp_idx << EDMA_RSP_Q_PTR_SHIFT;
WARN_ON(pp->crpb_dma & 0xff);
- writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
+ writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI);
+ writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR);
+ writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | index,
+ port_mmio + EDMA_RSP_Q_OUT_PTR);
+}
- if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
- writelfl((pp->crpb_dma & 0xffffffff) | index,
- port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
- else
- writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+static void mv_write_main_irq_mask(u32 mask, struct mv_host_priv *hpriv)
+{
+ /*
+ * When writing to the main_irq_mask in hardware,
+ * we must ensure exclusivity between the interrupt coalescing bits
+ * and the corresponding individual port DONE_IRQ bits.
+ *
+ * Note that this register is really an "IRQ enable" register,
+ * not an "IRQ mask" register as Marvell's naming might suggest.
+ */
+ if (mask & (ALL_PORTS_COAL_DONE | PORTS_0_3_COAL_DONE))
+ mask &= ~DONE_IRQ_0_3;
+ if (mask & (ALL_PORTS_COAL_DONE | PORTS_4_7_COAL_DONE))
+ mask &= ~DONE_IRQ_4_7;
+ writelfl(mask, hpriv->main_irq_mask_addr);
+}
- writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | index,
- port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+static void mv_set_main_irq_mask(struct ata_host *host,
+ u32 disable_bits, u32 enable_bits)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ u32 old_mask, new_mask;
+
+ old_mask = hpriv->main_irq_mask;
+ new_mask = (old_mask & ~disable_bits) | enable_bits;
+ if (new_mask != old_mask) {
+ hpriv->main_irq_mask = new_mask;
+ mv_write_main_irq_mask(new_mask, hpriv);
+ }
+}
+
+static void mv_enable_port_irqs(struct ata_port *ap,
+ unsigned int port_bits)
+{
+ unsigned int shift, hardport, port = ap->port_no;
+ u32 disable_bits, enable_bits;
+
+ MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
+
+ disable_bits = (DONE_IRQ | ERR_IRQ) << shift;
+ enable_bits = port_bits << shift;
+ mv_set_main_irq_mask(ap->host, disable_bits, enable_bits);
+}
+
+static void mv_clear_and_enable_port_irqs(struct ata_port *ap,
+ void __iomem *port_mmio,
+ unsigned int port_irqs)
+{
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ int hardport = mv_hardport_from_port(ap->port_no);
+ void __iomem *hc_mmio = mv_hc_base_from_port(
+ mv_host_base(ap->host), ap->port_no);
+ u32 hc_irq_cause;
+
+ /* clear EDMA event indicators, if any */
+ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE);
+
+ /* clear pending irq events */
+ hc_irq_cause = ~((DEV_IRQ | DMA_IRQ) << hardport);
+ writelfl(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE);
+
+ /* clear FIS IRQ Cause */
+ if (IS_GEN_IIE(hpriv))
+ writelfl(0, port_mmio + FIS_IRQ_CAUSE);
+
+ mv_enable_port_irqs(ap, port_irqs);
+}
+
+static void mv_set_irq_coalescing(struct ata_host *host,
+ unsigned int count, unsigned int usecs)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->base, *hc_mmio;
+ u32 coal_enable = 0;
+ unsigned long flags;
+ unsigned int clks, is_dual_hc = hpriv->n_ports > MV_PORTS_PER_HC;
+ const u32 coal_disable = PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
+ ALL_PORTS_COAL_DONE;
+
+ /* Disable IRQ coalescing if either threshold is zero */
+ if (!usecs || !count) {
+ clks = count = 0;
+ } else {
+ /* Respect maximum limits of the hardware */
+ clks = usecs * COAL_CLOCKS_PER_USEC;
+ if (clks > MAX_COAL_TIME_THRESHOLD)
+ clks = MAX_COAL_TIME_THRESHOLD;
+ if (count > MAX_COAL_IO_COUNT)
+ count = MAX_COAL_IO_COUNT;
+ }
+
+ spin_lock_irqsave(&host->lock, flags);
+ mv_set_main_irq_mask(host, coal_disable, 0);
+
+ if (is_dual_hc && !IS_GEN_I(hpriv)) {
+ /*
+ * GEN_II/GEN_IIE with dual host controllers:
+ * one set of global thresholds for the entire chip.
+ */
+ writel(clks, mmio + IRQ_COAL_TIME_THRESHOLD);
+ writel(count, mmio + IRQ_COAL_IO_THRESHOLD);
+ /* clear leftover coal IRQ bit */
+ writel(~ALL_PORTS_COAL_IRQ, mmio + IRQ_COAL_CAUSE);
+ if (count)
+ coal_enable = ALL_PORTS_COAL_DONE;
+ clks = count = 0; /* force clearing of regular regs below */
+ }
+
+ /*
+ * All chips: independent thresholds for each HC on the chip.
+ */
+ hc_mmio = mv_hc_base_from_port(mmio, 0);
+ writel(clks, hc_mmio + HC_IRQ_COAL_TIME_THRESHOLD);
+ writel(count, hc_mmio + HC_IRQ_COAL_IO_THRESHOLD);
+ writel(~HC_COAL_IRQ, hc_mmio + HC_IRQ_CAUSE);
+ if (count)
+ coal_enable |= PORTS_0_3_COAL_DONE;
+ if (is_dual_hc) {
+ hc_mmio = mv_hc_base_from_port(mmio, MV_PORTS_PER_HC);
+ writel(clks, hc_mmio + HC_IRQ_COAL_TIME_THRESHOLD);
+ writel(count, hc_mmio + HC_IRQ_COAL_IO_THRESHOLD);
+ writel(~HC_COAL_IRQ, hc_mmio + HC_IRQ_CAUSE);
+ if (count)
+ coal_enable |= PORTS_4_7_COAL_DONE;
+ }
+
+ mv_set_main_irq_mask(host, 0, coal_enable);
+ spin_unlock_irqrestore(&host->lock, flags);
}
/**
- * mv_start_dma - Enable eDMA engine
+ * mv_start_edma - Enable eDMA engine
* @base: port base address
* @pp: port private data
*
@@ -825,7 +1165,7 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
* LOCKING:
* Inherited from caller.
*/
-static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
+static void mv_start_edma(struct ata_port *ap, void __iomem *port_mmio,
struct mv_port_priv *pp, u8 protocol)
{
int want_ncq = (protocol == ATA_PROT_NCQ);
@@ -837,34 +1177,38 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
}
if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
struct mv_host_priv *hpriv = ap->host->private_data;
- int hard_port = mv_hardport_from_port(ap->port_no);
- void __iomem *hc_mmio = mv_hc_base_from_port(
- mv_host_base(ap->host), hard_port);
- u32 hc_irq_cause, ipending;
-
- /* clear EDMA event indicators, if any */
- writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
-
- /* clear EDMA interrupt indicator, if any */
- hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
- ipending = (DEV_IRQ << hard_port) |
- (CRPB_DMA_DONE << hard_port);
- if (hc_irq_cause & ipending) {
- writelfl(hc_irq_cause & ~ipending,
- hc_mmio + HC_IRQ_CAUSE_OFS);
- }
- mv_edma_cfg(ap, want_ncq);
-
- /* clear FIS IRQ Cause */
- writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
+ mv_edma_cfg(ap, want_ncq, 1);
mv_set_edma_ptrs(port_mmio, hpriv, pp);
+ mv_clear_and_enable_port_irqs(ap, port_mmio, DONE_IRQ|ERR_IRQ);
- writelfl(EDMA_EN, port_mmio + EDMA_CMD_OFS);
+ writelfl(EDMA_EN, port_mmio + EDMA_CMD);
pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
}
- WARN_ON(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)));
+}
+
+static void mv_wait_for_edma_empty_idle(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ const u32 empty_idle = (EDMA_STATUS_CACHE_EMPTY | EDMA_STATUS_IDLE);
+ const int per_loop = 5, timeout = (15 * 1000 / per_loop);
+ int i;
+
+ /*
+ * Wait for the EDMA engine to finish transactions in progress.
+ * No idea what a good "timeout" value might be, but measurements
+ * indicate that it often requires hundreds of microseconds
+ * with two drives in-use. So we use the 15msec value above
+ * as a rough guess at what even more drives might require.
+ */
+ for (i = 0; i < timeout; ++i) {
+ u32 edma_stat = readl(port_mmio + EDMA_STATUS);
+ if ((edma_stat & empty_idle) == empty_idle)
+ break;
+ udelay(per_loop);
+ }
+ /* ata_port_info(ap, "%s: %u+ usecs\n", __func__, i); */
}
/**
@@ -879,11 +1223,11 @@ static int mv_stop_edma_engine(void __iomem *port_mmio)
int i;
/* Disable eDMA. The disable bit auto clears. */
- writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
+ writelfl(EDMA_DS, port_mmio + EDMA_CMD);
/* Wait for the chip to confirm eDMA is off. */
for (i = 10000; i > 0; i--) {
- u32 reg = readl(port_mmio + EDMA_CMD_OFS);
+ u32 reg = readl(port_mmio + EDMA_CMD);
if (!(reg & EDMA_EN))
return 0;
udelay(10);
@@ -895,15 +1239,18 @@ static int mv_stop_edma(struct ata_port *ap)
{
void __iomem *port_mmio = mv_ap_base(ap);
struct mv_port_priv *pp = ap->private_data;
+ int err = 0;
if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN))
return 0;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+ mv_wait_for_edma_empty_idle(ap);
if (mv_stop_edma_engine(port_mmio)) {
- ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
- return -EIO;
+ ata_port_err(ap, "Unable to stop eDMA\n");
+ err = -EIO;
}
- return 0;
+ mv_edma_cfg(ap, 0, 0);
+ return err;
}
#ifdef ATA_DEBUG
@@ -920,7 +1267,7 @@ static void mv_dump_mem(void __iomem *start, unsigned bytes)
}
}
#endif
-
+#if defined(ATA_DEBUG) || defined(CONFIG_PCI)
static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
{
#ifdef ATA_DEBUG
@@ -937,6 +1284,7 @@ static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
}
#endif
}
+#endif
static void mv_dump_all_regs(void __iomem *mmio_base, int port,
struct pci_dev *pdev)
{
@@ -990,10 +1338,10 @@ static unsigned int mv_scr_offset(unsigned int sc_reg_in)
case SCR_STATUS:
case SCR_CONTROL:
case SCR_ERROR:
- ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
+ ofs = SATA_STATUS + (sc_reg_in * sizeof(u32));
break;
case SCR_ACTIVE:
- ofs = SATA_ACTIVE_OFS; /* active is not with the others */
+ ofs = SATA_ACTIVE; /* active is not with the others */
break;
default:
ofs = 0xffffffffU;
@@ -1002,23 +1350,54 @@ static unsigned int mv_scr_offset(unsigned int sc_reg_in)
return ofs;
}
-static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
+static int mv_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU) {
- *val = readl(mv_ap_base(ap) + ofs);
+ *val = readl(mv_ap_base(link->ap) + ofs);
return 0;
} else
return -EINVAL;
}
-static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU) {
- writelfl(val, mv_ap_base(ap) + ofs);
+ void __iomem *addr = mv_ap_base(link->ap) + ofs;
+ struct mv_host_priv *hpriv = link->ap->host->private_data;
+ if (sc_reg_in == SCR_CONTROL) {
+ /*
+ * Workaround for 88SX60x1 FEr SATA#26:
+ *
+ * COMRESETs have to take care not to accidentally
+ * put the drive to sleep when writing SCR_CONTROL.
+ * Setting bits 12..15 prevents this problem.
+ *
+ * So if we see an outbound COMMRESET, set those bits.
+ * Ditto for the followup write that clears the reset.
+ *
+ * The proprietary driver does this for
+ * all chip versions, and so do we.
+ */
+ if ((val & 0xf) == 1 || (readl(addr) & 0xf) == 1)
+ val |= 0xf000;
+
+ if (hpriv->hp_flags & MV_HP_FIX_LP_PHY_CTL) {
+ void __iomem *lp_phy_addr =
+ mv_ap_base(link->ap) + LP_PHY_CTL;
+ /*
+ * Set PHY speed according to SControl speed.
+ */
+ if ((val & 0xf0) == 0x10)
+ writelfl(0x7, lp_phy_addr);
+ else
+ writelfl(0x227, lp_phy_addr);
+ }
+ }
+ writelfl(val, addr);
return 0;
} else
return -EINVAL;
@@ -1031,41 +1410,196 @@ static void mv6_dev_config(struct ata_device *adev)
*
* Gen-II does not support NCQ over a port multiplier
* (no FIS-based switching).
- *
- * We don't have hob_nsect when doing NCQ commands on Gen-II.
- * See mv_qc_prep() for more info.
*/
if (adev->flags & ATA_DFLAG_NCQ) {
- if (sata_pmp_attached(adev->link->ap))
+ if (sata_pmp_attached(adev->link->ap)) {
adev->flags &= ~ATA_DFLAG_NCQ;
- else if (adev->max_sectors > ATA_MAX_SECTORS)
- adev->max_sectors = ATA_MAX_SECTORS;
+ ata_dev_info(adev,
+ "NCQ disabled for command-based switching\n");
+ }
}
}
-static void mv_config_fbs(void __iomem *port_mmio, int enable_fbs)
+static int mv_qc_defer(struct ata_queued_cmd *qc)
{
- u32 old_fcfg, new_fcfg, old_ltmode, new_ltmode;
+ struct ata_link *link = qc->dev->link;
+ struct ata_port *ap = link->ap;
+ struct mv_port_priv *pp = ap->private_data;
+
+ /*
+ * Don't allow new commands if we're in a delayed EH state
+ * for NCQ and/or FIS-based switching.
+ */
+ if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH)
+ return ATA_DEFER_PORT;
+
+ /* PIO commands need exclusive link: no other commands [DMA or PIO]
+ * can run concurrently.
+ * set excl_link when we want to send a PIO command in DMA mode
+ * or a non-NCQ command in NCQ mode.
+ * When we receive a command from that link, and there are no
+ * outstanding commands, mark a flag to clear excl_link and let
+ * the command go through.
+ */
+ if (unlikely(ap->excl_link)) {
+ if (link == ap->excl_link) {
+ if (ap->nr_active_links)
+ return ATA_DEFER_PORT;
+ qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+ return 0;
+ } else
+ return ATA_DEFER_PORT;
+ }
+
/*
- * Various bit settings required for operation
- * in FIS-based switching (fbs) mode on GenIIe:
+ * If the port is completely idle, then allow the new qc.
*/
- old_fcfg = readl(port_mmio + FIS_CFG_OFS);
- old_ltmode = readl(port_mmio + LTMODE_OFS);
- if (enable_fbs) {
- new_fcfg = old_fcfg | FIS_CFG_SINGLE_SYNC;
- new_ltmode = old_ltmode | LTMODE_BIT8;
- } else { /* disable fbs */
- new_fcfg = old_fcfg & ~FIS_CFG_SINGLE_SYNC;
- new_ltmode = old_ltmode & ~LTMODE_BIT8;
+ if (ap->nr_active_links == 0)
+ return 0;
+
+ /*
+ * The port is operating in host queuing mode (EDMA) with NCQ
+ * enabled, allow multiple NCQ commands. EDMA also allows
+ * queueing multiple DMA commands but libata core currently
+ * doesn't allow it.
+ */
+ if ((pp->pp_flags & MV_PP_FLAG_EDMA_EN) &&
+ (pp->pp_flags & MV_PP_FLAG_NCQ_EN)) {
+ if (ata_is_ncq(qc->tf.protocol))
+ return 0;
+ else {
+ ap->excl_link = link;
+ return ATA_DEFER_PORT;
+ }
+ }
+
+ return ATA_DEFER_PORT;
+}
+
+static void mv_config_fbs(struct ata_port *ap, int want_ncq, int want_fbs)
+{
+ struct mv_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio;
+
+ u32 fiscfg, *old_fiscfg = &pp->cached.fiscfg;
+ u32 ltmode, *old_ltmode = &pp->cached.ltmode;
+ u32 haltcond, *old_haltcond = &pp->cached.haltcond;
+
+ ltmode = *old_ltmode & ~LTMODE_BIT8;
+ haltcond = *old_haltcond | EDMA_ERR_DEV;
+
+ if (want_fbs) {
+ fiscfg = *old_fiscfg | FISCFG_SINGLE_SYNC;
+ ltmode = *old_ltmode | LTMODE_BIT8;
+ if (want_ncq)
+ haltcond &= ~EDMA_ERR_DEV;
+ else
+ fiscfg |= FISCFG_WAIT_DEV_ERR;
+ } else {
+ fiscfg = *old_fiscfg & ~(FISCFG_SINGLE_SYNC | FISCFG_WAIT_DEV_ERR);
+ }
+
+ port_mmio = mv_ap_base(ap);
+ mv_write_cached_reg(port_mmio + FISCFG, old_fiscfg, fiscfg);
+ mv_write_cached_reg(port_mmio + LTMODE, old_ltmode, ltmode);
+ mv_write_cached_reg(port_mmio + EDMA_HALTCOND, old_haltcond, haltcond);
+}
+
+static void mv_60x1_errata_sata25(struct ata_port *ap, int want_ncq)
+{
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ u32 old, new;
+
+ /* workaround for 88SX60x1 FEr SATA#25 (part 1) */
+ old = readl(hpriv->base + GPIO_PORT_CTL);
+ if (want_ncq)
+ new = old | (1 << 22);
+ else
+ new = old & ~(1 << 22);
+ if (new != old)
+ writel(new, hpriv->base + GPIO_PORT_CTL);
+}
+
+/**
+ * mv_bmdma_enable - set a magic bit on GEN_IIE to allow bmdma
+ * @ap: Port being initialized
+ *
+ * There are two DMA modes on these chips: basic DMA, and EDMA.
+ *
+ * Bit-0 of the "EDMA RESERVED" register enables/disables use
+ * of basic DMA on the GEN_IIE versions of the chips.
+ *
+ * This bit survives EDMA resets, and must be set for basic DMA
+ * to function, and should be cleared when EDMA is active.
+ */
+static void mv_bmdma_enable_iie(struct ata_port *ap, int enable_bmdma)
+{
+ struct mv_port_priv *pp = ap->private_data;
+ u32 new, *old = &pp->cached.unknown_rsvd;
+
+ if (enable_bmdma)
+ new = *old | 1;
+ else
+ new = *old & ~1;
+ mv_write_cached_reg(mv_ap_base(ap) + EDMA_UNKNOWN_RSVD, old, new);
+}
+
+/*
+ * SOC chips have an issue whereby the HDD LEDs don't always blink
+ * during I/O when NCQ is enabled. Enabling a special "LED blink" mode
+ * of the SOC takes care of it, generating a steady blink rate when
+ * any drive on the chip is active.
+ *
+ * Unfortunately, the blink mode is a global hardware setting for the SOC,
+ * so we must use it whenever at least one port on the SOC has NCQ enabled.
+ *
+ * We turn "LED blink" off when NCQ is not in use anywhere, because the normal
+ * LED operation works then, and provides better (more accurate) feedback.
+ *
+ * Note that this code assumes that an SOC never has more than one HC onboard.
+ */
+static void mv_soc_led_blink_enable(struct ata_port *ap)
+{
+ struct ata_host *host = ap->host;
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *hc_mmio;
+ u32 led_ctrl;
+
+ if (hpriv->hp_flags & MV_HP_QUIRK_LED_BLINK_EN)
+ return;
+ hpriv->hp_flags |= MV_HP_QUIRK_LED_BLINK_EN;
+ hc_mmio = mv_hc_base_from_port(mv_host_base(host), ap->port_no);
+ led_ctrl = readl(hc_mmio + SOC_LED_CTRL);
+ writel(led_ctrl | SOC_LED_CTRL_BLINK, hc_mmio + SOC_LED_CTRL);
+}
+
+static void mv_soc_led_blink_disable(struct ata_port *ap)
+{
+ struct ata_host *host = ap->host;
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *hc_mmio;
+ u32 led_ctrl;
+ unsigned int port;
+
+ if (!(hpriv->hp_flags & MV_HP_QUIRK_LED_BLINK_EN))
+ return;
+
+ /* disable led-blink only if no ports are using NCQ */
+ for (port = 0; port < hpriv->n_ports; port++) {
+ struct ata_port *this_ap = host->ports[port];
+ struct mv_port_priv *pp = this_ap->private_data;
+
+ if (pp->pp_flags & MV_PP_FLAG_NCQ_EN)
+ return;
}
- if (new_fcfg != old_fcfg)
- writelfl(new_fcfg, port_mmio + FIS_CFG_OFS);
- if (new_ltmode != old_ltmode)
- writelfl(new_ltmode, port_mmio + LTMODE_OFS);
+
+ hpriv->hp_flags &= ~MV_HP_QUIRK_LED_BLINK_EN;
+ hc_mmio = mv_hc_base_from_port(mv_host_base(host), ap->port_no);
+ led_ctrl = readl(hc_mmio + SOC_LED_CTRL);
+ writel(led_ctrl & ~SOC_LED_CTRL_BLINK, hc_mmio + SOC_LED_CTRL);
}
-static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
+static void mv_edma_cfg(struct ata_port *ap, int want_ncq, int want_edma)
{
u32 cfg;
struct mv_port_priv *pp = ap->private_data;
@@ -1074,34 +1608,59 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
/* set up non-NCQ EDMA configuration */
cfg = EDMA_CFG_Q_DEPTH; /* always 0x1f for *all* chips */
+ pp->pp_flags &=
+ ~(MV_PP_FLAG_FBS_EN | MV_PP_FLAG_NCQ_EN | MV_PP_FLAG_FAKE_ATA_BUSY);
if (IS_GEN_I(hpriv))
cfg |= (1 << 8); /* enab config burst size mask */
- else if (IS_GEN_II(hpriv))
+ else if (IS_GEN_II(hpriv)) {
cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
+ mv_60x1_errata_sata25(ap, want_ncq);
- else if (IS_GEN_IIE(hpriv)) {
- cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */
- cfg |= (1 << 22); /* enab 4-entry host queue cache */
- cfg |= (1 << 18); /* enab early completion */
- cfg |= (1 << 17); /* enab cut-through (dis stor&forwrd) */
+ } else if (IS_GEN_IIE(hpriv)) {
+ int want_fbs = sata_pmp_attached(ap);
+ /*
+ * Possible future enhancement:
+ *
+ * The chip can use FBS with non-NCQ, if we allow it,
+ * But first we need to have the error handling in place
+ * for this mode (datasheet section 7.3.15.4.2.3).
+ * So disallow non-NCQ FBS for now.
+ */
+ want_fbs &= want_ncq;
- if (want_ncq && sata_pmp_attached(ap)) {
+ mv_config_fbs(ap, want_ncq, want_fbs);
+
+ if (want_fbs) {
+ pp->pp_flags |= MV_PP_FLAG_FBS_EN;
cfg |= EDMA_CFG_EDMA_FBS; /* FIS-based switching */
- mv_config_fbs(port_mmio, 1);
- } else {
- mv_config_fbs(port_mmio, 0);
+ }
+
+ cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */
+ if (want_edma) {
+ cfg |= (1 << 22); /* enab 4-entry host queue cache */
+ if (!IS_SOC(hpriv))
+ cfg |= (1 << 18); /* enab early completion */
+ }
+ if (hpriv->hp_flags & MV_HP_CUT_THROUGH)
+ cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */
+ mv_bmdma_enable_iie(ap, !want_edma);
+
+ if (IS_SOC(hpriv)) {
+ if (want_ncq)
+ mv_soc_led_blink_enable(ap);
+ else
+ mv_soc_led_blink_disable(ap);
}
}
if (want_ncq) {
cfg |= EDMA_CFG_NCQ;
pp->pp_flags |= MV_PP_FLAG_NCQ_EN;
- } else
- pp->pp_flags &= ~MV_PP_FLAG_NCQ_EN;
+ }
- writelfl(cfg, port_mmio + EDMA_CFG_OFS);
+ writelfl(cfg, port_mmio + EDMA_CFG);
}
static void mv_port_free_dma_mem(struct ata_port *ap)
@@ -1148,6 +1707,7 @@ static int mv_port_start(struct ata_port *ap)
struct device *dev = ap->host->dev;
struct mv_host_priv *hpriv = ap->host->private_data;
struct mv_port_priv *pp;
+ unsigned long flags;
int tag;
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
@@ -1165,6 +1725,9 @@ static int mv_port_start(struct ata_port *ap)
goto out_port_free_dma_mem;
memset(pp->crpb, 0, MV_CRPB_Q_SZ);
+ /* 6041/6081 Rev. "C0" (and newer) are okay with async notify */
+ if (hpriv->hp_flags & MV_HP_ERRATA_60X1C0)
+ ap->flags |= ATA_FLAG_AN;
/*
* For GEN_I, there's no NCQ, so we only allocate a single sg_tbl.
* For later hardware, we need one unique sg_tbl per NCQ tag.
@@ -1180,6 +1743,12 @@ static int mv_port_start(struct ata_port *ap)
pp->sg_tbl_dma[tag] = pp->sg_tbl_dma[0];
}
}
+
+ spin_lock_irqsave(ap->lock, flags);
+ mv_save_cached_regs(ap);
+ mv_edma_cfg(ap, 0, 0);
+ spin_unlock_irqrestore(ap->lock, flags);
+
return 0;
out_port_free_dma_mem:
@@ -1198,7 +1767,12 @@ out_port_free_dma_mem:
*/
static void mv_port_stop(struct ata_port *ap)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(ap->lock, flags);
mv_stop_edma(ap);
+ mv_enable_port_irqs(ap, 0);
+ spin_unlock_irqrestore(ap->lock, flags);
mv_port_free_dma_mem(ap);
}
@@ -1227,12 +1801,13 @@ static void mv_fill_sg(struct ata_queued_cmd *qc)
u32 offset = addr & 0xffff;
u32 len = sg_len;
- if ((offset + sg_len > 0x10000))
+ if (offset + len > 0x10000)
len = 0x10000 - offset;
mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
mv_sg->flags_size = cpu_to_le32(len & 0xffff);
+ mv_sg->reserved = 0;
sg_len -= len;
addr += len;
@@ -1244,6 +1819,7 @@ static void mv_fill_sg(struct ata_queued_cmd *qc)
if (likely(last_sg))
last_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
+ mb(); /* ensure data structure is visible to the chipset */
}
static void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
@@ -1254,6 +1830,199 @@ static void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
}
/**
+ * mv_sff_irq_clear - Clear hardware interrupt after DMA.
+ * @ap: Port associated with this ATA transaction.
+ *
+ * We need this only for ATAPI bmdma transactions,
+ * as otherwise we experience spurious interrupts
+ * after libata-sff handles the bmdma interrupts.
+ */
+static void mv_sff_irq_clear(struct ata_port *ap)
+{
+ mv_clear_and_enable_port_irqs(ap, mv_ap_base(ap), ERR_IRQ);
+}
+
+/**
+ * mv_check_atapi_dma - Filter ATAPI cmds which are unsuitable for DMA.
+ * @qc: queued command to check for chipset/DMA compatibility.
+ *
+ * The bmdma engines cannot handle speculative data sizes
+ * (bytecount under/over flow). So only allow DMA for
+ * data transfer commands with known data sizes.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static int mv_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *scmd = qc->scsicmd;
+
+ if (scmd) {
+ switch (scmd->cmnd[0]) {
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ case GPCMD_READ_CD:
+ case GPCMD_SEND_DVD_STRUCTURE:
+ case GPCMD_SEND_CUE_SHEET:
+ return 0; /* DMA is safe */
+ }
+ }
+ return -EOPNOTSUPP; /* use PIO instead */
+}
+
+/**
+ * mv_bmdma_setup - Set up BMDMA transaction
+ * @qc: queued command to prepare DMA for.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *port_mmio = mv_ap_base(ap);
+ struct mv_port_priv *pp = ap->private_data;
+
+ mv_fill_sg(qc);
+
+ /* clear all DMA cmd bits */
+ writel(0, port_mmio + BMDMA_CMD);
+
+ /* load PRD table addr. */
+ writel((pp->sg_tbl_dma[qc->tag] >> 16) >> 16,
+ port_mmio + BMDMA_PRD_HIGH);
+ writelfl(pp->sg_tbl_dma[qc->tag],
+ port_mmio + BMDMA_PRD_LOW);
+
+ /* issue r/w command */
+ ap->ops->sff_exec_command(ap, &qc->tf);
+}
+
+/**
+ * mv_bmdma_start - Start a BMDMA transaction
+ * @qc: queued command to start DMA on.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *port_mmio = mv_ap_base(ap);
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+ u32 cmd = (rw ? 0 : ATA_DMA_WR) | ATA_DMA_START;
+
+ /* start host DMA transaction */
+ writelfl(cmd, port_mmio + BMDMA_CMD);
+}
+
+/**
+ * mv_bmdma_stop - Stop BMDMA transfer
+ * @qc: queued command to stop DMA on.
+ *
+ * Clears the ATA_DMA_START flag in the bmdma control register
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_bmdma_stop_ap(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ u32 cmd;
+
+ /* clear start/stop bit */
+ cmd = readl(port_mmio + BMDMA_CMD);
+ if (cmd & ATA_DMA_START) {
+ cmd &= ~ATA_DMA_START;
+ writelfl(cmd, port_mmio + BMDMA_CMD);
+
+ /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+ ata_sff_dma_pause(ap);
+ }
+}
+
+static void mv_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ mv_bmdma_stop_ap(qc->ap);
+}
+
+/**
+ * mv_bmdma_status - Read BMDMA status
+ * @ap: port for which to retrieve DMA status.
+ *
+ * Read and return equivalent of the sff BMDMA status register.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static u8 mv_bmdma_status(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ u32 reg, status;
+
+ /*
+ * Other bits are valid only if ATA_DMA_ACTIVE==0,
+ * and the ATA_DMA_INTR bit doesn't exist.
+ */
+ reg = readl(port_mmio + BMDMA_STATUS);
+ if (reg & ATA_DMA_ACTIVE)
+ status = ATA_DMA_ACTIVE;
+ else if (reg & ATA_DMA_ERR)
+ status = (reg & ATA_DMA_ERR) | ATA_DMA_INTR;
+ else {
+ /*
+ * Just because DMA_ACTIVE is 0 (DMA completed),
+ * this does _not_ mean the device is "done".
+ * So we should not yet be signalling ATA_DMA_INTR
+ * in some cases. Eg. DSM/TRIM, and perhaps others.
+ */
+ mv_bmdma_stop_ap(ap);
+ if (ioread8(ap->ioaddr.altstatus_addr) & ATA_BUSY)
+ status = 0;
+ else
+ status = ATA_DMA_INTR;
+ }
+ return status;
+}
+
+static void mv_rw_multi_errata_sata24(struct ata_queued_cmd *qc)
+{
+ struct ata_taskfile *tf = &qc->tf;
+ /*
+ * Workaround for 88SX60x1 FEr SATA#24.
+ *
+ * Chip may corrupt WRITEs if multi_count >= 4kB.
+ * Note that READs are unaffected.
+ *
+ * It's not clear if this errata really means "4K bytes",
+ * or if it always happens for multi_count > 7
+ * regardless of device sector_size.
+ *
+ * So, for safety, any write with multi_count > 7
+ * gets converted here into a regular PIO write instead:
+ */
+ if ((tf->flags & ATA_TFLAG_WRITE) && is_multi_taskfile(tf)) {
+ if (qc->dev->multi_count > 7) {
+ switch (tf->command) {
+ case ATA_CMD_WRITE_MULTI:
+ tf->command = ATA_CMD_PIO_WRITE;
+ break;
+ case ATA_CMD_WRITE_MULTI_FUA_EXT:
+ tf->flags &= ~ATA_TFLAG_FUA; /* ugh */
+ /* fall through */
+ case ATA_CMD_WRITE_MULTI_EXT:
+ tf->command = ATA_CMD_PIO_WRITE_EXT;
+ break;
+ }
+ }
+ }
+}
+
+/**
* mv_qc_prep - Host specific command preparation.
* @qc: queued command to prepare
*
@@ -1270,24 +2039,34 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct mv_port_priv *pp = ap->private_data;
__le16 *cw;
- struct ata_taskfile *tf;
+ struct ata_taskfile *tf = &qc->tf;
u16 flags = 0;
unsigned in_index;
- if ((qc->tf.protocol != ATA_PROT_DMA) &&
- (qc->tf.protocol != ATA_PROT_NCQ))
+ switch (tf->protocol) {
+ case ATA_PROT_DMA:
+ if (tf->command == ATA_CMD_DSM)
+ return;
+ /* fall-thru */
+ case ATA_PROT_NCQ:
+ break; /* continue below */
+ case ATA_PROT_PIO:
+ mv_rw_multi_errata_sata24(qc);
return;
+ default:
+ return;
+ }
/* Fill in command request block
*/
- if (!(qc->tf.flags & ATA_TFLAG_WRITE))
+ if (!(tf->flags & ATA_TFLAG_WRITE))
flags |= CRQB_FLAG_READ;
WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
flags |= qc->tag << CRQB_TAG_SHIFT;
flags |= (qc->dev->link->pmp & 0xf) << CRQB_PMP_SHIFT;
/* get current queue index from software */
- in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
+ in_index = pp->req_idx;
pp->crqb[in_index].sg_addr =
cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
@@ -1296,13 +2075,13 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
cw = &pp->crqb[in_index].ata_cmd[0];
- tf = &qc->tf;
- /* Sadly, the CRQB cannot accomodate all registers--there are
+ /* Sadly, the CRQB cannot accommodate all registers--there are
* only 11 bytes...so we must pick and choose required
* registers based on the command. So, we drop feature and
* hob_feature for [RW] DMA commands, but they are needed for
- * NCQ. NCQ will drop hob_nsect.
+ * NCQ. NCQ will drop hob_nsect, which is not needed there
+ * (nsect is used only for the tag; feat/hob_feat hold true nsect).
*/
switch (tf->command) {
case ATA_CMD_READ:
@@ -1361,16 +2140,18 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct mv_port_priv *pp = ap->private_data;
struct mv_crqb_iie *crqb;
- struct ata_taskfile *tf;
+ struct ata_taskfile *tf = &qc->tf;
unsigned in_index;
u32 flags = 0;
- if ((qc->tf.protocol != ATA_PROT_DMA) &&
- (qc->tf.protocol != ATA_PROT_NCQ))
+ if ((tf->protocol != ATA_PROT_DMA) &&
+ (tf->protocol != ATA_PROT_NCQ))
return;
+ if (tf->command == ATA_CMD_DSM)
+ return; /* use bmdma for this */
/* Fill in Gen IIE command request block */
- if (!(qc->tf.flags & ATA_TFLAG_WRITE))
+ if (!(tf->flags & ATA_TFLAG_WRITE))
flags |= CRQB_FLAG_READ;
WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
@@ -1379,14 +2160,13 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
flags |= (qc->dev->link->pmp & 0xf) << CRQB_PMP_SHIFT;
/* get current queue index from software */
- in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
+ in_index = pp->req_idx;
crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
crqb->addr = cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16);
crqb->flags = cpu_to_le32(flags);
- tf = &qc->tf;
crqb->ata_cmd[0] = cpu_to_le32(
(tf->command << 16) |
(tf->feature << 24)
@@ -1414,6 +2194,131 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
}
/**
+ * mv_sff_check_status - fetch device status, if valid
+ * @ap: ATA port to fetch status from
+ *
+ * When using command issue via mv_qc_issue_fis(),
+ * the initial ATA_BUSY state does not show up in the
+ * ATA status (shadow) register. This can confuse libata!
+ *
+ * So we have a hook here to fake ATA_BUSY for that situation,
+ * until the first time a BUSY, DRQ, or ERR bit is seen.
+ *
+ * The rest of the time, it simply returns the ATA status register.
+ */
+static u8 mv_sff_check_status(struct ata_port *ap)
+{
+ u8 stat = ioread8(ap->ioaddr.status_addr);
+ struct mv_port_priv *pp = ap->private_data;
+
+ if (pp->pp_flags & MV_PP_FLAG_FAKE_ATA_BUSY) {
+ if (stat & (ATA_BUSY | ATA_DRQ | ATA_ERR))
+ pp->pp_flags &= ~MV_PP_FLAG_FAKE_ATA_BUSY;
+ else
+ stat = ATA_BUSY;
+ }
+ return stat;
+}
+
+/**
+ * mv_send_fis - Send a FIS, using the "Vendor-Unique FIS" register
+ * @fis: fis to be sent
+ * @nwords: number of 32-bit words in the fis
+ */
+static unsigned int mv_send_fis(struct ata_port *ap, u32 *fis, int nwords)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ u32 ifctl, old_ifctl, ifstat;
+ int i, timeout = 200, final_word = nwords - 1;
+
+ /* Initiate FIS transmission mode */
+ old_ifctl = readl(port_mmio + SATA_IFCTL);
+ ifctl = 0x100 | (old_ifctl & 0xf);
+ writelfl(ifctl, port_mmio + SATA_IFCTL);
+
+ /* Send all words of the FIS except for the final word */
+ for (i = 0; i < final_word; ++i)
+ writel(fis[i], port_mmio + VENDOR_UNIQUE_FIS);
+
+ /* Flag end-of-transmission, and then send the final word */
+ writelfl(ifctl | 0x200, port_mmio + SATA_IFCTL);
+ writelfl(fis[final_word], port_mmio + VENDOR_UNIQUE_FIS);
+
+ /*
+ * Wait for FIS transmission to complete.
+ * This typically takes just a single iteration.
+ */
+ do {
+ ifstat = readl(port_mmio + SATA_IFSTAT);
+ } while (!(ifstat & 0x1000) && --timeout);
+
+ /* Restore original port configuration */
+ writelfl(old_ifctl, port_mmio + SATA_IFCTL);
+
+ /* See if it worked */
+ if ((ifstat & 0x3000) != 0x1000) {
+ ata_port_warn(ap, "%s transmission error, ifstat=%08x\n",
+ __func__, ifstat);
+ return AC_ERR_OTHER;
+ }
+ return 0;
+}
+
+/**
+ * mv_qc_issue_fis - Issue a command directly as a FIS
+ * @qc: queued command to start
+ *
+ * Note that the ATA shadow registers are not updated
+ * after command issue, so the device will appear "READY"
+ * if polled, even while it is BUSY processing the command.
+ *
+ * So we use a status hook to fake ATA_BUSY until the drive changes state.
+ *
+ * Note: we don't get updated shadow regs on *completion*
+ * of non-data commands. So avoid sending them via this function,
+ * as they will appear to have completed immediately.
+ *
+ * GEN_IIE has special registers that we could get the result tf from,
+ * but earlier chipsets do not. For now, we ignore those registers.
+ */
+static unsigned int mv_qc_issue_fis(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct mv_port_priv *pp = ap->private_data;
+ struct ata_link *link = qc->dev->link;
+ u32 fis[5];
+ int err = 0;
+
+ ata_tf_to_fis(&qc->tf, link->pmp, 1, (void *)fis);
+ err = mv_send_fis(ap, fis, ARRAY_SIZE(fis));
+ if (err)
+ return err;
+
+ switch (qc->tf.protocol) {
+ case ATAPI_PROT_PIO:
+ pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY;
+ /* fall through */
+ case ATAPI_PROT_NODATA:
+ ap->hsm_task_state = HSM_ST_FIRST;
+ break;
+ case ATA_PROT_PIO:
+ pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY;
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ ap->hsm_task_state = HSM_ST_FIRST;
+ else
+ ap->hsm_task_state = HSM_ST;
+ break;
+ default:
+ ap->hsm_task_state = HSM_ST_LAST;
+ break;
+ }
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_sff_queue_pio_task(link, 0);
+ return 0;
+}
+
+/**
* mv_qc_issue - Initiate a command to the host
* @qc: queued command to start
*
@@ -1427,80 +2332,370 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
*/
static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
{
+ static int limit_warnings = 10;
struct ata_port *ap = qc->ap;
void __iomem *port_mmio = mv_ap_base(ap);
struct mv_port_priv *pp = ap->private_data;
u32 in_index;
+ unsigned int port_irqs;
+
+ pp->pp_flags &= ~MV_PP_FLAG_FAKE_ATA_BUSY; /* paranoia */
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ if (qc->tf.command == ATA_CMD_DSM) {
+ if (!ap->ops->bmdma_setup) /* no bmdma on GEN_I */
+ return AC_ERR_OTHER;
+ break; /* use bmdma for this */
+ }
+ /* fall thru */
+ case ATA_PROT_NCQ:
+ mv_start_edma(ap, port_mmio, pp, qc->tf.protocol);
+ pp->req_idx = (pp->req_idx + 1) & MV_MAX_Q_DEPTH_MASK;
+ in_index = pp->req_idx << EDMA_REQ_Q_PTR_SHIFT;
+
+ /* Write the request in pointer to kick the EDMA to life */
+ writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | in_index,
+ port_mmio + EDMA_REQ_Q_IN_PTR);
+ return 0;
- if ((qc->tf.protocol != ATA_PROT_DMA) &&
- (qc->tf.protocol != ATA_PROT_NCQ)) {
+ case ATA_PROT_PIO:
/*
- * We're about to send a non-EDMA capable command to the
- * port. Turn off EDMA so there won't be problems accessing
- * shadow block, etc registers.
+ * Errata SATA#16, SATA#24: warn if multiple DRQs expected.
+ *
+ * Someday, we might implement special polling workarounds
+ * for these, but it all seems rather unnecessary since we
+ * normally use only DMA for commands which transfer more
+ * than a single block of data.
+ *
+ * Much of the time, this could just work regardless.
+ * So for now, just log the incident, and allow the attempt.
*/
+ if (limit_warnings > 0 && (qc->nbytes / qc->sect_size) > 1) {
+ --limit_warnings;
+ ata_link_warn(qc->dev->link, DRV_NAME
+ ": attempting PIO w/multiple DRQ: "
+ "this may fail due to h/w errata\n");
+ }
+ /* drop through */
+ case ATA_PROT_NODATA:
+ case ATAPI_PROT_PIO:
+ case ATAPI_PROT_NODATA:
+ if (ap->flags & ATA_FLAG_PIO_POLLING)
+ qc->tf.flags |= ATA_TFLAG_POLLING;
+ break;
+ }
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ port_irqs = ERR_IRQ; /* mask device interrupt when polling */
+ else
+ port_irqs = ERR_IRQ | DONE_IRQ; /* unmask all interrupts */
+
+ /*
+ * We're about to send a non-EDMA capable command to the
+ * port. Turn off EDMA so there won't be problems accessing
+ * shadow block, etc registers.
+ */
+ mv_stop_edma(ap);
+ mv_clear_and_enable_port_irqs(ap, mv_ap_base(ap), port_irqs);
+ mv_pmp_select(ap, qc->dev->link->pmp);
+
+ if (qc->tf.command == ATA_CMD_READ_LOG_EXT) {
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ /*
+ * Workaround for 88SX60x1 FEr SATA#25 (part 2).
+ *
+ * After any NCQ error, the READ_LOG_EXT command
+ * from libata-eh *must* use mv_qc_issue_fis().
+ * Otherwise it might fail, due to chip errata.
+ *
+ * Rather than special-case it, we'll just *always*
+ * use this method here for READ_LOG_EXT, making for
+ * easier testing.
+ */
+ if (IS_GEN_II(hpriv))
+ return mv_qc_issue_fis(qc);
+ }
+ return ata_bmdma_qc_issue(qc);
+}
+
+static struct ata_queued_cmd *mv_get_active_qc(struct ata_port *ap)
+{
+ struct mv_port_priv *pp = ap->private_data;
+ struct ata_queued_cmd *qc;
+
+ if (pp->pp_flags & MV_PP_FLAG_NCQ_EN)
+ return NULL;
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && !(qc->tf.flags & ATA_TFLAG_POLLING))
+ return qc;
+ return NULL;
+}
+
+static void mv_pmp_error_handler(struct ata_port *ap)
+{
+ unsigned int pmp, pmp_map;
+ struct mv_port_priv *pp = ap->private_data;
+
+ if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH) {
+ /*
+ * Perform NCQ error analysis on failed PMPs
+ * before we freeze the port entirely.
+ *
+ * The failed PMPs are marked earlier by mv_pmp_eh_prep().
+ */
+ pmp_map = pp->delayed_eh_pmp_map;
+ pp->pp_flags &= ~MV_PP_FLAG_DELAYED_EH;
+ for (pmp = 0; pmp_map != 0; pmp++) {
+ unsigned int this_pmp = (1 << pmp);
+ if (pmp_map & this_pmp) {
+ struct ata_link *link = &ap->pmp_link[pmp];
+ pmp_map &= ~this_pmp;
+ ata_eh_analyze_ncq_error(link);
+ }
+ }
+ ata_port_freeze(ap);
+ }
+ sata_pmp_error_handler(ap);
+}
+
+static unsigned int mv_get_err_pmp_map(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+
+ return readl(port_mmio + SATA_TESTCTL) >> 16;
+}
+
+static void mv_pmp_eh_prep(struct ata_port *ap, unsigned int pmp_map)
+{
+ struct ata_eh_info *ehi;
+ unsigned int pmp;
+
+ /*
+ * Initialize EH info for PMPs which saw device errors
+ */
+ ehi = &ap->link.eh_info;
+ for (pmp = 0; pmp_map != 0; pmp++) {
+ unsigned int this_pmp = (1 << pmp);
+ if (pmp_map & this_pmp) {
+ struct ata_link *link = &ap->pmp_link[pmp];
+
+ pmp_map &= ~this_pmp;
+ ehi = &link->eh_info;
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "dev err");
+ ehi->err_mask |= AC_ERR_DEV;
+ ehi->action |= ATA_EH_RESET;
+ ata_link_abort(link);
+ }
+ }
+}
+
+static int mv_req_q_empty(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ u32 in_ptr, out_ptr;
+
+ in_ptr = (readl(port_mmio + EDMA_REQ_Q_IN_PTR)
+ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+ out_ptr = (readl(port_mmio + EDMA_REQ_Q_OUT_PTR)
+ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+ return (in_ptr == out_ptr); /* 1 == queue_is_empty */
+}
+
+static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap)
+{
+ struct mv_port_priv *pp = ap->private_data;
+ int failed_links;
+ unsigned int old_map, new_map;
+
+ /*
+ * Device error during FBS+NCQ operation:
+ *
+ * Set a port flag to prevent further I/O being enqueued.
+ * Leave the EDMA running to drain outstanding commands from this port.
+ * Perform the post-mortem/EH only when all responses are complete.
+ * Follow recovery sequence from 6042/7042 datasheet (7.3.15.4.2.2).
+ */
+ if (!(pp->pp_flags & MV_PP_FLAG_DELAYED_EH)) {
+ pp->pp_flags |= MV_PP_FLAG_DELAYED_EH;
+ pp->delayed_eh_pmp_map = 0;
+ }
+ old_map = pp->delayed_eh_pmp_map;
+ new_map = old_map | mv_get_err_pmp_map(ap);
+
+ if (old_map != new_map) {
+ pp->delayed_eh_pmp_map = new_map;
+ mv_pmp_eh_prep(ap, new_map & ~old_map);
+ }
+ failed_links = hweight16(new_map);
+
+ ata_port_info(ap,
+ "%s: pmp_map=%04x qc_map=%04x failed_links=%d nr_active_links=%d\n",
+ __func__, pp->delayed_eh_pmp_map,
+ ap->qc_active, failed_links,
+ ap->nr_active_links);
+
+ if (ap->nr_active_links <= failed_links && mv_req_q_empty(ap)) {
+ mv_process_crpb_entries(ap, pp);
mv_stop_edma(ap);
- mv_pmp_select(ap, qc->dev->link->pmp);
- return ata_sff_qc_issue(qc);
+ mv_eh_freeze(ap);
+ ata_port_info(ap, "%s: done\n", __func__);
+ return 1; /* handled */
}
+ ata_port_info(ap, "%s: waiting\n", __func__);
+ return 1; /* handled */
+}
- mv_start_dma(ap, port_mmio, pp, qc->tf.protocol);
+static int mv_handle_fbs_non_ncq_dev_err(struct ata_port *ap)
+{
+ /*
+ * Possible future enhancement:
+ *
+ * FBS+non-NCQ operation is not yet implemented.
+ * See related notes in mv_edma_cfg().
+ *
+ * Device error during FBS+non-NCQ operation:
+ *
+ * We need to snapshot the shadow registers for each failed command.
+ * Follow recovery sequence from 6042/7042 datasheet (7.3.15.4.2.3).
+ */
+ return 0; /* not handled */
+}
- pp->req_idx++;
+static int mv_handle_dev_err(struct ata_port *ap, u32 edma_err_cause)
+{
+ struct mv_port_priv *pp = ap->private_data;
- in_index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
+ if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN))
+ return 0; /* EDMA was not active: not handled */
+ if (!(pp->pp_flags & MV_PP_FLAG_FBS_EN))
+ return 0; /* FBS was not active: not handled */
- /* and write the request in pointer to kick the EDMA to life */
- writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | in_index,
- port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+ if (!(edma_err_cause & EDMA_ERR_DEV))
+ return 0; /* non DEV error: not handled */
+ edma_err_cause &= ~EDMA_ERR_IRQ_TRANSIENT;
+ if (edma_err_cause & ~(EDMA_ERR_DEV | EDMA_ERR_SELF_DIS))
+ return 0; /* other problems: not handled */
- return 0;
+ if (pp->pp_flags & MV_PP_FLAG_NCQ_EN) {
+ /*
+ * EDMA should NOT have self-disabled for this case.
+ * If it did, then something is wrong elsewhere,
+ * and we cannot handle it here.
+ */
+ if (edma_err_cause & EDMA_ERR_SELF_DIS) {
+ ata_port_warn(ap, "%s: err_cause=0x%x pp_flags=0x%x\n",
+ __func__, edma_err_cause, pp->pp_flags);
+ return 0; /* not handled */
+ }
+ return mv_handle_fbs_ncq_dev_err(ap);
+ } else {
+ /*
+ * EDMA should have self-disabled for this case.
+ * If it did not, then something is wrong elsewhere,
+ * and we cannot handle it here.
+ */
+ if (!(edma_err_cause & EDMA_ERR_SELF_DIS)) {
+ ata_port_warn(ap, "%s: err_cause=0x%x pp_flags=0x%x\n",
+ __func__, edma_err_cause, pp->pp_flags);
+ return 0; /* not handled */
+ }
+ return mv_handle_fbs_non_ncq_dev_err(ap);
+ }
+ return 0; /* not handled */
+}
+
+static void mv_unexpected_intr(struct ata_port *ap, int edma_was_enabled)
+{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ char *when = "idle";
+
+ ata_ehi_clear_desc(ehi);
+ if (edma_was_enabled) {
+ when = "EDMA enabled";
+ } else {
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
+ when = "polling";
+ }
+ ata_ehi_push_desc(ehi, "unexpected device interrupt while %s", when);
+ ehi->err_mask |= AC_ERR_OTHER;
+ ehi->action |= ATA_EH_RESET;
+ ata_port_freeze(ap);
}
/**
* mv_err_intr - Handle error interrupts on the port
* @ap: ATA channel to manipulate
- * @reset_allowed: bool: 0 == don't trigger from reset here
*
- * In most cases, just clear the interrupt and move on. However,
- * some cases require an eDMA reset, which also performs a COMRESET.
- * The SERR case requires a clear of pending errors in the SATA
- * SERROR register. Finally, if the port disabled DMA,
- * update our cached copy to match.
+ * Most cases require a full reset of the chip's state machine,
+ * which also performs a COMRESET.
+ * Also, if the port disabled DMA, update our cached copy to match.
*
* LOCKING:
* Inherited from caller.
*/
-static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+static void mv_err_intr(struct ata_port *ap)
{
void __iomem *port_mmio = mv_ap_base(ap);
u32 edma_err_cause, eh_freeze_mask, serr = 0;
+ u32 fis_cause = 0;
struct mv_port_priv *pp = ap->private_data;
struct mv_host_priv *hpriv = ap->host->private_data;
- unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
unsigned int action = 0, err_mask = 0;
struct ata_eh_info *ehi = &ap->link.eh_info;
+ struct ata_queued_cmd *qc;
+ int abort = 0;
- ata_ehi_clear_desc(ehi);
+ /*
+ * Read and clear the SError and err_cause bits.
+ * For GenIIe, if EDMA_ERR_TRANS_IRQ_7 is set, we also must read/clear
+ * the FIS_IRQ_CAUSE register before clearing edma_err_cause.
+ */
+ sata_scr_read(&ap->link, SCR_ERROR, &serr);
+ sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
- if (!edma_enabled) {
- /* just a guess: do we need to do this? should we
- * expand this, and do it in all cases?
- */
- sata_scr_read(&ap->link, SCR_ERROR, &serr);
- sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
+ edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE);
+ if (IS_GEN_IIE(hpriv) && (edma_err_cause & EDMA_ERR_TRANS_IRQ_7)) {
+ fis_cause = readl(port_mmio + FIS_IRQ_CAUSE);
+ writelfl(~fis_cause, port_mmio + FIS_IRQ_CAUSE);
}
+ writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE);
- edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
-
- ata_ehi_push_desc(ehi, "edma_err 0x%08x", edma_err_cause);
+ if (edma_err_cause & EDMA_ERR_DEV) {
+ /*
+ * Device errors during FIS-based switching operation
+ * require special handling.
+ */
+ if (mv_handle_dev_err(ap, edma_err_cause))
+ return;
+ }
+ qc = mv_get_active_qc(ap);
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "edma_err_cause=%08x pp_flags=%08x",
+ edma_err_cause, pp->pp_flags);
+
+ if (IS_GEN_IIE(hpriv) && (edma_err_cause & EDMA_ERR_TRANS_IRQ_7)) {
+ ata_ehi_push_desc(ehi, "fis_cause=%08x", fis_cause);
+ if (fis_cause & FIS_IRQ_CAUSE_AN) {
+ u32 ec = edma_err_cause &
+ ~(EDMA_ERR_TRANS_IRQ_7 | EDMA_ERR_IRQ_TRANSIENT);
+ sata_async_notification(ap);
+ if (!ec)
+ return; /* Just an AN; no need for the nukes */
+ ata_ehi_push_desc(ehi, "SDB notify");
+ }
+ }
/*
- * all generations share these EDMA error cause bits
+ * All generations share these EDMA error cause bits:
*/
-
- if (edma_err_cause & EDMA_ERR_DEV)
+ if (edma_err_cause & EDMA_ERR_DEV) {
err_mask |= AC_ERR_DEV;
+ action |= ATA_EH_RESET;
+ ata_ehi_push_desc(ehi, "dev error");
+ }
if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
EDMA_ERR_INTRL_PAR)) {
@@ -1515,34 +2710,29 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
action |= ATA_EH_RESET;
}
+ /*
+ * Gen-I has a different SELF_DIS bit,
+ * different FREEZE bits, and no SERR bit:
+ */
if (IS_GEN_I(hpriv)) {
eh_freeze_mask = EDMA_EH_FREEZE_5;
-
if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
- pp = ap->private_data;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
ata_ehi_push_desc(ehi, "EDMA self-disable");
}
} else {
eh_freeze_mask = EDMA_EH_FREEZE;
-
if (edma_err_cause & EDMA_ERR_SELF_DIS) {
- pp = ap->private_data;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
ata_ehi_push_desc(ehi, "EDMA self-disable");
}
-
if (edma_err_cause & EDMA_ERR_SERR) {
- sata_scr_read(&ap->link, SCR_ERROR, &serr);
- sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
- err_mask = AC_ERR_ATA_BUS;
+ ata_ehi_push_desc(ehi, "SError=%08x", serr);
+ err_mask |= AC_ERR_ATA_BUS;
action |= ATA_EH_RESET;
}
}
- /* Clear EDMA now that SERR cleanup done */
- writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
-
if (!err_mask) {
err_mask = AC_ERR_OTHER;
action |= ATA_EH_RESET;
@@ -1556,184 +2746,209 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
else
ehi->err_mask |= err_mask;
- if (edma_err_cause & eh_freeze_mask)
+ if (err_mask == AC_ERR_DEV) {
+ /*
+ * Cannot do ata_port_freeze() here,
+ * because it would kill PIO access,
+ * which is needed for further diagnosis.
+ */
+ mv_eh_freeze(ap);
+ abort = 1;
+ } else if (edma_err_cause & eh_freeze_mask) {
+ /*
+ * Note to self: ata_port_freeze() calls ata_port_abort()
+ */
ata_port_freeze(ap);
- else
- ata_port_abort(ap);
+ } else {
+ abort = 1;
+ }
+
+ if (abort) {
+ if (qc)
+ ata_link_abort(qc->dev->link);
+ else
+ ata_port_abort(ap);
+ }
}
-static void mv_intr_pio(struct ata_port *ap)
+static bool mv_process_crpb_response(struct ata_port *ap,
+ struct mv_crpb *response, unsigned int tag, int ncq_enabled)
{
- struct ata_queued_cmd *qc;
u8 ata_status;
+ u16 edma_status = le16_to_cpu(response->flags);
- /* ignore spurious intr if drive still BUSY */
- ata_status = readb(ap->ioaddr.status_addr);
- if (unlikely(ata_status & ATA_BUSY))
- return;
-
- /* get active ATA command */
- qc = ata_qc_from_tag(ap, ap->link.active_tag);
- if (unlikely(!qc)) /* no active tag */
- return;
- if (qc->tf.flags & ATA_TFLAG_POLLING) /* polling; we don't own qc */
- return;
-
- /* and finally, complete the ATA command */
- qc->err_mask |= ac_err_mask(ata_status);
- ata_qc_complete(qc);
+ /*
+ * edma_status from a response queue entry:
+ * LSB is from EDMA_ERR_IRQ_CAUSE (non-NCQ only).
+ * MSB is saved ATA status from command completion.
+ */
+ if (!ncq_enabled) {
+ u8 err_cause = edma_status & 0xff & ~EDMA_ERR_DEV;
+ if (err_cause) {
+ /*
+ * Error will be seen/handled by
+ * mv_err_intr(). So do nothing at all here.
+ */
+ return false;
+ }
+ }
+ ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT;
+ if (!ac_err_mask(ata_status))
+ return true;
+ /* else: leave it for mv_err_intr() */
+ return false;
}
-static void mv_intr_edma(struct ata_port *ap)
+static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp)
{
void __iomem *port_mmio = mv_ap_base(ap);
struct mv_host_priv *hpriv = ap->host->private_data;
- struct mv_port_priv *pp = ap->private_data;
- struct ata_queued_cmd *qc;
- u32 out_index, in_index;
+ u32 in_index;
bool work_done = false;
+ u32 done_mask = 0;
+ int ncq_enabled = (pp->pp_flags & MV_PP_FLAG_NCQ_EN);
- /* get h/w response queue pointer */
- in_index = (readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
+ /* Get the hardware queue position index */
+ in_index = (readl(port_mmio + EDMA_RSP_Q_IN_PTR)
>> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
- while (1) {
- u16 status;
+ /* Process new responses from since the last time we looked */
+ while (in_index != pp->resp_idx) {
unsigned int tag;
+ struct mv_crpb *response = &pp->crpb[pp->resp_idx];
- /* get s/w response queue last-read pointer, and compare */
- out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
- if (in_index == out_index)
- break;
+ pp->resp_idx = (pp->resp_idx + 1) & MV_MAX_Q_DEPTH_MASK;
- /* 50xx: get active ATA command */
- if (IS_GEN_I(hpriv))
+ if (IS_GEN_I(hpriv)) {
+ /* 50xx: no NCQ, only one command active at a time */
tag = ap->link.active_tag;
-
- /* Gen II/IIE: get active ATA command via tag, to enable
- * support for queueing. this works transparently for
- * queued and non-queued modes.
- */
- else
- tag = le16_to_cpu(pp->crpb[out_index].id) & 0x1f;
-
- qc = ata_qc_from_tag(ap, tag);
-
- /* For non-NCQ mode, the lower 8 bits of status
- * are from EDMA_ERR_IRQ_CAUSE_OFS,
- * which should be zero if all went well.
- */
- status = le16_to_cpu(pp->crpb[out_index].flags);
- if ((status & 0xff) && !(pp->pp_flags & MV_PP_FLAG_NCQ_EN)) {
- mv_err_intr(ap, qc);
- return;
- }
-
- /* and finally, complete the ATA command */
- if (qc) {
- qc->err_mask |=
- ac_err_mask(status >> CRPB_FLAG_STATUS_SHIFT);
- ata_qc_complete(qc);
+ } else {
+ /* Gen II/IIE: get command tag from CRPB entry */
+ tag = le16_to_cpu(response->id) & 0x1f;
}
-
- /* advance software response queue pointer, to
- * indicate (after the loop completes) to hardware
- * that we have consumed a response queue entry.
- */
+ if (mv_process_crpb_response(ap, response, tag, ncq_enabled))
+ done_mask |= 1 << tag;
work_done = true;
- pp->resp_idx++;
}
- if (work_done)
+ if (work_done) {
+ ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
+
+ /* Update the software queue position index in hardware */
writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
- (out_index << EDMA_RSP_Q_PTR_SHIFT),
- port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+ (pp->resp_idx << EDMA_RSP_Q_PTR_SHIFT),
+ port_mmio + EDMA_RSP_Q_OUT_PTR);
+ }
+}
+
+static void mv_port_intr(struct ata_port *ap, u32 port_cause)
+{
+ struct mv_port_priv *pp;
+ int edma_was_enabled;
+
+ /*
+ * Grab a snapshot of the EDMA_EN flag setting,
+ * so that we have a consistent view for this port,
+ * even if something we call of our routines changes it.
+ */
+ pp = ap->private_data;
+ edma_was_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
+ /*
+ * Process completed CRPB response(s) before other events.
+ */
+ if (edma_was_enabled && (port_cause & DONE_IRQ)) {
+ mv_process_crpb_entries(ap, pp);
+ if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH)
+ mv_handle_fbs_ncq_dev_err(ap);
+ }
+ /*
+ * Handle chip-reported errors, or continue on to handle PIO.
+ */
+ if (unlikely(port_cause & ERR_IRQ)) {
+ mv_err_intr(ap);
+ } else if (!edma_was_enabled) {
+ struct ata_queued_cmd *qc = mv_get_active_qc(ap);
+ if (qc)
+ ata_bmdma_port_intr(ap, qc);
+ else
+ mv_unexpected_intr(ap, edma_was_enabled);
+ }
}
/**
* mv_host_intr - Handle all interrupts on the given host controller
* @host: host specific structure
- * @relevant: port error bits relevant to this host controller
- * @hc: which host controller we're to look at
- *
- * Read then write clear the HC interrupt status then walk each
- * port connected to the HC and see if it needs servicing. Port
- * success ints are reported in the HC interrupt status reg, the
- * port error ints are reported in the higher level main
- * interrupt status register and thus are passed in via the
- * 'relevant' argument.
+ * @main_irq_cause: Main interrupt cause register for the chip.
*
* LOCKING:
* Inherited from caller.
*/
-static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
+static int mv_host_intr(struct ata_host *host, u32 main_irq_cause)
{
struct mv_host_priv *hpriv = host->private_data;
- void __iomem *mmio = hpriv->base;
- void __iomem *hc_mmio = mv_hc_base(mmio, hc);
- u32 hc_irq_cause;
- int port, port0, last_port;
-
- if (hc == 0)
- port0 = 0;
- else
- port0 = MV_PORTS_PER_HC;
+ void __iomem *mmio = hpriv->base, *hc_mmio;
+ unsigned int handled = 0, port;
- if (HAS_PCI(host))
- last_port = port0 + MV_PORTS_PER_HC;
- else
- last_port = port0 + hpriv->n_ports;
- /* we'll need the HC success int register in most cases */
- hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
- if (!hc_irq_cause)
- return;
-
- writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
+ /* If asserted, clear the "all ports" IRQ coalescing bit */
+ if (main_irq_cause & ALL_PORTS_COAL_DONE)
+ writel(~ALL_PORTS_COAL_IRQ, mmio + IRQ_COAL_CAUSE);
- VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
- hc, relevant, hc_irq_cause);
-
- for (port = port0; port < last_port; port++) {
+ for (port = 0; port < hpriv->n_ports; port++) {
struct ata_port *ap = host->ports[port];
- struct mv_port_priv *pp;
- int have_err_bits, hard_port, shift;
-
- if ((!ap) || (ap->flags & ATA_FLAG_DISABLED))
- continue;
-
- pp = ap->private_data;
+ unsigned int p, shift, hardport, port_cause;
- shift = port << 1; /* (port * 2) */
- if (port >= MV_PORTS_PER_HC)
- shift++; /* skip bit 8 in the HC Main IRQ reg */
-
- have_err_bits = ((PORT0_ERR << shift) & relevant);
-
- if (unlikely(have_err_bits)) {
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_from_tag(ap, ap->link.active_tag);
- if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
+ MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
+ /*
+ * Each hc within the host has its own hc_irq_cause register,
+ * where the interrupting ports bits get ack'd.
+ */
+ if (hardport == 0) { /* first port on this hc ? */
+ u32 hc_cause = (main_irq_cause >> shift) & HC0_IRQ_PEND;
+ u32 port_mask, ack_irqs;
+ /*
+ * Skip this entire hc if nothing pending for any ports
+ */
+ if (!hc_cause) {
+ port += MV_PORTS_PER_HC - 1;
continue;
-
- mv_err_intr(ap, qc);
- continue;
- }
-
- hard_port = mv_hardport_from_port(port); /* range 0..3 */
-
- if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
- if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause)
- mv_intr_edma(ap);
- } else {
- if ((DEV_IRQ << hard_port) & hc_irq_cause)
- mv_intr_pio(ap);
+ }
+ /*
+ * We don't need/want to read the hc_irq_cause register,
+ * because doing so hurts performance, and
+ * main_irq_cause already gives us everything we need.
+ *
+ * But we do have to *write* to the hc_irq_cause to ack
+ * the ports that we are handling this time through.
+ *
+ * This requires that we create a bitmap for those
+ * ports which interrupted us, and use that bitmap
+ * to ack (only) those ports via hc_irq_cause.
+ */
+ ack_irqs = 0;
+ if (hc_cause & PORTS_0_3_COAL_DONE)
+ ack_irqs = HC_COAL_IRQ;
+ for (p = 0; p < MV_PORTS_PER_HC; ++p) {
+ if ((port + p) >= hpriv->n_ports)
+ break;
+ port_mask = (DONE_IRQ | ERR_IRQ) << (p * 2);
+ if (hc_cause & port_mask)
+ ack_irqs |= (DMA_IRQ | DEV_IRQ) << p;
+ }
+ hc_mmio = mv_hc_base_from_port(mmio, port);
+ writelfl(~ack_irqs, hc_mmio + HC_IRQ_CAUSE);
+ handled = 1;
}
+ /*
+ * Handle interrupts signalled for this port:
+ */
+ port_cause = (main_irq_cause >> shift) & (DONE_IRQ | ERR_IRQ);
+ if (port_cause)
+ mv_port_intr(ap, port_cause);
}
- VPRINTK("EXIT\n");
+ return handled;
}
-static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
+static int mv_pci_error(struct ata_host *host, void __iomem *mmio)
{
struct mv_host_priv *hpriv = host->private_data;
struct ata_port *ap;
@@ -1742,15 +2957,14 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
unsigned int i, err_mask, printed = 0;
u32 err_cause;
- err_cause = readl(mmio + hpriv->irq_cause_ofs);
+ err_cause = readl(mmio + hpriv->irq_cause_offset);
- dev_printk(KERN_ERR, host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n",
- err_cause);
+ dev_err(host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n", err_cause);
DPRINTK("All regs @ PCI error\n");
mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
- writelfl(0, mmio + hpriv->irq_cause_ofs);
+ writelfl(0, mmio + hpriv->irq_cause_offset);
for (i = 0; i < host->n_ports; i++) {
ap = host->ports[i];
@@ -1771,6 +2985,7 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
ata_port_freeze(ap);
}
}
+ return 1; /* handled */
}
/**
@@ -1791,39 +3006,33 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
struct mv_host_priv *hpriv = host->private_data;
- unsigned int hc, handled = 0, n_hcs;
- void __iomem *mmio = hpriv->base;
- u32 irq_stat, irq_mask;
+ unsigned int handled = 0;
+ int using_msi = hpriv->hp_flags & MV_HP_FLAG_MSI;
+ u32 main_irq_cause, pending_irqs;
- /* Note to self: &host->lock == &ap->host->lock == ap->lock */
spin_lock(&host->lock);
- irq_stat = readl(hpriv->main_cause_reg_addr);
- irq_mask = readl(hpriv->main_mask_reg_addr);
+ /* for MSI: block new interrupts while in here */
+ if (using_msi)
+ mv_write_main_irq_mask(0, hpriv);
- /* check the cases where we either have nothing pending or have read
- * a bogus register value which can indicate HW removal or PCI fault
+ main_irq_cause = readl(hpriv->main_irq_cause_addr);
+ pending_irqs = main_irq_cause & hpriv->main_irq_mask;
+ /*
+ * Deal with cases where we either have nothing pending, or have read
+ * a bogus register value which can indicate HW removal or PCI fault.
*/
- if (!(irq_stat & irq_mask) || (0xffffffffU == irq_stat))
- goto out_unlock;
-
- n_hcs = mv_get_hc_count(host->ports[0]->flags);
-
- if (unlikely((irq_stat & PCI_ERR) && HAS_PCI(host))) {
- mv_pci_error(host, mmio);
- handled = 1;
- goto out_unlock; /* skip all other HC irq handling */
+ if (pending_irqs && main_irq_cause != 0xffffffffU) {
+ if (unlikely((pending_irqs & PCI_ERR) && !IS_SOC(hpriv)))
+ handled = mv_pci_error(host, hpriv->base);
+ else
+ handled = mv_host_intr(host, pending_irqs);
}
- for (hc = 0; hc < n_hcs; hc++) {
- u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
- if (relevant) {
- mv_host_intr(host, relevant, hc);
- handled = 1;
- }
- }
+ /* for MSI: unmask; interrupt cause bits will retrigger now */
+ if (using_msi)
+ mv_write_main_irq_mask(hpriv->main_irq_mask, hpriv);
-out_unlock:
spin_unlock(&host->lock);
return IRQ_RETVAL(handled);
@@ -1846,11 +3055,11 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
return ofs;
}
-static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
+static int mv5_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val)
{
- struct mv_host_priv *hpriv = ap->host->private_data;
+ struct mv_host_priv *hpriv = link->ap->host->private_data;
void __iomem *mmio = hpriv->base;
- void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
+ void __iomem *addr = mv5_phy_base(mmio, link->ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU) {
@@ -1860,11 +3069,11 @@ static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
return -EINVAL;
}
-static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv5_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val)
{
- struct mv_host_priv *hpriv = ap->host->private_data;
+ struct mv_host_priv *hpriv = link->ap->host->private_data;
void __iomem *mmio = hpriv->base;
- void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
+ void __iomem *addr = mv5_phy_base(mmio, link->ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU) {
@@ -1892,7 +3101,7 @@ static void mv5_reset_bus(struct ata_host *host, void __iomem *mmio)
static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
{
- writel(0x0fcfffff, mmio + MV_FLASH_CTL);
+ writel(0x0fcfffff, mmio + FLASH_CTL);
}
static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
@@ -1911,7 +3120,7 @@ static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
{
u32 tmp;
- writel(0, mmio + MV_GPIO_PORT_CTL);
+ writel(0, mmio + GPIO_PORT_CTL);
/* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
@@ -1929,9 +3138,9 @@ static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
if (fix_apm_sq) {
- tmp = readl(phy_mmio + MV5_LT_MODE);
+ tmp = readl(phy_mmio + MV5_LTMODE);
tmp |= (1 << 19);
- writel(tmp, phy_mmio + MV5_LT_MODE);
+ writel(tmp, phy_mmio + MV5_LTMODE);
tmp = readl(phy_mmio + MV5_PHY_CTL);
tmp &= ~0x3;
@@ -1954,15 +3163,10 @@ static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
{
void __iomem *port_mmio = mv_port_base(mmio, port);
- /*
- * The datasheet warns against setting ATA_RST when EDMA is active
- * (but doesn't say what the problem might be). So we first try
- * to disable the EDMA engine before doing the ATA_RST operation.
- */
mv_reset_channel(hpriv, mmio, port);
ZERO(0x028); /* command */
- writel(0x11f, port_mmio + EDMA_CFG_OFS);
+ writel(0x11f, port_mmio + EDMA_CFG);
ZERO(0x004); /* timer */
ZERO(0x008); /* irq err cause */
ZERO(0x00c); /* irq err mask */
@@ -2026,10 +3230,9 @@ static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio)
ZERO(MV_PCI_DISC_TIMER);
ZERO(MV_PCI_MSI_TRIGGER);
writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
- ZERO(HC_MAIN_IRQ_MASK_OFS);
ZERO(MV_PCI_SERR_MASK);
- ZERO(hpriv->irq_cause_ofs);
- ZERO(hpriv->irq_mask_ofs);
+ ZERO(hpriv->irq_cause_offset);
+ ZERO(hpriv->irq_mask_offset);
ZERO(MV_PCI_ERR_LOW_ADDRESS);
ZERO(MV_PCI_ERR_HIGH_ADDRESS);
ZERO(MV_PCI_ERR_ATTRIBUTE);
@@ -2043,10 +3246,10 @@ static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
mv5_reset_flash(hpriv, mmio);
- tmp = readl(mmio + MV_GPIO_PORT_CTL);
+ tmp = readl(mmio + GPIO_PORT_CTL);
tmp &= 0x3;
tmp |= (1 << 5) | (1 << 6);
- writel(tmp, mmio + MV_GPIO_PORT_CTL);
+ writel(tmp, mmio + GPIO_PORT_CTL);
}
/**
@@ -2061,7 +3264,7 @@ static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int n_hc)
{
- void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
+ void __iomem *reg = mmio + PCI_MAIN_CMD_STS;
int i, rc = 0;
u32 t;
@@ -2109,13 +3312,6 @@ static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
rc = 1;
}
- /*
- * Temporary: wait 3 seconds before port-probing can happen,
- * so that we don't miss finding sleepy SilXXXX port-multipliers.
- * This can go away once hotplug is fully/correctly implemented.
- */
- if (rc == 0)
- msleep(3000);
done:
return rc;
}
@@ -2126,7 +3322,7 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
void __iomem *port_mmio;
u32 tmp;
- tmp = readl(mmio + MV_RESET_CFG);
+ tmp = readl(mmio + RESET_CFG);
if ((tmp & (1 << 0)) == 0) {
hpriv->signal[idx].amps = 0x7 << 8;
hpriv->signal[idx].pre = 0x1 << 5;
@@ -2142,7 +3338,7 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
{
- writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
+ writel(0x00000060, mmio + GPIO_PORT_CTL);
}
static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
@@ -2155,7 +3351,7 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
int fix_phy_mode4 =
hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
- u32 m2, tmp;
+ u32 m2, m3;
if (fix_phy_mode2) {
m2 = readl(port_mmio + PHY_MODE2);
@@ -2172,28 +3368,37 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
udelay(200);
}
- /* who knows what this magic does */
- tmp = readl(port_mmio + PHY_MODE3);
- tmp &= ~0x7F800000;
- tmp |= 0x2A800000;
- writel(tmp, port_mmio + PHY_MODE3);
-
- if (fix_phy_mode4) {
- u32 m4;
-
- m4 = readl(port_mmio + PHY_MODE4);
-
- if (hp_flags & MV_HP_ERRATA_60X1B2)
- tmp = readl(port_mmio + PHY_MODE3);
+ /*
+ * Gen-II/IIe PHY_MODE3 errata RM#2:
+ * Achieves better receiver noise performance than the h/w default:
+ */
+ m3 = readl(port_mmio + PHY_MODE3);
+ m3 = (m3 & 0x1f) | (0x5555601 << 5);
- /* workaround for errata FEr SATA#10 (part 1) */
- m4 = (m4 & ~(1 << 1)) | (1 << 0);
+ /* Guideline 88F5182 (GL# SATA-S11) */
+ if (IS_SOC(hpriv))
+ m3 &= ~0x1c;
+ if (fix_phy_mode4) {
+ u32 m4 = readl(port_mmio + PHY_MODE4);
+ /*
+ * Enforce reserved-bit restrictions on GenIIe devices only.
+ * For earlier chipsets, force only the internal config field
+ * (workaround for errata FEr SATA#10 part 1).
+ */
+ if (IS_GEN_IIE(hpriv))
+ m4 = (m4 & ~PHY_MODE4_RSVD_ZEROS) | PHY_MODE4_RSVD_ONES;
+ else
+ m4 = (m4 & ~PHY_MODE4_CFG_MASK) | PHY_MODE4_CFG_VALUE;
writel(m4, port_mmio + PHY_MODE4);
-
- if (hp_flags & MV_HP_ERRATA_60X1B2)
- writel(tmp, port_mmio + PHY_MODE3);
}
+ /*
+ * Workaround for 60x1-B2 errata SATA#13:
+ * Any write to PHY_MODE4 (above) may corrupt PHY_MODE3,
+ * so we must always rewrite PHY_MODE3 after PHY_MODE4.
+ * Or ensure we use writelfl() when writing PHY_MODE4.
+ */
+ writel(m3, port_mmio + PHY_MODE3);
/* Revert values of pre-emphasis and signal amps to the saved ones */
m2 = readl(port_mmio + PHY_MODE2);
@@ -2240,15 +3445,10 @@ static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
{
void __iomem *port_mmio = mv_port_base(mmio, port);
- /*
- * The datasheet warns against setting ATA_RST when EDMA is active
- * (but doesn't say what the problem might be). So we first try
- * to disable the EDMA engine before doing the ATA_RST operation.
- */
mv_reset_channel(hpriv, mmio, port);
ZERO(0x028); /* command */
- writel(0x101f, port_mmio + EDMA_CFG_OFS);
+ writel(0x101f, port_mmio + EDMA_CFG);
ZERO(0x004); /* timer */
ZERO(0x008); /* irq err cause */
ZERO(0x00c); /* irq err mask */
@@ -2259,7 +3459,7 @@ static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
ZERO(0x024); /* respq outp */
ZERO(0x020); /* respq inp */
ZERO(0x02c); /* test control */
- writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+ writel(0x800, port_mmio + EDMA_IORDY_TMOUT);
}
#undef ZERO
@@ -2302,40 +3502,88 @@ static void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio)
return;
}
-static void mv_setup_ifctl(void __iomem *port_mmio, int want_gen2i)
+static void mv_soc_65n_phy_errata(struct mv_host_priv *hpriv,
+ void __iomem *mmio, unsigned int port)
+{
+ void __iomem *port_mmio = mv_port_base(mmio, port);
+ u32 reg;
+
+ reg = readl(port_mmio + PHY_MODE3);
+ reg &= ~(0x3 << 27); /* SELMUPF (bits 28:27) to 1 */
+ reg |= (0x1 << 27);
+ reg &= ~(0x3 << 29); /* SELMUPI (bits 30:29) to 1 */
+ reg |= (0x1 << 29);
+ writel(reg, port_mmio + PHY_MODE3);
+
+ reg = readl(port_mmio + PHY_MODE4);
+ reg &= ~0x1; /* SATU_OD8 (bit 0) to 0, reserved bit 16 must be set */
+ reg |= (0x1 << 16);
+ writel(reg, port_mmio + PHY_MODE4);
+
+ reg = readl(port_mmio + PHY_MODE9_GEN2);
+ reg &= ~0xf; /* TXAMP[3:0] (bits 3:0) to 8 */
+ reg |= 0x8;
+ reg &= ~(0x1 << 14); /* TXAMP[4] (bit 14) to 0 */
+ writel(reg, port_mmio + PHY_MODE9_GEN2);
+
+ reg = readl(port_mmio + PHY_MODE9_GEN1);
+ reg &= ~0xf; /* TXAMP[3:0] (bits 3:0) to 8 */
+ reg |= 0x8;
+ reg &= ~(0x1 << 14); /* TXAMP[4] (bit 14) to 0 */
+ writel(reg, port_mmio + PHY_MODE9_GEN1);
+}
+
+/**
+ * soc_is_65 - check if the soc is 65 nano device
+ *
+ * Detect the type of the SoC, this is done by reading the PHYCFG_OFS
+ * register, this register should contain non-zero value and it exists only
+ * in the 65 nano devices, when reading it from older devices we get 0.
+ */
+static bool soc_is_65n(struct mv_host_priv *hpriv)
+{
+ void __iomem *port0_mmio = mv_port_base(hpriv->base, 0);
+
+ if (readl(port0_mmio + PHYCFG_OFS))
+ return true;
+ return false;
+}
+
+static void mv_setup_ifcfg(void __iomem *port_mmio, int want_gen2i)
{
- u32 ifctl = readl(port_mmio + SATA_INTERFACE_CFG);
+ u32 ifcfg = readl(port_mmio + SATA_IFCFG);
- ifctl = (ifctl & 0xf7f) | 0x9b1000; /* from chip spec */
+ ifcfg = (ifcfg & 0xf7f) | 0x9b1000; /* from chip spec */
if (want_gen2i)
- ifctl |= (1 << 7); /* enable gen2i speed */
- writelfl(ifctl, port_mmio + SATA_INTERFACE_CFG);
+ ifcfg |= (1 << 7); /* enable gen2i speed */
+ writelfl(ifcfg, port_mmio + SATA_IFCFG);
}
-/*
- * Caller must ensure that EDMA is not active,
- * by first doing mv_stop_edma() where needed.
- */
static void mv_reset_channel(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int port_no)
{
void __iomem *port_mmio = mv_port_base(mmio, port_no);
+ /*
+ * The datasheet warns against setting EDMA_RESET when EDMA is active
+ * (but doesn't say what the problem might be). So we first try
+ * to disable the EDMA engine before doing the EDMA_RESET operation.
+ */
mv_stop_edma_engine(port_mmio);
- writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
+ writelfl(EDMA_RESET, port_mmio + EDMA_CMD);
if (!IS_GEN_I(hpriv)) {
- /* Enable 3.0gb/s link speed */
- mv_setup_ifctl(port_mmio, 1);
+ /* Enable 3.0gb/s link speed: this survives EDMA_RESET */
+ mv_setup_ifcfg(port_mmio, 1);
}
/*
- * Strobing ATA_RST here causes a hard reset of the SATA transport,
+ * Strobing EDMA_RESET here causes a hard reset of the SATA transport,
* link, and physical layers. It resets all SATA interface registers
- * (except for SATA_INTERFACE_CFG), and issues a COMRESET to the dev.
+ * (except for SATA_IFCFG), and issues a COMRESET to the dev.
*/
- writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
+ writelfl(EDMA_RESET, port_mmio + EDMA_CMD);
udelay(25); /* allow reset propagation */
- writelfl(0, port_mmio + EDMA_CMD_OFS);
+ writelfl(0, port_mmio + EDMA_CMD);
hpriv->ops->phy_errata(hpriv, mmio, port_no);
@@ -2347,12 +3595,12 @@ static void mv_pmp_select(struct ata_port *ap, int pmp)
{
if (sata_pmp_supported(ap)) {
void __iomem *port_mmio = mv_ap_base(ap);
- u32 reg = readl(port_mmio + SATA_IFCTL_OFS);
+ u32 reg = readl(port_mmio + SATA_IFCTL);
int old = reg & 0xf;
if (old != pmp) {
reg = (reg & ~0xf) | pmp;
- writelfl(reg, port_mmio + SATA_IFCTL_OFS);
+ writelfl(reg, port_mmio + SATA_IFCTL);
}
}
}
@@ -2384,6 +3632,8 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
mv_reset_channel(hpriv, mmio, ap->port_no);
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+ pp->pp_flags &=
+ ~(MV_PP_FLAG_FBS_EN | MV_PP_FLAG_NCQ_EN | MV_PP_FLAG_FAKE_ATA_BUSY);
/* Workaround for errata FEr SATA#10 (part 2) */
do {
@@ -2392,72 +3642,46 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, timing, deadline + extra,
&online, NULL);
+ rc = online ? -EAGAIN : rc;
if (rc)
return rc;
sata_scr_read(link, SCR_STATUS, &sstatus);
if (!IS_GEN_I(hpriv) && ++attempts >= 5 && sstatus == 0x121) {
/* Force 1.5gb/s link speed and try again */
- mv_setup_ifctl(mv_ap_base(ap), 0);
+ mv_setup_ifcfg(mv_ap_base(ap), 0);
if (time_after(jiffies + HZ, deadline))
extra = HZ; /* only extend it once, max */
}
} while (sstatus != 0x0 && sstatus != 0x113 && sstatus != 0x123);
+ mv_save_cached_regs(ap);
+ mv_edma_cfg(ap, 0, 0);
return rc;
}
static void mv_eh_freeze(struct ata_port *ap)
{
- struct mv_host_priv *hpriv = ap->host->private_data;
- unsigned int hc = (ap->port_no > 3) ? 1 : 0;
- u32 tmp, mask;
- unsigned int shift;
-
- /* FIXME: handle coalescing completion events properly */
-
- shift = ap->port_no * 2;
- if (hc > 0)
- shift++;
-
- mask = 0x3 << shift;
-
- /* disable assertion of portN err, done events */
- tmp = readl(hpriv->main_mask_reg_addr);
- writelfl(tmp & ~mask, hpriv->main_mask_reg_addr);
+ mv_stop_edma(ap);
+ mv_enable_port_irqs(ap, 0);
}
static void mv_eh_thaw(struct ata_port *ap)
{
struct mv_host_priv *hpriv = ap->host->private_data;
- void __iomem *mmio = hpriv->base;
- unsigned int hc = (ap->port_no > 3) ? 1 : 0;
- void __iomem *hc_mmio = mv_hc_base(mmio, hc);
+ unsigned int port = ap->port_no;
+ unsigned int hardport = mv_hardport_from_port(port);
+ void __iomem *hc_mmio = mv_hc_base_from_port(hpriv->base, port);
void __iomem *port_mmio = mv_ap_base(ap);
- u32 tmp, mask, hc_irq_cause;
- unsigned int shift, hc_port_no = ap->port_no;
-
- /* FIXME: handle coalescing completion events properly */
-
- shift = ap->port_no * 2;
- if (hc > 0) {
- shift++;
- hc_port_no -= 4;
- }
-
- mask = 0x3 << shift;
+ u32 hc_irq_cause;
/* clear EDMA errors on this port */
- writel(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+ writel(0, port_mmio + EDMA_ERR_IRQ_CAUSE);
/* clear pending irq events */
- hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
- hc_irq_cause &= ~(1 << hc_port_no); /* clear CRPB-done */
- hc_irq_cause &= ~(1 << (hc_port_no + 8)); /* clear Device int */
- writel(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
+ hc_irq_cause = ~((DEV_IRQ | DMA_IRQ) << hardport);
+ writelfl(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE);
- /* enable assertion of portN err, done events */
- tmp = readl(hpriv->main_mask_reg_addr);
- writelfl(tmp | mask, hpriv->main_mask_reg_addr);
+ mv_enable_port_irqs(ap, ERR_IRQ);
}
/**
@@ -2474,8 +3698,7 @@ static void mv_eh_thaw(struct ata_port *ap)
*/
static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
{
- void __iomem *shd_base = port_mmio + SHD_BLK_OFS;
- unsigned serr_ofs;
+ void __iomem *serr, *shd_base = port_mmio + SHD_BLK;
/* PIO related setup
*/
@@ -2490,23 +3713,60 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
port->status_addr =
port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS);
/* special case: control/altstatus doesn't have ATA_REG_ address */
- port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
-
- /* unused: */
- port->cmd_addr = port->bmdma_addr = port->scr_addr = NULL;
+ port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST;
/* Clear any currently outstanding port interrupt conditions */
- serr_ofs = mv_scr_offset(SCR_ERROR);
- writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
- writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+ serr = port_mmio + mv_scr_offset(SCR_ERROR);
+ writelfl(readl(serr), serr);
+ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE);
/* unmask all non-transient EDMA error interrupts */
- writelfl(~EDMA_ERR_IRQ_TRANSIENT, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
+ writelfl(~EDMA_ERR_IRQ_TRANSIENT, port_mmio + EDMA_ERR_IRQ_MASK);
VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
- readl(port_mmio + EDMA_CFG_OFS),
- readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS),
- readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
+ readl(port_mmio + EDMA_CFG),
+ readl(port_mmio + EDMA_ERR_IRQ_CAUSE),
+ readl(port_mmio + EDMA_ERR_IRQ_MASK));
+}
+
+static unsigned int mv_in_pcix_mode(struct ata_host *host)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->base;
+ u32 reg;
+
+ if (IS_SOC(hpriv) || !IS_PCIE(hpriv))
+ return 0; /* not PCI-X capable */
+ reg = readl(mmio + MV_PCI_MODE);
+ if ((reg & MV_PCI_MODE_MASK) == 0)
+ return 0; /* conventional PCI mode */
+ return 1; /* chip is in PCI-X mode */
+}
+
+static int mv_pci_cut_through_okay(struct ata_host *host)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->base;
+ u32 reg;
+
+ if (!mv_in_pcix_mode(host)) {
+ reg = readl(mmio + MV_PCI_COMMAND);
+ if (reg & MV_PCI_COMMAND_MRDTRIG)
+ return 0; /* not okay */
+ }
+ return 1; /* okay */
+}
+
+static void mv_60x1b2_errata_pci7(struct ata_host *host)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->base;
+
+ /* workaround for 60x1-B2 errata PCI#7 */
+ if (mv_in_pcix_mode(host)) {
+ u32 reg = readl(mmio + MV_PCI_COMMAND);
+ writelfl(reg & ~MV_PCI_COMMAND_MWRCOM, mmio + MV_PCI_COMMAND);
+ }
}
static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
@@ -2528,8 +3788,8 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
hp_flags |= MV_HP_ERRATA_50XXB2;
break;
default:
- dev_printk(KERN_WARNING, &pdev->dev,
- "Applying 50XXB2 workarounds to unknown rev\n");
+ dev_warn(&pdev->dev,
+ "Applying 50XXB2 workarounds to unknown rev\n");
hp_flags |= MV_HP_ERRATA_50XXB2;
break;
}
@@ -2548,8 +3808,8 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
hp_flags |= MV_HP_ERRATA_50XXB2;
break;
default:
- dev_printk(KERN_WARNING, &pdev->dev,
- "Applying B2 workarounds to unknown rev\n");
+ dev_warn(&pdev->dev,
+ "Applying B2 workarounds to unknown rev\n");
hp_flags |= MV_HP_ERRATA_50XXB2;
break;
}
@@ -2562,21 +3822,22 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
switch (pdev->revision) {
case 0x7:
+ mv_60x1b2_errata_pci7(host);
hp_flags |= MV_HP_ERRATA_60X1B2;
break;
case 0x9:
hp_flags |= MV_HP_ERRATA_60X1C0;
break;
default:
- dev_printk(KERN_WARNING, &pdev->dev,
- "Applying B2 workarounds to unknown rev\n");
+ dev_warn(&pdev->dev,
+ "Applying B2 workarounds to unknown rev\n");
hp_flags |= MV_HP_ERRATA_60X1B2;
break;
}
break;
case chip_7042:
- hp_flags |= MV_HP_PCIE;
+ hp_flags |= MV_HP_PCIE | MV_HP_CUT_THROUGH;
if (pdev->vendor == PCI_VENDOR_ID_TTI &&
(pdev->device == 0x2300 || pdev->device == 0x2310))
{
@@ -2606,43 +3867,46 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
" and avoid the final two gigabytes on"
" all RocketRAID BIOS initialized drives.\n");
}
+ /* drop through */
case chip_6042:
hpriv->ops = &mv6xxx_ops;
hp_flags |= MV_HP_GEN_IIE;
+ if (board_idx == chip_6042 && mv_pci_cut_through_okay(host))
+ hp_flags |= MV_HP_CUT_THROUGH;
switch (pdev->revision) {
- case 0x0:
- hp_flags |= MV_HP_ERRATA_XX42A0;
- break;
- case 0x1:
+ case 0x2: /* Rev.B0: the first/only public release */
hp_flags |= MV_HP_ERRATA_60X1C0;
break;
default:
- dev_printk(KERN_WARNING, &pdev->dev,
- "Applying 60X1C0 workarounds to unknown rev\n");
+ dev_warn(&pdev->dev,
+ "Applying 60X1C0 workarounds to unknown rev\n");
hp_flags |= MV_HP_ERRATA_60X1C0;
break;
}
break;
case chip_soc:
- hpriv->ops = &mv_soc_ops;
- hp_flags |= MV_HP_ERRATA_60X1C0;
+ if (soc_is_65n(hpriv))
+ hpriv->ops = &mv_soc_65n_ops;
+ else
+ hpriv->ops = &mv_soc_ops;
+ hp_flags |= MV_HP_FLAG_SOC | MV_HP_GEN_IIE |
+ MV_HP_ERRATA_60X1C0;
break;
default:
- dev_printk(KERN_ERR, host->dev,
- "BUG: invalid board index %u\n", board_idx);
+ dev_err(host->dev, "BUG: invalid board index %u\n", board_idx);
return 1;
}
hpriv->hp_flags = hp_flags;
if (hp_flags & MV_HP_PCIE) {
- hpriv->irq_cause_ofs = PCIE_IRQ_CAUSE_OFS;
- hpriv->irq_mask_ofs = PCIE_IRQ_MASK_OFS;
+ hpriv->irq_cause_offset = PCIE_IRQ_CAUSE;
+ hpriv->irq_mask_offset = PCIE_IRQ_MASK;
hpriv->unmask_all_irqs = PCIE_UNMASK_ALL_IRQS;
} else {
- hpriv->irq_cause_ofs = PCI_IRQ_CAUSE_OFS;
- hpriv->irq_mask_ofs = PCI_IRQ_MASK_OFS;
+ hpriv->irq_cause_offset = PCI_IRQ_CAUSE;
+ hpriv->irq_mask_offset = PCI_IRQ_MASK;
hpriv->unmask_all_irqs = PCI_UNMASK_ALL_IRQS;
}
@@ -2652,7 +3916,6 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
/**
* mv_init_host - Perform some early initialization of the host.
* @host: ATA host to initialize
- * @board_idx: controller index
*
* If possible, do an early global reset of the host. Then do
* our port init and clear/unmask all/relevant host interrupts.
@@ -2660,33 +3923,35 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
* LOCKING:
* Inherited from caller.
*/
-static int mv_init_host(struct ata_host *host, unsigned int board_idx)
+static int mv_init_host(struct ata_host *host)
{
int rc = 0, n_hc, port, hc;
struct mv_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->base;
- rc = mv_chip_id(host, board_idx);
+ rc = mv_chip_id(host, hpriv->board_idx);
if (rc)
- goto done;
+ goto done;
- if (HAS_PCI(host)) {
- hpriv->main_cause_reg_addr = hpriv->base +
- HC_MAIN_IRQ_CAUSE_OFS;
- hpriv->main_mask_reg_addr = hpriv->base + HC_MAIN_IRQ_MASK_OFS;
+ if (IS_SOC(hpriv)) {
+ hpriv->main_irq_cause_addr = mmio + SOC_HC_MAIN_IRQ_CAUSE;
+ hpriv->main_irq_mask_addr = mmio + SOC_HC_MAIN_IRQ_MASK;
} else {
- hpriv->main_cause_reg_addr = hpriv->base +
- HC_SOC_MAIN_IRQ_CAUSE_OFS;
- hpriv->main_mask_reg_addr = hpriv->base +
- HC_SOC_MAIN_IRQ_MASK_OFS;
+ hpriv->main_irq_cause_addr = mmio + PCI_HC_MAIN_IRQ_CAUSE;
+ hpriv->main_irq_mask_addr = mmio + PCI_HC_MAIN_IRQ_MASK;
}
- /* global interrupt mask */
- writel(0, hpriv->main_mask_reg_addr);
+
+ /* initialize shadow irq mask with register's value */
+ hpriv->main_irq_mask = readl(hpriv->main_irq_mask_addr);
+
+ /* global interrupt mask: 0 == mask everything */
+ mv_set_main_irq_mask(host, ~0, 0);
n_hc = mv_get_hc_count(host->ports[0]->flags);
for (port = 0; port < host->n_ports; port++)
- hpriv->ops->read_preamp(hpriv, port, mmio);
+ if (hpriv->ops->read_preamp)
+ hpriv->ops->read_preamp(hpriv, port, mmio);
rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
if (rc)
@@ -2701,14 +3966,6 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
void __iomem *port_mmio = mv_port_base(mmio, port);
mv_port_init(&ap->ioaddr, port_mmio);
-
-#ifdef CONFIG_PCI
- if (HAS_PCI(host)) {
- unsigned int offset = port_mmio - mmio;
- ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
- ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
- }
-#endif
}
for (hc = 0; hc < n_hc; hc++) {
@@ -2716,39 +3973,28 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
VPRINTK("HC%i: HC config=0x%08x HC IRQ cause "
"(before clear)=0x%08x\n", hc,
- readl(hc_mmio + HC_CFG_OFS),
- readl(hc_mmio + HC_IRQ_CAUSE_OFS));
+ readl(hc_mmio + HC_CFG),
+ readl(hc_mmio + HC_IRQ_CAUSE));
/* Clear any currently outstanding hc interrupt conditions */
- writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
+ writelfl(0, hc_mmio + HC_IRQ_CAUSE);
}
- if (HAS_PCI(host)) {
+ if (!IS_SOC(hpriv)) {
/* Clear any currently outstanding host interrupt conditions */
- writelfl(0, mmio + hpriv->irq_cause_ofs);
+ writelfl(0, mmio + hpriv->irq_cause_offset);
/* and unmask interrupt generation for host regs */
- writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
- if (IS_GEN_I(hpriv))
- writelfl(~HC_MAIN_MASKED_IRQS_5,
- hpriv->main_mask_reg_addr);
- else
- writelfl(~HC_MAIN_MASKED_IRQS,
- hpriv->main_mask_reg_addr);
-
- VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
- "PCI int cause/mask=0x%08x/0x%08x\n",
- readl(hpriv->main_cause_reg_addr),
- readl(hpriv->main_mask_reg_addr),
- readl(mmio + hpriv->irq_cause_ofs),
- readl(mmio + hpriv->irq_mask_ofs));
- } else {
- writelfl(~HC_MAIN_MASKED_IRQS_SOC,
- hpriv->main_mask_reg_addr);
- VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n",
- readl(hpriv->main_cause_reg_addr),
- readl(hpriv->main_mask_reg_addr));
+ writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_offset);
}
+
+ /*
+ * enable only global host interrupts for now.
+ * The per-port interrupts get done later as ports are set up.
+ */
+ mv_set_main_irq_mask(host, 0, PCI_ERR);
+ mv_set_irq_coalescing(host, irq_coalescing_io_count,
+ irq_coalescing_usecs);
done:
return rc;
}
@@ -2774,7 +4020,7 @@ static int mv_create_dma_pools(struct mv_host_priv *hpriv, struct device *dev)
}
static void mv_conf_mbus_windows(struct mv_host_priv *hpriv,
- struct mbus_dram_target_info *dram)
+ const struct mbus_dram_target_info *dram)
{
int i;
@@ -2784,7 +4030,7 @@ static void mv_conf_mbus_windows(struct mv_host_priv *hpriv,
}
for (i = 0; i < dram->num_cs; i++) {
- struct mbus_dram_window *cs = dram->cs + i;
+ const struct mbus_dram_window *cs = dram->cs + i;
writel(((cs->size - 1) & 0xffff0000) |
(cs->mbus_attr << 8) |
@@ -2804,17 +4050,18 @@ static void mv_conf_mbus_windows(struct mv_host_priv *hpriv,
*/
static int mv_platform_probe(struct platform_device *pdev)
{
- static int printed_version;
const struct mv_sata_platform_data *mv_platform_data;
+ const struct mbus_dram_target_info *dram;
const struct ata_port_info *ppi[] =
{ &mv_port_info[chip_soc], NULL };
struct ata_host *host;
struct mv_host_priv *hpriv;
struct resource *res;
- int n_ports, rc;
+ int n_ports = 0, irq = 0;
+ int rc;
+ int port;
- if (!printed_version++)
- dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
/*
* Simple resource validation ..
@@ -2832,43 +4079,117 @@ static int mv_platform_probe(struct platform_device *pdev)
return -EINVAL;
/* allocate host */
- mv_platform_data = pdev->dev.platform_data;
- n_ports = mv_platform_data->n_ports;
+ if (pdev->dev.of_node) {
+ of_property_read_u32(pdev->dev.of_node, "nr-ports", &n_ports);
+ irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ } else {
+ mv_platform_data = dev_get_platdata(&pdev->dev);
+ n_ports = mv_platform_data->n_ports;
+ irq = platform_get_irq(pdev, 0);
+ }
host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
if (!host || !hpriv)
return -ENOMEM;
+ hpriv->port_clks = devm_kzalloc(&pdev->dev,
+ sizeof(struct clk *) * n_ports,
+ GFP_KERNEL);
+ if (!hpriv->port_clks)
+ return -ENOMEM;
+ hpriv->port_phys = devm_kzalloc(&pdev->dev,
+ sizeof(struct phy *) * n_ports,
+ GFP_KERNEL);
+ if (!hpriv->port_phys)
+ return -ENOMEM;
host->private_data = hpriv;
- hpriv->n_ports = n_ports;
+ hpriv->board_idx = chip_soc;
host->iomap = NULL;
hpriv->base = devm_ioremap(&pdev->dev, res->start,
- res->end - res->start + 1);
- hpriv->base -= MV_SATAHC0_REG_BASE;
+ resource_size(res));
+ hpriv->base -= SATAHC0_REG_BASE;
+
+ hpriv->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(hpriv->clk))
+ dev_notice(&pdev->dev, "cannot get optional clkdev\n");
+ else
+ clk_prepare_enable(hpriv->clk);
+
+ for (port = 0; port < n_ports; port++) {
+ char port_number[16];
+ sprintf(port_number, "%d", port);
+ hpriv->port_clks[port] = clk_get(&pdev->dev, port_number);
+ if (!IS_ERR(hpriv->port_clks[port]))
+ clk_prepare_enable(hpriv->port_clks[port]);
+
+ sprintf(port_number, "port%d", port);
+ hpriv->port_phys[port] = devm_phy_optional_get(&pdev->dev,
+ port_number);
+ if (IS_ERR(hpriv->port_phys[port])) {
+ rc = PTR_ERR(hpriv->port_phys[port]);
+ hpriv->port_phys[port] = NULL;
+ if (rc != -EPROBE_DEFER)
+ dev_warn(&pdev->dev, "error getting phy %d", rc);
+
+ /* Cleanup only the initialized ports */
+ hpriv->n_ports = port;
+ goto err;
+ } else
+ phy_power_on(hpriv->port_phys[port]);
+ }
+
+ /* All the ports have been initialized */
+ hpriv->n_ports = n_ports;
/*
* (Re-)program MBUS remapping windows if we are asked to.
*/
- if (mv_platform_data->dram != NULL)
- mv_conf_mbus_windows(hpriv, mv_platform_data->dram);
+ dram = mv_mbus_dram_info();
+ if (dram)
+ mv_conf_mbus_windows(hpriv, dram);
rc = mv_create_dma_pools(hpriv, &pdev->dev);
if (rc)
- return rc;
+ goto err;
+
+ /*
+ * To allow disk hotplug on Armada 370/XP SoCs, the PHY speed must be
+ * updated in the LP_PHY_CTL register.
+ */
+ if (pdev->dev.of_node &&
+ of_device_is_compatible(pdev->dev.of_node,
+ "marvell,armada-370-sata"))
+ hpriv->hp_flags |= MV_HP_FIX_LP_PHY_CTL;
/* initialize adapter */
- rc = mv_init_host(host, chip_soc);
+ rc = mv_init_host(host);
if (rc)
- return rc;
+ goto err;
- dev_printk(KERN_INFO, &pdev->dev,
- "slots %u ports %d\n", (unsigned)MV_MAX_Q_DEPTH,
- host->n_ports);
+ dev_info(&pdev->dev, "slots %u ports %d\n",
+ (unsigned)MV_MAX_Q_DEPTH, host->n_ports);
+
+ rc = ata_host_activate(host, irq, mv_interrupt, IRQF_SHARED, &mv6_sht);
+ if (!rc)
+ return 0;
+
+err:
+ if (!IS_ERR(hpriv->clk)) {
+ clk_disable_unprepare(hpriv->clk);
+ clk_put(hpriv->clk);
+ }
+ for (port = 0; port < hpriv->n_ports; port++) {
+ if (!IS_ERR(hpriv->port_clks[port])) {
+ clk_disable_unprepare(hpriv->port_clks[port]);
+ clk_put(hpriv->port_clks[port]);
+ }
+ if (hpriv->port_phys[port])
+ phy_power_off(hpriv->port_phys[port]);
+ }
- return ata_host_activate(host, platform_get_irq(pdev, 0), mv_interrupt,
- IRQF_SHARED, &mv6_sht);
+ return rc;
}
/*
@@ -2879,28 +4200,98 @@ static int mv_platform_probe(struct platform_device *pdev)
* A platform bus SATA device has been unplugged. Perform the needed
* cleanup. Also called on module unload for any active devices.
*/
-static int __devexit mv_platform_remove(struct platform_device *pdev)
+static int mv_platform_remove(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct ata_host *host = dev_get_drvdata(dev);
-
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct mv_host_priv *hpriv = host->private_data;
+ int port;
ata_host_detach(host);
+
+ if (!IS_ERR(hpriv->clk)) {
+ clk_disable_unprepare(hpriv->clk);
+ clk_put(hpriv->clk);
+ }
+ for (port = 0; port < host->n_ports; port++) {
+ if (!IS_ERR(hpriv->port_clks[port])) {
+ clk_disable_unprepare(hpriv->port_clks[port]);
+ clk_put(hpriv->port_clks[port]);
+ }
+ if (hpriv->port_phys[port])
+ phy_power_off(hpriv->port_phys[port]);
+ }
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int mv_platform_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ if (host)
+ return ata_host_suspend(host, state);
+ else
+ return 0;
+}
+
+static int mv_platform_resume(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ const struct mbus_dram_target_info *dram;
+ int ret;
+
+ if (host) {
+ struct mv_host_priv *hpriv = host->private_data;
+
+ /*
+ * (Re-)program MBUS remapping windows if we are asked to.
+ */
+ dram = mv_mbus_dram_info();
+ if (dram)
+ mv_conf_mbus_windows(hpriv, dram);
+
+ /* initialize adapter */
+ ret = mv_init_host(host);
+ if (ret) {
+ printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+ return ret;
+ }
+ ata_host_resume(host);
+ }
+
+ return 0;
+}
+#else
+#define mv_platform_suspend NULL
+#define mv_platform_resume NULL
+#endif
+
+#ifdef CONFIG_OF
+static struct of_device_id mv_sata_dt_ids[] = {
+ { .compatible = "marvell,armada-370-sata", },
+ { .compatible = "marvell,orion-sata", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mv_sata_dt_ids);
+#endif
+
static struct platform_driver mv_platform_driver = {
- .probe = mv_platform_probe,
- .remove = __devexit_p(mv_platform_remove),
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- },
+ .probe = mv_platform_probe,
+ .remove = mv_platform_remove,
+ .suspend = mv_platform_suspend,
+ .resume = mv_platform_resume,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(mv_sata_dt_ids),
+ },
};
#ifdef CONFIG_PCI
static int mv_pci_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent);
+#ifdef CONFIG_PM_SLEEP
+static int mv_pci_device_resume(struct pci_dev *pdev);
+#endif
static struct pci_driver mv_pci_driver = {
@@ -2908,40 +4299,38 @@ static struct pci_driver mv_pci_driver = {
.id_table = mv_pci_tbl,
.probe = mv_pci_init_one,
.remove = ata_pci_remove_one,
-};
-
-/*
- * module options
- */
-static int msi; /* Use PCI msi; either zero (off, default) or non-zero */
+#ifdef CONFIG_PM_SLEEP
+ .suspend = ata_pci_device_suspend,
+ .resume = mv_pci_device_resume,
+#endif
+};
/* move to PCI layer or libata core? */
static int pci_go_64(struct pci_dev *pdev)
{
int rc;
- if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
if (rc) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "64-bit DMA enable failed\n");
+ dev_err(&pdev->dev,
+ "64-bit DMA enable failed\n");
return rc;
}
}
} else {
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit DMA enable failed\n");
+ dev_err(&pdev->dev, "32-bit DMA enable failed\n");
return rc;
}
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit consistent DMA enable failed\n");
+ dev_err(&pdev->dev,
+ "32-bit consistent DMA enable failed\n");
return rc;
}
}
@@ -2985,10 +4374,9 @@ static void mv_print_info(struct ata_host *host)
else
gen = "?";
- dev_printk(KERN_INFO, &pdev->dev,
- "Gen-%s %u slots %u ports %s mode IRQ via %s\n",
- gen, (unsigned)MV_MAX_Q_DEPTH, host->n_ports,
- scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
+ dev_info(&pdev->dev, "Gen-%s %u slots %u ports %s mode IRQ via %s\n",
+ gen, (unsigned)MV_MAX_Q_DEPTH, host->n_ports,
+ scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
}
/**
@@ -3002,15 +4390,13 @@ static void mv_print_info(struct ata_host *host)
static int mv_pci_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- static int printed_version;
unsigned int board_idx = (unsigned int)ent->driver_data;
const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
struct ata_host *host;
struct mv_host_priv *hpriv;
- int n_ports, rc;
+ int n_ports, port, rc;
- if (!printed_version++)
- dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
/* allocate host */
n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC;
@@ -3021,6 +4407,7 @@ static int mv_pci_init_one(struct pci_dev *pdev,
return -ENOMEM;
host->private_data = hpriv;
hpriv->n_ports = n_ports;
+ hpriv->board_idx = board_idx;
/* acquire resources */
rc = pcim_enable_device(pdev);
@@ -3043,14 +4430,23 @@ static int mv_pci_init_one(struct pci_dev *pdev,
if (rc)
return rc;
+ for (port = 0; port < host->n_ports; port++) {
+ struct ata_port *ap = host->ports[port];
+ void __iomem *port_mmio = mv_port_base(hpriv->base, port);
+ unsigned int offset = port_mmio - hpriv->base;
+
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
+ }
+
/* initialize adapter */
- rc = mv_init_host(host, board_idx);
+ rc = mv_init_host(host);
if (rc)
return rc;
- /* Enable interrupts */
- if (msi && pci_enable_msi(pdev))
- pci_intx(pdev, 1);
+ /* Enable message-switched interrupts, if requested */
+ if (msi && pci_enable_msi(pdev) == 0)
+ hpriv->hp_flags |= MV_HP_FLAG_MSI;
mv_dump_pci_cfg(pdev, 0x68);
mv_print_info(host);
@@ -3060,10 +4456,28 @@ static int mv_pci_init_one(struct pci_dev *pdev,
return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
}
-#endif
-static int mv_platform_probe(struct platform_device *pdev);
-static int __devexit mv_platform_remove(struct platform_device *pdev);
+#ifdef CONFIG_PM_SLEEP
+static int mv_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ /* initialize adapter */
+ rc = mv_init_host(host);
+ if (rc)
+ return rc;
+
+ ata_host_resume(host);
+
+ return 0;
+}
+#endif
+#endif
static int __init mv_init(void)
{
@@ -3097,10 +4511,5 @@ MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
MODULE_VERSION(DRV_VERSION);
MODULE_ALIAS("platform:" DRV_NAME);
-#ifdef CONFIG_PCI
-module_param(msi, int, 0444);
-MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
-#endif
-
module_init(mv_init);
module_exit(mv_exit);
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 109b0749572..cdf99fac139 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -38,8 +38,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -57,9 +57,9 @@ enum {
NV_MMIO_BAR = 5,
NV_PORTS = 2,
- NV_PIO_MASK = 0x1f,
- NV_MWDMA_MASK = 0x07,
- NV_UDMA_MASK = 0x7f,
+ NV_PIO_MASK = ATA_PIO4,
+ NV_MWDMA_MASK = ATA_MWDMA2,
+ NV_UDMA_MASK = ATA_UDMA6,
NV_PORT0_SCR_REG_OFFSET = 0x00,
NV_PORT1_SCR_REG_OFFSET = 0x40,
@@ -271,7 +271,7 @@ enum ncq_saw_flag_list {
};
struct nv_swncq_port_priv {
- struct ata_prd *prd; /* our SG list */
+ struct ata_bmdma_prd *prd; /* our SG list */
dma_addr_t prd_dma; /* and its DMA mapping */
void __iomem *sactive_block;
void __iomem *irq_block;
@@ -295,22 +295,22 @@ struct nv_swncq_port_priv {
#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & (1 << (19 + (12 * (PORT)))))
static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int nv_pci_device_resume(struct pci_dev *pdev);
#endif
static void nv_ck804_host_stop(struct ata_host *host);
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
-static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
+static int nv_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline);
static void nv_nf2_freeze(struct ata_port *ap);
static void nv_nf2_thaw(struct ata_port *ap);
static void nv_ck804_freeze(struct ata_port *ap);
static void nv_ck804_thaw(struct ata_port *ap);
-static int nv_hardreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline);
static int nv_adma_slave_config(struct scsi_device *sdev);
static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc);
static void nv_adma_qc_prep(struct ata_queued_cmd *qc);
@@ -352,6 +352,7 @@ enum nv_host_type
NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */
CK804,
ADMA,
+ MCP5x,
SWNCQ,
};
@@ -363,10 +364,10 @@ static const struct pci_device_id nv_pci_tbl[] = {
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 },
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 },
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), SWNCQ },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), SWNCQ },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), SWNCQ },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), SWNCQ },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), MCP5x },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), MCP5x },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), MCP5x },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), MCP5x },
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC },
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC },
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC },
@@ -378,7 +379,7 @@ static struct pci_driver nv_pci_driver = {
.name = DRV_NAME,
.id_table = nv_pci_tbl,
.probe = nv_init_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = nv_pci_device_resume,
#endif
@@ -405,11 +406,70 @@ static struct scsi_host_template nv_swncq_sht = {
.slave_configure = nv_swncq_slave_config,
};
+/*
+ * NV SATA controllers have various different problems with hardreset
+ * protocol depending on the specific controller and device.
+ *
+ * GENERIC:
+ *
+ * bko11195 reports that link doesn't come online after hardreset on
+ * generic nv's and there have been several other similar reports on
+ * linux-ide.
+ *
+ * bko12351#c23 reports that warmplug on MCP61 doesn't work with
+ * softreset.
+ *
+ * NF2/3:
+ *
+ * bko3352 reports nf2/3 controllers can't determine device signature
+ * reliably after hardreset. The following thread reports detection
+ * failure on cold boot with the standard debouncing timing.
+ *
+ * http://thread.gmane.org/gmane.linux.ide/34098
+ *
+ * bko12176 reports that hardreset fails to bring up the link during
+ * boot on nf2.
+ *
+ * CK804:
+ *
+ * For initial probing after boot and hot plugging, hardreset mostly
+ * works fine on CK804 but curiously, reprobing on the initial port
+ * by rescanning or rmmod/insmod fails to acquire the initial D2H Reg
+ * FIS in somewhat undeterministic way.
+ *
+ * SWNCQ:
+ *
+ * bko12351 reports that when SWNCQ is enabled, for hotplug to work,
+ * hardreset should be used and hardreset can't report proper
+ * signature, which suggests that mcp5x is closer to nf2 as long as
+ * reset quirkiness is concerned.
+ *
+ * bko12703 reports that boot probing fails for intel SSD with
+ * hardreset. Link fails to come online. Softreset works fine.
+ *
+ * The failures are varied but the following patterns seem true for
+ * all flavors.
+ *
+ * - Softreset during boot always works.
+ *
+ * - Hardreset during boot sometimes fails to bring up the link on
+ * certain comibnations and device signature acquisition is
+ * unreliable.
+ *
+ * - Hardreset is often necessary after hotplug.
+ *
+ * So, preferring softreset for boot probing and error handling (as
+ * hardreset might bring down the link) but using hardreset for
+ * post-boot probing should work around the above issues in most
+ * cases. Define nv_hardreset() which only kicks in for post-boot
+ * probing and use it for all variants.
+ */
static struct ata_port_operations nv_generic_ops = {
.inherits = &ata_bmdma_port_ops,
- .hardreset = nv_hardreset,
+ .lost_interrupt = ATA_OP_NULL,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
+ .hardreset = nv_hardreset,
};
static struct ata_port_operations nv_nf2_ops = {
@@ -426,7 +486,7 @@ static struct ata_port_operations nv_ck804_ops = {
};
static struct ata_port_operations nv_adma_ops = {
- .inherits = &nv_generic_ops,
+ .inherits = &nv_ck804_ops,
.check_atapi_dma = nv_adma_check_atapi_dma,
.sff_tf_read = nv_adma_tf_read,
@@ -478,7 +538,7 @@ struct nv_pi_priv {
static const struct ata_port_info nv_port_info[] = {
/* generic */
{
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .flags = ATA_FLAG_SATA,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -487,7 +547,7 @@ static const struct ata_port_info nv_port_info[] = {
},
/* nforce2/3 */
{
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .flags = ATA_FLAG_SATA,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -496,7 +556,7 @@ static const struct ata_port_info nv_port_info[] = {
},
/* ck804 */
{
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .flags = ATA_FLAG_SATA,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -505,18 +565,25 @@ static const struct ata_port_info nv_port_info[] = {
},
/* ADMA */
{
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_NCQ,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NCQ,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
.port_ops = &nv_adma_ops,
.private_data = NV_PI_PRIV(nv_adma_interrupt, &nv_adma_sht),
},
+ /* MCP5x */
+ {
+ .flags = ATA_FLAG_SATA,
+ .pio_mask = NV_PIO_MASK,
+ .mwdma_mask = NV_MWDMA_MASK,
+ .udma_mask = NV_UDMA_MASK,
+ .port_ops = &nv_generic_ops,
+ .private_data = NV_PI_PRIV(nv_generic_interrupt, &nv_sht),
+ },
/* SWNCQ */
{
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_NCQ,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NCQ,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -531,8 +598,9 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-static int adma_enabled;
-static int swncq_enabled = 1;
+static bool adma_enabled;
+static bool swncq_enabled = 1;
+static bool msi_enabled;
static void nv_adma_register_mode(struct ata_port *ap)
{
@@ -551,9 +619,8 @@ static void nv_adma_register_mode(struct ata_port *ap)
count++;
}
if (count == 20)
- ata_port_printk(ap, KERN_WARNING,
- "timeout waiting for ADMA IDLE, stat=0x%hx\n",
- status);
+ ata_port_warn(ap, "timeout waiting for ADMA IDLE, stat=0x%hx\n",
+ status);
tmp = readw(mmio + NV_ADMA_CTL);
writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);
@@ -566,9 +633,9 @@ static void nv_adma_register_mode(struct ata_port *ap)
count++;
}
if (count == 20)
- ata_port_printk(ap, KERN_WARNING,
- "timeout waiting for ADMA LEGACY, stat=0x%hx\n",
- status);
+ ata_port_warn(ap,
+ "timeout waiting for ADMA LEGACY, stat=0x%hx\n",
+ status);
pp->flags |= NV_ADMA_PORT_REGISTER_MODE;
}
@@ -596,7 +663,7 @@ static void nv_adma_mode(struct ata_port *ap)
count++;
}
if (count == 20)
- ata_port_printk(ap, KERN_WARNING,
+ ata_port_warn(ap,
"timeout waiting for ADMA LEGACY clear and IDLE, stat=0x%hx\n",
status);
@@ -702,11 +769,11 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
}
blk_queue_segment_boundary(sdev->request_queue, segment_boundary);
- blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize);
- ata_port_printk(ap, KERN_INFO,
- "DMA mask 0x%llX, segment boundary 0x%lX, hw segs %hu\n",
- (unsigned long long)*ap->host->dev->dma_mask,
- segment_boundary, sg_tablesize);
+ blk_queue_max_segments(sdev->request_queue, sg_tablesize);
+ ata_port_info(ap,
+ "DMA mask 0x%llX, segment boundary 0x%lX, hw segs %hu\n",
+ (unsigned long long)*ap->host->dev->dma_mask,
+ segment_boundary, sg_tablesize);
spin_unlock_irqrestore(ap->lock, flags);
@@ -802,29 +869,11 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
ata_port_freeze(ap);
else
ata_port_abort(ap);
- return 1;
+ return -1;
}
- if (likely(flags & NV_CPB_RESP_DONE)) {
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
- VPRINTK("CPB flags done, flags=0x%x\n", flags);
- if (likely(qc)) {
- DPRINTK("Completing qc from tag %d\n", cpb_num);
- ata_qc_complete(qc);
- } else {
- struct ata_eh_info *ehi = &ap->link.eh_info;
- /* Notifier bits set without a command may indicate the drive
- is misbehaving. Raise host state machine violation on this
- condition. */
- ata_port_printk(ap, KERN_ERR,
- "notifier for tag %d with no cmd?\n",
- cpb_num);
- ehi->err_mask |= AC_ERR_HSM;
- ehi->action |= ATA_EH_RESET;
- ata_port_freeze(ap);
- return 1;
- }
- }
+ if (likely(flags & NV_CPB_RESP_DONE))
+ return 1;
return 0;
}
@@ -849,7 +898,7 @@ static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
}
/* handle interrupt */
- return ata_sff_host_intr(ap, qc);
+ return ata_bmdma_port_intr(ap, qc);
}
static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
@@ -862,108 +911,115 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
+ struct nv_adma_port_priv *pp = ap->private_data;
+ void __iomem *mmio = pp->ctl_block;
+ u16 status;
+ u32 gen_ctl;
+ u32 notifier, notifier_error;
+
notifier_clears[i] = 0;
- if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
- struct nv_adma_port_priv *pp = ap->private_data;
- void __iomem *mmio = pp->ctl_block;
- u16 status;
- u32 gen_ctl;
- u32 notifier, notifier_error;
-
- /* if ADMA is disabled, use standard ata interrupt handler */
- if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) {
- u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
- >> (NV_INT_PORT_SHIFT * i);
- handled += nv_host_intr(ap, irq_stat);
- continue;
- }
+ /* if ADMA is disabled, use standard ata interrupt handler */
+ if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) {
+ u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
+ >> (NV_INT_PORT_SHIFT * i);
+ handled += nv_host_intr(ap, irq_stat);
+ continue;
+ }
- /* if in ATA register mode, check for standard interrupts */
- if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
- u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
- >> (NV_INT_PORT_SHIFT * i);
- if (ata_tag_valid(ap->link.active_tag))
- /** NV_INT_DEV indication seems unreliable at times
- at least in ADMA mode. Force it on always when a
- command is active, to prevent losing interrupts. */
- irq_stat |= NV_INT_DEV;
- handled += nv_host_intr(ap, irq_stat);
- }
+ /* if in ATA register mode, check for standard interrupts */
+ if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
+ u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
+ >> (NV_INT_PORT_SHIFT * i);
+ if (ata_tag_valid(ap->link.active_tag))
+ /** NV_INT_DEV indication seems unreliable
+ at times at least in ADMA mode. Force it
+ on always when a command is active, to
+ prevent losing interrupts. */
+ irq_stat |= NV_INT_DEV;
+ handled += nv_host_intr(ap, irq_stat);
+ }
+
+ notifier = readl(mmio + NV_ADMA_NOTIFIER);
+ notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
+ notifier_clears[i] = notifier | notifier_error;
+
+ gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
+
+ if (!NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier &&
+ !notifier_error)
+ /* Nothing to do */
+ continue;
+
+ status = readw(mmio + NV_ADMA_STAT);
+
+ /*
+ * Clear status. Ensure the controller sees the
+ * clearing before we start looking at any of the CPB
+ * statuses, so that any CPB completions after this
+ * point in the handler will raise another interrupt.
+ */
+ writew(status, mmio + NV_ADMA_STAT);
+ readw(mmio + NV_ADMA_STAT); /* flush posted write */
+ rmb();
+
+ handled++; /* irq handled if we got here */
- notifier = readl(mmio + NV_ADMA_NOTIFIER);
- notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
- notifier_clears[i] = notifier | notifier_error;
-
- gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
-
- if (!NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier &&
- !notifier_error)
- /* Nothing to do */
- continue;
-
- status = readw(mmio + NV_ADMA_STAT);
-
- /* Clear status. Ensure the controller sees the clearing before we start
- looking at any of the CPB statuses, so that any CPB completions after
- this point in the handler will raise another interrupt. */
- writew(status, mmio + NV_ADMA_STAT);
- readw(mmio + NV_ADMA_STAT); /* flush posted write */
- rmb();
-
- handled++; /* irq handled if we got here */
-
- /* freeze if hotplugged or controller error */
- if (unlikely(status & (NV_ADMA_STAT_HOTPLUG |
- NV_ADMA_STAT_HOTUNPLUG |
- NV_ADMA_STAT_TIMEOUT |
- NV_ADMA_STAT_SERROR))) {
- struct ata_eh_info *ehi = &ap->link.eh_info;
-
- ata_ehi_clear_desc(ehi);
- __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status);
- if (status & NV_ADMA_STAT_TIMEOUT) {
- ehi->err_mask |= AC_ERR_SYSTEM;
- ata_ehi_push_desc(ehi, "timeout");
- } else if (status & NV_ADMA_STAT_HOTPLUG) {
- ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, "hotplug");
- } else if (status & NV_ADMA_STAT_HOTUNPLUG) {
- ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, "hot unplug");
- } else if (status & NV_ADMA_STAT_SERROR) {
- /* let libata analyze SError and figure out the cause */
- ata_ehi_push_desc(ehi, "SError");
- } else
- ata_ehi_push_desc(ehi, "unknown");
- ata_port_freeze(ap);
- continue;
+ /* freeze if hotplugged or controller error */
+ if (unlikely(status & (NV_ADMA_STAT_HOTPLUG |
+ NV_ADMA_STAT_HOTUNPLUG |
+ NV_ADMA_STAT_TIMEOUT |
+ NV_ADMA_STAT_SERROR))) {
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+
+ ata_ehi_clear_desc(ehi);
+ __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status);
+ if (status & NV_ADMA_STAT_TIMEOUT) {
+ ehi->err_mask |= AC_ERR_SYSTEM;
+ ata_ehi_push_desc(ehi, "timeout");
+ } else if (status & NV_ADMA_STAT_HOTPLUG) {
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, "hotplug");
+ } else if (status & NV_ADMA_STAT_HOTUNPLUG) {
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, "hot unplug");
+ } else if (status & NV_ADMA_STAT_SERROR) {
+ /* let EH analyze SError and figure out cause */
+ ata_ehi_push_desc(ehi, "SError");
+ } else
+ ata_ehi_push_desc(ehi, "unknown");
+ ata_port_freeze(ap);
+ continue;
+ }
+
+ if (status & (NV_ADMA_STAT_DONE |
+ NV_ADMA_STAT_CPBERR |
+ NV_ADMA_STAT_CMD_COMPLETE)) {
+ u32 check_commands = notifier_clears[i];
+ u32 done_mask = 0;
+ int pos, rc;
+
+ if (status & NV_ADMA_STAT_CPBERR) {
+ /* check all active commands */
+ if (ata_tag_valid(ap->link.active_tag))
+ check_commands = 1 <<
+ ap->link.active_tag;
+ else
+ check_commands = ap->link.sactive;
}
- if (status & (NV_ADMA_STAT_DONE |
- NV_ADMA_STAT_CPBERR |
- NV_ADMA_STAT_CMD_COMPLETE)) {
- u32 check_commands = notifier_clears[i];
- int pos, error = 0;
-
- if (status & NV_ADMA_STAT_CPBERR) {
- /* Check all active commands */
- if (ata_tag_valid(ap->link.active_tag))
- check_commands = 1 <<
- ap->link.active_tag;
- else
- check_commands = ap->
- link.sactive;
- }
-
- /** Check CPBs for completed commands */
- while ((pos = ffs(check_commands)) && !error) {
- pos--;
- error = nv_adma_check_cpb(ap, pos,
+ /* check CPBs for completed commands */
+ while ((pos = ffs(check_commands))) {
+ pos--;
+ rc = nv_adma_check_cpb(ap, pos,
notifier_error & (1 << pos));
- check_commands &= ~(1 << pos);
- }
+ if (rc > 0)
+ done_mask |= 1 << pos;
+ else if (unlikely(rc < 0))
+ check_commands = 0;
+ check_commands &= ~(1 << pos);
}
+ ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
}
}
@@ -1028,7 +1084,7 @@ static void nv_adma_irq_clear(struct ata_port *ap)
u32 notifier_clears[2];
if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) {
- ata_sff_irq_clear(ap);
+ ata_bmdma_irq_clear(ap);
return;
}
@@ -1059,7 +1115,7 @@ static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc)
struct nv_adma_port_priv *pp = qc->ap->private_data;
if (pp->flags & NV_ADMA_PORT_REGISTER_MODE)
- ata_sff_post_internal_cmd(qc);
+ ata_bmdma_post_internal_cmd(qc);
}
static int nv_adma_port_start(struct ata_port *ap)
@@ -1084,7 +1140,8 @@ static int nv_adma_port_start(struct ata_port *ap)
if (rc)
return rc;
- rc = ata_port_start(ap);
+ /* we might fallback to bmdma, allocate bmdma resources */
+ rc = ata_bmdma_port_start(ap);
if (rc)
return rc;
@@ -1336,7 +1393,7 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
BUG_ON(!(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) &&
(qc->flags & ATA_QCFLAG_DMAMAP));
nv_adma_register_mode(qc->ap);
- ata_sff_qc_prep(qc);
+ ata_bmdma_qc_prep(qc);
return;
}
@@ -1384,8 +1441,7 @@ static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
existing commands. */
if (unlikely(qc->tf.protocol == ATA_PROT_NCQ &&
(qc->flags & ATA_QCFLAG_RESULT_TF))) {
- ata_dev_printk(qc->dev, KERN_ERR,
- "NCQ w/ RESULT_TF not allowed\n");
+ ata_dev_err(qc->dev, "NCQ w/ RESULT_TF not allowed\n");
return AC_ERR_SYSTEM;
}
@@ -1395,7 +1451,7 @@ static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
BUG_ON(!(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) &&
(qc->flags & ATA_QCFLAG_DMAMAP));
nv_adma_register_mode(qc->ap);
- return ata_sff_qc_issue(qc);
+ return ata_bmdma_qc_issue(qc);
} else
nv_adma_mode(qc->ap);
@@ -1427,22 +1483,19 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance)
spin_lock_irqsave(&host->lock, flags);
for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap;
-
- ap = host->ports[i];
- if (ap &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
+ struct ata_port *ap = host->ports[i];
+ struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->link.active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
- handled += ata_sff_host_intr(ap, qc);
- else
- // No request pending? Clear interrupt status
- // anyway, in case there's one pending.
- ap->ops->sff_check_status(ap);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
+ handled += ata_bmdma_port_intr(ap, qc);
+ } else {
+ /*
+ * No request pending? Clear interrupt status
+ * anyway, in case there's one pending.
+ */
+ ap->ops->sff_check_status(ap);
}
-
}
spin_unlock_irqrestore(&host->lock, flags);
@@ -1455,11 +1508,7 @@ static irqreturn_t nv_do_interrupt(struct ata_host *host, u8 irq_stat)
int i, handled = 0;
for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
-
- if (ap && !(ap->flags & ATA_FLAG_DISABLED))
- handled += nv_host_intr(ap, irq_stat);
-
+ handled += nv_host_intr(host->ports[i], irq_stat);
irq_stat >>= NV_INT_PORT_SHIFT;
}
@@ -1494,24 +1543,56 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
return ret;
}
-static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = ioread32(link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
-static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ iowrite32(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
+static int nv_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_eh_context *ehc = &link->eh_context;
+
+ /* Do hardreset iff it's post-boot probing, please read the
+ * comment above port ops for details.
+ */
+ if (!(link->ap->pflags & ATA_PFLAG_LOADING) &&
+ !ata_dev_enabled(link->device))
+ sata_link_hardreset(link, sata_deb_timing_hotplug, deadline,
+ NULL, NULL);
+ else {
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
+ int rc;
+
+ if (!(ehc->i.flags & ATA_EHI_QUIET))
+ ata_link_info(link,
+ "nv: skipping hardreset on occupied port\n");
+
+ /* make sure the link is online */
+ rc = sata_link_resume(link, timing, deadline);
+ /* whine about phy resume failure but proceed */
+ if (rc && rc != -EOPNOTSUPP)
+ ata_link_warn(link, "failed to resume link (errno=%d)\n",
+ rc);
+ }
+
+ /* device signature acquisition is unreliable */
+ return -EAGAIN;
+}
+
static void nv_nf2_freeze(struct ata_port *ap)
{
void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
@@ -1571,7 +1652,6 @@ static void nv_mcp55_freeze(struct ata_port *ap)
mask = readl(mmio_base + NV_INT_ENABLE_MCP55);
mask &= ~(NV_INT_ALL_MCP55 << shift);
writel(mask, mmio_base + NV_INT_ENABLE_MCP55);
- ata_sff_freeze(ap);
}
static void nv_mcp55_thaw(struct ata_port *ap)
@@ -1585,19 +1665,6 @@ static void nv_mcp55_thaw(struct ata_port *ap)
mask = readl(mmio_base + NV_INT_ENABLE_MCP55);
mask |= (NV_INT_MASK_MCP55 << shift);
writel(mask, mmio_base + NV_INT_ENABLE_MCP55);
- ata_sff_thaw(ap);
-}
-
-static int nv_hardreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
-{
- unsigned int dummy;
-
- /* SATA hardreset fails to retrieve proper device signature on
- * some controllers. Don't classify on hardreset. For more
- * info, see http://bugzilla.kernel.org/show_bug.cgi?id=3352
- */
- return sata_sff_hardreset(link, &dummy, deadline);
}
static void nv_adma_error_handler(struct ata_port *ap)
@@ -1616,7 +1683,7 @@ static void nv_adma_error_handler(struct ata_port *ap)
u8 cpb_count = readb(mmio + NV_ADMA_CPB_COUNT);
u8 next_cpb_idx = readb(mmio + NV_ADMA_NEXT_CPB_IDX);
- ata_port_printk(ap, KERN_ERR,
+ ata_port_err(ap,
"EH in ADMA mode, notifier 0x%X "
"notifier_error 0x%X gen_ctl 0x%X status 0x%X "
"next cpb count 0x%X next cpb idx 0x%x\n",
@@ -1627,7 +1694,7 @@ static void nv_adma_error_handler(struct ata_port *ap)
struct nv_adma_cpb *cpb = &pp->cpb[i];
if ((ata_tag_valid(ap->link.active_tag) && i == ap->link.active_tag) ||
ap->link.sactive & (1 << i))
- ata_port_printk(ap, KERN_ERR,
+ ata_port_err(ap,
"CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n",
i, cpb->ctl_flags, cpb->resp_flags);
}
@@ -1653,7 +1720,7 @@ static void nv_adma_error_handler(struct ata_port *ap)
readw(mmio + NV_ADMA_CTL); /* flush posted write */
}
- ata_sff_error_handler(ap);
+ ata_bmdma_error_handler(ap);
}
static void nv_swncq_qc_to_dq(struct ata_port *ap, struct ata_queued_cmd *qc)
@@ -1729,23 +1796,22 @@ static void nv_swncq_ncq_stop(struct ata_port *ap)
u32 sactive;
u32 done_mask;
- ata_port_printk(ap, KERN_ERR,
- "EH in SWNCQ mode,QC:qc_active 0x%X sactive 0x%X\n",
- ap->qc_active, ap->link.sactive);
- ata_port_printk(ap, KERN_ERR,
+ ata_port_err(ap, "EH in SWNCQ mode,QC:qc_active 0x%X sactive 0x%X\n",
+ ap->qc_active, ap->link.sactive);
+ ata_port_err(ap,
"SWNCQ:qc_active 0x%X defer_bits 0x%X last_issue_tag 0x%x\n "
"dhfis 0x%X dmafis 0x%X sdbfis 0x%X\n",
pp->qc_active, pp->defer_queue.defer_bits, pp->last_issue_tag,
pp->dhfis_bits, pp->dmafis_bits, pp->sdbfis_bits);
- ata_port_printk(ap, KERN_ERR, "ATA_REG 0x%X ERR_REG 0x%X\n",
- ap->ops->sff_check_status(ap),
- ioread8(ap->ioaddr.error_addr));
+ ata_port_err(ap, "ATA_REG 0x%X ERR_REG 0x%X\n",
+ ap->ops->sff_check_status(ap),
+ ioread8(ap->ioaddr.error_addr));
sactive = readl(pp->sactive_block);
done_mask = pp->qc_active ^ sactive;
- ata_port_printk(ap, KERN_ERR, "tag : dhfis dmafis sdbfis sacitve\n");
+ ata_port_err(ap, "tag : dhfis dmafis sdbfis sactive\n");
for (i = 0; i < ATA_MAX_QUEUE; i++) {
u8 err = 0;
if (pp->qc_active & (1 << i))
@@ -1755,13 +1821,13 @@ static void nv_swncq_ncq_stop(struct ata_port *ap)
else
continue;
- ata_port_printk(ap, KERN_ERR,
- "tag 0x%x: %01x %01x %01x %01x %s\n", i,
- (pp->dhfis_bits >> i) & 0x1,
- (pp->dmafis_bits >> i) & 0x1,
- (pp->sdbfis_bits >> i) & 0x1,
- (sactive >> i) & 0x1,
- (err ? "error! tag doesn't exit" : " "));
+ ata_port_err(ap,
+ "tag 0x%x: %01x %01x %01x %01x %s\n", i,
+ (pp->dhfis_bits >> i) & 0x1,
+ (pp->dmafis_bits >> i) & 0x1,
+ (pp->sdbfis_bits >> i) & 0x1,
+ (sactive >> i) & 0x1,
+ (err ? "error! tag doesn't exit" : " "));
}
nv_swncq_pp_reinit(ap);
@@ -1779,7 +1845,7 @@ static void nv_swncq_error_handler(struct ata_port *ap)
ehc->i.action |= ATA_EH_RESET;
}
- ata_sff_error_handler(ap);
+ ata_bmdma_error_handler(ap);
}
#ifdef CONFIG_PM
@@ -1885,9 +1951,9 @@ static int nv_swncq_slave_config(struct scsi_device *sdev)
ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
if (strncmp(model_num, "Maxtor", 6) == 0) {
- ata_scsi_change_queue_depth(sdev, 1);
- ata_dev_printk(dev, KERN_NOTICE,
- "Disabling SWNCQ mode (depth %x)\n", sdev->queue_depth);
+ ata_scsi_change_queue_depth(sdev, 1, SCSI_QDEPTH_DEFAULT);
+ ata_dev_notice(dev, "Disabling SWNCQ mode (depth %x)\n",
+ sdev->queue_depth);
}
return rc;
@@ -1900,7 +1966,8 @@ static int nv_swncq_port_start(struct ata_port *ap)
struct nv_swncq_port_priv *pp;
int rc;
- rc = ata_port_start(ap);
+ /* we might fallback to bmdma, allocate bmdma resources */
+ rc = ata_bmdma_port_start(ap);
if (rc)
return rc;
@@ -1925,7 +1992,7 @@ static int nv_swncq_port_start(struct ata_port *ap)
static void nv_swncq_qc_prep(struct ata_queued_cmd *qc)
{
if (qc->tf.protocol != ATA_PROT_NCQ) {
- ata_sff_qc_prep(qc);
+ ata_bmdma_qc_prep(qc);
return;
}
@@ -1940,7 +2007,7 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct scatterlist *sg;
struct nv_swncq_port_priv *pp = ap->private_data;
- struct ata_prd *prd;
+ struct ata_bmdma_prd *prd;
unsigned int si, idx;
prd = pp->prd + ATA_MAX_PRD * qc->tag;
@@ -2001,7 +2068,7 @@ static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc)
struct nv_swncq_port_priv *pp = ap->private_data;
if (qc->tf.protocol != ATA_PROT_NCQ)
- return ata_sff_qc_issue(qc);
+ return ata_bmdma_qc_issue(qc);
DPRINTK("Enter\n");
@@ -2044,15 +2111,13 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
struct nv_swncq_port_priv *pp = ap->private_data;
struct ata_eh_info *ehi = &ap->link.eh_info;
u32 sactive;
- int nr_done = 0;
u32 done_mask;
- int i;
u8 host_stat;
u8 lack_dhfis = 0;
host_stat = ap->ops->bmdma_status(ap);
if (unlikely(host_stat & ATA_DMA_ERR)) {
- /* error when transfering data to/from memory */
+ /* error when transferring data to/from memory */
ata_ehi_clear_desc(ehi);
ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
ehi->err_mask |= AC_ERR_HOST_BUS;
@@ -2066,41 +2131,24 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
sactive = readl(pp->sactive_block);
done_mask = pp->qc_active ^ sactive;
- if (unlikely(done_mask & sactive)) {
- ata_ehi_clear_desc(ehi);
- ata_ehi_push_desc(ehi, "illegal SWNCQ:qc_active transition"
- "(%08x->%08x)", pp->qc_active, sactive);
- ehi->err_mask |= AC_ERR_HSM;
- ehi->action |= ATA_EH_RESET;
- return -EINVAL;
- }
- for (i = 0; i < ATA_MAX_QUEUE; i++) {
- if (!(done_mask & (1 << i)))
- continue;
-
- qc = ata_qc_from_tag(ap, i);
- if (qc) {
- ata_qc_complete(qc);
- pp->qc_active &= ~(1 << i);
- pp->dhfis_bits &= ~(1 << i);
- pp->dmafis_bits &= ~(1 << i);
- pp->sdbfis_bits |= (1 << i);
- nr_done++;
- }
- }
+ pp->qc_active &= ~done_mask;
+ pp->dhfis_bits &= ~done_mask;
+ pp->dmafis_bits &= ~done_mask;
+ pp->sdbfis_bits |= done_mask;
+ ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
if (!ap->qc_active) {
DPRINTK("over\n");
nv_swncq_pp_reinit(ap);
- return nr_done;
+ return 0;
}
if (pp->qc_active & pp->dhfis_bits)
- return nr_done;
+ return 0;
if ((pp->ncq_flags & ncq_saw_backout) ||
(pp->qc_active ^ pp->dhfis_bits))
- /* if the controller cann't get a device to host register FIS,
+ /* if the controller can't get a device to host register FIS,
* The driver needs to reissue the new command.
*/
lack_dhfis = 1;
@@ -2117,7 +2165,7 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
if (lack_dhfis) {
qc = ata_qc_from_tag(ap, pp->last_issue_tag);
nv_swncq_issue_atacmd(ap, qc);
- return nr_done;
+ return 0;
}
if (pp->defer_queue.defer_bits) {
@@ -2127,7 +2175,7 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
nv_swncq_issue_atacmd(ap, qc);
}
- return nr_done;
+ return 0;
}
static inline u32 nv_swncq_tag(struct ata_port *ap)
@@ -2139,7 +2187,7 @@ static inline u32 nv_swncq_tag(struct ata_port *ap)
return (tag & 0x1f);
}
-static int nv_swncq_dmafis(struct ata_port *ap)
+static void nv_swncq_dmafis(struct ata_port *ap)
{
struct ata_queued_cmd *qc;
unsigned int rw;
@@ -2154,7 +2202,7 @@ static int nv_swncq_dmafis(struct ata_port *ap)
qc = ata_qc_from_tag(ap, tag);
if (unlikely(!qc))
- return 0;
+ return;
rw = qc->tf.flags & ATA_TFLAG_WRITE;
@@ -2169,8 +2217,6 @@ static int nv_swncq_dmafis(struct ata_port *ap)
dmactl |= ATA_DMA_WR;
iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-
- return 1;
}
static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
@@ -2180,7 +2226,6 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
struct ata_eh_info *ehi = &ap->link.eh_info;
u32 serror;
u8 ata_stat;
- int rc = 0;
ata_stat = ap->ops->sff_check_status(ap);
nv_swncq_irq_clear(ap, fis);
@@ -2198,9 +2243,9 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
if (!pp->qc_active)
return;
- if (ap->ops->scr_read(ap, SCR_ERROR, &serror))
+ if (ap->ops->scr_read(&ap->link, SCR_ERROR, &serror))
return;
- ap->ops->scr_write(ap, SCR_ERROR, serror);
+ ap->ops->scr_write(&ap->link, SCR_ERROR, serror);
if (ata_stat & ATA_ERR) {
ata_ehi_clear_desc(ehi);
@@ -2225,8 +2270,7 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
"dhfis 0x%X dmafis 0x%X sactive 0x%X\n",
ap->print_id, pp->qc_active, pp->dhfis_bits,
pp->dmafis_bits, readl(pp->sactive_block));
- rc = nv_swncq_sdbfis(ap);
- if (rc < 0)
+ if (nv_swncq_sdbfis(ap) < 0)
goto irq_error;
}
@@ -2263,7 +2307,7 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
*/
pp->dmafis_bits |= (0x1 << nv_swncq_tag(ap));
pp->ncq_flags |= ncq_saw_dmas;
- rc = nv_swncq_dmafis(ap);
+ nv_swncq_dmafis(ap);
}
irq_exit:
@@ -2289,16 +2333,14 @@ static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance)
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
- if (ap->link.sactive) {
- nv_swncq_host_interrupt(ap, (u16)irq_stat);
- handled = 1;
- } else {
- if (irq_stat) /* reserve Hotplug */
- nv_swncq_irq_clear(ap, 0xfff0);
+ if (ap->link.sactive) {
+ nv_swncq_host_interrupt(ap, (u16)irq_stat);
+ handled = 1;
+ } else {
+ if (irq_stat) /* reserve Hotplug */
+ nv_swncq_irq_clear(ap, 0xfff0);
- handled += nv_host_intr(ap, (u8)irq_stat);
- }
+ handled += nv_host_intr(ap, (u8)irq_stat);
}
irq_stat >>= NV_INT_PORT_SHIFT_MCP55;
}
@@ -2310,7 +2352,6 @@ static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance)
static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
const struct ata_port_info *ppi[] = { NULL, NULL };
struct nv_pi_priv *ipriv;
struct ata_host *host;
@@ -2327,8 +2368,7 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (pci_resource_start(pdev, bar) == 0)
return -ENODEV;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
rc = pcim_enable_device(pdev);
if (rc)
@@ -2336,21 +2376,16 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* determine type and allocate host */
if (type == CK804 && adma_enabled) {
- dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n");
+ dev_notice(&pdev->dev, "Using ADMA mode\n");
type = ADMA;
- }
-
- if (type == SWNCQ) {
- if (swncq_enabled)
- dev_printk(KERN_NOTICE, &pdev->dev,
- "Using SWNCQ mode\n");
- else
- type = GENERIC;
+ } else if (type == MCP5x && swncq_enabled) {
+ dev_notice(&pdev->dev, "Using SWNCQ mode\n");
+ type = SWNCQ;
}
ppi[0] = &nv_port_info[type];
ipriv = ppi[0]->private_data;
- rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+ rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
if (rc)
return rc;
@@ -2387,15 +2422,19 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
} else if (type == SWNCQ)
nv_swncq_host_init(host);
+ if (msi_enabled) {
+ dev_notice(&pdev->dev, "Using MSI\n");
+ pci_enable_msi(pdev);
+ }
+
pci_set_master(pdev);
- return ata_host_activate(host, pdev->irq, ipriv->irq_handler,
- IRQF_SHARED, ipriv->sht);
+ return ata_pci_sff_activate_host(host, ipriv->irq_handler, ipriv->sht);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int nv_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
struct nv_host_priv *hpriv = host->private_data;
int rc;
@@ -2470,20 +2509,11 @@ static void nv_adma_host_stop(struct ata_host *host)
nv_ck804_host_stop(host);
}
-static int __init nv_init(void)
-{
- return pci_register_driver(&nv_pci_driver);
-}
-
-static void __exit nv_exit(void)
-{
- pci_unregister_driver(&nv_pci_driver);
-}
+module_pci_driver(nv_pci_driver);
-module_init(nv_init);
-module_exit(nv_exit);
module_param_named(adma, adma_enabled, bool, 0444);
-MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)");
+MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: false)");
module_param_named(swncq, swncq_enabled, bool, 0444);
MODULE_PARM_DESC(swncq, "Enable use of SWNCQ (Default: true)");
-
+module_param_named(msi, msi_enabled, bool, 0444);
+MODULE_PARM_DESC(msi, "Enable use of MSI (Default: false)");
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 5a10dc5048a..3638887476f 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -1,8 +1,8 @@
/*
* sata_promise.c - Promise SATA
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
- * Mikael Pettersson <mikpe@it.uu.se>
+ * Maintained by: Tejun Heo <tj@kernel.org>
+ * Mikael Pettersson
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -33,8 +33,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -53,7 +53,16 @@ enum {
PDC_MMIO_BAR = 3,
PDC_MAX_PRD = LIBATA_MAX_PRD - 1, /* -1 for ASIC PRD bug workaround */
- /* register offsets */
+ /* host register offsets (from host->iomap[PDC_MMIO_BAR]) */
+ PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
+ PDC_FLASH_CTL = 0x44, /* Flash control register */
+ PDC_PCI_CTL = 0x48, /* PCI control/status reg */
+ PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
+ PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
+ PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */
+ PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */
+
+ /* per-port ATA register offsets (from ap->ioaddr.cmd_addr) */
PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */
PDC_SECTOR_COUNT = 0x08, /* Sector count reg (per port) */
PDC_SECTOR_NUMBER = 0x0C, /* Sector number reg (per port) */
@@ -63,14 +72,21 @@ enum {
PDC_COMMAND = 0x1C, /* Command/status reg (per port) */
PDC_ALTSTATUS = 0x38, /* Alternate-status/device-control reg (per port) */
PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
- PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
- PDC_FLASH_CTL = 0x44, /* Flash control register */
PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */
PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */
- PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
- PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
- PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */
- PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */
+
+ /* per-port SATA register offsets (from ap->ioaddr.scr_addr) */
+ PDC_SATA_ERROR = 0x04,
+ PDC_PHYMODE4 = 0x14,
+ PDC_LINK_LAYER_ERRORS = 0x6C,
+ PDC_FPDMA_CTLSTAT = 0xD8,
+ PDC_INTERNAL_DEBUG_1 = 0xF8, /* also used for PATA */
+ PDC_INTERNAL_DEBUG_2 = 0xFC, /* also used for PATA */
+
+ /* PDC_FPDMA_CTLSTAT bit definitions */
+ PDC_FPDMA_CTLSTAT_RESET = 1 << 3,
+ PDC_FPDMA_CTLSTAT_DMASETUP_INT_FLAG = 1 << 10,
+ PDC_FPDMA_CTLSTAT_SETDB_INT_FLAG = 1 << 11,
/* PDC_GLOBAL_CTL bit definitions */
PDC_PH_ERR = (1 << 8), /* PCI error while loading packet */
@@ -117,9 +133,7 @@ enum {
PDC_IRQ_DISABLE = (1 << 10),
PDC_RESET = (1 << 11), /* HDMA reset */
- PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO |
- ATA_FLAG_PIO_POLLING,
+ PDC_COMMON_FLAGS = ATA_FLAG_PIO_POLLING,
/* ap->flags bits */
PDC_FLAG_GEN_II = (1 << 24),
@@ -132,9 +146,13 @@ struct pdc_port_priv {
dma_addr_t pkt_dma;
};
-static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
-static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+struct pdc_host_priv {
+ spinlock_t hard_reset_lock;
+};
+
+static int pdc_sata_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int pdc_sata_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
+static int pdc_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int pdc_common_port_start(struct ata_port *ap);
static int pdc_sata_port_start(struct ata_port *ap);
static void pdc_qc_prep(struct ata_queued_cmd *qc);
@@ -148,6 +166,10 @@ static void pdc_freeze(struct ata_port *ap);
static void pdc_sata_freeze(struct ata_port *ap);
static void pdc_thaw(struct ata_port *ap);
static void pdc_sata_thaw(struct ata_port *ap);
+static int pdc_pata_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline);
+static int pdc_sata_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline);
static void pdc_error_handler(struct ata_port *ap);
static void pdc_post_internal_cmd(struct ata_queued_cmd *qc);
static int pdc_pata_cable_detect(struct ata_port *ap);
@@ -167,7 +189,9 @@ static const struct ata_port_operations pdc_common_ops = {
.check_atapi_dma = pdc_check_atapi_dma,
.qc_prep = pdc_qc_prep,
.qc_issue = pdc_qc_issue,
+
.sff_irq_clear = pdc_irq_clear,
+ .lost_interrupt = ATA_OP_NULL,
.post_internal_cmd = pdc_post_internal_cmd,
.error_handler = pdc_error_handler,
@@ -181,11 +205,15 @@ static struct ata_port_operations pdc_sata_ops = {
.scr_read = pdc_sata_scr_read,
.scr_write = pdc_sata_scr_write,
.port_start = pdc_sata_port_start,
+ .hardreset = pdc_sata_hardreset,
};
-/* First-generation chips need a more restrictive ->check_atapi_dma op */
+/* First-generation chips need a more restrictive ->check_atapi_dma op,
+ and ->freeze/thaw that ignore the hotplug controls. */
static struct ata_port_operations pdc_old_sata_ops = {
.inherits = &pdc_sata_ops,
+ .freeze = pdc_freeze,
+ .thaw = pdc_thaw,
.check_atapi_dma = pdc_old_sata_check_atapi_dma,
};
@@ -195,6 +223,7 @@ static struct ata_port_operations pdc_pata_ops = {
.freeze = pdc_freeze,
.thaw = pdc_thaw,
.port_start = pdc_common_port_start,
+ .softreset = pdc_pata_softreset,
};
static const struct ata_port_info pdc_port_info[] = {
@@ -202,8 +231,8 @@ static const struct ata_port_info pdc_port_info[] = {
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
PDC_FLAG_SATA_PATA,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &pdc_old_sata_ops,
},
@@ -211,8 +240,8 @@ static const struct ata_port_info pdc_port_info[] = {
[board_2037x_pata] =
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &pdc_pata_ops,
},
@@ -221,8 +250,8 @@ static const struct ata_port_info pdc_port_info[] = {
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
PDC_FLAG_4_PORTS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &pdc_old_sata_ops,
},
@@ -231,8 +260,8 @@ static const struct ata_port_info pdc_port_info[] = {
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
PDC_FLAG_4_PORTS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &pdc_pata_ops,
},
@@ -241,8 +270,8 @@ static const struct ata_port_info pdc_port_info[] = {
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &pdc_sata_ops,
},
@@ -251,8 +280,8 @@ static const struct ata_port_info pdc_port_info[] = {
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
PDC_FLAG_GEN_II,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &pdc_pata_ops,
},
@@ -261,8 +290,8 @@ static const struct ata_port_info pdc_port_info[] = {
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &pdc_sata_ops,
},
@@ -305,7 +334,8 @@ static int pdc_common_port_start(struct ata_port *ap)
struct pdc_port_priv *pp;
int rc;
- rc = ata_port_start(ap);
+ /* we use the same prd table as bmdma, allocate it */
+ rc = ata_bmdma_port_start(ap);
if (rc)
return rc;
@@ -332,45 +362,114 @@ static int pdc_sata_port_start(struct ata_port *ap)
/* fix up PHYMODE4 align timing */
if (ap->flags & PDC_FLAG_GEN_II) {
- void __iomem *mmio = ap->ioaddr.scr_addr;
+ void __iomem *sata_mmio = ap->ioaddr.scr_addr;
unsigned int tmp;
- tmp = readl(mmio + 0x014);
+ tmp = readl(sata_mmio + PDC_PHYMODE4);
tmp = (tmp & ~3) | 1; /* set bits 1:0 = 0:1 */
- writel(tmp, mmio + 0x014);
+ writel(tmp, sata_mmio + PDC_PHYMODE4);
}
return 0;
}
+static void pdc_fpdma_clear_interrupt_flag(struct ata_port *ap)
+{
+ void __iomem *sata_mmio = ap->ioaddr.scr_addr;
+ u32 tmp;
+
+ tmp = readl(sata_mmio + PDC_FPDMA_CTLSTAT);
+ tmp |= PDC_FPDMA_CTLSTAT_DMASETUP_INT_FLAG;
+ tmp |= PDC_FPDMA_CTLSTAT_SETDB_INT_FLAG;
+
+ /* It's not allowed to write to the entire FPDMA_CTLSTAT register
+ when NCQ is running. So do a byte-sized write to bits 10 and 11. */
+ writeb(tmp >> 8, sata_mmio + PDC_FPDMA_CTLSTAT + 1);
+ readb(sata_mmio + PDC_FPDMA_CTLSTAT + 1); /* flush */
+}
+
+static void pdc_fpdma_reset(struct ata_port *ap)
+{
+ void __iomem *sata_mmio = ap->ioaddr.scr_addr;
+ u8 tmp;
+
+ tmp = (u8)readl(sata_mmio + PDC_FPDMA_CTLSTAT);
+ tmp &= 0x7F;
+ tmp |= PDC_FPDMA_CTLSTAT_RESET;
+ writeb(tmp, sata_mmio + PDC_FPDMA_CTLSTAT);
+ readl(sata_mmio + PDC_FPDMA_CTLSTAT); /* flush */
+ udelay(100);
+ tmp &= ~PDC_FPDMA_CTLSTAT_RESET;
+ writeb(tmp, sata_mmio + PDC_FPDMA_CTLSTAT);
+ readl(sata_mmio + PDC_FPDMA_CTLSTAT); /* flush */
+
+ pdc_fpdma_clear_interrupt_flag(ap);
+}
+
+static void pdc_not_at_command_packet_phase(struct ata_port *ap)
+{
+ void __iomem *sata_mmio = ap->ioaddr.scr_addr;
+ unsigned int i;
+ u32 tmp;
+
+ /* check not at ASIC packet command phase */
+ for (i = 0; i < 100; ++i) {
+ writel(0, sata_mmio + PDC_INTERNAL_DEBUG_1);
+ tmp = readl(sata_mmio + PDC_INTERNAL_DEBUG_2);
+ if ((tmp & 0xF) != 1)
+ break;
+ udelay(100);
+ }
+}
+
+static void pdc_clear_internal_debug_record_error_register(struct ata_port *ap)
+{
+ void __iomem *sata_mmio = ap->ioaddr.scr_addr;
+
+ writel(0xffffffff, sata_mmio + PDC_SATA_ERROR);
+ writel(0xffff0000, sata_mmio + PDC_LINK_LAYER_ERRORS);
+}
+
static void pdc_reset_port(struct ata_port *ap)
{
- void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT;
+ void __iomem *ata_ctlstat_mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT;
unsigned int i;
u32 tmp;
+ if (ap->flags & PDC_FLAG_GEN_II)
+ pdc_not_at_command_packet_phase(ap);
+
+ tmp = readl(ata_ctlstat_mmio);
+ tmp |= PDC_RESET;
+ writel(tmp, ata_ctlstat_mmio);
+
for (i = 11; i > 0; i--) {
- tmp = readl(mmio);
+ tmp = readl(ata_ctlstat_mmio);
if (tmp & PDC_RESET)
break;
udelay(100);
tmp |= PDC_RESET;
- writel(tmp, mmio);
+ writel(tmp, ata_ctlstat_mmio);
}
tmp &= ~PDC_RESET;
- writel(tmp, mmio);
- readl(mmio); /* flush */
+ writel(tmp, ata_ctlstat_mmio);
+ readl(ata_ctlstat_mmio); /* flush */
+
+ if (sata_scr_valid(&ap->link) && (ap->flags & PDC_FLAG_GEN_II)) {
+ pdc_fpdma_reset(ap);
+ pdc_clear_internal_debug_record_error_register(ap);
+ }
}
static int pdc_pata_cable_detect(struct ata_port *ap)
{
u8 tmp;
- void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03;
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
- tmp = readb(mmio);
+ tmp = readb(ata_mmio + PDC_CTLSTAT + 3);
if (tmp & 0x01)
return ATA_CBL_PATA40;
return ATA_CBL_PATA80;
@@ -381,26 +480,28 @@ static int pdc_sata_cable_detect(struct ata_port *ap)
return ATA_CBL_SATA;
}
-static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int pdc_sata_scr_read(struct ata_link *link,
+ unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
-static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int pdc_sata_scr_write(struct ata_link *link,
+ unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- dma_addr_t sg_table = ap->prd_dma;
+ dma_addr_t sg_table = ap->bmdma_prd_dma;
unsigned int cdb_len = qc->dev->cdb_len;
u8 *cdb = qc->cdb;
struct pdc_port_priv *pp = ap->private_data;
@@ -488,6 +589,7 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
static void pdc_fill_sg(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ struct ata_bmdma_prd *prd = ap->bmdma_prd;
struct scatterlist *sg;
const u32 SG_COUNT_ASIC_BUG = 41*4;
unsigned int si, idx;
@@ -514,8 +616,8 @@ static void pdc_fill_sg(struct ata_queued_cmd *qc)
if ((offset + sg_len) > 0x10000)
len = 0x10000 - offset;
- ap->prd[idx].addr = cpu_to_le32(addr);
- ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
+ prd[idx].addr = cpu_to_le32(addr);
+ prd[idx].flags_len = cpu_to_le32(len & 0xffff);
VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
idx++;
@@ -524,27 +626,27 @@ static void pdc_fill_sg(struct ata_queued_cmd *qc)
}
}
- len = le32_to_cpu(ap->prd[idx - 1].flags_len);
+ len = le32_to_cpu(prd[idx - 1].flags_len);
if (len > SG_COUNT_ASIC_BUG) {
u32 addr;
VPRINTK("Splitting last PRD.\n");
- addr = le32_to_cpu(ap->prd[idx - 1].addr);
- ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG);
+ addr = le32_to_cpu(prd[idx - 1].addr);
+ prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG);
VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG);
addr = addr + len - SG_COUNT_ASIC_BUG;
len = SG_COUNT_ASIC_BUG;
- ap->prd[idx].addr = cpu_to_le32(addr);
- ap->prd[idx].flags_len = cpu_to_le32(len);
+ prd[idx].addr = cpu_to_le32(addr);
+ prd[idx].flags_len = cpu_to_le32(len);
VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
idx++;
}
- ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+ prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
}
static void pdc_qc_prep(struct ata_queued_cmd *qc)
@@ -557,31 +659,25 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
pdc_fill_sg(qc);
- /* fall through */
-
+ /*FALLTHROUGH*/
case ATA_PROT_NODATA:
- i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma,
+ i = pdc_pkt_header(&qc->tf, qc->ap->bmdma_prd_dma,
qc->dev->devno, pp->pkt);
-
if (qc->tf.flags & ATA_TFLAG_LBA48)
i = pdc_prep_lba48(&qc->tf, pp->pkt, i);
else
i = pdc_prep_lba28(&qc->tf, pp->pkt, i);
-
pdc_pkt_footer(&qc->tf, pp->pkt, i);
break;
-
case ATAPI_PROT_PIO:
pdc_fill_sg(qc);
break;
-
case ATAPI_PROT_DMA:
pdc_fill_sg(qc);
/*FALLTHROUGH*/
case ATAPI_PROT_NODATA:
pdc_atapi_pkt(qc);
break;
-
default:
break;
}
@@ -611,34 +707,29 @@ static unsigned int pdc_sata_ata_port_to_ata_no(const struct ata_port *ap)
unsigned int nr_ports = pdc_sata_nr_ports(ap);
unsigned int i;
- for(i = 0; i < nr_ports && host->ports[i] != ap; ++i)
+ for (i = 0; i < nr_ports && host->ports[i] != ap; ++i)
;
BUG_ON(i >= nr_ports);
return pdc_port_no_to_ata_no(i, pdc_is_sataii_tx4(ap->flags));
}
-static unsigned int pdc_sata_hotplug_offset(const struct ata_port *ap)
-{
- return (ap->flags & PDC_FLAG_GEN_II) ? PDC2_SATA_PLUG_CSR : PDC_SATA_PLUG_CSR;
-}
-
static void pdc_freeze(struct ata_port *ap)
{
- void __iomem *mmio = ap->ioaddr.cmd_addr;
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
u32 tmp;
- tmp = readl(mmio + PDC_CTLSTAT);
+ tmp = readl(ata_mmio + PDC_CTLSTAT);
tmp |= PDC_IRQ_DISABLE;
tmp &= ~PDC_DMA_ENABLE;
- writel(tmp, mmio + PDC_CTLSTAT);
- readl(mmio + PDC_CTLSTAT); /* flush */
+ writel(tmp, ata_mmio + PDC_CTLSTAT);
+ readl(ata_mmio + PDC_CTLSTAT); /* flush */
}
static void pdc_sata_freeze(struct ata_port *ap)
{
struct ata_host *host = ap->host;
void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR];
- unsigned int hotplug_offset = pdc_sata_hotplug_offset(ap);
+ unsigned int hotplug_offset = PDC2_SATA_PLUG_CSR;
unsigned int ata_no = pdc_sata_ata_port_to_ata_no(ap);
u32 hotplug_status;
@@ -659,24 +750,24 @@ static void pdc_sata_freeze(struct ata_port *ap)
static void pdc_thaw(struct ata_port *ap)
{
- void __iomem *mmio = ap->ioaddr.cmd_addr;
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
u32 tmp;
/* clear IRQ */
- readl(mmio + PDC_INT_SEQMASK);
+ readl(ata_mmio + PDC_COMMAND);
/* turn IRQ back on */
- tmp = readl(mmio + PDC_CTLSTAT);
+ tmp = readl(ata_mmio + PDC_CTLSTAT);
tmp &= ~PDC_IRQ_DISABLE;
- writel(tmp, mmio + PDC_CTLSTAT);
- readl(mmio + PDC_CTLSTAT); /* flush */
+ writel(tmp, ata_mmio + PDC_CTLSTAT);
+ readl(ata_mmio + PDC_CTLSTAT); /* flush */
}
static void pdc_sata_thaw(struct ata_port *ap)
{
struct ata_host *host = ap->host;
void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR];
- unsigned int hotplug_offset = pdc_sata_hotplug_offset(ap);
+ unsigned int hotplug_offset = PDC2_SATA_PLUG_CSR;
unsigned int ata_no = pdc_sata_ata_port_to_ata_no(ap);
u32 hotplug_status;
@@ -692,12 +783,66 @@ static void pdc_sata_thaw(struct ata_port *ap)
readl(host_mmio + hotplug_offset); /* flush */
}
+static int pdc_pata_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ pdc_reset_port(link->ap);
+ return ata_sff_softreset(link, class, deadline);
+}
+
+static unsigned int pdc_ata_port_to_ata_no(const struct ata_port *ap)
+{
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
+ void __iomem *host_mmio = ap->host->iomap[PDC_MMIO_BAR];
+
+ /* ata_mmio == host_mmio + 0x200 + ata_no * 0x80 */
+ return (ata_mmio - host_mmio - 0x200) / 0x80;
+}
+
+static void pdc_hard_reset_port(struct ata_port *ap)
+{
+ void __iomem *host_mmio = ap->host->iomap[PDC_MMIO_BAR];
+ void __iomem *pcictl_b1_mmio = host_mmio + PDC_PCI_CTL + 1;
+ unsigned int ata_no = pdc_ata_port_to_ata_no(ap);
+ struct pdc_host_priv *hpriv = ap->host->private_data;
+ u8 tmp;
+
+ spin_lock(&hpriv->hard_reset_lock);
+
+ tmp = readb(pcictl_b1_mmio);
+ tmp &= ~(0x10 << ata_no);
+ writeb(tmp, pcictl_b1_mmio);
+ readb(pcictl_b1_mmio); /* flush */
+ udelay(100);
+ tmp |= (0x10 << ata_no);
+ writeb(tmp, pcictl_b1_mmio);
+ readb(pcictl_b1_mmio); /* flush */
+
+ spin_unlock(&hpriv->hard_reset_lock);
+}
+
+static int pdc_sata_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ if (link->ap->flags & PDC_FLAG_GEN_II)
+ pdc_not_at_command_packet_phase(link->ap);
+ /* hotplug IRQs should have been masked by pdc_sata_freeze() */
+ pdc_hard_reset_port(link->ap);
+ pdc_reset_port(link->ap);
+
+ /* sata_promise can't reliably acquire the first D2H Reg FIS
+ * after hardreset. Do non-waiting hardreset and request
+ * follow-up SRST.
+ */
+ return sata_std_hardreset(link, class, deadline);
+}
+
static void pdc_error_handler(struct ata_port *ap)
{
if (!(ap->pflags & ATA_PFLAG_FROZEN))
pdc_reset_port(ap);
- ata_std_error_handler(ap);
+ ata_sff_error_handler(ap);
}
static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
@@ -722,7 +867,7 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
if (port_status & PDC_DRIVE_ERR)
ac_err_mask |= AC_ERR_DEV;
if (port_status & (PDC_OVERRUN_ERR | PDC_UNDERRUN_ERR))
- ac_err_mask |= AC_ERR_HSM;
+ ac_err_mask |= AC_ERR_OTHER;
if (port_status & (PDC2_ATA_HBA_ERR | PDC2_ATA_DMA_CNT_ERR))
ac_err_mask |= AC_ERR_ATA_BUS;
if (port_status & (PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR | PDC2_HTO_ERR
@@ -732,7 +877,7 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
if (sata_scr_valid(&ap->link)) {
u32 serror;
- pdc_sata_scr_read(ap, SCR_ERROR, &serror);
+ pdc_sata_scr_read(&ap->link, SCR_ERROR, &serror);
ehi->serror |= serror;
}
@@ -743,11 +888,11 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
ata_port_abort(ap);
}
-static inline unsigned int pdc_host_intr(struct ata_port *ap,
- struct ata_queued_cmd *qc)
+static unsigned int pdc_host_intr(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
{
unsigned int handled = 0;
- void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
u32 port_status, err_mask;
err_mask = PDC_ERR_MASK;
@@ -755,7 +900,7 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap,
err_mask &= ~PDC1_ERR_MASK;
else
err_mask &= ~PDC2_ERR_MASK;
- port_status = readl(port_mmio + PDC_GLOBAL_CTL);
+ port_status = readl(ata_mmio + PDC_GLOBAL_CTL);
if (unlikely(port_status & err_mask)) {
pdc_error_intr(ap, qc, port_status, err_mask);
return 1;
@@ -770,7 +915,6 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap,
ata_qc_complete(qc);
handled = 1;
break;
-
default:
ap->stats.idle_irq++;
break;
@@ -781,10 +925,9 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap,
static void pdc_irq_clear(struct ata_port *ap)
{
- struct ata_host *host = ap->host;
- void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
- readl(mmio + PDC_INT_SEQMASK);
+ readl(ata_mmio + PDC_COMMAND);
}
static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
@@ -794,7 +937,7 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
u32 mask = 0;
unsigned int i, tmp;
unsigned int handled = 0;
- void __iomem *mmio_base;
+ void __iomem *host_mmio;
unsigned int hotplug_offset, ata_no;
u32 hotplug_status;
int is_sataii_tx4;
@@ -806,35 +949,35 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
return IRQ_NONE;
}
- mmio_base = host->iomap[PDC_MMIO_BAR];
+ host_mmio = host->iomap[PDC_MMIO_BAR];
spin_lock(&host->lock);
/* read and clear hotplug flags for all ports */
- if (host->ports[0]->flags & PDC_FLAG_GEN_II)
+ if (host->ports[0]->flags & PDC_FLAG_GEN_II) {
hotplug_offset = PDC2_SATA_PLUG_CSR;
- else
- hotplug_offset = PDC_SATA_PLUG_CSR;
- hotplug_status = readl(mmio_base + hotplug_offset);
- if (hotplug_status & 0xff)
- writel(hotplug_status | 0xff, mmio_base + hotplug_offset);
- hotplug_status &= 0xff; /* clear uninteresting bits */
+ hotplug_status = readl(host_mmio + hotplug_offset);
+ if (hotplug_status & 0xff)
+ writel(hotplug_status | 0xff, host_mmio + hotplug_offset);
+ hotplug_status &= 0xff; /* clear uninteresting bits */
+ } else
+ hotplug_status = 0;
/* reading should also clear interrupts */
- mask = readl(mmio_base + PDC_INT_SEQMASK);
+ mask = readl(host_mmio + PDC_INT_SEQMASK);
if (mask == 0xffffffff && hotplug_status == 0) {
VPRINTK("QUICK EXIT 2\n");
goto done_irq;
}
- mask &= 0xffff; /* only 16 tags possible */
+ mask &= 0xffff; /* only 16 SEQIDs possible */
if (mask == 0 && hotplug_status == 0) {
VPRINTK("QUICK EXIT 3\n");
goto done_irq;
}
- writel(mask, mmio_base + PDC_INT_SEQMASK);
+ writel(mask, host_mmio + PDC_INT_SEQMASK);
is_sataii_tx4 = pdc_is_sataii_tx4(host->ports[0]->flags);
@@ -845,8 +988,7 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
/* check for a plug or unplug event */
ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);
tmp = hotplug_status & (0x11 << ata_no);
- if (tmp && ap &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
+ if (tmp) {
struct ata_eh_info *ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
ata_ehi_hotplugged(ehi);
@@ -858,8 +1000,7 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
/* check for a packet interrupt */
tmp = mask & (1 << (i + 1));
- if (tmp && ap &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
+ if (tmp) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->link.active_tag);
@@ -875,23 +1016,24 @@ done_irq:
return IRQ_RETVAL(handled);
}
-static inline void pdc_packet_start(struct ata_queued_cmd *qc)
+static void pdc_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
+ void __iomem *host_mmio = ap->host->iomap[PDC_MMIO_BAR];
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
unsigned int port_no = ap->port_no;
u8 seq = (u8) (port_no + 1);
VPRINTK("ENTER, ap %p\n", ap);
- writel(0x00000001, mmio + (seq * 4));
- readl(mmio + (seq * 4)); /* flush */
+ writel(0x00000001, host_mmio + (seq * 4));
+ readl(host_mmio + (seq * 4)); /* flush */
pp->pkt[2] = seq;
wmb(); /* flush PRD, pkt writes */
- writel(pp->pkt_dma, ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
+ writel(pp->pkt_dma, ata_mmio + PDC_PKT_SUBMIT);
+ readl(ata_mmio + PDC_PKT_SUBMIT); /* flush */
}
static unsigned int pdc_qc_issue(struct ata_queued_cmd *qc)
@@ -909,11 +1051,9 @@ static unsigned int pdc_qc_issue(struct ata_queued_cmd *qc)
case ATA_PROT_DMA:
pdc_packet_start(qc);
return 0;
-
default:
break;
}
-
return ata_sff_qc_issue(qc);
}
@@ -987,7 +1127,7 @@ static void pdc_ata_setup_port(struct ata_port *ap,
static void pdc_host_init(struct ata_host *host)
{
- void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+ void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR];
int is_gen2 = host->ports[0]->flags & PDC_FLAG_GEN_II;
int hotplug_offset;
u32 tmp;
@@ -1004,53 +1144,54 @@ static void pdc_host_init(struct ata_host *host)
*/
/* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */
- tmp = readl(mmio + PDC_FLASH_CTL);
+ tmp = readl(host_mmio + PDC_FLASH_CTL);
tmp |= 0x02000; /* bit 13 (enable bmr burst) */
if (!is_gen2)
tmp |= 0x10000; /* bit 16 (fifo threshold at 8 dw) */
- writel(tmp, mmio + PDC_FLASH_CTL);
+ writel(tmp, host_mmio + PDC_FLASH_CTL);
/* clear plug/unplug flags for all ports */
- tmp = readl(mmio + hotplug_offset);
- writel(tmp | 0xff, mmio + hotplug_offset);
+ tmp = readl(host_mmio + hotplug_offset);
+ writel(tmp | 0xff, host_mmio + hotplug_offset);
- /* unmask plug/unplug ints */
- tmp = readl(mmio + hotplug_offset);
- writel(tmp & ~0xff0000, mmio + hotplug_offset);
+ tmp = readl(host_mmio + hotplug_offset);
+ if (is_gen2) /* unmask plug/unplug ints */
+ writel(tmp & ~0xff0000, host_mmio + hotplug_offset);
+ else /* mask plug/unplug ints */
+ writel(tmp | 0xff0000, host_mmio + hotplug_offset);
/* don't initialise TBG or SLEW on 2nd generation chips */
if (is_gen2)
return;
/* reduce TBG clock to 133 Mhz. */
- tmp = readl(mmio + PDC_TBG_MODE);
+ tmp = readl(host_mmio + PDC_TBG_MODE);
tmp &= ~0x30000; /* clear bit 17, 16*/
tmp |= 0x10000; /* set bit 17:16 = 0:1 */
- writel(tmp, mmio + PDC_TBG_MODE);
+ writel(tmp, host_mmio + PDC_TBG_MODE);
- readl(mmio + PDC_TBG_MODE); /* flush */
+ readl(host_mmio + PDC_TBG_MODE); /* flush */
msleep(10);
/* adjust slew rate control register. */
- tmp = readl(mmio + PDC_SLEW_CTL);
+ tmp = readl(host_mmio + PDC_SLEW_CTL);
tmp &= 0xFFFFF03F; /* clear bit 11 ~ 6 */
tmp |= 0x00000900; /* set bit 11-9 = 100b , bit 8-6 = 100 */
- writel(tmp, mmio + PDC_SLEW_CTL);
+ writel(tmp, host_mmio + PDC_SLEW_CTL);
}
static int pdc_ata_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- static int printed_version;
const struct ata_port_info *pi = &pdc_port_info[ent->driver_data];
const struct ata_port_info *ppi[PDC_MAX_PORTS];
struct ata_host *host;
- void __iomem *base;
+ struct pdc_host_priv *hpriv;
+ void __iomem *host_mmio;
int n_ports, i, rc;
int is_sataii_tx4;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
/* enable and acquire resources */
rc = pcim_enable_device(pdev);
@@ -1062,7 +1203,7 @@ static int pdc_ata_init_one(struct pci_dev *pdev,
pcim_pin_device(pdev);
if (rc)
return rc;
- base = pcim_iomap_table(pdev)[PDC_MMIO_BAR];
+ host_mmio = pcim_iomap_table(pdev)[PDC_MMIO_BAR];
/* determine port configuration and setup host */
n_ports = 2;
@@ -1072,29 +1213,34 @@ static int pdc_ata_init_one(struct pci_dev *pdev,
ppi[i] = pi;
if (pi->flags & PDC_FLAG_SATA_PATA) {
- u8 tmp = readb(base + PDC_FLASH_CTL+1);
+ u8 tmp = readb(host_mmio + PDC_FLASH_CTL + 1);
if (!(tmp & 0x80))
ppi[n_ports++] = pi + 1;
}
host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
if (!host) {
- dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n");
+ dev_err(&pdev->dev, "failed to allocate host\n");
return -ENOMEM;
}
+ hpriv = devm_kzalloc(&pdev->dev, sizeof *hpriv, GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
+ spin_lock_init(&hpriv->hard_reset_lock);
+ host->private_data = hpriv;
host->iomap = pcim_iomap_table(pdev);
is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags);
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);
- unsigned int port_offset = 0x200 + ata_no * 0x80;
+ unsigned int ata_offset = 0x200 + ata_no * 0x80;
unsigned int scr_offset = 0x400 + ata_no * 0x100;
- pdc_ata_setup_port(ap, base + port_offset, base + scr_offset);
+ pdc_ata_setup_port(ap, host_mmio + ata_offset, host_mmio + scr_offset);
ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
- ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port");
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, ata_offset, "ata");
}
/* initialize adapter */
@@ -1113,21 +1259,10 @@ static int pdc_ata_init_one(struct pci_dev *pdev,
&pdc_ata_sht);
}
-static int __init pdc_ata_init(void)
-{
- return pci_register_driver(&pdc_ata_pci_driver);
-}
-
-static void __exit pdc_ata_exit(void)
-{
- pci_unregister_driver(&pdc_ata_pci_driver);
-}
+module_pci_driver(pdc_ata_pci_driver);
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("Promise ATA TX2/TX4/TX4000 low-level driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, pdc_ata_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
-module_init(pdc_ata_init);
-module_exit(pdc_ata_exit);
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 1600107047c..9a6bd4cd29a 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -29,8 +29,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -111,16 +111,14 @@ struct qs_port_priv {
qs_state_t state;
};
-static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int qs_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int qs_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int qs_port_start(struct ata_port *ap);
static void qs_host_stop(struct ata_host *host);
static void qs_qc_prep(struct ata_queued_cmd *qc);
static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
-static void qs_bmdma_stop(struct ata_queued_cmd *qc);
-static u8 qs_bmdma_status(struct ata_port *ap);
static void qs_freeze(struct ata_port *ap);
static void qs_thaw(struct ata_port *ap);
static int qs_prereset(struct ata_link *link, unsigned long deadline);
@@ -136,8 +134,6 @@ static struct ata_port_operations qs_ata_ops = {
.inherits = &ata_sff_port_ops,
.check_atapi_dma = qs_check_atapi_dma,
- .bmdma_stop = qs_bmdma_stop,
- .bmdma_status = qs_bmdma_status,
.qc_prep = qs_qc_prep,
.qc_issue = qs_qc_issue,
@@ -146,7 +142,7 @@ static struct ata_port_operations qs_ata_ops = {
.prereset = qs_prereset,
.softreset = ATA_OP_NULL,
.error_handler = qs_error_handler,
- .post_internal_cmd = ATA_OP_NULL,
+ .lost_interrupt = ATA_OP_NULL,
.scr_read = qs_scr_read,
.scr_write = qs_scr_write,
@@ -158,9 +154,8 @@ static struct ata_port_operations qs_ata_ops = {
static const struct ata_port_info qs_port_info[] = {
/* board_2068_idx */
{
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
- .pio_mask = 0x10, /* pio4 */
+ .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_POLLING,
+ .pio_mask = ATA_PIO4_ONLY,
.udma_mask = ATA_UDMA6,
.port_ops = &qs_ata_ops,
},
@@ -189,16 +184,6 @@ static int qs_check_atapi_dma(struct ata_queued_cmd *qc)
return 1; /* ATAPI DMA not supported */
}
-static void qs_bmdma_stop(struct ata_queued_cmd *qc)
-{
- /* nothing */
-}
-
-static u8 qs_bmdma_status(struct ata_port *ap)
-{
- return 0;
-}
-
static inline void qs_enter_reg_mode(struct ata_port *ap)
{
u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000);
@@ -242,25 +227,25 @@ static int qs_prereset(struct ata_link *link, unsigned long deadline)
return ata_sff_prereset(link, deadline);
}
-static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int qs_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+ *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 8));
return 0;
}
static void qs_error_handler(struct ata_port *ap)
{
qs_enter_reg_mode(ap);
- ata_std_error_handler(ap);
+ ata_sff_error_handler(ap);
}
-static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int qs_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- writel(val, ap->ioaddr.scr_addr + (sc_reg * 8));
+ writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 8));
return 0;
}
@@ -302,10 +287,8 @@ static void qs_qc_prep(struct ata_queued_cmd *qc)
VPRINTK("ENTER\n");
qs_enter_reg_mode(qc->ap);
- if (qc->tf.protocol != ATA_PROT_DMA) {
- ata_sff_qc_prep(qc);
+ if (qc->tf.protocol != ATA_PROT_DMA)
return;
- }
nelem = qs_fill_sg(qc);
@@ -402,26 +385,24 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host)
u8 sHST = sff1 & 0x3f; /* host status */
unsigned int port_no = (sff1 >> 8) & 0x03;
struct ata_port *ap = host->ports[port_no];
+ struct qs_port_priv *pp = ap->private_data;
+ struct ata_queued_cmd *qc;
DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
sff1, sff0, port_no, sHST, sDST);
handled = 1;
- if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
- struct qs_port_priv *pp = ap->private_data;
- if (!pp || pp->state != qs_state_pkt)
- continue;
- qc = ata_qc_from_tag(ap, ap->link.active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
- switch (sHST) {
- case 0: /* successful CPB */
- case 3: /* device error */
- qs_enter_reg_mode(qc->ap);
- qs_do_or_die(qc, sDST);
- break;
- default:
- break;
- }
+ if (!pp || pp->state != qs_state_pkt)
+ continue;
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
+ switch (sHST) {
+ case 0: /* successful CPB */
+ case 3: /* device error */
+ qs_enter_reg_mode(qc->ap);
+ qs_do_or_die(qc, sDST);
+ break;
+ default:
+ break;
}
}
}
@@ -434,33 +415,30 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host)
unsigned int handled = 0, port_no;
for (port_no = 0; port_no < host->n_ports; ++port_no) {
- struct ata_port *ap;
- ap = host->ports[port_no];
- if (ap &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
- struct qs_port_priv *pp;
- qc = ata_qc_from_tag(ap, ap->link.active_tag);
- if (!qc || !(qc->flags & ATA_QCFLAG_ACTIVE)) {
- /*
- * The qstor hardware generates spurious
- * interrupts from time to time when switching
- * in and out of packet mode.
- * There's no obvious way to know if we're
- * here now due to that, so just ack the irq
- * and pretend we knew it was ours.. (ugh).
- * This does not affect packet mode.
- */
- ata_sff_check_status(ap);
- handled = 1;
- continue;
- }
- pp = ap->private_data;
- if (!pp || pp->state != qs_state_mmio)
- continue;
- if (!(qc->tf.flags & ATA_TFLAG_POLLING))
- handled |= ata_sff_host_intr(ap, qc);
+ struct ata_port *ap = host->ports[port_no];
+ struct qs_port_priv *pp = ap->private_data;
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (!qc) {
+ /*
+ * The qstor hardware generates spurious
+ * interrupts from time to time when switching
+ * in and out of packet mode. There's no
+ * obvious way to know if we're here now due
+ * to that, so just ack the irq and pretend we
+ * knew it was ours.. (ugh). This does not
+ * affect packet mode.
+ */
+ ata_sff_check_status(ap);
+ handled = 1;
+ continue;
}
+
+ if (!pp || pp->state != qs_state_mmio)
+ continue;
+ if (!(qc->tf.flags & ATA_TFLAG_POLLING))
+ handled |= ata_sff_port_intr(ap, qc);
}
return handled;
}
@@ -507,11 +485,7 @@ static int qs_port_start(struct ata_port *ap)
void __iomem *mmio_base = qs_mmio_base(ap->host);
void __iomem *chan = mmio_base + (ap->port_no * 0x4000);
u64 addr;
- int rc;
- rc = ata_port_start(ap);
- if (rc)
- return rc;
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
@@ -583,26 +557,25 @@ static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT);
if (have_64bit_bus &&
- !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
if (rc) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "64-bit DMA enable failed\n");
+ dev_err(&pdev->dev,
+ "64-bit DMA enable failed\n");
return rc;
}
}
} else {
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit DMA enable failed\n");
+ dev_err(&pdev->dev, "32-bit DMA enable failed\n");
return rc;
}
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
+ dev_err(&pdev->dev,
"32-bit consistent DMA enable failed\n");
return rc;
}
@@ -613,14 +586,12 @@ static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
static int qs_ata_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- static int printed_version;
unsigned int board_idx = (unsigned int) ent->driver_data;
const struct ata_port_info *ppi[] = { &qs_port_info[board_idx], NULL };
struct ata_host *host;
int rc, port_no;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
/* alloc host */
host = ata_host_alloc_pinfo(&pdev->dev, ppi, QS_PORTS);
@@ -663,21 +634,10 @@ static int qs_ata_init_one(struct pci_dev *pdev,
&qs_ata_sht);
}
-static int __init qs_ata_init(void)
-{
- return pci_register_driver(&qs_ata_pci_driver);
-}
-
-static void __exit qs_ata_exit(void)
-{
- pci_unregister_driver(&qs_ata_pci_driver);
-}
+module_pci_driver(qs_ata_pci_driver);
MODULE_AUTHOR("Mark Lord");
MODULE_DESCRIPTION("Pacific Digital Corporation QStor SATA low-level driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, qs_ata_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
-module_init(qs_ata_init);
-module_exit(qs_ata_exit);
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
new file mode 100644
index 00000000000..61eb6d77dac
--- /dev/null
+++ b/drivers/ata/sata_rcar.c
@@ -0,0 +1,1004 @@
+/*
+ * Renesas R-Car SATA driver
+ *
+ * Author: Vladimir Barinov <source@cogentembedded.com>
+ * Copyright (C) 2013 Cogent Embedded, Inc.
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#define DRV_NAME "sata_rcar"
+
+/* SH-Navi2G/ATAPI-ATA compatible task registers */
+#define DATA_REG 0x100
+#define SDEVCON_REG 0x138
+
+/* SH-Navi2G/ATAPI module compatible control registers */
+#define ATAPI_CONTROL1_REG 0x180
+#define ATAPI_STATUS_REG 0x184
+#define ATAPI_INT_ENABLE_REG 0x188
+#define ATAPI_DTB_ADR_REG 0x198
+#define ATAPI_DMA_START_ADR_REG 0x19C
+#define ATAPI_DMA_TRANS_CNT_REG 0x1A0
+#define ATAPI_CONTROL2_REG 0x1A4
+#define ATAPI_SIG_ST_REG 0x1B0
+#define ATAPI_BYTE_SWAP_REG 0x1BC
+
+/* ATAPI control 1 register (ATAPI_CONTROL1) bits */
+#define ATAPI_CONTROL1_ISM BIT(16)
+#define ATAPI_CONTROL1_DTA32M BIT(11)
+#define ATAPI_CONTROL1_RESET BIT(7)
+#define ATAPI_CONTROL1_DESE BIT(3)
+#define ATAPI_CONTROL1_RW BIT(2)
+#define ATAPI_CONTROL1_STOP BIT(1)
+#define ATAPI_CONTROL1_START BIT(0)
+
+/* ATAPI status register (ATAPI_STATUS) bits */
+#define ATAPI_STATUS_SATAINT BIT(11)
+#define ATAPI_STATUS_DNEND BIT(6)
+#define ATAPI_STATUS_DEVTRM BIT(5)
+#define ATAPI_STATUS_DEVINT BIT(4)
+#define ATAPI_STATUS_ERR BIT(2)
+#define ATAPI_STATUS_NEND BIT(1)
+#define ATAPI_STATUS_ACT BIT(0)
+
+/* Interrupt enable register (ATAPI_INT_ENABLE) bits */
+#define ATAPI_INT_ENABLE_SATAINT BIT(11)
+#define ATAPI_INT_ENABLE_DNEND BIT(6)
+#define ATAPI_INT_ENABLE_DEVTRM BIT(5)
+#define ATAPI_INT_ENABLE_DEVINT BIT(4)
+#define ATAPI_INT_ENABLE_ERR BIT(2)
+#define ATAPI_INT_ENABLE_NEND BIT(1)
+#define ATAPI_INT_ENABLE_ACT BIT(0)
+
+/* Access control registers for physical layer control register */
+#define SATAPHYADDR_REG 0x200
+#define SATAPHYWDATA_REG 0x204
+#define SATAPHYACCEN_REG 0x208
+#define SATAPHYRESET_REG 0x20C
+#define SATAPHYRDATA_REG 0x210
+#define SATAPHYACK_REG 0x214
+
+/* Physical layer control address command register (SATAPHYADDR) bits */
+#define SATAPHYADDR_PHYRATEMODE BIT(10)
+#define SATAPHYADDR_PHYCMD_READ BIT(9)
+#define SATAPHYADDR_PHYCMD_WRITE BIT(8)
+
+/* Physical layer control enable register (SATAPHYACCEN) bits */
+#define SATAPHYACCEN_PHYLANE BIT(0)
+
+/* Physical layer control reset register (SATAPHYRESET) bits */
+#define SATAPHYRESET_PHYRST BIT(1)
+#define SATAPHYRESET_PHYSRES BIT(0)
+
+/* Physical layer control acknowledge register (SATAPHYACK) bits */
+#define SATAPHYACK_PHYACK BIT(0)
+
+/* Serial-ATA HOST control registers */
+#define BISTCONF_REG 0x102C
+#define SDATA_REG 0x1100
+#define SSDEVCON_REG 0x1204
+
+#define SCRSSTS_REG 0x1400
+#define SCRSERR_REG 0x1404
+#define SCRSCON_REG 0x1408
+#define SCRSACT_REG 0x140C
+
+#define SATAINTSTAT_REG 0x1508
+#define SATAINTMASK_REG 0x150C
+
+/* SATA INT status register (SATAINTSTAT) bits */
+#define SATAINTSTAT_SERR BIT(3)
+#define SATAINTSTAT_ATA BIT(0)
+
+/* SATA INT mask register (SATAINTSTAT) bits */
+#define SATAINTMASK_SERRMSK BIT(3)
+#define SATAINTMASK_ERRMSK BIT(2)
+#define SATAINTMASK_ERRCRTMSK BIT(1)
+#define SATAINTMASK_ATAMSK BIT(0)
+
+#define SATA_RCAR_INT_MASK (SATAINTMASK_SERRMSK | \
+ SATAINTMASK_ATAMSK)
+
+/* Physical Layer Control Registers */
+#define SATAPCTLR1_REG 0x43
+#define SATAPCTLR2_REG 0x52
+#define SATAPCTLR3_REG 0x5A
+#define SATAPCTLR4_REG 0x60
+
+/* Descriptor table word 0 bit (when DTA32M = 1) */
+#define SATA_RCAR_DTEND BIT(0)
+
+#define SATA_RCAR_DMA_BOUNDARY 0x1FFFFFFEUL
+
+/* Gen2 Physical Layer Control Registers */
+#define RCAR_GEN2_PHY_CTL1_REG 0x1704
+#define RCAR_GEN2_PHY_CTL1 0x34180002
+#define RCAR_GEN2_PHY_CTL1_SS 0xC180 /* Spread Spectrum */
+
+#define RCAR_GEN2_PHY_CTL2_REG 0x170C
+#define RCAR_GEN2_PHY_CTL2 0x00002303
+
+#define RCAR_GEN2_PHY_CTL3_REG 0x171C
+#define RCAR_GEN2_PHY_CTL3 0x000B0194
+
+#define RCAR_GEN2_PHY_CTL4_REG 0x1724
+#define RCAR_GEN2_PHY_CTL4 0x00030994
+
+#define RCAR_GEN2_PHY_CTL5_REG 0x1740
+#define RCAR_GEN2_PHY_CTL5 0x03004001
+#define RCAR_GEN2_PHY_CTL5_DC BIT(1) /* DC connection */
+#define RCAR_GEN2_PHY_CTL5_TR BIT(2) /* Termination Resistor */
+
+enum sata_rcar_type {
+ RCAR_GEN1_SATA,
+ RCAR_GEN2_SATA,
+};
+
+struct sata_rcar_priv {
+ void __iomem *base;
+ struct clk *clk;
+ enum sata_rcar_type type;
+};
+
+static void sata_rcar_gen1_phy_preinit(struct sata_rcar_priv *priv)
+{
+ void __iomem *base = priv->base;
+
+ /* idle state */
+ iowrite32(0, base + SATAPHYADDR_REG);
+ /* reset */
+ iowrite32(SATAPHYRESET_PHYRST, base + SATAPHYRESET_REG);
+ udelay(10);
+ /* deassert reset */
+ iowrite32(0, base + SATAPHYRESET_REG);
+}
+
+static void sata_rcar_gen1_phy_write(struct sata_rcar_priv *priv, u16 reg,
+ u32 val, int group)
+{
+ void __iomem *base = priv->base;
+ int timeout;
+
+ /* deassert reset */
+ iowrite32(0, base + SATAPHYRESET_REG);
+ /* lane 1 */
+ iowrite32(SATAPHYACCEN_PHYLANE, base + SATAPHYACCEN_REG);
+ /* write phy register value */
+ iowrite32(val, base + SATAPHYWDATA_REG);
+ /* set register group */
+ if (group)
+ reg |= SATAPHYADDR_PHYRATEMODE;
+ /* write command */
+ iowrite32(SATAPHYADDR_PHYCMD_WRITE | reg, base + SATAPHYADDR_REG);
+ /* wait for ack */
+ for (timeout = 0; timeout < 100; timeout++) {
+ val = ioread32(base + SATAPHYACK_REG);
+ if (val & SATAPHYACK_PHYACK)
+ break;
+ }
+ if (timeout >= 100)
+ pr_err("%s timeout\n", __func__);
+ /* idle state */
+ iowrite32(0, base + SATAPHYADDR_REG);
+}
+
+static void sata_rcar_gen1_phy_init(struct sata_rcar_priv *priv)
+{
+ sata_rcar_gen1_phy_preinit(priv);
+ sata_rcar_gen1_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 0);
+ sata_rcar_gen1_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 1);
+ sata_rcar_gen1_phy_write(priv, SATAPCTLR3_REG, 0x0000A061, 0);
+ sata_rcar_gen1_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 0);
+ sata_rcar_gen1_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 1);
+ sata_rcar_gen1_phy_write(priv, SATAPCTLR4_REG, 0x28E80000, 0);
+}
+
+static void sata_rcar_gen2_phy_init(struct sata_rcar_priv *priv)
+{
+ void __iomem *base = priv->base;
+
+ iowrite32(RCAR_GEN2_PHY_CTL1, base + RCAR_GEN2_PHY_CTL1_REG);
+ iowrite32(RCAR_GEN2_PHY_CTL2, base + RCAR_GEN2_PHY_CTL2_REG);
+ iowrite32(RCAR_GEN2_PHY_CTL3, base + RCAR_GEN2_PHY_CTL3_REG);
+ iowrite32(RCAR_GEN2_PHY_CTL4, base + RCAR_GEN2_PHY_CTL4_REG);
+ iowrite32(RCAR_GEN2_PHY_CTL5 | RCAR_GEN2_PHY_CTL5_DC |
+ RCAR_GEN2_PHY_CTL5_TR, base + RCAR_GEN2_PHY_CTL5_REG);
+}
+
+static void sata_rcar_freeze(struct ata_port *ap)
+{
+ struct sata_rcar_priv *priv = ap->host->private_data;
+
+ /* mask */
+ iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+
+ ata_sff_freeze(ap);
+}
+
+static void sata_rcar_thaw(struct ata_port *ap)
+{
+ struct sata_rcar_priv *priv = ap->host->private_data;
+ void __iomem *base = priv->base;
+
+ /* ack */
+ iowrite32(~(u32)SATA_RCAR_INT_MASK, base + SATAINTSTAT_REG);
+
+ ata_sff_thaw(ap);
+
+ /* unmask */
+ iowrite32(0x7ff & ~SATA_RCAR_INT_MASK, base + SATAINTMASK_REG);
+}
+
+static void sata_rcar_ioread16_rep(void __iomem *reg, void *buffer, int count)
+{
+ u16 *ptr = buffer;
+
+ while (count--) {
+ u16 data = ioread32(reg);
+
+ *ptr++ = data;
+ }
+}
+
+static void sata_rcar_iowrite16_rep(void __iomem *reg, void *buffer, int count)
+{
+ const u16 *ptr = buffer;
+
+ while (count--)
+ iowrite32(*ptr++, reg);
+}
+
+static u8 sata_rcar_check_status(struct ata_port *ap)
+{
+ return ioread32(ap->ioaddr.status_addr);
+}
+
+static u8 sata_rcar_check_altstatus(struct ata_port *ap)
+{
+ return ioread32(ap->ioaddr.altstatus_addr);
+}
+
+static void sata_rcar_set_devctl(struct ata_port *ap, u8 ctl)
+{
+ iowrite32(ctl, ap->ioaddr.ctl_addr);
+}
+
+static void sata_rcar_dev_select(struct ata_port *ap, unsigned int device)
+{
+ iowrite32(ATA_DEVICE_OBS, ap->ioaddr.device_addr);
+ ata_sff_pause(ap); /* needed; also flushes, for mmio */
+}
+
+static unsigned int sata_rcar_ata_devchk(struct ata_port *ap,
+ unsigned int device)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ u8 nsect, lbal;
+
+ sata_rcar_dev_select(ap, device);
+
+ iowrite32(0x55, ioaddr->nsect_addr);
+ iowrite32(0xaa, ioaddr->lbal_addr);
+
+ iowrite32(0xaa, ioaddr->nsect_addr);
+ iowrite32(0x55, ioaddr->lbal_addr);
+
+ iowrite32(0x55, ioaddr->nsect_addr);
+ iowrite32(0xaa, ioaddr->lbal_addr);
+
+ nsect = ioread32(ioaddr->nsect_addr);
+ lbal = ioread32(ioaddr->lbal_addr);
+
+ if (nsect == 0x55 && lbal == 0xaa)
+ return 1; /* found a device */
+
+ return 0; /* nothing found */
+}
+
+static int sata_rcar_wait_after_reset(struct ata_link *link,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+
+ ata_msleep(ap, ATA_WAIT_AFTER_RESET);
+
+ return ata_sff_wait_ready(link, deadline);
+}
+
+static int sata_rcar_bus_softreset(struct ata_port *ap, unsigned long deadline)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ DPRINTK("ata%u: bus reset via SRST\n", ap->print_id);
+
+ /* software reset. causes dev0 to be selected */
+ iowrite32(ap->ctl, ioaddr->ctl_addr);
+ udelay(20);
+ iowrite32(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+ udelay(20);
+ iowrite32(ap->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = ap->ctl;
+
+ /* wait the port to become ready */
+ return sata_rcar_wait_after_reset(&ap->link, deadline);
+}
+
+static int sata_rcar_softreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ unsigned int devmask = 0;
+ int rc;
+ u8 err;
+
+ /* determine if device 0 is present */
+ if (sata_rcar_ata_devchk(ap, 0))
+ devmask |= 1 << 0;
+
+ /* issue bus reset */
+ DPRINTK("about to softreset, devmask=%x\n", devmask);
+ rc = sata_rcar_bus_softreset(ap, deadline);
+ /* if link is occupied, -ENODEV too is an error */
+ if (rc && (rc != -ENODEV || sata_scr_valid(link))) {
+ ata_link_err(link, "SRST failed (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_sff_dev_classify(&link->device[0], devmask, &err);
+
+ DPRINTK("classes[0]=%u\n", classes[0]);
+ return 0;
+}
+
+static void sata_rcar_tf_load(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ iowrite32(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ iowrite32(tf->hob_feature, ioaddr->feature_addr);
+ iowrite32(tf->hob_nsect, ioaddr->nsect_addr);
+ iowrite32(tf->hob_lbal, ioaddr->lbal_addr);
+ iowrite32(tf->hob_lbam, ioaddr->lbam_addr);
+ iowrite32(tf->hob_lbah, ioaddr->lbah_addr);
+ VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+ tf->hob_feature,
+ tf->hob_nsect,
+ tf->hob_lbal,
+ tf->hob_lbam,
+ tf->hob_lbah);
+ }
+
+ if (is_addr) {
+ iowrite32(tf->feature, ioaddr->feature_addr);
+ iowrite32(tf->nsect, ioaddr->nsect_addr);
+ iowrite32(tf->lbal, ioaddr->lbal_addr);
+ iowrite32(tf->lbam, ioaddr->lbam_addr);
+ iowrite32(tf->lbah, ioaddr->lbah_addr);
+ VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+ tf->feature,
+ tf->nsect,
+ tf->lbal,
+ tf->lbam,
+ tf->lbah);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ iowrite32(tf->device, ioaddr->device_addr);
+ VPRINTK("device 0x%X\n", tf->device);
+ }
+
+ ata_wait_idle(ap);
+}
+
+static void sata_rcar_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->command = sata_rcar_check_status(ap);
+ tf->feature = ioread32(ioaddr->error_addr);
+ tf->nsect = ioread32(ioaddr->nsect_addr);
+ tf->lbal = ioread32(ioaddr->lbal_addr);
+ tf->lbam = ioread32(ioaddr->lbam_addr);
+ tf->lbah = ioread32(ioaddr->lbah_addr);
+ tf->device = ioread32(ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ iowrite32(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+ tf->hob_feature = ioread32(ioaddr->error_addr);
+ tf->hob_nsect = ioread32(ioaddr->nsect_addr);
+ tf->hob_lbal = ioread32(ioaddr->lbal_addr);
+ tf->hob_lbam = ioread32(ioaddr->lbam_addr);
+ tf->hob_lbah = ioread32(ioaddr->lbah_addr);
+ iowrite32(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ }
+}
+
+static void sata_rcar_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+
+ iowrite32(tf->command, ap->ioaddr.command_addr);
+ ata_sff_pause(ap);
+}
+
+static unsigned int sata_rcar_data_xfer(struct ata_device *dev,
+ unsigned char *buf,
+ unsigned int buflen, int rw)
+{
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned int words = buflen >> 1;
+
+ /* Transfer multiple of 2 bytes */
+ if (rw == READ)
+ sata_rcar_ioread16_rep(data_addr, buf, words);
+ else
+ sata_rcar_iowrite16_rep(data_addr, buf, words);
+
+ /* Transfer trailing byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ unsigned char pad[2] = { };
+
+ /* Point buf to the tail of buffer */
+ buf += buflen - 1;
+
+ /*
+ * Use io*16_rep() accessors here as well to avoid pointlessly
+ * swapping bytes to and from on the big endian machines...
+ */
+ if (rw == READ) {
+ sata_rcar_ioread16_rep(data_addr, pad, 1);
+ *buf = pad[0];
+ } else {
+ pad[0] = *buf;
+ sata_rcar_iowrite16_rep(data_addr, pad, 1);
+ }
+ words++;
+ }
+
+ return words << 1;
+}
+
+static void sata_rcar_drain_fifo(struct ata_queued_cmd *qc)
+{
+ int count;
+ struct ata_port *ap;
+
+ /* We only need to flush incoming data when a command was running */
+ if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
+ return;
+
+ ap = qc->ap;
+ /* Drain up to 64K of data before we give up this recovery method */
+ for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ) &&
+ count < 65536; count += 2)
+ ioread32(ap->ioaddr.data_addr);
+
+ /* Can become DEBUG later */
+ if (count)
+ ata_port_dbg(ap, "drained %d bytes to clear DRQ\n", count);
+}
+
+static int sata_rcar_scr_read(struct ata_link *link, unsigned int sc_reg,
+ u32 *val)
+{
+ if (sc_reg > SCR_ACTIVE)
+ return -EINVAL;
+
+ *val = ioread32(link->ap->ioaddr.scr_addr + (sc_reg << 2));
+ return 0;
+}
+
+static int sata_rcar_scr_write(struct ata_link *link, unsigned int sc_reg,
+ u32 val)
+{
+ if (sc_reg > SCR_ACTIVE)
+ return -EINVAL;
+
+ iowrite32(val, link->ap->ioaddr.scr_addr + (sc_reg << 2));
+ return 0;
+}
+
+static void sata_rcar_bmdma_fill_sg(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_bmdma_prd *prd = ap->bmdma_prd;
+ struct scatterlist *sg;
+ unsigned int si;
+
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ u32 addr, sg_len;
+
+ /*
+ * Note: h/w doesn't support 64-bit, so we unconditionally
+ * truncate dma_addr_t to u32.
+ */
+ addr = (u32)sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ prd[si].addr = cpu_to_le32(addr);
+ prd[si].flags_len = cpu_to_le32(sg_len);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", si, addr, sg_len);
+ }
+
+ /* end-of-table flag */
+ prd[si - 1].addr |= cpu_to_le32(SATA_RCAR_DTEND);
+}
+
+static void sata_rcar_qc_prep(struct ata_queued_cmd *qc)
+{
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
+
+ sata_rcar_bmdma_fill_sg(qc);
+}
+
+static void sata_rcar_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int rw = qc->tf.flags & ATA_TFLAG_WRITE;
+ struct sata_rcar_priv *priv = ap->host->private_data;
+ void __iomem *base = priv->base;
+ u32 dmactl;
+
+ /* load PRD table addr. */
+ mb(); /* make sure PRD table writes are visible to controller */
+ iowrite32(ap->bmdma_prd_dma, base + ATAPI_DTB_ADR_REG);
+
+ /* specify data direction, triple-check start bit is clear */
+ dmactl = ioread32(base + ATAPI_CONTROL1_REG);
+ dmactl &= ~(ATAPI_CONTROL1_RW | ATAPI_CONTROL1_STOP);
+ if (dmactl & ATAPI_CONTROL1_START) {
+ dmactl &= ~ATAPI_CONTROL1_START;
+ dmactl |= ATAPI_CONTROL1_STOP;
+ }
+ if (!rw)
+ dmactl |= ATAPI_CONTROL1_RW;
+ iowrite32(dmactl, base + ATAPI_CONTROL1_REG);
+
+ /* issue r/w command */
+ ap->ops->sff_exec_command(ap, &qc->tf);
+}
+
+static void sata_rcar_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct sata_rcar_priv *priv = ap->host->private_data;
+ void __iomem *base = priv->base;
+ u32 dmactl;
+
+ /* start host DMA transaction */
+ dmactl = ioread32(base + ATAPI_CONTROL1_REG);
+ dmactl &= ~ATAPI_CONTROL1_STOP;
+ dmactl |= ATAPI_CONTROL1_START;
+ iowrite32(dmactl, base + ATAPI_CONTROL1_REG);
+}
+
+static void sata_rcar_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct sata_rcar_priv *priv = ap->host->private_data;
+ void __iomem *base = priv->base;
+ u32 dmactl;
+
+ /* force termination of DMA transfer if active */
+ dmactl = ioread32(base + ATAPI_CONTROL1_REG);
+ if (dmactl & ATAPI_CONTROL1_START) {
+ dmactl &= ~ATAPI_CONTROL1_START;
+ dmactl |= ATAPI_CONTROL1_STOP;
+ iowrite32(dmactl, base + ATAPI_CONTROL1_REG);
+ }
+
+ /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+ ata_sff_dma_pause(ap);
+}
+
+static u8 sata_rcar_bmdma_status(struct ata_port *ap)
+{
+ struct sata_rcar_priv *priv = ap->host->private_data;
+ u8 host_stat = 0;
+ u32 status;
+
+ status = ioread32(priv->base + ATAPI_STATUS_REG);
+ if (status & ATAPI_STATUS_DEVINT)
+ host_stat |= ATA_DMA_INTR;
+ if (status & ATAPI_STATUS_ACT)
+ host_stat |= ATA_DMA_ACTIVE;
+
+ return host_stat;
+}
+
+static struct scsi_host_template sata_rcar_sht = {
+ ATA_BASE_SHT(DRV_NAME),
+ /*
+ * This controller allows transfer chunks up to 512MB which cross 64KB
+ * boundaries, therefore the DMA limits are more relaxed than standard
+ * ATA SFF.
+ */
+ .sg_tablesize = ATA_MAX_PRD,
+ .dma_boundary = SATA_RCAR_DMA_BOUNDARY,
+};
+
+static struct ata_port_operations sata_rcar_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+
+ .freeze = sata_rcar_freeze,
+ .thaw = sata_rcar_thaw,
+ .softreset = sata_rcar_softreset,
+
+ .scr_read = sata_rcar_scr_read,
+ .scr_write = sata_rcar_scr_write,
+
+ .sff_dev_select = sata_rcar_dev_select,
+ .sff_set_devctl = sata_rcar_set_devctl,
+ .sff_check_status = sata_rcar_check_status,
+ .sff_check_altstatus = sata_rcar_check_altstatus,
+ .sff_tf_load = sata_rcar_tf_load,
+ .sff_tf_read = sata_rcar_tf_read,
+ .sff_exec_command = sata_rcar_exec_command,
+ .sff_data_xfer = sata_rcar_data_xfer,
+ .sff_drain_fifo = sata_rcar_drain_fifo,
+
+ .qc_prep = sata_rcar_qc_prep,
+
+ .bmdma_setup = sata_rcar_bmdma_setup,
+ .bmdma_start = sata_rcar_bmdma_start,
+ .bmdma_stop = sata_rcar_bmdma_stop,
+ .bmdma_status = sata_rcar_bmdma_status,
+};
+
+static void sata_rcar_serr_interrupt(struct ata_port *ap)
+{
+ struct sata_rcar_priv *priv = ap->host->private_data;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ int freeze = 0;
+ u32 serror;
+
+ serror = ioread32(priv->base + SCRSERR_REG);
+ if (!serror)
+ return;
+
+ DPRINTK("SError @host_intr: 0x%x\n", serror);
+
+ /* first, analyze and record host port events */
+ ata_ehi_clear_desc(ehi);
+
+ if (serror & (SERR_DEV_XCHG | SERR_PHYRDY_CHG)) {
+ /* Setup a soft-reset EH action */
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, "%s", "hotplug");
+
+ freeze = serror & SERR_COMM_WAKE ? 0 : 1;
+ }
+
+ /* freeze or abort */
+ if (freeze)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
+}
+
+static void sata_rcar_ata_interrupt(struct ata_port *ap)
+{
+ struct ata_queued_cmd *qc;
+ int handled = 0;
+
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc)
+ handled |= ata_bmdma_port_intr(ap, qc);
+
+ /* be sure to clear ATA interrupt */
+ if (!handled)
+ sata_rcar_check_status(ap);
+}
+
+static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ struct sata_rcar_priv *priv = host->private_data;
+ void __iomem *base = priv->base;
+ unsigned int handled = 0;
+ struct ata_port *ap;
+ u32 sataintstat;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ sataintstat = ioread32(base + SATAINTSTAT_REG);
+ sataintstat &= SATA_RCAR_INT_MASK;
+ if (!sataintstat)
+ goto done;
+ /* ack */
+ iowrite32(~sataintstat & 0x7ff, base + SATAINTSTAT_REG);
+
+ ap = host->ports[0];
+
+ if (sataintstat & SATAINTSTAT_ATA)
+ sata_rcar_ata_interrupt(ap);
+
+ if (sataintstat & SATAINTSTAT_SERR)
+ sata_rcar_serr_interrupt(ap);
+
+ handled = 1;
+done:
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+static void sata_rcar_setup_port(struct ata_host *host)
+{
+ struct ata_port *ap = host->ports[0];
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ struct sata_rcar_priv *priv = host->private_data;
+ void __iomem *base = priv->base;
+
+ ap->ops = &sata_rcar_port_ops;
+ ap->pio_mask = ATA_PIO4;
+ ap->udma_mask = ATA_UDMA6;
+ ap->flags |= ATA_FLAG_SATA;
+
+ ioaddr->cmd_addr = base + SDATA_REG;
+ ioaddr->ctl_addr = base + SSDEVCON_REG;
+ ioaddr->scr_addr = base + SCRSSTS_REG;
+ ioaddr->altstatus_addr = ioaddr->ctl_addr;
+
+ ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << 2);
+ ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << 2);
+ ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << 2);
+ ioaddr->nsect_addr = ioaddr->cmd_addr + (ATA_REG_NSECT << 2);
+ ioaddr->lbal_addr = ioaddr->cmd_addr + (ATA_REG_LBAL << 2);
+ ioaddr->lbam_addr = ioaddr->cmd_addr + (ATA_REG_LBAM << 2);
+ ioaddr->lbah_addr = ioaddr->cmd_addr + (ATA_REG_LBAH << 2);
+ ioaddr->device_addr = ioaddr->cmd_addr + (ATA_REG_DEVICE << 2);
+ ioaddr->status_addr = ioaddr->cmd_addr + (ATA_REG_STATUS << 2);
+ ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << 2);
+}
+
+static void sata_rcar_init_controller(struct ata_host *host)
+{
+ struct sata_rcar_priv *priv = host->private_data;
+ void __iomem *base = priv->base;
+ u32 val;
+
+ /* reset and setup phy */
+ switch (priv->type) {
+ case RCAR_GEN1_SATA:
+ sata_rcar_gen1_phy_init(priv);
+ break;
+ case RCAR_GEN2_SATA:
+ sata_rcar_gen2_phy_init(priv);
+ break;
+ default:
+ dev_warn(host->dev, "SATA phy is not initialized\n");
+ break;
+ }
+
+ /* SATA-IP reset state */
+ val = ioread32(base + ATAPI_CONTROL1_REG);
+ val |= ATAPI_CONTROL1_RESET;
+ iowrite32(val, base + ATAPI_CONTROL1_REG);
+
+ /* ISM mode, PRD mode, DTEND flag at bit 0 */
+ val = ioread32(base + ATAPI_CONTROL1_REG);
+ val |= ATAPI_CONTROL1_ISM;
+ val |= ATAPI_CONTROL1_DESE;
+ val |= ATAPI_CONTROL1_DTA32M;
+ iowrite32(val, base + ATAPI_CONTROL1_REG);
+
+ /* Release the SATA-IP from the reset state */
+ val = ioread32(base + ATAPI_CONTROL1_REG);
+ val &= ~ATAPI_CONTROL1_RESET;
+ iowrite32(val, base + ATAPI_CONTROL1_REG);
+
+ /* ack and mask */
+ iowrite32(0, base + SATAINTSTAT_REG);
+ iowrite32(0x7ff, base + SATAINTMASK_REG);
+ /* enable interrupts */
+ iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG);
+}
+
+static struct of_device_id sata_rcar_match[] = {
+ {
+ /* Deprecated by "renesas,sata-r8a7779" */
+ .compatible = "renesas,rcar-sata",
+ .data = (void *)RCAR_GEN1_SATA,
+ },
+ {
+ .compatible = "renesas,sata-r8a7779",
+ .data = (void *)RCAR_GEN1_SATA,
+ },
+ {
+ .compatible = "renesas,sata-r8a7790",
+ .data = (void *)RCAR_GEN2_SATA
+ },
+ {
+ .compatible = "renesas,sata-r8a7791",
+ .data = (void *)RCAR_GEN2_SATA
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sata_rcar_match);
+
+static const struct platform_device_id sata_rcar_id_table[] = {
+ { "sata_rcar", RCAR_GEN1_SATA }, /* Deprecated by "sata-r8a7779" */
+ { "sata-r8a7779", RCAR_GEN1_SATA },
+ { "sata-r8a7790", RCAR_GEN2_SATA },
+ { "sata-r8a7791", RCAR_GEN2_SATA },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, sata_rcar_id_table);
+
+static int sata_rcar_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id;
+ struct ata_host *host;
+ struct sata_rcar_priv *priv;
+ struct resource *mem;
+ int irq;
+ int ret = 0;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0)
+ return -EINVAL;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct sata_rcar_priv),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ of_id = of_match_device(sata_rcar_match, &pdev->dev);
+ if (of_id)
+ priv->type = (enum sata_rcar_type)of_id->data;
+ else
+ priv->type = platform_get_device_id(pdev)->driver_data;
+
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(&pdev->dev, "failed to get access to sata clock\n");
+ return PTR_ERR(priv->clk);
+ }
+ clk_prepare_enable(priv->clk);
+
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host) {
+ dev_err(&pdev->dev, "ata_host_alloc failed\n");
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ host->private_data = priv;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(priv->base)) {
+ ret = PTR_ERR(priv->base);
+ goto cleanup;
+ }
+
+ /* setup port */
+ sata_rcar_setup_port(host);
+
+ /* initialize host controller */
+ sata_rcar_init_controller(host);
+
+ ret = ata_host_activate(host, irq, sata_rcar_interrupt, 0,
+ &sata_rcar_sht);
+ if (!ret)
+ return 0;
+
+cleanup:
+ clk_disable_unprepare(priv->clk);
+
+ return ret;
+}
+
+static int sata_rcar_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct sata_rcar_priv *priv = host->private_data;
+ void __iomem *base = priv->base;
+
+ ata_host_detach(host);
+
+ /* disable interrupts */
+ iowrite32(0, base + ATAPI_INT_ENABLE_REG);
+ /* ack and mask */
+ iowrite32(0, base + SATAINTSTAT_REG);
+ iowrite32(0x7ff, base + SATAINTMASK_REG);
+
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sata_rcar_suspend(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_rcar_priv *priv = host->private_data;
+ void __iomem *base = priv->base;
+ int ret;
+
+ ret = ata_host_suspend(host, PMSG_SUSPEND);
+ if (!ret) {
+ /* disable interrupts */
+ iowrite32(0, base + ATAPI_INT_ENABLE_REG);
+ /* mask */
+ iowrite32(0x7ff, base + SATAINTMASK_REG);
+
+ clk_disable_unprepare(priv->clk);
+ }
+
+ return ret;
+}
+
+static int sata_rcar_resume(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_rcar_priv *priv = host->private_data;
+ void __iomem *base = priv->base;
+
+ clk_prepare_enable(priv->clk);
+
+ /* ack and mask */
+ iowrite32(0, base + SATAINTSTAT_REG);
+ iowrite32(0x7ff, base + SATAINTMASK_REG);
+ /* enable interrupts */
+ iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG);
+
+ ata_host_resume(host);
+
+ return 0;
+}
+
+static const struct dev_pm_ops sata_rcar_pm_ops = {
+ .suspend = sata_rcar_suspend,
+ .resume = sata_rcar_resume,
+};
+#endif
+
+static struct platform_driver sata_rcar_driver = {
+ .probe = sata_rcar_probe,
+ .remove = sata_rcar_remove,
+ .id_table = sata_rcar_id_table,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = sata_rcar_match,
+#ifdef CONFIG_PM_SLEEP
+ .pm = &sata_rcar_pm_ops,
+#endif
+ },
+};
+
+module_platform_driver(sata_rcar_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_DESCRIPTION("Renesas R-Car SATA controller low level driver");
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 88bf4212590..40b76b2d18c 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -1,7 +1,7 @@
/*
* sata_sil.c - Silicon Image SATA
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -37,16 +37,18 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
+#include <linux/dmi.h>
#define DRV_NAME "sata_sil"
-#define DRV_VERSION "2.3"
+#define DRV_VERSION "2.4"
+
+#define SIL_DMA_BOUNDARY 0x7fffffffUL
enum {
SIL_MMIO_BAR = 5,
@@ -58,8 +60,7 @@ enum {
SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
SIL_FLAG_MOD15WRITE = (1 << 30),
- SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO,
+ SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA,
/*
* Controller IDs
@@ -111,13 +112,17 @@ enum {
};
static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int sil_pci_device_resume(struct pci_dev *pdev);
#endif
static void sil_dev_config(struct ata_device *dev);
-static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);
+static void sil_qc_prep(struct ata_queued_cmd *qc);
+static void sil_bmdma_setup(struct ata_queued_cmd *qc);
+static void sil_bmdma_start(struct ata_queued_cmd *qc);
+static void sil_bmdma_stop(struct ata_queued_cmd *qc);
static void sil_freeze(struct ata_port *ap);
static void sil_thaw(struct ata_port *ap);
@@ -151,6 +156,7 @@ static const struct sil_drivelist {
{ "ST380011ASL", SIL_QUIRK_MOD15WRITE },
{ "ST3120022ASL", SIL_QUIRK_MOD15WRITE },
{ "ST3160021ASL", SIL_QUIRK_MOD15WRITE },
+ { "TOSHIBA MK2561GSYN", SIL_QUIRK_MOD15WRITE },
{ "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX },
{ }
};
@@ -160,20 +166,29 @@ static struct pci_driver sil_pci_driver = {
.id_table = sil_pci_tbl,
.probe = sil_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = sil_pci_device_resume,
#endif
};
static struct scsi_host_template sil_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
+ ATA_BASE_SHT(DRV_NAME),
+ /** These controllers support Large Block Transfer which allows
+ transfer chunks up to 2GB and which cross 64KB boundaries,
+ therefore the DMA limits are more relaxed than standard ATA SFF. */
+ .dma_boundary = SIL_DMA_BOUNDARY,
+ .sg_tablesize = ATA_MAX_PRD
};
static struct ata_port_operations sil_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma32_port_ops,
.dev_config = sil_dev_config,
.set_mode = sil_set_mode,
+ .bmdma_setup = sil_bmdma_setup,
+ .bmdma_start = sil_bmdma_start,
+ .bmdma_stop = sil_bmdma_stop,
+ .qc_prep = sil_qc_prep,
.freeze = sil_freeze,
.thaw = sil_thaw,
.scr_read = sil_scr_read,
@@ -184,8 +199,8 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3112 */
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &sil_ops,
},
@@ -193,24 +208,24 @@ static const struct ata_port_info sil_port_info[] = {
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
SIL_FLAG_NO_SATA_IRQ,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &sil_ops,
},
/* sil_3512 */
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &sil_ops,
},
/* sil_3114 */
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA5,
.port_ops = &sil_ops,
},
@@ -249,6 +264,83 @@ module_param(slow_down, int, 0444);
MODULE_PARM_DESC(slow_down, "Sledgehammer used to work around random problems, by limiting commands to 15 sectors (0=off, 1=on)");
+static void sil_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
+ void __iomem *bmdma2 = mmio_base + sil_port[ap->port_no].bmdma2;
+
+ /* clear start/stop bit - can safely always write 0 */
+ iowrite8(0, bmdma2);
+
+ /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+ ata_sff_dma_pause(ap);
+}
+
+static void sil_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *bmdma = ap->ioaddr.bmdma_addr;
+
+ /* load PRD table addr. */
+ iowrite32(ap->bmdma_prd_dma, bmdma + ATA_DMA_TABLE_OFS);
+
+ /* issue r/w command */
+ ap->ops->sff_exec_command(ap, &qc->tf);
+}
+
+static void sil_bmdma_start(struct ata_queued_cmd *qc)
+{
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+ struct ata_port *ap = qc->ap;
+ void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
+ void __iomem *bmdma2 = mmio_base + sil_port[ap->port_no].bmdma2;
+ u8 dmactl = ATA_DMA_START;
+
+ /* set transfer direction, start host DMA transaction
+ Note: For Large Block Transfer to work, the DMA must be started
+ using the bmdma2 register. */
+ if (!rw)
+ dmactl |= ATA_DMA_WR;
+ iowrite8(dmactl, bmdma2);
+}
+
+/* The way God intended PCI IDE scatter/gather lists to look and behave... */
+static void sil_fill_sg(struct ata_queued_cmd *qc)
+{
+ struct scatterlist *sg;
+ struct ata_port *ap = qc->ap;
+ struct ata_bmdma_prd *prd, *last_prd = NULL;
+ unsigned int si;
+
+ prd = &ap->bmdma_prd[0];
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ /* Note h/w doesn't support 64-bit, so we unconditionally
+ * truncate dma_addr_t to u32.
+ */
+ u32 addr = (u32) sg_dma_address(sg);
+ u32 sg_len = sg_dma_len(sg);
+
+ prd->addr = cpu_to_le32(addr);
+ prd->flags_len = cpu_to_le32(sg_len);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", si, addr, sg_len);
+
+ last_prd = prd;
+ prd++;
+ }
+
+ if (likely(last_prd))
+ last_prd->flags_len |= cpu_to_le32(ATA_PRD_EOT);
+}
+
+static void sil_qc_prep(struct ata_queued_cmd *qc)
+{
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
+
+ sil_fill_sg(qc);
+}
+
static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
{
u8 cache_line = 0;
@@ -278,7 +370,7 @@ static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed)
if (rc)
return rc;
- ata_link_for_each_dev(dev, link) {
+ ata_for_each_dev(dev, link, ALL) {
if (!ata_dev_enabled(dev))
dev_mode[dev->devno] = 0; /* PIO0/1/2 */
else if (dev->flags & ATA_DFLAG_PIO)
@@ -317,9 +409,9 @@ static inline void __iomem *sil_scr_addr(struct ata_port *ap,
return NULL;
}
-static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
- void __iomem *mmio = sil_scr_addr(ap, sc_reg);
+ void __iomem *mmio = sil_scr_addr(link->ap, sc_reg);
if (mmio) {
*val = readl(mmio);
@@ -328,9 +420,9 @@ static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
return -EINVAL;
}
-static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
- void __iomem *mmio = sil_scr_addr(ap, sc_reg);
+ void __iomem *mmio = sil_scr_addr(link->ap, sc_reg);
if (mmio) {
writel(val, mmio);
@@ -346,14 +438,14 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
u8 status;
if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
- u32 serror;
+ u32 serror = 0xffffffff;
/* SIEN doesn't mask SATA IRQs on some 3112s. Those
* controllers continue to assert IRQ as long as
* SError bits are pending. Clear SError immediately.
*/
- sil_scr_read(ap, SCR_ERROR, &serror);
- sil_scr_write(ap, SCR_ERROR, serror);
+ sil_scr_read(&ap->link, SCR_ERROR, &serror);
+ sil_scr_write(&ap->link, SCR_ERROR, serror);
/* Sometimes spurious interrupts occur, double check
* it's PHYRDY CHG.
@@ -410,7 +502,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
goto err_hsm;
/* ack bmdma irq events */
- ata_sff_irq_clear(ap);
+ ata_bmdma_irq_clear(ap);
/* kick HSM in the ass */
ata_sff_hsm_move(ap, qc, status, 0);
@@ -439,9 +531,6 @@ static irqreturn_t sil_interrupt(int irq, void *dev_instance)
struct ata_port *ap = host->ports[i];
u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);
- if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
- continue;
-
/* turn off SATA_IRQ if not supported */
if (ap->flags & SIL_FLAG_NO_SATA_IRQ)
bmdma2 &= ~SIL_DMA_SATA_IRQ;
@@ -472,6 +561,19 @@ static void sil_freeze(struct ata_port *ap)
tmp |= SIL_MASK_IDE0_INT << ap->port_no;
writel(tmp, mmio_base + SIL_SYSCFG);
readl(mmio_base + SIL_SYSCFG); /* flush */
+
+ /* Ensure DMA_ENABLE is off.
+ *
+ * This is because the controller will not give us access to the
+ * taskfile registers while a DMA is in progress
+ */
+ iowrite8(ioread8(ap->ioaddr.bmdma_addr) & ~SIL_DMA_ENABLE,
+ ap->ioaddr.bmdma_addr);
+
+ /* According to ata_bmdma_stop, an HDMA transition requires
+ * on PIO cycle. But we can't read a taskfile register.
+ */
+ ioread8(ap->ioaddr.bmdma_addr);
}
static void sil_thaw(struct ata_port *ap)
@@ -481,7 +583,7 @@ static void sil_thaw(struct ata_port *ap)
/* clear IRQ */
ap->ops->sff_check_status(ap);
- ata_sff_irq_clear(ap);
+ ata_bmdma_irq_clear(ap);
/* turn on SATA IRQ if supported */
if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ))
@@ -541,8 +643,8 @@ static void sil_dev_config(struct ata_device *dev)
((ap->flags & SIL_FLAG_MOD15WRITE) &&
(quirks & SIL_QUIRK_MOD15WRITE))) {
if (print_info)
- ata_dev_printk(dev, KERN_INFO, "applying Seagate "
- "errata fix (mod15write workaround)\n");
+ ata_dev_info(dev,
+ "applying Seagate errata fix (mod15write workaround)\n");
dev->max_sectors = 15;
return;
}
@@ -550,8 +652,8 @@ static void sil_dev_config(struct ata_device *dev)
/* limit to udma5 */
if (quirks & SIL_QUIRK_UDMA5MAX) {
if (print_info)
- ata_dev_printk(dev, KERN_INFO, "applying Maxtor "
- "errata fix %s\n", model_num);
+ ata_dev_info(dev, "applying Maxtor errata fix %s\n",
+ model_num);
dev->udma_mask &= ATA_UDMA5;
return;
}
@@ -574,8 +676,8 @@ static void sil_init_controller(struct ata_host *host)
writew(cls << 8 | cls,
mmio_base + sil_port[i].fifo_cfg);
} else
- dev_printk(KERN_WARNING, &pdev->dev,
- "cache line size not set. Driver may not function\n");
+ dev_warn(&pdev->dev,
+ "cache line size not set. Driver may not function\n");
/* Apply R_ERR on DMA activate FIS errata workaround */
if (host->ports[0]->flags & SIL_FLAG_RERR_ON_DMA_ACT) {
@@ -586,9 +688,8 @@ static void sil_init_controller(struct ata_host *host)
if ((tmp & 0x3) != 0x01)
continue;
if (!cnt)
- dev_printk(KERN_INFO, &pdev->dev,
- "Applying R_ERR on DMA activate "
- "FIS errata fix\n");
+ dev_info(&pdev->dev,
+ "Applying R_ERR on DMA activate FIS errata fix\n");
writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
cnt++;
}
@@ -603,24 +704,56 @@ static void sil_init_controller(struct ata_host *host)
}
}
+static bool sil_broken_system_poweroff(struct pci_dev *pdev)
+{
+ static const struct dmi_system_id broken_systems[] = {
+ {
+ .ident = "HP Compaq nx6325",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"),
+ },
+ /* PCI slot number of the controller */
+ .driver_data = (void *)0x12UL,
+ },
+
+ { } /* terminate list */
+ };
+ const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
+
+ if (dmi) {
+ unsigned long slot = (unsigned long)dmi->driver_data;
+ /* apply the quirk only to on-board controllers */
+ return slot == PCI_SLOT(pdev->devfn);
+ }
+
+ return false;
+}
+
static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
int board_id = ent->driver_data;
- const struct ata_port_info *ppi[] = { &sil_port_info[board_id], NULL };
+ struct ata_port_info pi = sil_port_info[board_id];
+ const struct ata_port_info *ppi[] = { &pi, NULL };
struct ata_host *host;
void __iomem *mmio_base;
int n_ports, rc;
unsigned int i;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
/* allocate host */
n_ports = 2;
if (board_id == sil_3114)
n_ports = 4;
+ if (sil_broken_system_poweroff(pdev)) {
+ pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN |
+ ATA_FLAG_NO_HIBERNATE_SPINDOWN;
+ dev_info(&pdev->dev, "quirky BIOS, skipping spindown "
+ "on poweroff and hibernation\n");
+ }
+
host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
if (!host)
return -ENOMEM;
@@ -669,10 +802,10 @@ static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
&sil_sht);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int sil_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -686,16 +819,4 @@ static int sil_pci_device_resume(struct pci_dev *pdev)
}
#endif
-static int __init sil_init(void)
-{
- return pci_register_driver(&sil_pci_driver);
-}
-
-static void __exit sil_exit(void)
-{
- pci_unregister_driver(&sil_pci_driver);
-}
-
-
-module_init(sil_init);
-module_exit(sil_exit);
+module_pci_driver(sil_pci_driver);
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 27a11011007..0534890f118 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/gfp.h>
#include <linux/pci.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
@@ -51,13 +52,6 @@ struct sil24_sge {
__le32 flags;
};
-/*
- * Port multiplier
- */
-struct sil24_port_multiplier {
- __le32 diag;
- __le32 sactive;
-};
enum {
SIL24_HOST_BAR = 0,
@@ -250,8 +244,7 @@ enum {
BID_SIL3131 = 2,
/* host flags */
- SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA |
ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA |
ATA_FLAG_AN | ATA_FLAG_PMP,
SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
@@ -275,7 +268,7 @@ union sil24_cmd_block {
struct sil24_atapi_block atapi;
};
-static struct sil24_cerr_info {
+static const struct sil24_cerr_info {
unsigned int err_mask, action;
const char *desc;
} sil24_cerr_db[] = {
@@ -340,8 +333,8 @@ struct sil24_port_priv {
};
static void sil24_dev_config(struct ata_device *dev);
-static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
-static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
+static int sil24_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val);
+static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val);
static int sil24_qc_defer(struct ata_queued_cmd *qc);
static void sil24_qc_prep(struct ata_queued_cmd *qc);
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
@@ -360,8 +353,10 @@ static void sil24_error_handler(struct ata_port *ap);
static void sil24_post_internal_cmd(struct ata_queued_cmd *qc);
static int sil24_port_start(struct ata_port *ap);
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int sil24_pci_device_resume(struct pci_dev *pdev);
+#endif
+#ifdef CONFIG_PM
static int sil24_port_resume(struct ata_port *ap);
#endif
@@ -370,6 +365,7 @@ static const struct pci_device_id sil24_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x3124), BID_SIL3124 },
{ PCI_VDEVICE(CMD, 0x3132), BID_SIL3132 },
{ PCI_VDEVICE(CMD, 0x0242), BID_SIL3132 },
+ { PCI_VDEVICE(CMD, 0x0244), BID_SIL3132 },
{ PCI_VDEVICE(CMD, 0x3131), BID_SIL3131 },
{ PCI_VDEVICE(CMD, 0x3531), BID_SIL3131 },
@@ -381,7 +377,7 @@ static struct pci_driver sil24_pci_driver = {
.id_table = sil24_pci_tbl,
.probe = sil24_init_one,
.remove = ata_pci_remove_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = sil24_pci_device_resume,
#endif
@@ -423,6 +419,10 @@ static struct ata_port_operations sil24_ops = {
#endif
};
+static bool sata_sil24_msi; /* Disable MSI */
+module_param_named(msi, sata_sil24_msi, bool, S_IRUGO);
+MODULE_PARM_DESC(msi, "Enable MSI (Default: false)");
+
/*
* Use bits 30-31 of port_flags to encode available port numbers.
* Current maxium is 4.
@@ -435,25 +435,25 @@ static const struct ata_port_info sil24_port_info[] = {
{
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
SIL24_FLAG_PCIX_IRQ_WOC,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = ATA_UDMA5, /* udma0-5 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
.port_ops = &sil24_ops,
},
/* sil_3132 */
{
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = ATA_UDMA5, /* udma0-5 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
.port_ops = &sil24_ops,
},
/* sil_3131/sil_3531 */
{
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = ATA_UDMA5, /* udma0-5 */
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
.port_ops = &sil24_ops,
},
};
@@ -503,26 +503,22 @@ static int sil24_scr_map[] = {
[SCR_ACTIVE] = 3,
};
-static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
+static int sil24_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val)
{
- void __iomem *scr_addr = sil24_port_base(ap) + PORT_SCONTROL;
+ void __iomem *scr_addr = sil24_port_base(link->ap) + PORT_SCONTROL;
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
- void __iomem *addr;
- addr = scr_addr + sil24_scr_map[sc_reg] * 4;
*val = readl(scr_addr + sil24_scr_map[sc_reg] * 4);
return 0;
}
return -EINVAL;
}
-static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val)
{
- void __iomem *scr_addr = sil24_port_base(ap) + PORT_SCONTROL;
+ void __iomem *scr_addr = sil24_port_base(link->ap) + PORT_SCONTROL;
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
- void __iomem *addr;
- addr = scr_addr + sil24_scr_map[sc_reg] * 4;
writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
return 0;
}
@@ -540,12 +536,12 @@ static void sil24_config_port(struct ata_port *ap)
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
/* zero error counters. */
- writel(0x8000, port + PORT_DECODE_ERR_THRESH);
- writel(0x8000, port + PORT_CRC_ERR_THRESH);
- writel(0x8000, port + PORT_HSHK_ERR_THRESH);
- writel(0x0000, port + PORT_DECODE_ERR_CNT);
- writel(0x0000, port + PORT_CRC_ERR_CNT);
- writel(0x0000, port + PORT_HSHK_ERR_CNT);
+ writew(0x8000, port + PORT_DECODE_ERR_THRESH);
+ writew(0x8000, port + PORT_CRC_ERR_THRESH);
+ writew(0x8000, port + PORT_HSHK_ERR_THRESH);
+ writew(0x0000, port + PORT_DECODE_ERR_CNT);
+ writew(0x0000, port + PORT_CRC_ERR_CNT);
+ writew(0x0000, port + PORT_HSHK_ERR_CNT);
/* always use 64bit activation */
writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
@@ -590,9 +586,9 @@ static int sil24_init_port(struct ata_port *ap)
sil24_clear_pmp(ap);
writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
- ata_wait_register(port + PORT_CTRL_STAT,
+ ata_wait_register(ap, port + PORT_CTRL_STAT,
PORT_CS_INIT, PORT_CS_INIT, 10, 100);
- tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ tmp = ata_wait_register(ap, port + PORT_CTRL_STAT,
PORT_CS_RDY, 0, 10, 100);
if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) {
@@ -623,11 +619,16 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
irq_enabled = readl(port + PORT_IRQ_ENABLE_SET);
writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
+ /*
+ * The barrier is required to ensure that writes to cmd_block reach
+ * the memory before the write to PORT_CMD_ACTIVATE.
+ */
+ wmb();
writel((u32)paddr, port + PORT_CMD_ACTIVATE);
writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
- irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
+ irq_stat = ata_wait_register(ap, port + PORT_IRQ_STAT, irq_mask, 0x0,
10, timeout_msec);
writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
@@ -691,7 +692,7 @@ static int sil24_softreset(struct ata_link *link, unsigned int *class,
return 0;
err:
- ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
+ ata_link_err(link, "softreset failed (%s)\n", reason);
return -EIO;
}
@@ -711,13 +712,13 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class,
* This happens often after PM DMA CS errata.
*/
if (pp->do_port_rst) {
- ata_port_printk(ap, KERN_WARNING, "controller in dubious "
- "state, performing PORT_RST\n");
+ ata_port_warn(ap,
+ "controller in dubious state, performing PORT_RST\n");
writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT);
- msleep(10);
+ ata_msleep(ap, 10);
writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
- ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
+ ata_wait_register(ap, port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
10, 5000);
/* restore port configuration */
@@ -736,7 +737,7 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class,
tout_msec = 5000;
writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
- tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ tmp = ata_wait_register(ap, port + PORT_CTRL_STAT,
PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10,
tout_msec);
@@ -770,7 +771,7 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class,
goto retry;
}
- ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason);
+ ata_link_err(link, "hardreset failed (%s)\n", reason);
return -EIO;
}
@@ -852,10 +853,21 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
if (!ata_is_atapi(qc->tf.protocol)) {
prb = &cb->ata.prb;
sge = cb->ata.sge;
+ if (ata_is_data(qc->tf.protocol)) {
+ u16 prot = 0;
+ ctrl = PRB_CTRL_PROTOCOL;
+ if (ata_is_ncq(qc->tf.protocol))
+ prot |= PRB_PROT_NCQ;
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ prot |= PRB_PROT_WRITE;
+ else
+ prot |= PRB_PROT_READ;
+ prb->prot = cpu_to_le16(prot);
+ }
} else {
prb = &cb->atapi.prb;
sge = cb->atapi.sge;
- memset(cb->atapi.cdb, 0, 32);
+ memset(cb->atapi.cdb, 0, sizeof(cb->atapi.cdb));
memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len);
if (ata_is_data(qc->tf.protocol)) {
@@ -885,6 +897,11 @@ static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
paddr = pp->cmd_block_dma + tag * sizeof(*pp->cmd_block);
activate = port + PORT_CMD_ACTIVATE + tag * 8;
+ /*
+ * The barrier is required to ensure that writes to cmd_block reach
+ * the memory before the write to PORT_CMD_ACTIVATE.
+ */
+ wmb();
writel((u32)paddr, activate);
writel((u64)paddr >> 32, activate + 4);
@@ -899,14 +916,25 @@ static bool sil24_qc_fill_rtf(struct ata_queued_cmd *qc)
static void sil24_pmp_attach(struct ata_port *ap)
{
+ u32 *gscr = ap->link.device->gscr;
+
sil24_config_pmp(ap, 1);
sil24_init_port(ap);
+
+ if (sata_pmp_gscr_vendor(gscr) == 0x11ab &&
+ sata_pmp_gscr_devid(gscr) == 0x4140) {
+ ata_port_info(ap,
+ "disabling NCQ support due to sil24-mv4140 quirk\n");
+ ap->flags &= ~ATA_FLAG_NCQ;
+ }
}
static void sil24_pmp_detach(struct ata_port *ap)
{
sil24_init_port(ap);
sil24_config_pmp(ap, 0);
+
+ ap->flags |= ATA_FLAG_NCQ;
}
static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class,
@@ -916,8 +944,7 @@ static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class,
rc = sil24_init_port(link->ap);
if (rc) {
- ata_link_printk(link, KERN_ERR,
- "hardreset failed (port not ready)\n");
+ ata_link_err(link, "hardreset failed (port not ready)\n");
return rc;
}
@@ -990,7 +1017,7 @@ static void sil24_error_intr(struct ata_port *ap)
/* deal with command error */
if (irq_stat & PORT_IRQ_ERROR) {
- struct sil24_cerr_info *ci = NULL;
+ const struct sil24_cerr_info *ci = NULL;
unsigned int err_mask = 0, action = 0;
u32 context, cerr;
int pmp;
@@ -1111,8 +1138,8 @@ static inline void sil24_host_intr(struct ata_port *ap)
/* spurious interrupts are expected if PCIX_IRQ_WOC */
if (!(ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) && ata_ratelimit())
- ata_port_printk(ap, KERN_INFO, "spurious interrupt "
- "(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
+ ata_port_info(ap,
+ "spurious interrupt (slot_stat 0x%x active_tag %d sactive 0x%x)\n",
slot_stat, ap->link.active_tag, ap->link.sactive);
}
@@ -1139,13 +1166,8 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
for (i = 0; i < host->n_ports; i++)
if (status & (1 << i)) {
- struct ata_port *ap = host->ports[i];
- if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
- sil24_host_intr(ap);
- handled++;
- } else
- printk(KERN_ERR DRV_NAME
- ": interrupt from disabled port %d\n", i);
+ sil24_host_intr(host->ports[i]);
+ handled++;
}
spin_unlock(&host->lock);
@@ -1227,12 +1249,12 @@ static void sil24_init_controller(struct ata_host *host)
tmp = readl(port + PORT_CTRL_STAT);
if (tmp & PORT_CS_PORT_RST) {
writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
- tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ tmp = ata_wait_register(NULL, port + PORT_CTRL_STAT,
PORT_CS_PORT_RST,
PORT_CS_PORT_RST, 10, 100);
if (tmp & PORT_CS_PORT_RST)
- dev_printk(KERN_ERR, host->dev,
- "failed to clear port RST\n");
+ dev_err(host->dev,
+ "failed to clear port RST\n");
}
/* configure port */
@@ -1246,7 +1268,6 @@ static void sil24_init_controller(struct ata_host *host)
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
extern int __MARKER__sil24_cmd_block_is_sized_wrongly;
- static int printed_version;
struct ata_port_info pi = sil24_port_info[ent->driver_data];
const struct ata_port_info *ppi[] = { &pi, NULL };
void __iomem * const *iomap;
@@ -1258,8 +1279,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (sizeof(union sil24_cmd_block) != PAGE_SIZE)
__MARKER__sil24_cmd_block_is_sized_wrongly = 1;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
/* acquire resources */
rc = pcim_enable_device(pdev);
@@ -1277,9 +1297,8 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (pi.flags & SIL24_FLAG_PCIX_IRQ_WOC) {
tmp = readl(iomap[SIL24_HOST_BAR] + HOST_CTRL);
if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL))
- dev_printk(KERN_INFO, &pdev->dev,
- "Applying completion IRQ loss on PCI-X "
- "errata fix\n");
+ dev_info(&pdev->dev,
+ "Applying completion IRQ loss on PCI-X errata fix\n");
else
pi.flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
}
@@ -1292,42 +1311,51 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
host->iomap = iomap;
/* configure and activate the device */
- if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
if (rc) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "64-bit DMA enable failed\n");
+ dev_err(&pdev->dev,
+ "64-bit DMA enable failed\n");
return rc;
}
}
} else {
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit DMA enable failed\n");
+ dev_err(&pdev->dev, "32-bit DMA enable failed\n");
return rc;
}
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit consistent DMA enable failed\n");
+ dev_err(&pdev->dev,
+ "32-bit consistent DMA enable failed\n");
return rc;
}
}
+ /* Set max read request size to 4096. This slightly increases
+ * write throughput for pci-e variants.
+ */
+ pcie_set_readrq(pdev, 4096);
+
sil24_init_controller(host);
+ if (sata_sil24_msi && !pci_enable_msi(pdev)) {
+ dev_info(&pdev->dev, "Using MSI\n");
+ pci_intx(pdev, 0);
+ }
+
pci_set_master(pdev);
return ata_host_activate(host, pdev->irq, sil24_interrupt, IRQF_SHARED,
&sil24_sht);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int sil24_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
int rc;
@@ -1344,7 +1372,9 @@ static int sil24_pci_device_resume(struct pci_dev *pdev)
return 0;
}
+#endif
+#ifdef CONFIG_PM
static int sil24_port_resume(struct ata_port *ap)
{
sil24_config_pmp(ap, ap->nr_pmp_links);
@@ -1352,20 +1382,9 @@ static int sil24_port_resume(struct ata_port *ap)
}
#endif
-static int __init sil24_init(void)
-{
- return pci_register_driver(&sil24_pci_driver);
-}
-
-static void __exit sil24_exit(void)
-{
- pci_unregister_driver(&sil24_pci_driver);
-}
+module_pci_driver(sil24_pci_driver);
MODULE_AUTHOR("Tejun Heo");
MODULE_DESCRIPTION("Silicon Image 3124/3132 SATA low-level driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, sil24_pci_tbl);
-
-module_init(sil24_init);
-module_exit(sil24_exit);
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 6b8e45ba32e..d1637ac40a7 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -33,7 +33,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -64,8 +63,8 @@ enum {
};
static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static const struct pci_device_id sis_pci_tbl[] = {
{ PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */
@@ -83,6 +82,10 @@ static struct pci_driver sis_pci_driver = {
.id_table = sis_pci_tbl,
.probe = sis_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
};
static struct scsi_host_template sis_sht = {
@@ -96,21 +99,22 @@ static struct ata_port_operations sis_ops = {
};
static const struct ata_port_info sis_port_info = {
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x7,
+ .flags = ATA_FLAG_SATA,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &sis_ops,
};
MODULE_AUTHOR("Uwe Koziolek");
-MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller");
+MODULE_DESCRIPTION("low-level driver for Silicon Integrated Systems SATA controller");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
+static unsigned int get_scr_cfg_addr(struct ata_link *link, unsigned int sc_reg)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
u8 pmr;
@@ -131,109 +135,76 @@ static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
break;
}
}
+ if (link->pmp)
+ addr += 0x10;
+
return addr;
}
-static u32 sis_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static u32 sis_scr_cfg_read(struct ata_link *link,
+ unsigned int sc_reg, u32 *val)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
- u32 val2 = 0;
- u8 pmr;
+ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+ unsigned int cfg_addr = get_scr_cfg_addr(link, sc_reg);
if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
- return 0xffffffff;
-
- pci_read_config_byte(pdev, SIS_PMR, &pmr);
+ return -EINVAL;
pci_read_config_dword(pdev, cfg_addr, val);
-
- if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
- (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
- pci_read_config_dword(pdev, cfg_addr+0x10, &val2);
-
- *val |= val2;
- *val &= 0xfffffffb; /* avoid problems with powerdowned ports */
-
return 0;
}
-static void sis_scr_cfg_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_cfg_write(struct ata_link *link,
+ unsigned int sc_reg, u32 val)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
- u8 pmr;
-
- if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
- return;
-
- pci_read_config_byte(pdev, SIS_PMR, &pmr);
+ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+ unsigned int cfg_addr = get_scr_cfg_addr(link, sc_reg);
pci_write_config_dword(pdev, cfg_addr, val);
-
- if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
- (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
- pci_write_config_dword(pdev, cfg_addr+0x10, val);
+ return 0;
}
-static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u8 pmr;
+ struct ata_port *ap = link->ap;
+ void __iomem *base = ap->ioaddr.scr_addr + link->pmp * 0x10;
if (sc_reg > SCR_CONTROL)
return -EINVAL;
if (ap->flags & SIS_FLAG_CFGSCR)
- return sis_scr_cfg_read(ap, sc_reg, val);
-
- pci_read_config_byte(pdev, SIS_PMR, &pmr);
-
- *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
-
- if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
- (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
- *val |= ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
-
- *val &= 0xfffffffb;
+ return sis_scr_cfg_read(link, sc_reg, val);
+ *val = ioread32(base + sc_reg * 4);
return 0;
}
-static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u8 pmr;
+ struct ata_port *ap = link->ap;
+ void __iomem *base = ap->ioaddr.scr_addr + link->pmp * 0x10;
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- pci_read_config_byte(pdev, SIS_PMR, &pmr);
-
if (ap->flags & SIS_FLAG_CFGSCR)
- sis_scr_cfg_write(ap, sc_reg, val);
- else {
- iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
- if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
- (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
- iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
- }
+ return sis_scr_cfg_write(link, sc_reg, val);
+
+ iowrite32(val, base + (sc_reg * 4));
return 0;
}
static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
struct ata_port_info pi = sis_port_info;
const struct ata_port_info *ppi[] = { &pi, &pi };
struct ata_host *host;
u32 genctl, val;
u8 pmr;
u8 port2_start = 0x20;
- int rc;
+ int i, rc;
- if (!printed_version++)
- dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
rc = pcim_enable_device(pdev);
if (rc)
@@ -271,12 +242,12 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
break;
}
if ((pmr & SIS_PMR_COMBINED) == 0) {
- dev_printk(KERN_INFO, &pdev->dev,
- "Detected SiS 180/181/964 chipset in SATA mode\n");
+ dev_info(&pdev->dev,
+ "Detected SiS 180/181/964 chipset in SATA mode\n");
port2_start = 64;
} else {
- dev_printk(KERN_INFO, &pdev->dev,
- "Detected SiS 180/181 chipset in combined mode\n");
+ dev_info(&pdev->dev,
+ "Detected SiS 180/181 chipset in combined mode\n");
port2_start = 0;
pi.flags |= ATA_FLAG_SLAVE_POSS;
}
@@ -286,33 +257,42 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
case 0x0183:
pci_read_config_dword(pdev, 0x6C, &val);
if (val & (1L << 31)) {
- dev_printk(KERN_INFO, &pdev->dev,
- "Detected SiS 182/965 chipset\n");
+ dev_info(&pdev->dev, "Detected SiS 182/965 chipset\n");
pi.flags |= ATA_FLAG_SLAVE_POSS;
} else {
- dev_printk(KERN_INFO, &pdev->dev,
- "Detected SiS 182/965L chipset\n");
+ dev_info(&pdev->dev, "Detected SiS 182/965L chipset\n");
}
break;
case 0x1182:
- dev_printk(KERN_INFO, &pdev->dev,
- "Detected SiS 1182/966/680 SATA controller\n");
+ dev_info(&pdev->dev,
+ "Detected SiS 1182/966/680 SATA controller\n");
pi.flags |= ATA_FLAG_SLAVE_POSS;
break;
case 0x1183:
- dev_printk(KERN_INFO, &pdev->dev,
- "Detected SiS 1183/966/966L/968/680 controller in PATA mode\n");
+ dev_info(&pdev->dev,
+ "Detected SiS 1183/966/966L/968/680 controller in PATA mode\n");
ppi[0] = &sis_info133_for_sata;
ppi[1] = &sis_info133_for_sata;
break;
}
- rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+ rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
if (rc)
return rc;
+ for (i = 0; i < 2; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (ap->flags & ATA_FLAG_SATA &&
+ ap->flags & ATA_FLAG_SLAVE_POSS) {
+ rc = ata_slave_link_init(ap);
+ if (rc)
+ return rc;
+ }
+ }
+
if (!(pi.flags & SIS_FLAG_CFGSCR)) {
void __iomem *mmio;
@@ -327,19 +307,8 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
pci_intx(pdev, 1);
- return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+ return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
IRQF_SHARED, &sis_sht);
}
-static int __init sis_init(void)
-{
- return pci_register_driver(&sis_pci_driver);
-}
-
-static void __exit sis_exit(void)
-{
- pci_unregister_driver(&sis_pci_driver);
-}
-
-module_init(sis_init);
-module_exit(sis_exit);
+module_pci_driver(sis_pci_driver);
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index 16aa6839aa5..c630fa81262 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -39,7 +39,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -123,23 +122,58 @@ static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
}
}
-static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int k2_sata_scr_read(struct ata_link *link,
+ unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
-static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int k2_sata_scr_write(struct ata_link *link,
+ unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
+static int k2_sata_softreset(struct ata_link *link,
+ unsigned int *class, unsigned long deadline)
+{
+ u8 dmactl;
+ void __iomem *mmio = link->ap->ioaddr.bmdma_addr;
+
+ dmactl = readb(mmio + ATA_DMA_CMD);
+
+ /* Clear the start bit */
+ if (dmactl & ATA_DMA_START) {
+ dmactl &= ~ATA_DMA_START;
+ writeb(dmactl, mmio + ATA_DMA_CMD);
+ }
+
+ return ata_sff_softreset(link, class, deadline);
+}
+
+static int k2_sata_hardreset(struct ata_link *link,
+ unsigned int *class, unsigned long deadline)
+{
+ u8 dmactl;
+ void __iomem *mmio = link->ap->ioaddr.bmdma_addr;
+
+ dmactl = readb(mmio + ATA_DMA_CMD);
+
+ /* Clear the start bit */
+ if (dmactl & ATA_DMA_START) {
+ dmactl &= ~ATA_DMA_START;
+ writeb(dmactl, mmio + ATA_DMA_CMD);
+ }
+
+ return sata_sff_hardreset(link, class, deadline);
+}
static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
{
@@ -222,7 +256,7 @@ static void k2_bmdma_setup_mmio(struct ata_queued_cmd *qc)
/* load PRD table addr. */
mb(); /* make sure PRD table writes are visible to controller */
- writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
+ writel(ap->bmdma_prd_dma, mmio + ATA_DMA_TABLE_OFS);
/* specify data direction, triple-check start bit is clear */
dmactl = readb(mmio + ATA_DMA_CMD);
@@ -253,21 +287,29 @@ static void k2_bmdma_start_mmio(struct ata_queued_cmd *qc)
/* start host DMA transaction */
dmactl = readb(mmio + ATA_DMA_CMD);
writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
- /* There is a race condition in certain SATA controllers that can
- be seen when the r/w command is given to the controller before the
- host DMA is started. On a Read command, the controller would initiate
- the command to the drive even before it sees the DMA start. When there
- are very fast drives connected to the controller, or when the data request
- hits in the drive cache, there is the possibility that the drive returns a part
- or all of the requested data to the controller before the DMA start is issued.
- In this case, the controller would become confused as to what to do with the data.
- In the worst case when all the data is returned back to the controller, the
- controller could hang. In other cases it could return partial data returning
- in data corruption. This problem has been seen in PPC systems and can also appear
- on an system with very fast disks, where the SATA controller is sitting behind a
- number of bridges, and hence there is significant latency between the r/w command
- and the start command. */
- /* issue r/w command if the access is to ATA*/
+ /* This works around possible data corruption.
+
+ On certain SATA controllers that can be seen when the r/w
+ command is given to the controller before the host DMA is
+ started.
+
+ On a Read command, the controller would initiate the
+ command to the drive even before it sees the DMA
+ start. When there are very fast drives connected to the
+ controller, or when the data request hits in the drive
+ cache, there is the possibility that the drive returns a
+ part or all of the requested data to the controller before
+ the DMA start is issued. In this case, the controller
+ would become confused as to what to do with the data. In
+ the worst case when all the data is returned back to the
+ controller, the controller could hang. In other cases it
+ could return partial data returning in data
+ corruption. This problem has been seen in PPC systems and
+ can also appear on an system with very fast disks, where
+ the SATA controller is sitting behind a number of bridges,
+ and hence there is significant latency between the r/w
+ command and the start command. */
+ /* issue r/w command if the access is to ATA */
if (qc->tf.protocol == ATA_PROT_DMA)
ap->ops->sff_exec_command(ap, &qc->tf);
}
@@ -279,23 +321,11 @@ static u8 k2_stat_check_status(struct ata_port *ap)
}
#ifdef CONFIG_PPC_OF
-/*
- * k2_sata_proc_info
- * inout : decides on the direction of the dataflow and the meaning of the
- * variables
- * buffer: If inout==FALSE data is being written to it else read from it
- * *start: If inout==FALSE start of the valid data in the buffer
- * offset: If inout==FALSE offset from the beginning of the imaginary file
- * from which we start writing into the buffer
- * length: If inout==FALSE max number of bytes to be written into the buffer
- * else number of bytes in the buffer
- */
-static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start,
- off_t offset, int count, int inout)
+static int k2_sata_show_info(struct seq_file *m, struct Scsi_Host *shost)
{
struct ata_port *ap;
struct device_node *np;
- int len, index;
+ int index;
/* Find the ata_port */
ap = ata_shost_to_port(shost);
@@ -313,15 +343,12 @@ static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start,
const u32 *reg = of_get_property(np, "reg", NULL);
if (!reg)
continue;
- if (index == *reg)
+ if (index == *reg) {
+ seq_printf(m, "devspec: %s\n", np->full_name);
break;
+ }
}
- if (np == NULL)
- return 0;
-
- len = sprintf(page, "devspec: %s\n", np->full_name);
-
- return len;
+ return 0;
}
#endif /* CONFIG_PPC_OF */
@@ -329,13 +356,15 @@ static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start,
static struct scsi_host_template k2_sata_sht = {
ATA_BMDMA_SHT(DRV_NAME),
#ifdef CONFIG_PPC_OF
- .proc_info = k2_sata_proc_info,
+ .show_info = k2_sata_show_info,
#endif
};
static struct ata_port_operations k2_sata_ops = {
.inherits = &ata_bmdma_port_ops,
+ .softreset = k2_sata_softreset,
+ .hardreset = k2_sata_hardreset,
.sff_tf_load = k2_sata_tf_load,
.sff_tf_read = k2_sata_tf_read,
.sff_check_status = k2_stat_check_status,
@@ -349,38 +378,34 @@ static struct ata_port_operations k2_sata_ops = {
static const struct ata_port_info k2_port_info[] = {
/* chip_svw4 */
{
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .flags = ATA_FLAG_SATA | K2_FLAG_NO_ATAPI_DMA,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &k2_sata_ops,
},
/* chip_svw8 */
{
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA |
+ .flags = ATA_FLAG_SATA | K2_FLAG_NO_ATAPI_DMA |
K2_FLAG_SATA_8_PORTS,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &k2_sata_ops,
},
/* chip_svw42 */
{
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | K2_FLAG_BAR_POS_3,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .flags = ATA_FLAG_SATA | K2_FLAG_BAR_POS_3,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &k2_sata_ops,
},
/* chip_svw43 */
{
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .flags = ATA_FLAG_SATA,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &k2_sata_ops,
},
@@ -408,15 +433,13 @@ static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base)
static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
const struct ata_port_info *ppi[] =
{ &k2_port_info[ent->driver_data], NULL };
struct ata_host *host;
void __iomem *mmio_base;
int n_ports, i, rc, bar_pos;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
/* allocate host */
n_ports = 4;
@@ -492,7 +515,7 @@ static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *en
writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
pci_set_master(pdev);
- return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+ return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
IRQF_SHARED, &k2_sata_sht);
}
@@ -521,21 +544,10 @@ static struct pci_driver k2_sata_pci_driver = {
.remove = ata_pci_remove_one,
};
-static int __init k2_sata_init(void)
-{
- return pci_register_driver(&k2_sata_pci_driver);
-}
-
-static void __exit k2_sata_exit(void)
-{
- pci_unregister_driver(&k2_sata_pci_driver);
-}
+module_pci_driver(k2_sata_pci_driver);
MODULE_AUTHOR("Benjamin Herrenschmidt");
MODULE_DESCRIPTION("low-level driver for K2 SATA controller");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, k2_sata_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
-module_init(k2_sata_init);
-module_exit(k2_sata_exit);
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index ec04b8d3c79..39b5de60a1f 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -1,7 +1,7 @@
/*
* sata_sx4.c - Promise SATA
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -81,7 +81,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
+#include <linux/slab.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -193,6 +193,7 @@ enum {
PDC_TIMER_MASK_INT,
};
+#define ECC_ERASE_BUF_SZ (128 * 1024)
struct pdc_port_priv {
u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
@@ -213,8 +214,9 @@ struct pdc_host_priv {
static int pdc_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static void pdc_eng_timeout(struct ata_port *ap);
-static void pdc_20621_phy_reset(struct ata_port *ap);
+static void pdc_error_handler(struct ata_port *ap);
+static void pdc_freeze(struct ata_port *ap);
+static void pdc_thaw(struct ata_port *ap);
static int pdc_port_start(struct ata_port *ap);
static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
@@ -233,6 +235,10 @@ static void pdc20621_put_to_dimm(struct ata_host *host,
void *psource, u32 offset, u32 size);
static void pdc20621_irq_clear(struct ata_port *ap);
static unsigned int pdc20621_qc_issue(struct ata_queued_cmd *qc);
+static int pdc_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline);
+static void pdc_post_internal_cmd(struct ata_queued_cmd *qc);
+static int pdc_check_atapi_dma(struct ata_queued_cmd *qc);
static struct scsi_host_template pdc_sata_sht = {
@@ -243,30 +249,33 @@ static struct scsi_host_template pdc_sata_sht = {
/* TODO: inherit from base port_ops after converting to new EH */
static struct ata_port_operations pdc_20621_ops = {
- .sff_tf_load = pdc_tf_load_mmio,
- .sff_tf_read = ata_sff_tf_read,
- .sff_check_status = ata_sff_check_status,
- .sff_exec_command = pdc_exec_command_mmio,
- .sff_dev_select = ata_sff_dev_select,
- .phy_reset = pdc_20621_phy_reset,
+ .inherits = &ata_sff_port_ops,
+
+ .check_atapi_dma = pdc_check_atapi_dma,
.qc_prep = pdc20621_qc_prep,
.qc_issue = pdc20621_qc_issue,
- .qc_fill_rtf = ata_sff_qc_fill_rtf,
- .sff_data_xfer = ata_sff_data_xfer,
- .eng_timeout = pdc_eng_timeout,
- .sff_irq_clear = pdc20621_irq_clear,
- .sff_irq_on = ata_sff_irq_on,
+
+ .freeze = pdc_freeze,
+ .thaw = pdc_thaw,
+ .softreset = pdc_softreset,
+ .error_handler = pdc_error_handler,
+ .lost_interrupt = ATA_OP_NULL,
+ .post_internal_cmd = pdc_post_internal_cmd,
+
.port_start = pdc_port_start,
+
+ .sff_tf_load = pdc_tf_load_mmio,
+ .sff_exec_command = pdc_exec_command_mmio,
+ .sff_irq_clear = pdc20621_irq_clear,
};
static const struct ata_port_info pdc_port_info[] = {
/* board_20621 */
{
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO |
- ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_ATAPI |
+ ATA_FLAG_PIO_POLLING,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &pdc_20621_ops,
},
@@ -291,11 +300,6 @@ static int pdc_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
struct pdc_port_priv *pp;
- int rc;
-
- rc = ata_port_start(ap);
- if (rc)
- return rc;
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
@@ -310,17 +314,8 @@ static int pdc_port_start(struct ata_port *ap)
return 0;
}
-static void pdc_20621_phy_reset(struct ata_port *ap)
-{
- VPRINTK("ENTER\n");
- ap->cbl = ATA_CBL_SATA;
- ata_port_probe(ap);
- ata_bus_reset(ap);
-}
-
-static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
- unsigned int portno,
- unsigned int total_len)
+static inline void pdc20621_ata_sg(u8 *buf, unsigned int portno,
+ unsigned int total_len)
{
u32 addr;
unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
@@ -340,9 +335,8 @@ static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
buf32[dw], buf32[dw + 1]);
}
-static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
- unsigned int portno,
- unsigned int total_len)
+static inline void pdc20621_host_sg(u8 *buf, unsigned int portno,
+ unsigned int total_len)
{
u32 addr;
unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
@@ -489,10 +483,10 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
/*
* Build ATA, host DMA packets
*/
- pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+ pdc20621_host_sg(&pp->dimm_buf[0], portno, total_len);
pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
- pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+ pdc20621_ata_sg(&pp->dimm_buf[0], portno, total_len);
i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
if (qc->tf.flags & ATA_TFLAG_LBA48)
@@ -686,8 +680,11 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc)
static unsigned int pdc20621_qc_issue(struct ata_queued_cmd *qc)
{
switch (qc->tf.protocol) {
- case ATA_PROT_DMA:
case ATA_PROT_NODATA:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ break;
+ /*FALLTHROUGH*/
+ case ATA_PROT_DMA:
pdc20621_packet_start(qc);
return 0;
@@ -786,12 +783,7 @@ static inline unsigned int pdc20621_host_intr(struct ata_port *ap,
static void pdc20621_irq_clear(struct ata_port *ap)
{
- struct ata_host *host = ap->host;
- void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
-
- mmio += PDC_CHIP0_OFS;
-
- readl(mmio + PDC_20621_SEQMASK);
+ ioread8(ap->ioaddr.status_addr);
}
static irqreturn_t pdc20621_interrupt(int irq, void *dev_instance)
@@ -839,8 +831,7 @@ static irqreturn_t pdc20621_interrupt(int irq, void *dev_instance)
ap = host->ports[port_no];
tmp = mask & (1 << i);
VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
- if (tmp && ap &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
+ if (tmp && ap) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->link.active_tag);
@@ -859,46 +850,119 @@ static irqreturn_t pdc20621_interrupt(int irq, void *dev_instance)
return IRQ_RETVAL(handled);
}
-static void pdc_eng_timeout(struct ata_port *ap)
+static void pdc_freeze(struct ata_port *ap)
{
- u8 drv_stat;
- struct ata_host *host = ap->host;
- struct ata_queued_cmd *qc;
- unsigned long flags;
+ void __iomem *mmio = ap->ioaddr.cmd_addr;
+ u32 tmp;
- DPRINTK("ENTER\n");
+ /* FIXME: if all 4 ATA engines are stopped, also stop HDMA engine */
- spin_lock_irqsave(&host->lock, flags);
+ tmp = readl(mmio + PDC_CTLSTAT);
+ tmp |= PDC_MASK_INT;
+ tmp &= ~PDC_DMA_ENABLE;
+ writel(tmp, mmio + PDC_CTLSTAT);
+ readl(mmio + PDC_CTLSTAT); /* flush */
+}
- qc = ata_qc_from_tag(ap, ap->link.active_tag);
+static void pdc_thaw(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->ioaddr.cmd_addr;
+ u32 tmp;
- switch (qc->tf.protocol) {
- case ATA_PROT_DMA:
- case ATA_PROT_NODATA:
- ata_port_printk(ap, KERN_ERR, "command timeout\n");
- qc->err_mask |= __ac_err_mask(ata_wait_idle(ap));
- break;
+ /* FIXME: start HDMA engine, if zero ATA engines running */
- default:
- drv_stat = ata_sff_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+ /* clear IRQ */
+ ioread8(ap->ioaddr.status_addr);
+
+ /* turn IRQ back on */
+ tmp = readl(mmio + PDC_CTLSTAT);
+ tmp &= ~PDC_MASK_INT;
+ writel(tmp, mmio + PDC_CTLSTAT);
+ readl(mmio + PDC_CTLSTAT); /* flush */
+}
- ata_port_printk(ap, KERN_ERR,
- "unknown timeout, cmd 0x%x stat 0x%x\n",
- qc->tf.command, drv_stat);
+static void pdc_reset_port(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT;
+ unsigned int i;
+ u32 tmp;
- qc->err_mask |= ac_err_mask(drv_stat);
- break;
+ /* FIXME: handle HDMA copy engine */
+
+ for (i = 11; i > 0; i--) {
+ tmp = readl(mmio);
+ if (tmp & PDC_RESET)
+ break;
+
+ udelay(100);
+
+ tmp |= PDC_RESET;
+ writel(tmp, mmio);
}
- spin_unlock_irqrestore(&host->lock, flags);
- ata_eh_qc_complete(qc);
- DPRINTK("EXIT\n");
+ tmp &= ~PDC_RESET;
+ writel(tmp, mmio);
+ readl(mmio); /* flush */
+}
+
+static int pdc_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ pdc_reset_port(link->ap);
+ return ata_sff_softreset(link, class, deadline);
+}
+
+static void pdc_error_handler(struct ata_port *ap)
+{
+ if (!(ap->pflags & ATA_PFLAG_FROZEN))
+ pdc_reset_port(ap);
+
+ ata_sff_error_handler(ap);
+}
+
+static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ /* make DMA engine forget about the failed command */
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ pdc_reset_port(ap);
+}
+
+static int pdc_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ u8 *scsicmd = qc->scsicmd->cmnd;
+ int pio = 1; /* atapi dma off by default */
+
+ /* Whitelist commands that may use DMA. */
+ switch (scsicmd[0]) {
+ case WRITE_12:
+ case WRITE_10:
+ case WRITE_6:
+ case READ_12:
+ case READ_10:
+ case READ_6:
+ case 0xad: /* READ_DVD_STRUCTURE */
+ case 0xbe: /* READ_CD */
+ pio = 0;
+ }
+ /* -45150 (FFFF4FA2) to -1 (FFFFFFFF) shall use PIO mode */
+ if (scsicmd[0] == WRITE_10) {
+ unsigned int lba =
+ (scsicmd[2] << 24) |
+ (scsicmd[3] << 16) |
+ (scsicmd[4] << 8) |
+ scsicmd[5];
+ if (lba >= 0xFFFF4FA2)
+ pio = 1;
+ }
+ return pio;
}
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
{
WARN_ON(tf->protocol == ATA_PROT_DMA ||
- tf->protocol == ATA_PROT_NODATA);
+ tf->protocol == ATAPI_PROT_DMA);
ata_sff_tf_load(ap, tf);
}
@@ -906,7 +970,7 @@ static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
{
WARN_ON(tf->protocol == ATA_PROT_DMA ||
- tf->protocol == ATA_PROT_NODATA);
+ tf->protocol == ATAPI_PROT_DMA);
ata_sff_exec_command(ap, tf);
}
@@ -956,8 +1020,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
idx++;
dist = ((long) (window_size - (offset + size))) >= 0 ? size :
(long) (window_size - offset);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
- dist);
+ memcpy_fromio(psource, dimm_mmio + offset / 4, dist);
psource += dist;
size -= dist;
@@ -966,8 +1029,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
readl(mmio + PDC_GENERAL_CTLR);
writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio),
- window_size / 4);
+ memcpy_fromio(psource, dimm_mmio, window_size / 4);
psource += window_size;
size -= window_size;
idx++;
@@ -978,8 +1040,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
readl(mmio + PDC_GENERAL_CTLR);
writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio),
- size / 4);
+ memcpy_fromio(psource, dimm_mmio, size / 4);
}
}
#endif
@@ -1208,7 +1269,6 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
{
int speed, size, length;
u32 addr, spd0, pci_status;
- u32 tmp = 0;
u32 time_period = 0;
u32 tcount = 0;
u32 ticks = 0;
@@ -1323,14 +1383,17 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
PDC_DIMM_SPD_TYPE, &spd0);
if (spd0 == 0x02) {
+ void *buf;
VPRINTK("Start ECC initialization\n");
addr = 0;
length = size * 1024 * 1024;
+ buf = kzalloc(ECC_ERASE_BUF_SZ, GFP_KERNEL);
while (addr < length) {
- pdc20621_put_to_dimm(host, (void *) &tmp, addr,
- sizeof(u32));
- addr += sizeof(u32);
+ pdc20621_put_to_dimm(host, buf, addr,
+ ECC_ERASE_BUF_SZ);
+ addr += ECC_ERASE_BUF_SZ;
}
+ kfree(buf);
VPRINTK("Finish ECC initialization\n");
}
return 0;
@@ -1371,15 +1434,13 @@ static void pdc_20621_init(struct ata_host *host)
static int pdc_sata_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- static int printed_version;
const struct ata_port_info *ppi[] =
{ &pdc_port_info[ent->driver_data], NULL };
struct ata_host *host;
struct pdc_host_priv *hpriv;
int i, rc;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
/* allocate host */
host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);
@@ -1431,24 +1492,10 @@ static int pdc_sata_init_one(struct pci_dev *pdev,
IRQF_SHARED, &pdc_sata_sht);
}
-
-static int __init pdc_sata_init(void)
-{
- return pci_register_driver(&pdc_sata_pci_driver);
-}
-
-
-static void __exit pdc_sata_exit(void)
-{
- pci_unregister_driver(&pdc_sata_pci_driver);
-}
-
+module_pci_driver(pdc_sata_pci_driver);
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("Promise SATA low-level driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
-module_init(pdc_sata_init);
-module_exit(pdc_sata_exit);
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index f277cea904c..08f98c3ed5c 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -26,8 +26,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/gfp.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -57,8 +57,8 @@ struct uli_priv {
};
static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static int uli_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int uli_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int uli_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int uli_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static const struct pci_device_id uli_pci_tbl[] = {
{ PCI_VDEVICE(AL, 0x5289), uli_5289 },
@@ -83,12 +83,12 @@ static struct ata_port_operations uli_ops = {
.inherits = &ata_bmdma_port_ops,
.scr_read = uli_scr_read,
.scr_write = uli_scr_write,
+ .hardreset = ATA_OP_NULL,
};
static const struct ata_port_info uli_port_info = {
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_IGN_SIMPLEX,
- .pio_mask = 0x1f, /* pio0-4 */
+ .flags = ATA_FLAG_SATA | ATA_FLAG_IGN_SIMPLEX,
+ .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &uli_ops,
};
@@ -106,45 +106,44 @@ static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg);
}
-static u32 uli_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg)
+static u32 uli_scr_cfg_read(struct ata_link *link, unsigned int sc_reg)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
+ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+ unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg);
u32 val;
pci_read_config_dword(pdev, cfg_addr, &val);
return val;
}
-static void uli_scr_cfg_write(struct ata_port *ap, unsigned int scr, u32 val)
+static void uli_scr_cfg_write(struct ata_link *link, unsigned int scr, u32 val)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap, scr);
+ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+ unsigned int cfg_addr = get_scr_cfg_addr(link->ap, scr);
pci_write_config_dword(pdev, cfg_addr, val);
}
-static int uli_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int uli_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = uli_scr_cfg_read(ap, sc_reg);
+ *val = uli_scr_cfg_read(link, sc_reg);
return 0;
}
-static int uli_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int uli_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
return -EINVAL;
- uli_scr_cfg_write(ap, sc_reg, val);
+ uli_scr_cfg_write(link, sc_reg, val);
return 0;
}
static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
const struct ata_port_info *ppi[] = { &uli_port_info, NULL };
unsigned int board_idx = (unsigned int) ent->driver_data;
struct ata_host *host;
@@ -153,8 +152,7 @@ static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_ioports *ioaddr;
int n_ports, rc;
- if (!printed_version++)
- dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
rc = pcim_enable_device(pdev);
if (rc)
@@ -179,9 +177,7 @@ static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- rc = ata_pci_bmdma_init(host);
- if (rc)
- return rc;
+ ata_pci_bmdma_init(host);
iomap = host->iomap;
@@ -242,20 +238,8 @@ static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
pci_intx(pdev, 1);
- return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+ return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
IRQF_SHARED, &uli_sht);
}
-static int __init uli_init(void)
-{
- return pci_register_driver(&uli_pci_driver);
-}
-
-static void __exit uli_exit(void)
-{
- pci_unregister_driver(&uli_pci_driver);
-}
-
-
-module_init(uli_init);
-module_exit(uli_exit);
+module_pci_driver(uli_pci_driver);
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 96deeb354e1..47bf89464ce 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -1,7 +1,7 @@
/*
* sata_via.c - VIA Serial ATA controllers
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -36,19 +36,25 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "sata_via"
-#define DRV_VERSION "2.3"
+#define DRV_VERSION "2.6"
+/*
+ * vt8251 is different from other sata controllers of VIA. It has two
+ * channels, each channel has both Master and Slave slot.
+ */
enum board_ids_enum {
vt6420,
vt6421,
+ vt8251,
};
enum {
@@ -68,22 +74,27 @@ enum {
};
static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
+static int vt8251_scr_read(struct ata_link *link, unsigned int scr, u32 *val);
+static int vt8251_scr_write(struct ata_link *link, unsigned int scr, u32 val);
+static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
static void svia_noop_freeze(struct ata_port *ap);
static int vt6420_prereset(struct ata_link *link, unsigned long deadline);
+static void vt6420_bmdma_start(struct ata_queued_cmd *qc);
static int vt6421_pata_cable_detect(struct ata_port *ap);
static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev);
static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev);
static const struct pci_device_id svia_pci_tbl[] = {
{ PCI_VDEVICE(VIA, 0x5337), vt6420 },
- { PCI_VDEVICE(VIA, 0x0591), vt6420 },
- { PCI_VDEVICE(VIA, 0x3149), vt6420 },
- { PCI_VDEVICE(VIA, 0x3249), vt6421 },
- { PCI_VDEVICE(VIA, 0x5287), vt6420 },
+ { PCI_VDEVICE(VIA, 0x0591), vt6420 }, /* 2 sata chnls (Master) */
+ { PCI_VDEVICE(VIA, 0x3149), vt6420 }, /* 2 sata chnls (Master) */
+ { PCI_VDEVICE(VIA, 0x3249), vt6421 }, /* 2 sata chnls, 1 pata chnl */
{ PCI_VDEVICE(VIA, 0x5372), vt6420 },
{ PCI_VDEVICE(VIA, 0x7372), vt6420 },
+ { PCI_VDEVICE(VIA, 0x5287), vt8251 }, /* 2 sata chnls (Master/Slave) */
+ { PCI_VDEVICE(VIA, 0x9000), vt8251 },
{ } /* terminate list */
};
@@ -92,7 +103,7 @@ static struct pci_driver svia_pci_driver = {
.name = DRV_NAME,
.id_table = svia_pci_tbl,
.probe = svia_init_one,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
@@ -103,78 +114,199 @@ static struct scsi_host_template svia_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
-static struct ata_port_operations vt6420_sata_ops = {
+static struct ata_port_operations svia_base_ops = {
.inherits = &ata_bmdma_port_ops,
+ .sff_tf_load = svia_tf_load,
+};
+
+static struct ata_port_operations vt6420_sata_ops = {
+ .inherits = &svia_base_ops,
.freeze = svia_noop_freeze,
.prereset = vt6420_prereset,
+ .bmdma_start = vt6420_bmdma_start,
};
static struct ata_port_operations vt6421_pata_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &svia_base_ops,
.cable_detect = vt6421_pata_cable_detect,
.set_piomode = vt6421_set_pio_mode,
.set_dmamode = vt6421_set_dma_mode,
};
static struct ata_port_operations vt6421_sata_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &svia_base_ops,
.scr_read = svia_scr_read,
.scr_write = svia_scr_write,
};
+static struct ata_port_operations vt8251_ops = {
+ .inherits = &svia_base_ops,
+ .hardreset = sata_std_hardreset,
+ .scr_read = vt8251_scr_read,
+ .scr_write = vt8251_scr_write,
+};
+
static const struct ata_port_info vt6420_port_info = {
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .flags = ATA_FLAG_SATA,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &vt6420_sata_ops,
};
static struct ata_port_info vt6421_sport_info = {
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .flags = ATA_FLAG_SATA,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &vt6421_sata_ops,
};
static struct ata_port_info vt6421_pport_info = {
- .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY,
- .pio_mask = 0x1f,
- .mwdma_mask = 0,
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ /* No MWDMA */
.udma_mask = ATA_UDMA6,
.port_ops = &vt6421_pata_ops,
};
+static struct ata_port_info vt8251_port_info = {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_SLAVE_POSS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &vt8251_ops,
+};
+
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+ *val = ioread32(link->ap->ioaddr.scr_addr + (4 * sc_reg));
return 0;
}
-static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+ iowrite32(val, link->ap->ioaddr.scr_addr + (4 * sc_reg));
+ return 0;
+}
+
+static int vt8251_scr_read(struct ata_link *link, unsigned int scr, u32 *val)
+{
+ static const u8 ipm_tbl[] = { 1, 2, 6, 0 };
+ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+ int slot = 2 * link->ap->port_no + link->pmp;
+ u32 v = 0;
+ u8 raw;
+
+ switch (scr) {
+ case SCR_STATUS:
+ pci_read_config_byte(pdev, 0xA0 + slot, &raw);
+
+ /* read the DET field, bit0 and 1 of the config byte */
+ v |= raw & 0x03;
+
+ /* read the SPD field, bit4 of the configure byte */
+ if (raw & (1 << 4))
+ v |= 0x02 << 4;
+ else
+ v |= 0x01 << 4;
+
+ /* read the IPM field, bit2 and 3 of the config byte */
+ v |= ipm_tbl[(raw >> 2) & 0x3];
+ break;
+
+ case SCR_ERROR:
+ /* devices other than 5287 uses 0xA8 as base */
+ WARN_ON(pdev->device != 0x5287);
+ pci_read_config_dword(pdev, 0xB0 + slot * 4, &v);
+ break;
+
+ case SCR_CONTROL:
+ pci_read_config_byte(pdev, 0xA4 + slot, &raw);
+
+ /* read the DET field, bit0 and bit1 */
+ v |= ((raw & 0x02) << 1) | (raw & 0x01);
+
+ /* read the IPM field, bit2 and bit3 */
+ v |= ((raw >> 2) & 0x03) << 8;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ *val = v;
return 0;
}
+static int vt8251_scr_write(struct ata_link *link, unsigned int scr, u32 val)
+{
+ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+ int slot = 2 * link->ap->port_no + link->pmp;
+ u32 v = 0;
+
+ switch (scr) {
+ case SCR_ERROR:
+ /* devices other than 5287 uses 0xA8 as base */
+ WARN_ON(pdev->device != 0x5287);
+ pci_write_config_dword(pdev, 0xB0 + slot * 4, val);
+ return 0;
+
+ case SCR_CONTROL:
+ /* set the DET field */
+ v |= ((val & 0x4) >> 1) | (val & 0x1);
+
+ /* set the IPM field */
+ v |= ((val >> 8) & 0x3) << 2;
+
+ pci_write_config_byte(pdev, 0xA4 + slot, v);
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * svia_tf_load - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @tf: ATA taskfile register set
+ *
+ * Outputs ATA taskfile to standard ATA host controller.
+ *
+ * This is to fix the internal bug of via chipsets, which will
+ * reset the device register after changing the IEN bit on ctl
+ * register.
+ */
+static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ struct ata_taskfile ttf;
+
+ if (tf->ctl != ap->last_ctl) {
+ ttf = *tf;
+ ttf.flags |= ATA_TFLAG_DEVICE;
+ tf = &ttf;
+ }
+ ata_sff_tf_load(ap, tf);
+}
+
static void svia_noop_freeze(struct ata_port *ap)
{
/* Some VIA controllers choke if ATA_NIEN is manipulated in
* certain way. Leave it alone and just clear pending IRQ.
*/
ap->ops->sff_check_status(ap);
- ata_sff_irq_clear(ap);
+ ata_bmdma_irq_clear(ap);
}
/**
@@ -210,29 +342,29 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
goto skip_scr;
/* Resume phy. This is the old SATA resume sequence */
- svia_scr_write(ap, SCR_CONTROL, 0x300);
- svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */
+ svia_scr_write(link, SCR_CONTROL, 0x300);
+ svia_scr_read(link, SCR_CONTROL, &scontrol); /* flush */
/* wait for phy to become ready, if necessary */
do {
- msleep(200);
- svia_scr_read(ap, SCR_STATUS, &sstatus);
+ ata_msleep(link->ap, 200);
+ svia_scr_read(link, SCR_STATUS, &sstatus);
if ((sstatus & 0xf) != 1)
break;
} while (time_before(jiffies, timeout));
/* open code sata_print_link_status() */
- svia_scr_read(ap, SCR_STATUS, &sstatus);
- svia_scr_read(ap, SCR_CONTROL, &scontrol);
+ svia_scr_read(link, SCR_STATUS, &sstatus);
+ svia_scr_read(link, SCR_CONTROL, &scontrol);
online = (sstatus & 0xf) == 0x3;
- ata_port_printk(ap, KERN_INFO,
- "SATA link %s 1.5 Gbps (SStatus %X SControl %X)\n",
- online ? "up" : "down", sstatus, scontrol);
+ ata_port_info(ap,
+ "SATA link %s 1.5 Gbps (SStatus %X SControl %X)\n",
+ online ? "up" : "down", sstatus, scontrol);
/* SStatus is read one more time */
- svia_scr_read(ap, SCR_STATUS, &sstatus);
+ svia_scr_read(link, SCR_STATUS, &sstatus);
if (!online) {
/* tell EH to bail */
@@ -247,6 +379,17 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
return 0;
}
+static void vt6420_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ if ((qc->tf.command == ATA_CMD_PACKET) &&
+ (qc->scsicmd->sc_data_direction == DMA_TO_DEVICE)) {
+ /* Prevents corruption on some ATAPI burners */
+ ata_sff_pause(ap);
+ }
+ ata_bmdma_start(qc);
+}
+
static int vt6421_pata_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -262,14 +405,16 @@ static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const u8 pio_bits[] = { 0xA8, 0x65, 0x65, 0x31, 0x20 };
- pci_write_config_byte(pdev, PATA_PIO_TIMING, pio_bits[adev->pio_mode - XFER_PIO_0]);
+ pci_write_config_byte(pdev, PATA_PIO_TIMING - adev->devno,
+ pio_bits[adev->pio_mode - XFER_PIO_0]);
}
static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const u8 udma_bits[] = { 0xEE, 0xE8, 0xE6, 0xE4, 0xE2, 0xE1, 0xE0, 0xE0 };
- pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->dma_mode - XFER_UDMA_0]);
+ pci_write_config_byte(pdev, PATA_UDMA_TIMING - adev->devno,
+ udma_bits[adev->dma_mode - XFER_UDMA_0]);
}
static const unsigned int svia_bar_sizes[] = {
@@ -316,14 +461,14 @@ static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
struct ata_host *host;
int rc;
- rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+ rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
if (rc)
return rc;
*r_host = host;
rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n");
+ dev_err(&pdev->dev, "failed to iomap PCI BAR 5\n");
return rc;
}
@@ -342,14 +487,14 @@ static int vt6421_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
*r_host = host = ata_host_alloc_pinfo(&pdev->dev, ppi, ARRAY_SIZE(ppi));
if (!host) {
- dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n");
+ dev_err(&pdev->dev, "failed to allocate host\n");
return -ENOMEM;
}
rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME);
if (rc) {
- dev_printk(KERN_ERR, &pdev->dev, "failed to request/iomap "
- "PCI BARs (errno=%d)\n", rc);
+ dev_err(&pdev->dev, "failed to request/iomap PCI BARs (errno=%d)\n",
+ rc);
return rc;
}
host->iomap = pcim_iomap_table(pdev);
@@ -367,20 +512,43 @@ static int vt6421_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
return 0;
}
-static void svia_configure(struct pci_dev *pdev)
+static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
+{
+ const struct ata_port_info *ppi[] = { &vt8251_port_info, NULL };
+ struct ata_host *host;
+ int i, rc;
+
+ rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
+ if (rc)
+ return rc;
+ *r_host = host;
+
+ rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to iomap PCI BAR 5\n");
+ return rc;
+ }
+
+ /* 8251 hosts four sata ports as M/S of the two channels */
+ for (i = 0; i < host->n_ports; i++)
+ ata_slave_link_init(host->ports[i]);
+
+ return 0;
+}
+
+static void svia_configure(struct pci_dev *pdev, int board_id)
{
u8 tmp8;
pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8);
- dev_printk(KERN_INFO, &pdev->dev, "routed to hard irq line %d\n",
- (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
+ dev_info(&pdev->dev, "routed to hard irq line %d\n",
+ (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
/* make sure SATA channels are enabled */
pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8);
if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
- dev_printk(KERN_DEBUG, &pdev->dev,
- "enabling SATA channels (0x%x)\n",
- (int) tmp8);
+ dev_dbg(&pdev->dev, "enabling SATA channels (0x%x)\n",
+ (int)tmp8);
tmp8 |= ALL_PORTS;
pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
}
@@ -388,9 +556,8 @@ static void svia_configure(struct pci_dev *pdev)
/* make sure interrupts for each channel sent to us */
pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8);
if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
- dev_printk(KERN_DEBUG, &pdev->dev,
- "enabling SATA channel interrupts (0x%x)\n",
- (int) tmp8);
+ dev_dbg(&pdev->dev, "enabling SATA channel interrupts (0x%x)\n",
+ (int) tmp8);
tmp8 |= ALL_PORTS;
pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
}
@@ -398,39 +565,65 @@ static void svia_configure(struct pci_dev *pdev)
/* make sure native mode is enabled */
pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8);
if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
- dev_printk(KERN_DEBUG, &pdev->dev,
- "enabling SATA channel native mode (0x%x)\n",
- (int) tmp8);
+ dev_dbg(&pdev->dev,
+ "enabling SATA channel native mode (0x%x)\n",
+ (int) tmp8);
tmp8 |= NATIVE_MODE_ALL;
pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
}
+
+ /*
+ * vt6420/1 has problems talking to some drives. The following
+ * is the fix from Joseph Chan <JosephChan@via.com.tw>.
+ *
+ * When host issues HOLD, device may send up to 20DW of data
+ * before acknowledging it with HOLDA and the host should be
+ * able to buffer them in FIFO. Unfortunately, some WD drives
+ * send up to 40DW before acknowledging HOLD and, in the
+ * default configuration, this ends up overflowing vt6421's
+ * FIFO, making the controller abort the transaction with
+ * R_ERR.
+ *
+ * Rx52[2] is the internal 128DW FIFO Flow control watermark
+ * adjusting mechanism enable bit and the default value 0
+ * means host will issue HOLD to device when the left FIFO
+ * size goes below 32DW. Setting it to 1 makes the watermark
+ * 64DW.
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=15173
+ * http://article.gmane.org/gmane.linux.ide/46352
+ * http://thread.gmane.org/gmane.linux.kernel/1062139
+ */
+ if (board_id == vt6420 || board_id == vt6421) {
+ pci_read_config_byte(pdev, 0x52, &tmp8);
+ tmp8 |= 1 << 2;
+ pci_write_config_byte(pdev, 0x52, tmp8);
+ }
}
static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version;
unsigned int i;
int rc;
- struct ata_host *host;
+ struct ata_host *host = NULL;
int board_id = (int) ent->driver_data;
const unsigned *bar_sizes;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- if (board_id == vt6420)
- bar_sizes = &svia_bar_sizes[0];
- else
+ if (board_id == vt6421)
bar_sizes = &vt6421_bar_sizes[0];
+ else
+ bar_sizes = &svia_bar_sizes[0];
for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
if ((pci_resource_start(pdev, i) == 0) ||
(pci_resource_len(pdev, i) < bar_sizes[i])) {
- dev_printk(KERN_ERR, &pdev->dev,
+ dev_err(&pdev->dev,
"invalid PCI BAR %u (sz 0x%llx, val 0x%llx)\n",
i,
(unsigned long long)pci_resource_start(pdev, i),
@@ -438,29 +631,27 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return -ENODEV;
}
- if (board_id == vt6420)
+ switch (board_id) {
+ case vt6420:
rc = vt6420_prepare_host(pdev, &host);
- else
+ break;
+ case vt6421:
rc = vt6421_prepare_host(pdev, &host);
+ break;
+ case vt8251:
+ rc = vt8251_prepare_host(pdev, &host);
+ break;
+ default:
+ rc = -EINVAL;
+ }
if (rc)
return rc;
- svia_configure(pdev);
+ svia_configure(pdev, board_id);
pci_set_master(pdev);
- return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+ return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
IRQF_SHARED, &svia_sht);
}
-static int __init svia_init(void)
-{
- return pci_register_driver(&svia_pci_driver);
-}
-
-static void __exit svia_exit(void)
-{
- pci_unregister_driver(&svia_pci_driver);
-}
-
-module_init(svia_init);
-module_exit(svia_exit);
+module_pci_driver(svia_pci_driver);
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index f3d635c0a2e..29e847aac34 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -37,7 +37,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -98,20 +97,22 @@ enum {
VSC_SATA_INT_PHY_CHANGE),
};
-static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int vsc_sata_scr_read(struct ata_link *link,
+ unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
-static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int vsc_sata_scr_write(struct ata_link *link,
+ unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
@@ -243,7 +244,7 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap)
qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING)))
- handled = ata_sff_host_intr(ap, qc);
+ handled = ata_bmdma_port_intr(ap, qc);
/* We received an interrupt during a polled command,
* or some other spurious condition. Interrupt reporting
@@ -271,9 +272,8 @@ static irqreturn_t vsc_sata_interrupt(int irq, void *dev_instance)
if (unlikely(status == 0xffffffff || status == 0)) {
if (status)
- dev_printk(KERN_ERR, host->dev,
- ": IRQ status == 0xffffffff, "
- "PCI fault or device removal?\n");
+ dev_err(host->dev,
+ ": IRQ status == 0xffffffff, PCI fault or device removal?\n");
goto out;
}
@@ -282,14 +282,8 @@ static irqreturn_t vsc_sata_interrupt(int irq, void *dev_instance)
for (i = 0; i < host->n_ports; i++) {
u8 port_status = (status >> (8 * i)) & 0xff;
if (port_status) {
- struct ata_port *ap = host->ports[i];
-
- if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
- vsc_port_intr(port_status, ap);
- handled++;
- } else
- dev_printk(KERN_ERR, host->dev,
- "interrupt from disabled port %d\n", i);
+ vsc_port_intr(port_status, host->ports[i]);
+ handled++;
}
}
@@ -306,6 +300,9 @@ static struct scsi_host_template vsc_sata_sht = {
static struct ata_port_operations vsc_sata_ops = {
.inherits = &ata_bmdma_port_ops,
+ /* The IRQ handling is not quite standard SFF behaviour so we
+ cannot use the default lost interrupt handler */
+ .lost_interrupt = ATA_OP_NULL,
.sff_tf_load = vsc_sata_tf_load,
.sff_tf_read = vsc_sata_tf_read,
.freeze = vsc_freeze,
@@ -314,8 +311,7 @@ static struct ata_port_operations vsc_sata_ops = {
.scr_write = vsc_sata_scr_write,
};
-static void __devinit vsc_sata_setup_port(struct ata_ioports *port,
- void __iomem *base)
+static void vsc_sata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr = base + VSC_SATA_TF_CMD_OFFSET;
port->data_addr = base + VSC_SATA_TF_DATA_OFFSET;
@@ -337,26 +333,23 @@ static void __devinit vsc_sata_setup_port(struct ata_ioports *port,
}
-static int __devinit vsc_sata_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int vsc_sata_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
static const struct ata_port_info pi = {
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
+ .flags = ATA_FLAG_SATA,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &vsc_sata_ops,
};
const struct ata_port_info *ppi[] = { &pi, NULL };
- static int printed_version;
struct ata_host *host;
void __iomem *mmio_base;
int i, rc;
u8 cls;
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ ata_print_version_once(&pdev->dev, DRV_VERSION);
/* allocate host */
host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);
@@ -371,7 +364,7 @@ static int __devinit vsc_sata_init_one(struct pci_dev *pdev,
if (pci_resource_len(pdev, 0) == 0)
return -ENODEV;
- /* map IO regions and intialize host accordingly */
+ /* map IO regions and initialize host accordingly */
rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME);
if (rc == -EBUSY)
pcim_pin_device(pdev);
@@ -394,10 +387,10 @@ static int __devinit vsc_sata_init_one(struct pci_dev *pdev,
/*
* Use 32 bit DMA mask, because 64 bit address support is poor.
*/
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc)
return rc;
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc)
return rc;
@@ -441,21 +434,10 @@ static struct pci_driver vsc_sata_pci_driver = {
.remove = ata_pci_remove_one,
};
-static int __init vsc_sata_init(void)
-{
- return pci_register_driver(&vsc_sata_pci_driver);
-}
-
-static void __exit vsc_sata_exit(void)
-{
- pci_unregister_driver(&vsc_sata_pci_driver);
-}
+module_pci_driver(vsc_sata_pci_driver);
MODULE_AUTHOR("Jeremy Higdon");
MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, vsc_sata_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-
-module_init(vsc_sata_init);
-module_exit(vsc_sata_exit);