summaryrefslogtreecommitdiff
path: root/drivers/ata
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2013-11-01 21:17:16 (GMT)
committerScott Wood <scottwood@freescale.com>2013-11-03 22:47:10 (GMT)
commit31110de40dca4d4aeff4f253b3def948b88fa590 (patch)
tree0d811783836d52f15e37b4244de54f44ed4f93ad /drivers/ata
parentae60d5d27c429b13cf28a09ab8b9d30682433c5a (diff)
parent8bb495e3f02401ee6f76d1b1d77f3ac9f079e376 (diff)
downloadlinux-fsl-qoriq-31110de40dca4d4aeff4f253b3def948b88fa590.tar.xz
Merge tag 'v3.10' into sdk-kernel-3.10
git rebase --continue Linux 3.10 Conflicts: Documentation/virtual/kvm/api.txt arch/ia64/kvm/Makefile arch/powerpc/Kconfig arch/powerpc/Makefile arch/powerpc/boot/dts/b4420qds.dts arch/powerpc/boot/dts/b4860qds.dts arch/powerpc/boot/dts/b4qds.dts arch/powerpc/boot/dts/fsl/b4420si-post.dtsi arch/powerpc/boot/dts/fsl/b4420si-pre.dtsi arch/powerpc/boot/dts/fsl/b4860si-post.dtsi arch/powerpc/boot/dts/fsl/b4860si-pre.dtsi arch/powerpc/boot/dts/fsl/b4si-post.dtsi arch/powerpc/boot/dts/fsl/p1010si-post.dtsi arch/powerpc/boot/dts/fsl/p2041si-post.dtsi arch/powerpc/boot/dts/fsl/p3041si-post.dtsi arch/powerpc/boot/dts/fsl/p4080si-post.dtsi arch/powerpc/boot/dts/fsl/p5020si-post.dtsi arch/powerpc/boot/dts/fsl/p5040si-post.dtsi arch/powerpc/boot/dts/fsl/qonverge-usb2-dr-0.dtsi arch/powerpc/boot/dts/fsl/qoriq-sec5.0-0.dtsi arch/powerpc/boot/dts/fsl/t4240si-post.dtsi arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi arch/powerpc/boot/dts/p1025rdb_36b.dts arch/powerpc/boot/dts/t4240qds.dts arch/powerpc/configs/corenet64_smp_defconfig arch/powerpc/configs/mpc85xx_defconfig arch/powerpc/configs/mpc85xx_smp_defconfig arch/powerpc/include/asm/cputable.h arch/powerpc/include/asm/kvm_host.h arch/powerpc/include/asm/kvm_ppc.h arch/powerpc/include/asm/machdep.h arch/powerpc/include/uapi/asm/kvm.h arch/powerpc/kernel/cpu_setup_fsl_booke.S arch/powerpc/kernel/cputable.c arch/powerpc/kernel/idle.c arch/powerpc/kernel/pci-common.c arch/powerpc/kvm/Kconfig arch/powerpc/kvm/book3s.c arch/powerpc/kvm/booke.c arch/powerpc/kvm/e500.c arch/powerpc/kvm/e500_mmu.c arch/powerpc/kvm/e500_mmu_host.c arch/powerpc/kvm/e500mc.c arch/powerpc/kvm/emulate.c arch/powerpc/kvm/irq.h arch/powerpc/kvm/mpic.c arch/powerpc/kvm/powerpc.c arch/powerpc/mm/tlb_nohash.c arch/powerpc/platforms/85xx/Kconfig arch/powerpc/platforms/85xx/b4_qds.c arch/powerpc/platforms/85xx/t4240_qds.c arch/powerpc/platforms/pseries/smp.c arch/powerpc/sysdev/fsl_85xx_l2ctlr.c arch/powerpc/sysdev/fsl_msi.c arch/powerpc/sysdev/fsl_pci.c arch/powerpc/sysdev/fsl_pci.h arch/powerpc/sysdev/mpic.c arch/x86/kvm/Makefile arch/x86/kvm/x86.c drivers/Kconfig drivers/clk/Kconfig drivers/cpufreq/Makefile drivers/crypto/caam/caamalg.c drivers/crypto/caam/intern.h drivers/crypto/caam/jr.c drivers/crypto/caam/regs.h drivers/infiniband/ulp/ipoib/ipoib_ethtool.c drivers/iommu/Makefile drivers/iommu/amd_iommu.c drivers/iommu/exynos-iommu.c drivers/iommu/intel-iommu.c drivers/iommu/iommu.c drivers/iommu/msm_iommu.c drivers/iommu/omap-iommu.c drivers/iommu/tegra-gart.c drivers/iommu/tegra-smmu.c drivers/misc/Makefile drivers/mmc/card/block.c drivers/mmc/card/queue.c drivers/mmc/core/core.c drivers/mtd/nand/fsl_ifc_nand.c drivers/net/ethernet/3com/3c501.c drivers/net/ethernet/8390/3c503.c drivers/net/ethernet/dec/ewrk3.c drivers/net/ethernet/freescale/fec.c drivers/net/ethernet/freescale/gianfar.c drivers/net/ethernet/freescale/gianfar.h drivers/net/ethernet/i825xx/3c505.c drivers/net/ethernet/i825xx/3c507.c drivers/rtc/rtc-ds3232.c drivers/s390/net/qeth_core_main.c drivers/staging/Kconfig drivers/staging/Makefile drivers/staging/ccg/u_ether.c drivers/usb/gadget/fsl_udc_core.c drivers/usb/otg/fsl_otg.c drivers/vfio/vfio.c drivers/watchdog/Kconfig include/linux/iommu.h include/linux/kvm_host.h include/linux/mmc/sdhci.h include/linux/msi.h include/linux/netdev_features.h include/linux/pci.h include/linux/skbuff.h include/net/ip6_route.h include/net/sch_generic.h include/net/xfrm.h include/uapi/linux/kvm.h net/core/netpoll.c virt/kvm/irqchip.c virt/kvm/kvm_main.c
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/Kconfig48
-rw-r--r--drivers/ata/Makefile2
-rw-r--r--drivers/ata/acard-ahci.c2
-rw-r--r--drivers/ata/ahci.c133
-rw-r--r--drivers/ata/ahci.h8
-rw-r--r--drivers/ata/ata_piix.c52
-rw-r--r--drivers/ata/libahci.c120
-rw-r--r--drivers/ata/libata-acpi.c307
-rw-r--r--drivers/ata/libata-core.c82
-rw-r--r--drivers/ata/libata-eh.c29
-rw-r--r--drivers/ata/libata-scsi.c37
-rw-r--r--drivers/ata/libata-sff.c2
-rw-r--r--drivers/ata/libata-zpodd.c299
-rw-r--r--drivers/ata/libata.h29
-rw-r--r--drivers/ata/pata_arasan_cf.c37
-rw-r--r--drivers/ata/pata_at32.c13
-rw-r--r--drivers/ata/pata_ep93xx.c12
-rw-r--r--drivers/ata/pata_imx.c36
-rw-r--r--drivers/ata/pata_legacy.c2
-rw-r--r--drivers/ata/pata_mpc52xx.c6
-rw-r--r--drivers/ata/pata_octeon_cf.c2
-rw-r--r--drivers/ata/pata_pcmcia.c14
-rw-r--r--drivers/ata/pata_pdc2027x.c2
-rw-r--r--drivers/ata/pata_samsung_cf.c17
-rw-r--r--drivers/ata/pdc_adma.c2
-rw-r--r--drivers/ata/sata_fsl.c5
-rw-r--r--drivers/ata/sata_highbank.c4
-rw-r--r--drivers/ata/sata_promise.c2
-rw-r--r--drivers/ata/sata_rcar.c911
-rw-r--r--drivers/ata/sata_sil.c2
-rw-r--r--drivers/ata/sata_svw.c29
-rw-r--r--drivers/ata/sata_sx4.c2
-rw-r--r--drivers/ata/sata_via.c2
33 files changed, 1893 insertions, 357 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index e08d322..a5a3ebc 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -14,7 +14,7 @@ menuconfig ATA
tristate "Serial ATA and Parallel ATA drivers"
depends on HAS_IOMEM
depends on BLOCK
- depends on !(M32R || M68K) || 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
@@ -58,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
+ 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
@@ -163,7 +177,7 @@ config SATA_QSTOR
config SATA_SX4
tristate "Promise SATA SX4 support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables support for Promise Serial ATA SX4.
@@ -247,6 +261,14 @@ config SATA_PROMISE
If unsure, say N.
+config SATA_RCAR
+ tristate "Renesas R-Car SATA support"
+ depends on ARCH_SHMOBILE && ARCH_R8A7779
+ help
+ This option enables support for Renesas R-Car Serial ATA.
+
+ If unsure, say N.
+
config SATA_SIL
tristate "Silicon Image SATA support"
depends on PCI
@@ -390,7 +412,7 @@ config PATA_CS5530
config PATA_CS5535
tristate "CS5535 PATA support (Experimental)"
- depends on PCI && X86 && !X86_64 && EXPERIMENTAL
+ depends on PCI && X86 && !X86_64
help
This option enables support for the NatSemi/AMD CS5535
companion chip used with the Geode processor family.
@@ -408,7 +430,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
@@ -496,7 +518,7 @@ config PATA_IMX
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.
@@ -589,7 +611,7 @@ config PATA_OLDPIIX
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
@@ -616,7 +638,7 @@ config PATA_PDC_OLD
config PATA_RADISYS
tristate "RADISYS 82600 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables support for the RADISYS 82600
PATA controllers via the new ATA layer
@@ -687,7 +709,7 @@ config PATA_SIS
config PATA_TOSHIBA
tristate "Toshiba Piccolo support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
Support for the Toshiba Piccolo controllers. Currently only the
primary channel is supported by this driver.
@@ -738,7 +760,7 @@ comment "PIO-only SFF controllers"
config PATA_AT32
tristate "Atmel AVR32 PATA support (Experimental)"
- depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL
+ depends on AVR32 && PLATFORM_AT32AP
help
This option enables support for the IDE devices on the
Atmel AT32AP platform.
@@ -755,7 +777,7 @@ config PATA_AT91
config PATA_CMD640_PCI
tristate "CMD640 PCI PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables support for the CMD640 PCI IDE
interface chip. Only the primary channel is currently
@@ -801,7 +823,7 @@ config PATA_NS87410
config PATA_OPTI
tristate "OPTI621/6215 PATA support (Very Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI
help
This option enables full PIO support for the early Opti ATA
controllers found on some old motherboards.
@@ -881,7 +903,7 @@ config PATA_SAMSUNG_CF
config PATA_WINBOND_VLB
tristate "Winbond W83759A VLB PATA support (Experimental)"
- depends on ISA && EXPERIMENTAL
+ depends on ISA
select PATA_LEGACY
help
Support for the Winbond W83759A controller on Vesa Local Bus
@@ -909,7 +931,7 @@ config ATA_GENERIC
config PATA_LEGACY
tristate "Legacy ISA PATA support (Experimental)"
- depends on (ISA || PCI) && 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.
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 9329daf..c04d0fd 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -23,6 +23,7 @@ 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_RCAR) += sata_rcar.o
obj-$(CONFIG_SATA_SIL) += sata_sil.o
obj-$(CONFIG_SATA_SIS) += sata_sis.o
obj-$(CONFIG_SATA_SVW) += sata_svw.o
@@ -107,3 +108,4 @@ 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
index 4e94ba2..9d0cf01 100644
--- a/drivers/ata/acard-ahci.c
+++ b/drivers/ata/acard-ahci.c
@@ -2,7 +2,7 @@
/*
* acard-ahci.c - ACard 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.
*
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 4979127..2b50dfd 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.
*
@@ -265,6 +265,32 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ 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 */
/* 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,
@@ -389,17 +415,19 @@ static const struct pci_device_id ahci_pci_tbl[] = {
/* Marvell */
{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */
{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */
- { PCI_DEVICE(0x1b4b, 0x9123),
+ { 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(0x1b4b, 0x9125),
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9125),
.driver_data = board_ahci_yes_fbs }, /* 88se9125 */
- { PCI_DEVICE(0x1b4b, 0x917a),
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),
.driver_data = board_ahci_yes_fbs }, /* 88se9172 */
- { PCI_DEVICE(0x1b4b, 0x9192),
+ { 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(0x1b4b, 0x91a3),
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),
.driver_data = board_ahci_yes_fbs },
/* Promise */
@@ -1061,6 +1089,86 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
{}
#endif
+int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
+{
+ int rc;
+ unsigned int maxvec;
+
+ if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) {
+ rc = pci_enable_msi_block_auto(pdev, &maxvec);
+ if (rc > 0) {
+ if ((rc == maxvec) || (rc == 1))
+ return rc;
+ /*
+ * Assume that advantage of multipe MSIs is negated,
+ * so fallback to single MSI mode to save resources
+ */
+ pci_disable_msi(pdev);
+ if (!pci_enable_msi(pdev))
+ return 1;
+ }
+ }
+
+ 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++) {
+ rc = devm_request_threaded_irq(host->dev,
+ irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
+ dev_driver_string(host->dev), 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)
{
unsigned int board_id = ent->driver_data;
@@ -1069,7 +1177,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
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");
@@ -1156,11 +1264,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ahci_sb600_enable_64bit(pdev))
hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
- if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
- pci_intx(pdev, 1);
-
hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
+ n_msis = ahci_init_interrupts(pdev, hpriv);
+ if (n_msis > 1)
+ hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
+
/* save initial config */
ahci_pci_save_initial_config(pdev, hpriv);
@@ -1256,6 +1365,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
ahci_pci_print_info(host);
pci_set_master(pdev);
+
+ if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
+ return ahci_host_activate(host, pdev->irq, n_msis);
+
return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
&ahci_sht);
}
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 9be4712..10b14d4 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -1,7 +1,7 @@
/*
* ahci.h - Common AHCI SATA definitions and declarations
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -231,6 +231,7 @@ enum {
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 */
/* ap->flags bits */
@@ -297,6 +298,8 @@ struct ahci_port_priv {
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 */
@@ -359,7 +362,10 @@ 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);
static inline void __iomem *__ahci_port_base(struct ata_host *host,
unsigned int port_no)
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 174eca6..9a8a674 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.
*
@@ -150,6 +150,8 @@ enum piix_controller_ids {
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 {
@@ -304,7 +306,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* 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 },
+ { 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) */
@@ -317,6 +319,26 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 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 },
+ /* 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 },
+
{ } /* terminate list */
};
@@ -422,6 +444,8 @@ static const struct piix_map_db *piix_map_db_table[] = {
[ich8m_apple_sata] = &ich8m_apple_map_db,
[tolapai_sata] = &tolapai_map_db,
[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[] = {
@@ -1225,6 +1249,26 @@ static struct ata_port_info piix_port_info[] = {
.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
@@ -1530,6 +1574,10 @@ static bool piix_broken_system_poweroff(struct pci_dev *pdev)
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)
{
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 6cd7805..a70ff15 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -1,7 +1,7 @@
/*
* libahci.c - Common AHCI SATA low-level routines
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -1655,19 +1655,16 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
ata_port_abort(ap);
}
-static void ahci_port_intr(struct ata_port *ap)
+static void ahci_handle_port_interrupt(struct ata_port *ap,
+ void __iomem *port_mmio, u32 status)
{
- 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 = 0;
+ u32 qc_active = 0;
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;
@@ -1743,6 +1740,107 @@ static void ahci_port_intr(struct ata_port *ap)
}
}
+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);
+
+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;
@@ -2196,6 +2294,14 @@ static int ahci_port_start(struct ata_port *ap)
*/
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 */
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index ef01ac0..cf4e702 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -60,7 +60,8 @@ acpi_handle ata_ap_acpi_handle(struct ata_port *ap)
if (ap->flags & ATA_FLAG_ACPI_SATA)
return NULL;
- return acpi_get_child(DEVICE_ACPI_HANDLE(ap->host->dev), ap->port_no);
+ return ap->scsi_host ?
+ DEVICE_ACPI_HANDLE(&ap->scsi_host->shost_gendev) : NULL;
}
EXPORT_SYMBOL(ata_ap_acpi_handle);
@@ -76,7 +77,7 @@ acpi_handle ata_dev_acpi_handle(struct ata_device *dev)
acpi_integer adr;
struct ata_port *ap = dev->link->ap;
- if (dev->flags & ATA_DFLAG_ACPI_DISABLED)
+ if (libata_noacpi || dev->flags & ATA_DFLAG_ACPI_DISABLED)
return NULL;
if (ap->flags & ATA_FLAG_ACPI_SATA) {
@@ -155,8 +156,10 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
spin_unlock_irqrestore(ap->lock, flags);
- if (wait)
+ if (wait) {
ata_port_wait_eh(ap);
+ flush_work(&ap->hotplug_task.work);
+ }
}
static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
@@ -213,6 +216,39 @@ static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
.uevent = ata_acpi_ap_uevent,
};
+void ata_acpi_hotplug_init(struct ata_host *host)
+{
+ int i;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ acpi_handle handle;
+ struct ata_device *dev;
+
+ if (!ap)
+ continue;
+
+ handle = ata_ap_acpi_handle(ap);
+ if (handle) {
+ /* we might be on a docking station */
+ register_hotplug_dock_device(handle,
+ &ata_acpi_ap_dock_ops, ap,
+ NULL, NULL);
+ }
+
+ ata_for_each_dev(dev, &ap->link, ALL) {
+ handle = ata_dev_acpi_handle(dev);
+ if (!handle)
+ continue;
+
+ /* we might be on a docking station */
+ register_hotplug_dock_device(handle,
+ &ata_acpi_dev_dock_ops,
+ dev, NULL, NULL);
+ }
+ }
+}
+
/**
* ata_acpi_dissociate - dissociate ATA host from ACPI objects
* @host: target ATA host
@@ -239,28 +275,15 @@ void ata_acpi_dissociate(struct ata_host *host)
}
}
-/**
- * ata_acpi_gtm - execute _GTM
- * @ap: target ATA port
- * @gtm: out parameter for _GTM result
- *
- * Evaluate _GTM and store the result in @gtm.
- *
- * LOCKING:
- * EH context.
- *
- * RETURNS:
- * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
- */
-int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)
+static int __ata_acpi_gtm(struct ata_port *ap, acpi_handle handle,
+ struct ata_acpi_gtm *gtm)
{
struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER };
union acpi_object *out_obj;
acpi_status status;
int rc = 0;
- status = acpi_evaluate_object(ata_ap_acpi_handle(ap), "_GTM", NULL,
- &output);
+ status = acpi_evaluate_object(handle, "_GTM", NULL, &output);
rc = -ENOENT;
if (status == AE_NOT_FOUND)
@@ -294,6 +317,27 @@ int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)
return rc;
}
+/**
+ * ata_acpi_gtm - execute _GTM
+ * @ap: target ATA port
+ * @gtm: out parameter for _GTM result
+ *
+ * Evaluate _GTM and store the result in @gtm.
+ *
+ * LOCKING:
+ * EH context.
+ *
+ * RETURNS:
+ * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
+ */
+int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)
+{
+ if (ata_ap_acpi_handle(ap))
+ return __ata_acpi_gtm(ap, ata_ap_acpi_handle(ap), gtm);
+ else
+ return -EINVAL;
+}
+
EXPORT_SYMBOL_GPL(ata_acpi_gtm);
/**
@@ -835,50 +879,95 @@ 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->sdev->sdev_gendev,
+ 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;
- /* channel first and then drives for power on and vica versa
- for power off */
- handle = ata_ap_acpi_handle(ap);
- if (handle && state.event == PM_EVENT_ON)
- acpi_bus_set_power(handle, ACPI_STATE_D0);
-
ata_for_each_dev(dev, &ap->link, ENABLED) {
handle = ata_dev_acpi_handle(dev);
if (!handle)
continue;
- if (state.event != PM_EVENT_ON) {
- acpi_state = acpi_pm_device_sleep_state(
- &dev->sdev->sdev_gendev, NULL, ACPI_STATE_D3);
- if (acpi_state > 0)
- acpi_bus_set_power(handle, acpi_state);
- /* TBD: need to check if it's runtime pm request */
- acpi_pm_device_run_wake(
- &dev->sdev->sdev_gendev, true);
+ 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 {
- /* Ditto */
- acpi_pm_device_run_wake(
- &dev->sdev->sdev_gendev, false);
+ 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;
+
+ port_handle = ata_ap_acpi_handle(ap);
+ if (!port_handle)
+ return;
+
+ /* channel first and then drives for power on and vica versa
+ for power off */
+ if (state.event & PM_EVENT_RESUME)
+ acpi_bus_set_power(port_handle, ACPI_STATE_D0);
- handle = ata_ap_acpi_handle(ap);
- if (handle && state.event != PM_EVENT_ON)
- acpi_bus_set_power(handle, ACPI_STATE_D3);
+ 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);
+ }
+
+ if (!(state.event & PM_EVENT_RESUME))
+ acpi_bus_set_power(port_handle, ACPI_STATE_D3);
+}
+
+/**
+ * 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);
}
/**
@@ -974,99 +1063,6 @@ void ata_acpi_on_disable(struct ata_device *dev)
ata_acpi_clear_gtf(dev);
}
-static void ata_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
-{
- struct ata_device *ata_dev = context;
-
- if (event == ACPI_NOTIFY_DEVICE_WAKE && ata_dev &&
- pm_runtime_suspended(&ata_dev->sdev->sdev_gendev))
- scsi_autopm_get_device(ata_dev->sdev);
-}
-
-static void ata_acpi_add_pm_notifier(struct ata_device *dev)
-{
- struct acpi_device *acpi_dev;
- acpi_handle handle;
- acpi_status status;
-
- handle = ata_dev_acpi_handle(dev);
- if (!handle)
- return;
-
- status = acpi_bus_get_device(handle, &acpi_dev);
- if (ACPI_FAILURE(status))
- return;
-
- if (dev->sdev->can_power_off) {
- acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- ata_acpi_wake_dev, dev);
- device_set_run_wake(&dev->sdev->sdev_gendev, true);
- }
-}
-
-static void ata_acpi_remove_pm_notifier(struct ata_device *dev)
-{
- struct acpi_device *acpi_dev;
- acpi_handle handle;
- acpi_status status;
-
- handle = ata_dev_acpi_handle(dev);
- if (!handle)
- return;
-
- status = acpi_bus_get_device(handle, &acpi_dev);
- if (ACPI_FAILURE(status))
- return;
-
- if (dev->sdev->can_power_off) {
- device_set_run_wake(&dev->sdev->sdev_gendev, false);
- acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- ata_acpi_wake_dev);
- }
-}
-
-static void ata_acpi_register_power_resource(struct ata_device *dev)
-{
- struct scsi_device *sdev = dev->sdev;
- acpi_handle handle;
- struct device *device;
-
- handle = ata_dev_acpi_handle(dev);
- if (!handle)
- return;
-
- device = &sdev->sdev_gendev;
-
- acpi_power_resource_register_device(device, handle);
-}
-
-static void ata_acpi_unregister_power_resource(struct ata_device *dev)
-{
- struct scsi_device *sdev = dev->sdev;
- acpi_handle handle;
- struct device *device;
-
- handle = ata_dev_acpi_handle(dev);
- if (!handle)
- return;
-
- device = &sdev->sdev_gendev;
-
- acpi_power_resource_unregister_device(device, handle);
-}
-
-void ata_acpi_bind(struct ata_device *dev)
-{
- ata_acpi_add_pm_notifier(dev);
- ata_acpi_register_power_resource(dev);
-}
-
-void ata_acpi_unbind(struct ata_device *dev)
-{
- ata_acpi_remove_pm_notifier(dev);
- ata_acpi_unregister_power_resource(dev);
-}
-
static int compat_pci_ata(struct ata_port *ap)
{
struct device *dev = ap->tdev.parent;
@@ -1086,7 +1082,7 @@ static int compat_pci_ata(struct ata_port *ap)
static int ata_acpi_bind_host(struct ata_port *ap, acpi_handle *handle)
{
- if (ap->flags & ATA_FLAG_ACPI_SATA)
+ if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA)
return -ENODEV;
*handle = acpi_get_child(DEVICE_ACPI_HANDLE(ap->tdev.parent),
@@ -1095,7 +1091,7 @@ static int ata_acpi_bind_host(struct ata_port *ap, acpi_handle *handle)
if (!*handle)
return -ENODEV;
- if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
+ if (__ata_acpi_gtm(ap, *handle, &ap->__acpi_init_gtm) == 0)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
return 0;
@@ -1105,9 +1101,6 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev,
acpi_handle *handle)
{
struct ata_device *ata_dev;
- acpi_status status;
- struct acpi_device *acpi_dev;
- struct acpi_device_power_state *states;
if (ap->flags & ATA_FLAG_ACPI_SATA) {
if (!sata_pmp_attached(ap))
@@ -1124,21 +1117,6 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev,
if (!*handle)
return -ENODEV;
- status = acpi_bus_get_device(*handle, &acpi_dev);
- if (ACPI_FAILURE(status))
- return 0;
-
- /*
- * If firmware has _PS3 or _PR3 for this device,
- * and this ata ODD device support device attention,
- * it means this device can be powered off
- */
- states = acpi_dev->power.states;
- if ((states[ACPI_STATE_D3_HOT].flags.valid ||
- states[ACPI_STATE_D3_COLD].flags.explicit_set) &&
- ata_dev->flags & ATA_DFLAG_DA)
- sdev->can_power_off = 1;
-
return 0;
}
@@ -1177,13 +1155,8 @@ static int ata_acpi_find_device(struct device *dev, acpi_handle *handle)
return -ENODEV;
}
-static int ata_acpi_find_dummy(struct device *dev, acpi_handle *handle)
-{
- return -ENODEV;
-}
-
static struct acpi_bus_type ata_acpi_bus = {
- .find_bridge = ata_acpi_find_dummy,
+ .name = "ATA",
.find_device = ata_acpi_find_device,
};
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 70c4c28..587353b 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.
*
@@ -1602,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) {
@@ -2344,7 +2350,7 @@ int ata_dev_configure(struct ata_device *dev)
* from SATA Settings page of Identify Device Data Log.
*/
if (ata_id_has_devslp(dev->id)) {
- u8 sata_setting[ATA_SECT_SIZE];
+ u8 *sata_setting = ap->sector_buf;
int i, j;
dev->flags |= ATA_DFLAG_DEVSLP;
@@ -2415,8 +2421,10 @@ int ata_dev_configure(struct ata_device *dev)
dma_dir_string = ", DMADIR";
}
- if (ata_id_has_da(dev->id))
+ 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)
@@ -2452,6 +2460,9 @@ int ata_dev_configure(struct ata_device *dev)
dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
dev->max_sectors);
+ 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);
@@ -4113,6 +4124,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* 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 },
/* Devices we expect to fail diagnostics */
@@ -5346,9 +5358,6 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async)
{
- unsigned int ehi_flags = ATA_EHI_QUIET;
- int rc;
-
/*
* On some hardware, device fails to respond after spun down
* for suspend. As the device won't be used before being
@@ -5357,11 +5366,9 @@ static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int
*
* http://thread.gmane.org/gmane.linux.ide/46764
*/
- if (mesg.event == PM_EVENT_SUSPEND)
- ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
-
- rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
- return rc;
+ unsigned int ehi_flags = ATA_EHI_QUIET | ATA_EHI_NO_AUTOPSY |
+ ATA_EHI_NO_RECOVERY;
+ return ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
}
static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
@@ -5382,40 +5389,38 @@ static int ata_port_suspend(struct device *dev)
static int ata_port_do_freeze(struct device *dev)
{
if (pm_runtime_suspended(dev))
- pm_runtime_resume(dev);
+ return 0;
return ata_port_suspend_common(dev, PMSG_FREEZE);
}
static int ata_port_poweroff(struct device *dev)
{
- if (pm_runtime_suspended(dev))
- return 0;
-
return ata_port_suspend_common(dev, PMSG_HIBERNATE);
}
-static int __ata_port_resume_common(struct ata_port *ap, int *async)
+static int __ata_port_resume_common(struct ata_port *ap, pm_message_t mesg,
+ int *async)
{
int rc;
- rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET,
+ rc = ata_port_request_pm(ap, mesg, ATA_EH_RESET,
ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
return rc;
}
-static int ata_port_resume_common(struct device *dev)
+static int ata_port_resume_common(struct device *dev, pm_message_t mesg)
{
struct ata_port *ap = to_ata_port(dev);
- return __ata_port_resume_common(ap, NULL);
+ return __ata_port_resume_common(ap, mesg, NULL);
}
static int ata_port_resume(struct device *dev)
{
int rc;
- rc = ata_port_resume_common(dev);
+ rc = ata_port_resume_common(dev, PMSG_RESUME);
if (!rc) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
@@ -5425,11 +5430,40 @@ static int ata_port_resume(struct device *dev)
return rc;
}
+/*
+ * 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 pm_runtime_suspend(dev);
}
+static int ata_port_runtime_suspend(struct device *dev)
+{
+ return ata_port_suspend_common(dev, PMSG_AUTO_SUSPEND);
+}
+
+static int ata_port_runtime_resume(struct device *dev)
+{
+ return ata_port_resume_common(dev, PMSG_AUTO_RESUME);
+}
+
static const struct dev_pm_ops ata_port_pm_ops = {
.suspend = ata_port_suspend,
.resume = ata_port_resume,
@@ -5438,8 +5472,8 @@ static const struct dev_pm_ops ata_port_pm_ops = {
.poweroff = ata_port_poweroff,
.restore = ata_port_resume,
- .runtime_suspend = ata_port_suspend,
- .runtime_resume = ata_port_resume_common,
+ .runtime_suspend = ata_port_runtime_suspend,
+ .runtime_resume = ata_port_runtime_resume,
.runtime_idle = ata_port_runtime_idle,
};
@@ -5456,7 +5490,7 @@ EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend);
int ata_sas_port_async_resume(struct ata_port *ap, int *async)
{
- return __ata_port_resume_common(ap, async);
+ return __ata_port_resume_common(ap, PMSG_RESUME, async);
}
EXPORT_SYMBOL_GPL(ata_sas_port_async_resume);
@@ -6129,6 +6163,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
if (rc)
goto err_tadd;
+ ata_acpi_hotplug_init(host);
+
/* set cable, sata_spd_limit and report */
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index bcf4437..c69fcce 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.
*
@@ -1591,7 +1591,7 @@ 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_tur(struct ata_device *dev, u8 *r_sense_key)
+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;
@@ -1624,7 +1624,7 @@ static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
* RETURNS:
* 0 on success, AC_ERR_* mask on failure
*/
-static unsigned int atapi_eh_request_sense(struct ata_device *dev,
+unsigned int atapi_eh_request_sense(struct ata_device *dev,
u8 *sense_buf, u8 dfl_sense_key)
{
u8 cdb[ATAPI_CDB_LEN] =
@@ -3857,6 +3857,8 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
rc = atapi_eh_clear_ua(dev);
if (rc)
goto rest_fail;
+ if (zpodd_dev_enabled(dev))
+ zpodd_post_poweron(dev);
}
}
@@ -4022,11 +4024,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;
}
@@ -4034,6 +4037,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)
@@ -4045,7 +4060,7 @@ 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 */
spin_lock_irqsave(ap->lock, flags);
@@ -4085,7 +4100,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
/* 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;
}
@@ -4104,7 +4119,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
ata_for_each_dev(dev, link, ALL)
ata_ering_clear(&dev->ering);
- ata_acpi_set_state(ap, PMSG_ON);
+ ata_acpi_set_state(ap, ap->pm_mesg);
if (ap->ops->port_resume)
rc = ap->ops->port_resume(ap);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 7c337e7..0101af5 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.
*
@@ -49,6 +49,7 @@
#include <linux/hdreg.h>
#include <linux/uaccess.h>
#include <linux/suspend.h>
+#include <linux/pm_qos.h>
#include <asm/unaligned.h>
#include "libata.h"
@@ -532,8 +533,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;
}
@@ -618,8 +619,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;
}
@@ -933,7 +934,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.
@@ -959,6 +964,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;
}
/*
@@ -1733,10 +1742,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)) {
@@ -2116,7 +2127,6 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)
memcpy(&rbuf[8], "linux ", 8);
memcpy(&rbuf[16], "libata ", 16);
memcpy(&rbuf[32], DRV_VERSION, 4);
- ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);
/* we don't store the ATA device signature, so we fake it */
@@ -3658,7 +3668,9 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
if (!IS_ERR(sdev)) {
dev->sdev = sdev;
scsi_device_put(sdev);
- ata_acpi_bind(dev);
+ if (zpodd_dev_enabled(dev))
+ dev_pm_qos_expose_flags(
+ &sdev->sdev_gendev, 0);
} else {
dev->sdev = NULL;
}
@@ -3755,7 +3767,8 @@ static void ata_scsi_remove_dev(struct ata_device *dev)
mutex_lock(&ap->scsi_host->scan_mutex);
spin_lock_irqsave(ap->lock, flags);
- ata_acpi_unbind(dev);
+ if (zpodd_dev_enabled(dev))
+ zpodd_exit(dev);
/* clearing dev->sdev is protected by host lock */
sdev = dev->sdev;
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index d8af325..b603720 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.
*
diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c
new file mode 100644
index 0000000..90b159b
--- /dev/null
+++ b/drivers/ata/libata-zpodd.c
@@ -0,0 +1,299 @@
+#include <linux/libata.h>
+#include <linux/cdrom.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.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,
+ };
+
+ 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,
+ };
+
+ 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;
+}
+
+static bool odd_can_poweroff(struct ata_device *ata_dev)
+{
+ acpi_handle handle;
+ acpi_status status;
+ struct acpi_device *acpi_dev;
+
+ handle = ata_dev_acpi_handle(ata_dev);
+ if (!handle)
+ return false;
+
+ status = acpi_bus_get_device(handle, &acpi_dev);
+ if (ACPI_FAILURE(status))
+ return false;
+
+ return acpi_device_can_poweroff(acpi_dev);
+}
+
+/* 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->sdev->sdev_gendev, true);
+ acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, 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->sdev->sdev_gendev, false);
+ device_set_run_wake(&dev->sdev->sdev_gendev, 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 = DEVICE_ACPI_HANDLE(&dev->sdev->sdev_gendev);
+ acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, zpodd_wake_dev);
+}
+
+void zpodd_init(struct ata_device *dev)
+{
+ enum odd_mech_type mech_type;
+ struct zpodd *zpodd;
+
+ if (dev->zpodd)
+ return;
+
+ if (!odd_can_poweroff(dev))
+ 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;
+}
+
+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 7148a58..577d902 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -122,6 +122,7 @@ extern int ata_acpi_register(void);
extern void ata_acpi_unregister(void);
extern void ata_acpi_bind(struct ata_device *dev);
extern void ata_acpi_unbind(struct ata_device *dev);
+extern void ata_acpi_hotplug_init(struct ata_host *host);
#else
static inline void ata_acpi_dissociate(struct ata_host *host) { }
static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
@@ -134,6 +135,7 @@ static inline int ata_acpi_register(void) { return 0; }
static inline void ata_acpi_unregister(void) { }
static inline void ata_acpi_bind(struct ata_device *dev) { }
static inline void ata_acpi_unbind(struct ata_device *dev) { }
+static inline void ata_acpi_hotplug_init(struct ata_host *host) {}
#endif
/* libata-scsi.c */
@@ -182,6 +184,9 @@ 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
@@ -230,4 +235,28 @@ 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_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
index 405022d..7638121 100644
--- a/drivers/ata/pata_arasan_cf.c
+++ b/drivers/ata/pata_arasan_cf.c
@@ -209,8 +209,6 @@ struct arasan_cf_dev {
struct dma_chan *dma_chan;
/* Mask for DMA transfers */
dma_cap_mask_t mask;
- /* dma channel private data */
- void *dma_priv;
/* DMA transfer work */
struct work_struct work;
/* DMA delayed finish work */
@@ -308,6 +306,7 @@ static void cf_card_detect(struct arasan_cf_dev *acdev, bool hotplugged)
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;
@@ -325,8 +324,12 @@ static int cf_init(struct arasan_cf_dev *acdev)
spin_lock_irqsave(&acdev->host->lock, flags);
/* configure CF interface clock */
- writel((pdata->cf_if_clk <= CF_IF_CLK_200M) ? pdata->cf_if_clk :
- CF_IF_CLK_166M, acdev->vbase + CLK_CFG);
+ /* 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);
@@ -357,12 +360,6 @@ static void dma_callback(void *dev)
complete(&acdev->dma_completion);
}
-static bool filter(struct dma_chan *chan, void *slave)
-{
- chan->private = slave;
- return true;
-}
-
static inline void dma_complete(struct arasan_cf_dev *acdev)
{
struct ata_queued_cmd *qc = acdev->qc;
@@ -530,8 +527,7 @@ static void data_xfer(struct work_struct *work)
/* request dma channels */
/* dma_request_channel may sleep, so calling from process context */
- acdev->dma_chan = dma_request_channel(acdev->mask, filter,
- acdev->dma_priv);
+ 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;
@@ -798,6 +794,7 @@ static int arasan_cf_probe(struct platform_device *pdev)
struct ata_host *host;
struct ata_port *ap;
struct resource *res;
+ u32 quirk;
irq_handler_t irq_handler = NULL;
int ret = 0;
@@ -817,12 +814,17 @@ static int arasan_cf_probe(struct platform_device *pdev)
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
- pdata->quirk |= CF_BROKEN_MWDMA | CF_BROKEN_UDMA;
+ quirk |= CF_BROKEN_MWDMA | CF_BROKEN_UDMA;
acdev->pbase = res->start;
acdev->vbase = devm_ioremap_nocache(&pdev->dev, res->start,
@@ -859,17 +861,16 @@ static int arasan_cf_probe(struct platform_device *pdev)
INIT_WORK(&acdev->work, data_xfer);
INIT_DELAYED_WORK(&acdev->dwork, delayed_finish);
dma_cap_set(DMA_MEMCPY, acdev->mask);
- acdev->dma_priv = pdata->dma_priv;
/* Handle platform specific quirks */
- if (pdata->quirk) {
- if (pdata->quirk & CF_BROKEN_PIO) {
+ if (quirk) {
+ if (quirk & CF_BROKEN_PIO) {
ap->ops->set_piomode = NULL;
ap->pio_mask = 0;
}
- if (pdata->quirk & CF_BROKEN_MWDMA)
+ if (quirk & CF_BROKEN_MWDMA)
ap->mwdma_mask = 0;
- if (pdata->quirk & CF_BROKEN_UDMA)
+ if (quirk & CF_BROKEN_UDMA)
ap->udma_mask = 0;
}
ap->flags |= ATA_FLAG_PIO_POLLING | ATA_FLAG_NO_ATAPI;
diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c
index 36f189c..8d493b4 100644
--- a/drivers/ata/pata_at32.c
+++ b/drivers/ata/pata_at32.c
@@ -393,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_ep93xx.c b/drivers/ata/pata_ep93xx.c
index 556222f..980b88e 100644
--- a/drivers/ata/pata_ep93xx.c
+++ b/drivers/ata/pata_ep93xx.c
@@ -31,6 +31,7 @@
* Copyright (C) 2006 Tower Technologies
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -932,14 +933,9 @@ static int ep93xx_pata_probe(struct platform_device *pdev)
}
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res) {
- err = -ENXIO;
- goto err_rel_gpio;
- }
-
- ide_base = devm_request_and_ioremap(&pdev->dev, mem_res);
- if (!ide_base) {
- err = -ENXIO;
+ ide_base = devm_ioremap_resource(&pdev->dev, mem_res);
+ if (IS_ERR(ide_base)) {
+ err = PTR_ERR(ide_base);
goto err_rel_gpio;
}
diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c
index 4084944..aa3d166 100644
--- a/drivers/ata/pata_imx.c
+++ b/drivers/ata/pata_imx.c
@@ -37,7 +37,7 @@
struct pata_imx_priv {
struct clk *clk;
/* timings/interrupt/control regs */
- u8 *host_regs;
+ void __iomem *host_regs;
u32 ata_ctl;
};
@@ -98,6 +98,7 @@ static int pata_imx_probe(struct platform_device *pdev)
struct pata_imx_priv *priv;
int irq = 0;
struct resource *io_res;
+ int ret;
io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (io_res == NULL)
@@ -112,7 +113,7 @@ static int pata_imx_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- priv->clk = clk_get(&pdev->dev, NULL);
+ 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);
@@ -121,8 +122,10 @@ static int pata_imx_probe(struct platform_device *pdev)
clk_prepare_enable(priv->clk);
host = ata_host_alloc(&pdev->dev, 1);
- if (!host)
- goto free_priv;
+ if (!host) {
+ ret = -ENOMEM;
+ goto err;
+ }
host->private_data = priv;
ap = host->ports[0];
@@ -135,7 +138,8 @@ static int pata_imx_probe(struct platform_device *pdev)
resource_size(io_res));
if (!priv->host_regs) {
dev_err(&pdev->dev, "failed to map IO/CTL base\n");
- goto free_priv;
+ ret = -EBUSY;
+ goto err;
}
ap->ioaddr.cmd_addr = priv->host_regs + PATA_IMX_DRIVE_DATA;
@@ -158,13 +162,17 @@ static int pata_imx_probe(struct platform_device *pdev)
priv->host_regs + PATA_IMX_ATA_INT_EN);
/* activate */
- return ata_host_activate(host, irq, ata_sff_interrupt, 0,
+ ret = ata_host_activate(host, irq, ata_sff_interrupt, 0,
&pata_imx_sht);
-free_priv:
+ if (ret)
+ goto err;
+
+ return 0;
+err:
clk_disable_unprepare(priv->clk);
- clk_put(priv->clk);
- return -ENOMEM;
+
+ return ret;
}
static int pata_imx_remove(struct platform_device *pdev)
@@ -177,7 +185,6 @@ static int pata_imx_remove(struct platform_device *pdev)
__raw_writel(0, priv->host_regs + PATA_IMX_ATA_INT_EN);
clk_disable_unprepare(priv->clk);
- clk_put(priv->clk);
return 0;
}
@@ -223,11 +230,20 @@ static const struct dev_pm_ops pata_imx_pm_ops = {
};
#endif
+static const struct of_device_id imx_pata_dt_ids[] = {
+ {
+ .compatible = "fsl,imx27-pata",
+ }, {
+ /* sentinel */
+ }
+};
+
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
.pm = &pata_imx_pm_ops,
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 4fe9d21..be81642 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -542,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);
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 652f57e..3a8fb28 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -26,9 +26,9 @@
#include <asm/prom.h>
#include <asm/mpc52xx.h>
-#include <sysdev/bestcomm/bestcomm.h>
-#include <sysdev/bestcomm/bestcomm_priv.h>
-#include <sysdev/bestcomm/ata.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"
diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c
index ff2e57f..e73bef3 100644
--- a/drivers/ata/pata_octeon_cf.c
+++ b/drivers/ata/pata_octeon_cf.c
@@ -926,7 +926,7 @@ static int octeon_cf_probe(struct platform_device *pdev)
goto free_cf_port;
}
cs1 = devm_ioremap_nocache(&pdev->dev, res_cs1->start,
- res_cs1->end - res_cs1->start + 1);
+ resource_size(res_cs1));
if (!cs1)
goto free_cf_port;
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 958238d..40254f4 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -387,21 +387,9 @@ static struct pcmcia_driver pcmcia_driver = {
.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 3f94a88..c76e659 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -63,7 +63,9 @@ enum {
};
static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+#ifdef CONFIG_PM
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);
diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c
index 63ffb00..6ef27e9 100644
--- a/drivers/ata/pata_samsung_cf.c
+++ b/drivers/ata/pata_samsung_cf.c
@@ -512,7 +512,7 @@ static int __init pata_s3c_probe(struct platform_device *pdev)
return -ENOMEM;
}
- info->clk = clk_get(&pdev->dev, "cfcon");
+ 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);
@@ -589,7 +589,6 @@ static int __init pata_s3c_probe(struct platform_device *pdev)
stop_clk:
clk_disable(info->clk);
- clk_put(info->clk);
return ret;
}
@@ -601,7 +600,6 @@ static int __exit pata_s3c_remove(struct platform_device *pdev)
ata_host_detach(host);
clk_disable(info->clk);
- clk_put(info->clk);
return 0;
}
@@ -663,18 +661,7 @@ static struct platform_driver pata_s3c_driver = {
},
};
-static int __init pata_s3c_init(void)
-{
- return platform_driver_probe(&pata_s3c_driver, pata_s3c_probe);
-}
-
-static void __exit pata_s3c_exit(void)
-{
- platform_driver_unregister(&pata_s3c_driver);
-}
-
-module_init(pata_s3c_init);
-module_exit(pata_s3c_exit);
+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");
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 5053333..8ea6e6a 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
*
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index ca754b5..84e0f9b 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -312,7 +312,7 @@ static void fsl_sata_set_irq_coalescing(struct ata_host *host,
intr_coalescing_ticks = ticks;
spin_unlock(&host->lock);
- DPRINTK("intrrupt coalescing, count = 0x%x, ticks = %x\n",
+ 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));
@@ -1573,8 +1573,7 @@ error_exit_with_cleanup:
if (hcr_base)
iounmap(hcr_base);
- if (host_priv)
- kfree(host_priv);
+ kfree(host_priv);
return retval;
}
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index 5dba77c..b20aa96 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -251,7 +251,7 @@ static const struct ata_port_info ahci_highbank_port_info = {
};
static struct scsi_host_template ahci_highbank_platform_sht = {
- AHCI_SHT("highbank-ahci"),
+ AHCI_SHT("sata_highbank"),
};
static const struct of_device_id ahci_of_match[] = {
@@ -418,7 +418,7 @@ static int ahci_highbank_resume(struct device *dev)
}
#endif
-SIMPLE_DEV_PM_OPS(ahci_highbank_pm_ops,
+static SIMPLE_DEV_PM_OPS(ahci_highbank_pm_ops,
ahci_highbank_suspend, ahci_highbank_resume);
static struct platform_driver ahci_highbank_driver = {
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index fb0dd87..958ba2a 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -1,7 +1,7 @@
/*
* sata_promise.c - Promise SATA
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Mikael Pettersson <mikpe@it.uu.se>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
new file mode 100644
index 0000000..249c8a2
--- /dev/null
+++ b/drivers/ata/sata_rcar.c
@@ -0,0 +1,911 @@
+/*
+ * 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/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)
+
+struct sata_rcar_priv {
+ void __iomem *base;
+ struct clk *clk;
+};
+
+static void sata_rcar_phy_initialize(struct sata_rcar_priv *priv)
+{
+ /* idle state */
+ iowrite32(0, priv->base + SATAPHYADDR_REG);
+ /* reset */
+ iowrite32(SATAPHYRESET_PHYRST, priv->base + SATAPHYRESET_REG);
+ udelay(10);
+ /* deassert reset */
+ iowrite32(0, priv->base + SATAPHYRESET_REG);
+}
+
+static void sata_rcar_phy_write(struct sata_rcar_priv *priv, u16 reg, u32 val,
+ int group)
+{
+ int timeout;
+
+ /* deassert reset */
+ iowrite32(0, priv->base + SATAPHYRESET_REG);
+ /* lane 1 */
+ iowrite32(SATAPHYACCEN_PHYLANE, priv->base + SATAPHYACCEN_REG);
+ /* write phy register value */
+ iowrite32(val, priv->base + SATAPHYWDATA_REG);
+ /* set register group */
+ if (group)
+ reg |= SATAPHYADDR_PHYRATEMODE;
+ /* write command */
+ iowrite32(SATAPHYADDR_PHYCMD_WRITE | reg, priv->base + SATAPHYADDR_REG);
+ /* wait for ack */
+ for (timeout = 0; timeout < 100; timeout++) {
+ val = ioread32(priv->base + SATAPHYACK_REG);
+ if (val & SATAPHYACK_PHYACK)
+ break;
+ }
+ if (timeout >= 100)
+ pr_err("%s timeout\n", __func__);
+ /* idle state */
+ iowrite32(0, priv->base + SATAPHYADDR_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;
+
+ /* ack */
+ iowrite32(~SATA_RCAR_INT_MASK, priv->base + SATAINTSTAT_REG);
+
+ ata_sff_thaw(ap);
+
+ /* unmask */
+ iowrite32(0x7ff & ~SATA_RCAR_INT_MASK, priv->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, pi;
+
+ pi = 0;
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ u32 addr, sg_len, 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);
+
+ /* H/w transfer count is only 29 bits long, let's be careful */
+ while (sg_len) {
+ len = sg_len;
+ if (len > 0x1ffffffe)
+ len = 0x1ffffffe;
+
+ prd[pi].addr = cpu_to_le32(addr);
+ prd[pi].flags_len = cpu_to_le32(len);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
+
+ pi++;
+ sg_len -= len;
+ addr += len;
+ }
+ }
+
+ /* end-of-table flag */
+ prd[pi - 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;
+ u32 dmactl;
+ struct sata_rcar_priv *priv = ap->host->private_data;
+
+ /* load PRD table addr. */
+ mb(); /* make sure PRD table writes are visible to controller */
+ iowrite32(ap->bmdma_prd_dma, priv->base + ATAPI_DTB_ADR_REG);
+
+ /* specify data direction, triple-check start bit is clear */
+ dmactl = ioread32(priv->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, priv->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;
+ u32 dmactl;
+ struct sata_rcar_priv *priv = ap->host->private_data;
+
+ /* start host DMA transaction */
+ dmactl = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ dmactl &= ~ATAPI_CONTROL1_STOP;
+ dmactl |= ATAPI_CONTROL1_START;
+ iowrite32(dmactl, priv->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;
+ u32 dmactl;
+
+ /* force termination of DMA transfer if active */
+ dmactl = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ if (dmactl & ATAPI_CONTROL1_START) {
+ dmactl &= ~ATAPI_CONTROL1_START;
+ dmactl |= ATAPI_CONTROL1_STOP;
+ iowrite32(dmactl, priv->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;
+ u32 status;
+ u8 host_stat = 0;
+
+ 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_BMDMA_SHT(DRV_NAME),
+};
+
+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;
+ struct ata_port *ap;
+ unsigned int handled = 0;
+ u32 sataintstat;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ sataintstat = ioread32(priv->base + SATAINTSTAT_REG);
+ sataintstat &= SATA_RCAR_INT_MASK;
+ if (!sataintstat)
+ goto done;
+ /* ack */
+ iowrite32(~sataintstat & 0x7ff, priv->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;
+
+ ap->ops = &sata_rcar_port_ops;
+ ap->pio_mask = ATA_PIO4;
+ ap->udma_mask = ATA_UDMA6;
+ ap->flags |= ATA_FLAG_SATA;
+
+ ioaddr->cmd_addr = priv->base + SDATA_REG;
+ ioaddr->ctl_addr = priv->base + SSDEVCON_REG;
+ ioaddr->scr_addr = priv->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;
+ u32 val;
+
+ /* reset and setup phy */
+ sata_rcar_phy_initialize(priv);
+ sata_rcar_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 0);
+ sata_rcar_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 1);
+ sata_rcar_phy_write(priv, SATAPCTLR3_REG, 0x0000A061, 0);
+ sata_rcar_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 0);
+ sata_rcar_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 1);
+ sata_rcar_phy_write(priv, SATAPCTLR4_REG, 0x28E80000, 0);
+
+ /* SATA-IP reset state */
+ val = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ val |= ATAPI_CONTROL1_RESET;
+ iowrite32(val, priv->base + ATAPI_CONTROL1_REG);
+
+ /* ISM mode, PRD mode, DTEND flag at bit 0 */
+ val = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ val |= ATAPI_CONTROL1_ISM;
+ val |= ATAPI_CONTROL1_DESE;
+ val |= ATAPI_CONTROL1_DTA32M;
+ iowrite32(val, priv->base + ATAPI_CONTROL1_REG);
+
+ /* Release the SATA-IP from the reset state */
+ val = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ val &= ~ATAPI_CONTROL1_RESET;
+ iowrite32(val, priv->base + ATAPI_CONTROL1_REG);
+
+ /* ack and mask */
+ iowrite32(0, priv->base + SATAINTSTAT_REG);
+ iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+ /* enable interrupts */
+ iowrite32(ATAPI_INT_ENABLE_SATAINT, priv->base + ATAPI_INT_ENABLE_REG);
+}
+
+static int sata_rcar_probe(struct platform_device *pdev)
+{
+ struct ata_host *host;
+ struct sata_rcar_priv *priv;
+ struct resource *mem;
+ int irq;
+ int ret = 0;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (mem == NULL)
+ return -EINVAL;
+
+ 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;
+
+ 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_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;
+
+ 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(priv->clk);
+
+ return ret;
+}
+
+static int sata_rcar_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct sata_rcar_priv *priv = host->private_data;
+
+ ata_host_detach(host);
+
+ /* disable interrupts */
+ iowrite32(0, priv->base + ATAPI_INT_ENABLE_REG);
+ /* ack and mask */
+ iowrite32(0, priv->base + SATAINTSTAT_REG);
+ iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+
+ clk_disable(priv->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int sata_rcar_suspend(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_rcar_priv *priv = host->private_data;
+ int ret;
+
+ ret = ata_host_suspend(host, PMSG_SUSPEND);
+ if (!ret) {
+ /* disable interrupts */
+ iowrite32(0, priv->base + ATAPI_INT_ENABLE_REG);
+ /* mask */
+ iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+
+ clk_disable(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;
+
+ clk_enable(priv->clk);
+
+ /* ack and mask */
+ iowrite32(0, priv->base + SATAINTSTAT_REG);
+ iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+ /* enable interrupts */
+ iowrite32(ATAPI_INT_ENABLE_SATAINT, priv->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 of_device_id sata_rcar_match[] = {
+ { .compatible = "renesas,rcar-sata", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sata_rcar_match);
+
+static struct platform_driver sata_rcar_driver = {
+ .probe = sata_rcar_probe,
+ .remove = sata_rcar_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = sata_rcar_match,
+#ifdef CONFIG_PM
+ .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 a7b3167..0ae3ca4 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.
*
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index 08608de..dc4f701 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -322,23 +322,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);
@@ -356,15 +344,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 */
@@ -372,7 +357,7 @@ 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
};
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 7b7127a..9947010 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.
*
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 5913ea9..87f056e 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.
*